Java中的AES加密和C#中的解密

Tes*_*est 5 c# java encryption aes

您好我已使用标准AES算法加密的加密十六进制字符串和密钥.码:

        final String key = "=abcd!#Axd*G!pxP";
        final javax.crypto.spec.SecretKeySpec keySpec = new SecretKeySpec(key.getBytes(), "AES");
        final javax.crypto.Cipher cipher = Cipher.getInstance("AES");
        cipher.init(Cipher.ENCRYPT_MODE, keySpec);
        byte [] encryptedValue = cipher.doFinal(input.getBytes());
        return new String(org.apache.commons.codec.binary.Hex.encodeHex(encryptedValue));
Run Code Online (Sandbox Code Playgroud)

现在我尝试使用C#代码解密它:

            RijndaelManaged rijndaelCipher = new RijndaelManaged();
            // Assumed Mode and padding values.
            rijndaelCipher.Mode = CipherMode.ECB;
            rijndaelCipher.Padding = PaddingMode.None;

            // AssumedKeySize and BlockSize values.
            rijndaelCipher.KeySize = 0x80;
            rijndaelCipher.BlockSize = 0x80;
            // Convert Hex keys to byte Array.
            byte[] encryptedData = hexStringToByteArray(textToDecrypt);

            byte[] pwdBytes = Encoding.Unicode.GetBytes(key);
            byte[] keyBytes = new byte[0x10];
            int len = pwdBytes.Length;
            if (len > keyBytes.Length)
            {
                len = keyBytes.Length;
            }
            Array.Copy(pwdBytes, keyBytes, len);
            rijndaelCipher.Key = keyBytes;
            rijndaelCipher.IV = keyBytes;
            // Decrypt data
            byte[] plainText = rijndaelCipher.CreateDecryptor().TransformFinalBlock(encryptedData, 0, encryptedData.Length);
            str = Encoding.UTF8.GetString(plainText);
Run Code Online (Sandbox Code Playgroud)

    static private byte[] HexToBytes(string str)
    {
        if (str.Length == 0 || str.Length % 2 != 0)
            return new byte[0];
        byte[] buffer = new byte[str.Length / 2];
        char c;
        for (int bx = 0, sx = 0; bx < buffer.Length; ++bx, ++sx)
        {
            // Convert first half of byte   
            c = str[sx];
            buffer[bx] = (byte)((c > '9' ? (c > 'Z' ? (c - 'a' + 10) : (c - 'A' + 10)) : (c - '0')) << 4);
            // Convert second half of byte    
            c = str[++sx];
            buffer[bx] |= (byte)(c > '9' ? (c > 'Z' ? (c - 'a' + 10) : (c - 'A' + 10)) : (c - '0'));
        }
        return buffer;
    } 
Run Code Online (Sandbox Code Playgroud)

但输出并不像预期的那样.请指出我哪里出错了?

Rob*_*ert 8

你的代码有一个大问题:它混合了字符编码!

在Java中,您正在调用key.getBytes(),没有参数.此方法返回UTF-8或CP1252/ISO 8859-1编码数据,具体取决于您的操作系统和Java中的默认字符集.

在C#端你正在使用Encoding.Unicode.GetBytes(key)- .Net中的"Unicode"是双字节字符别名UTF-16(Little-Endian)的同义词.因此,您在C#中使用不同的密钥.

您应该能够通过比较Java和C#中的字节数来查看差异:

Java的: "=abcd!#Axd*G!pxP".getBytes().length = 16

C#: Encoding.Unicode.GetBytes("=abcd!#Axd*G!pxP").Length = 32

我强烈建议您使用字节数组而不是字符串来定义加密密钥.

更新:另一个区别是您在C#中设置初始化向量(IV),而在Java中则没有这样做.当您使用ECB时,不应使用IV,但如果您更改为CBC,例如这会产生很大的不同.

  • ECB只应用于加密密钥和其他可以被认为是随机的数据,请建议对使用相同密钥加密的每个数据使用CBC和不同的IV.指定PKCS#5填充可能更有用; 无填充意味着必须隐式知道编码数据的长度. (2认同)

Chr*_*son 0

我怀疑错误是您没有在这个等式的 Java 方面指定填充或操作模式。我不确定 Java 的 AES 实现默认是什么,但我会在您获取密码时首先指定这两者。例如:

Cipher.getInstance("<algorithm>/<mode of operation>/<padding>");
Run Code Online (Sandbox Code Playgroud)

您需要查找 Java 中 AES 支持的填充方案和操作模式,然后确保将 C# 代码配置为使用完全相同的配置。