在Java中加密和在C#中解密为AES 256位

1.我有java函数加密xml文件并返回加密的String。

/// Java Class import java.security.Key; import javax.crypto.Cipher; import javax.crypto.spec.SecretKeySpec; import org.apache.commons.codec.binary.Base64; public class Crypt { public static String key = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; public static byte[] key_Array = Base64.decodeBase64(key); public static String encrypt(String strToEncrypt) { try { //Cipher _Cipher = Cipher.getInstance("AES"); //Cipher _Cipher = Cipher.getInstance("AES/ECB/PKCS5PADDING"); //Cipher _Cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING"); Key SecretKey = new SecretKeySpec(key_Array, "AES"); Cipher _Cipher = Cipher.getInstance("AES"); _Cipher.init(Cipher.ENCRYPT_MODE, SecretKey); return Base64.encodeBase64String(_Cipher.doFinal(strToEncrypt.getBytes())); } catch (Exception e) { System.out.println("[Exception]:"+e.getMessage()); } return null; } public static void main(String[] args) { StringBuilder sb = new StringBuilder(); sb.append("xml file string ..."); String EncryptedString = encrypt(sb.toString()); System.out.println("[EncryptedString]:"+EncryptedString); } } 

2.我有c#函数解密由java函数加密的消息。

 /// C# Function private static string Decrypt(string encryptedText) { RijndaelManaged aesEncryption = new RijndaelManaged(); aesEncryption.BlockSize = 256; //aesEncryption.KeySize = 256; //aesEncryption.Mode = CipherMode.CBC; //aesEncryption.Padding = PaddingMode.PKCS7; string keyStr = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; //string ivStr = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; byte[] keyArr = Convert.FromBase64String(keyStr); //byte[] ivArr = Convert.FromBase64String(ivStr); aesEncryption.Key = keyArr; //aesEncryption.IV = ivArr; ICryptoTransform decrypto = aesEncryption.CreateDecryptor(); byte[] encryptedBytes = Convert.FromBase64CharArray(encryptedText.ToCharArray(), 0, encryptedText.Length); byte[] decryptedData = decrypto.TransformFinalBlock(encryptedBytes, 0, encryptedBytes.Length); /// CryptographicException: Length of the data to decrypt is invalid. return ASCIIEncoding.UTF8.GetString(decryptedData); } 

Java加密function运行良好。 但问题是C#function,
当我解密时,我收到以下错误消息

 CryptographicException: Length of the data to decrypt is invalid. 

我使用下面的参考搜索了解决方案

  1. Java中的AES加密和C#中的解密
  2. C#/ Java | AES256加密/解密
  3. C#和Java中的加密/解密

但是我仍然面临同样的错误。请问有人给我建议。

更新

我只是改变了我的C#加密function。 以下是我的更改列表

  1. 块大小为128
  2. 密钥大小为256
  3. IV尺寸为16
  4. 密钥大小为32
 /// Updated decrypt function private static string Decrypt(string encryptedText) { RijndaelManaged aesEncryption = new RijndaelManaged(); aesEncryption.BlockSize = 128; aesEncryption.KeySize = 256; //aesEncryption.Mode = CipherMode.CBC; aesEncryption.Padding = PaddingMode.None; string keyStr = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; string ivStr = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; byte[] ivArr = Convert.FromBase64String(ivStr); byte[] IVkey16BytesValue = new byte[16]; Array.Copy(ivArr, IVkey16BytesValue, 16); byte[] keyArr = Convert.FromBase64String(keyStr); byte[] KeyArr32BytesValue = new byte[32]; Array.Copy(keyArr, KeyArr32BytesValue, 32); aesEncryption.IV = IVkey16BytesValue; aesEncryption.Key = KeyArr32BytesValue; ICryptoTransform decrypto = aesEncryption.CreateDecryptor(); byte[] encryptedBytes = Convert.FromBase64CharArray(encryptedText.ToCharArray(), 0, encryptedText.Length); byte[] decryptedData = decrypto.TransformFinalBlock(encryptedBytes, 0, encryptedBytes.Length); return ASCIIEncoding.UTF8.GetString(decryptedData); } 

在这个时候,没有错误发生。 但我得到了解密的消息,我无法阅读。

 g: \0 \td  Y\\符O    \rL  W wHm >f \au    %  0  \ .......... 

请让我再次得到你的建议。

我相信blockSize应该是128,密钥大小是256.keyStr应该是32个字符长,IVstr应该是16个字符长。 这可能有所帮助,因为它描述了为什么128位必须用于块大小以及密钥大小可以是什么。 csrc.nist.gov/publications/fips/fips197/fips-197.pdf

你在解密方法中有这个。

  aesEncryption.Padding = PaddingMode.None; 

我相信你也需要把它放在加密方法中。

另外,为什么不将此方法用于键和IV。

  aes.Key = ASCIIEncoding.ASCII.GetBytes(keyStr); aes.IV = ASCIIEncoding.ASCII.GetBytes(ivStr); 

在我从@deathismyfriend和其他人那里得到非常有用的建议之后,我发现了我在C#Decrypt函数中缺少的东西。所以我改变了我的function如下。

 /// C# Error Fixed Version - CipherMode.ECB public static string keyStr = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; private static string Encrypt(string PlainText) { RijndaelManaged aes = new RijndaelManaged(); aes.BlockSize = 128; aes.KeySize = 256; /// In Java, Same with below code /// Cipher _Cipher = Cipher.getInstance("AES"); // Java Code aes.Mode = CipherMode.ECB; byte[] keyArr = Convert.FromBase64String(keyStr); byte[] KeyArrBytes32Value = new byte[32]; Array.Copy(keyArr, KeyArrBytes32Value, 32); aes.Key = KeyArrBytes32Value; ICryptoTransform encrypto = aes.CreateEncryptor(); byte[] plainTextByte = ASCIIEncoding.UTF8.GetBytes(PlainText); byte[] CipherText = encrypto.TransformFinalBlock(plainTextByte, 0, plainTextByte.Length); return Convert.ToBase64String(CipherText); } private static string Decrypt(string CipherText) { RijndaelManaged aes = new RijndaelManaged(); aes.BlockSize = 128; aes.KeySize = 256; /// In Java, Same with below code /// Cipher _Cipher = Cipher.getInstance("AES"); // Java Code aes.Mode = CipherMode.ECB; byte[] keyArr = Convert.FromBase64String(keyStr); byte[] KeyArrBytes32Value = new byte[32]; Array.Copy(keyArr, KeyArrBytes32Value, 32); aes.Key = KeyArrBytes32Value; ICryptoTransform decrypto = aes.CreateDecryptor(); byte[] encryptedBytes = Convert.FromBase64CharArray(CipherText.ToCharArray(), 0, CipherText.Length); byte[] decryptedData = decrypto.TransformFinalBlock(encryptedBytes, 0, encryptedBytes.Length); return ASCIIEncoding.UTF8.GetString(decryptedData); } 

通过使用上层c#函数,现在我可以解密并读取密文。
以下是我一次又一次收到错误后发现的内容。

 CryptographicException: Padding is invalid and cannot be removed. Solution: _RijndaelManaged.Padding = CipherMode.xxx; ///should toggle here _RijndaelManaged.Padding = PaddingMode.xxx; ///should toggle here CryptographicException: Length of the data to decrypt is invalid. CryptographicException: Specified initialization vector (IV) does not match the block size for this algorithm. Solution 1. _RijndaelManaged.BlockSize = 128; /// Must be 2. _RijndaelManaged.KeySize = 256; /// Must be 3. _RijndaelManaged.Key = Byte Array Size must be 32 in length ( more detail 32*8 = 256 KeySize ) 4. _RijndaelManaged.IV = Byte Array Size must be 16 in length ( more detail 16*8 = 128 BlockSize) 

但是当出于安全原因时,我认为我不应该使用ECB模式。
根据

  1. ECB模式不安全
  2. StackOverFlow链接

所以我在Java和C#中再次修改它。

 // Java code - Cipher mode CBC version. // CBC version need Initialization vector IV. // Reference from https://stackoverflow.com/questions/6669181/why-does-my-aes-encryption-throws-an-invalidkeyexception/6669812#6669812 import java.security.Key; import javax.crypto.Cipher; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; import org.apache.commons.codec.binary.Base64; public class CryptoSecurity { public static String key = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; public static byte[] key_Array = Base64.decodeBase64(key); public static String encrypt(String strToEncrypt) { try { //Cipher _Cipher = Cipher.getInstance("AES"); //Cipher _Cipher = Cipher.getInstance("AES/ECB/PKCS5PADDING"); Cipher _Cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING"); // Initialization vector. // It could be any value or generated using a random number generator. byte[] iv = { 1, 2, 3, 4, 5, 6, 6, 5, 4, 3, 2, 1, 7, 7, 7, 7 }; IvParameterSpec ivspec = new IvParameterSpec(iv); Key SecretKey = new SecretKeySpec(key_Array, "AES"); _Cipher.init(Cipher.ENCRYPT_MODE, SecretKey, ivspec); return Base64.encodeBase64String(_Cipher.doFinal(strToEncrypt.getBytes())); } catch (Exception e) { System.out.println("[Exception]:"+e.getMessage()); } return null; } public static String decrypt(String EncryptedMessage) { try { //Cipher _Cipher = Cipher.getInstance("AES"); //Cipher _Cipher = Cipher.getInstance("AES/ECB/PKCS5PADDING"); Cipher _Cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING"); // Initialization vector. // It could be any value or generated using a random number generator. byte[] iv = { 1, 2, 3, 4, 5, 6, 6, 5, 4, 3, 2, 1, 7, 7, 7, 7 }; IvParameterSpec ivspec = new IvParameterSpec(iv); Key SecretKey = new SecretKeySpec(key_Array, "AES"); _Cipher.init(Cipher.DECRYPT_MODE, SecretKey, ivspec); byte DecodedMessage[] = Base64.decodeBase64(EncryptedMessage); return new String(_Cipher.doFinal(DecodedMessage)); } catch (Exception e) { System.out.println("[Exception]:"+e.getMessage()); } return null; } public static void main(String[] args) { // TODO Auto-generated method stub StringBuilder sb = new StringBuilder(); sb.append("xml file string ..."); String outputOfEncrypt = encrypt(sb.toString()); System.out.println("[CryptoSecurity.outputOfEncrypt]:"+outputOfEncrypt); String outputOfDecrypt = decrypt(outputOfEncrypt); //String outputOfDecrypt = decrypt(sb.toString()); System.out.println("[CryptoSecurity.outputOfDecrypt]:"+outputOfDecrypt); } } 

在C#中,我将其修改如下。

 // C# Code, CipherMode.CBC // CBC version need Initialization vector IV. public static string keyStr = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; private static string Encrypt(string PlainText) { RijndaelManaged aes = new RijndaelManaged(); aes.BlockSize = 128; aes.KeySize = 256; // It is equal in java /// Cipher _Cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING"); aes.Mode = CipherMode.CBC; aes.Padding = PaddingMode.PKCS7; byte[] keyArr = Convert.FromBase64String(keyStr); byte[] KeyArrBytes32Value = new byte[32]; Array.Copy(keyArr, KeyArrBytes32Value, 32); // Initialization vector. // It could be any value or generated using a random number generator. byte[] ivArr = { 1, 2, 3, 4, 5, 6, 6, 5, 4, 3, 2, 1, 7, 7, 7, 7 }; byte[] IVBytes16Value = new byte[16]; Array.Copy(ivArr, IVBytes16Value, 16); aes.Key = KeyArrBytes32Value; aes.IV = IVBytes16Value; ICryptoTransform encrypto = aes.CreateEncryptor(); byte[] plainTextByte = ASCIIEncoding.UTF8.GetBytes(PlainText); byte[] CipherText = encrypto.TransformFinalBlock(plainTextByte, 0, plainTextByte.Length); return Convert.ToBase64String(CipherText); } private static string Decrypt(string CipherText) { RijndaelManaged aes = new RijndaelManaged(); aes.BlockSize = 128; aes.KeySize = 256; aes.Mode = CipherMode.CBC; aes.Padding = PaddingMode.PKCS7; byte[] keyArr = Convert.FromBase64String(keyStr); byte[] KeyArrBytes32Value = new byte[32]; Array.Copy(keyArr, KeyArrBytes32Value, 32); // Initialization vector. // It could be any value or generated using a random number generator. byte[] ivArr = { 1, 2, 3, 4, 5, 6, 6, 5, 4, 3, 2, 1, 7, 7, 7, 7 }; byte[] IVBytes16Value = new byte[16]; Array.Copy(ivArr, IVBytes16Value, 16); aes.Key = KeyArrBytes32Value; aes.IV = IVBytes16Value; ICryptoTransform decrypto = aes.CreateDecryptor(); byte[] encryptedBytes = Convert.FromBase64CharArray(CipherText.ToCharArray(), 0, CipherText.Length); byte[] decryptedData = decrypto.TransformFinalBlock(encryptedBytes, 0, encryptedBytes.Length); return ASCIIEncoding.UTF8.GetString(decryptedData); } 

现在一切正常。
有关AES的更多详细信息, 请单击 @deathismyfriend给出的链接。
它也非常有用。

在我最近的一个项目中,我的任务是建立一个带有加密部分的URL以传递到另一个网站。 他们在服务器上运行java,而我们用c#开发。

我知道这不是你要创建的任务的完全匹配,但希望这可以帮助那些试图找到答案的人:)

我从他们的开发人员那里收到了以下内容来构建我们的加密

在此处输入图像描述

为了在c#中实现这一点,我做了以下事情:

  public String Encrypt(String plainText, String key) { var plainBytes = Encoding.UTF8.GetBytes(plainText); return Convert.ToBase64String(Encrypt(plainBytes, GetRijndaelManaged(key))); } private RijndaelManaged GetRijndaelManaged(String secretKey) { var keyBytes = new byte[16]; var secretKeyBytes = Encoding.ASCII.GetBytes(secretKey); Array.Copy(secretKeyBytes, keyBytes, Math.Min(keyBytes.Length, secretKeyBytes.Length)); return new RijndaelManaged { Mode = CipherMode.ECB, Padding = PaddingMode.PKCS7, KeySize = 128, BlockSize = 128, Key = keyBytes, IV = keyBytes }; } private byte[] Encrypt(byte[] plainBytes, RijndaelManaged rijndaelManaged) { return rijndaelManaged.CreateEncryptor() .TransformFinalBlock(plainBytes, 0, plainBytes.Length); }