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

时间:2013-10-31 04:08:38

标签: c# java encryption aes

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加密功能运行良好。但问题是C#功能,当我解密时我得到以下错误信息

CryptographicException: Length of the data to decrypt is invalid.

我使用下面的参考

搜索了解决方案
  1. AES Encryption in Java and Decryption in C#
  2. C# / Java | AES256 encrypt/decrypt
  3. Encyption/Decryption in C# and Java
  4. 但我仍然面临同样的错误。请有人给我建议。

    更新

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

    1. 块大小为128
    2. 密钥大小为256
    3. IV尺寸为16
    4. 密钥大小为32
    5. /// 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��\ ..........
      

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

4 个答案:

答案 0 :(得分:16)

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

/// 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);
}

通过使用upper 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 mode is not secure
  2. StackOverFlow link
  3. 所以我在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的详细信息,{@ 3}}由@deathismyfriend提供。
    它也很有用。

答案 1 :(得分:4)

我认为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);

答案 2 :(得分:2)

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

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

我从他们的开发人员那里收到了以下内容,以便从

中构建加密

enter image description here

要在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);
    }

答案 3 :(得分:1)

我对此算法有问题(仅在Java中),并且做了小小的改动。

Diff Image

// 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
public static String key = "FFClY170hLrhsDnKUEhJ4FhVOnrpNNFFClY170hLrhsDnKUE";
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_Array = Arrays.copyOf(key_Array, 32);

        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_Array = Arrays.copyOf(key_Array, 32);

        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;
}