在Java中加密并在C#中解密用于AES 256位

我有java函数,它加密xml文件并返回加密的字符串。

/// 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.

我通过使用以下参考搜索解决方案

  • Java中的AES加密和C#中的解密
  • C#/ Java | AES256加密/解密
  • 在C#和Java中的加密/解密
  • 但我仍然面临同样的错误。请有人给我建议。

    更新

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

  • 块大小为128
  • 密钥大小为256
  • IV大小为16
  • 密钥大小为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:��td��Y符O����rL��W�wHm�>f�au����%��0�� ..........
    

    请让我再次提出您的建议。


    我相信blockSize应该是128,而keysize是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函数中缺少的东西。所以我改变了我的函数,如下所示。

    /// 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模式。
    根据

  • ECB模式不安全
  • 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);
        }
    
    链接地址: http://www.djcxy.com/p/49161.html

    上一篇: Encrypt in java and Decrypt in C# For AES 256 bit

    下一篇: Downloading Java JDK on Linux via wget is shown license page instead