C# AES解密失败,返回“0”;填充无效,无法删除“;

C# AES解密失败,返回“0”;填充无效,无法删除“;,c#,cryptography,aes,C#,Cryptography,Aes,我正在用Java编写跨平台应用程序,服务器是用Java编写的,所以我最终使用了C#for Windows。 我终于克服了这两种语言(Java:big-endian,C#:little)中的所有障碍,比如大整数的不同endian,所以我也成功地进行了密钥交换。 这就是问题所在,在Java中,我使用AES/CBC/PKCS5Padding进行加密,但在C中,没有可用的PKCS5,但正如我在本主题的其他帖子中所读到的,PKCS7被告知与PKCS5相同,或者Java实际上使用的是PKCS7而不是PKCS

我正在用Java编写跨平台应用程序,服务器是用Java编写的,所以我最终使用了C#for Windows。 我终于克服了这两种语言(Java:big-endian,C#:little)中的所有障碍,比如大整数的不同endian,所以我也成功地进行了密钥交换。 这就是问题所在,在Java中,我使用
AES/CBC/PKCS5Padding
进行加密,但在C中,没有可用的PKCS5,但正如我在本主题的其他帖子中所读到的,PKCS7被告知与PKCS5相同,或者Java实际上使用的是PKCS7而不是PKCS5。我不知道什么是正确的

这就是代码:

using (System.Security.Cryptography.RijndaelManaged rijndael = new System.Security.Cryptography.RijndaelManaged())
{
    byte[] iv = new byte[16];
    for (int i = 0; i < 16; i++)
        iv[i] = 0;
    rijndael.Padding = PaddingMode.PKCS7;
    rijndael.Mode = CipherMode.CBC;
    rijndael.Key = Sys.PrivateKey;
    rijndael.KeySize = 128;
    rijndael.BlockSize = 128;
    rijndael.IV = iv;
    Sys.LogWrite("Decrypt input bytes length: " + buff.Length + ", keyLength: " + Sys.PrivateKey.Length);
    Sys.LogWriteBuffer("Input bytes", buff);
    Sys.LogWriteBuffer("Input key", Sys.PrivateKey);
    ICryptoTransform decryptor = rijndael.CreateDecryptor(rijndael.Key, rijndael.IV);
    buff=rijndael.CreateDecryptor().TransformFinalBlock(buff, 0, buff.Length);
    Sys.LogWriteBuffer("buffer: ", buff);
}
如果我像这样把它放到任何在线AES解密程序中,我总能得到正确的结果:
[[27,{“已建立”:true}]
但在C#中,我只知道:

System.Security.Cryptography.CryptographicException: Padding is invalid and cannot be removed.
   at System.Security.Cryptography.RijndaelManagedTransform.DecryptData(Byte[] inputBuffer, Int32 inputOffset, Int32 inputCount, Byte[]& outputBuffer, Int32 outputOffset, PaddingMode paddingMode, Boolean fLast)
   at System.Security.Cryptography.RijndaelManagedTransform.TransformFinalBlock(Byte[] inputBuffer, Int32 inputOffset, Int32 inputCount)
我甚至尝试了PaddingMode.None,这不会引发任何异常,但输出只是随机字节。 即使是在线解密程序也能正确解决问题,我做错了什么

应产生相同结果的其他示例输入数据
[[27,{“已建立”:true}]

Decrypt input bytes length: 32, keyLength: 16
Input bytes: 85 5C 55 24 44 B8 77 A5 EF CE E7 A1 45 EC F3 84 2F 8B 74 1F AB D9 BE D0 82 64 BC 0D B0 50 73 63 
Input key: B2 21 FA 17 63 E6 4C 25 48 03 84 64 8B 70 05 00 

Decrypt input bytes length: 32, keyLength: 16
Input bytes: 8B FC 47 B4 91 05 B7 E1 6C 0E 61 78 D2 51 6B 77 EF 80 30 49 37 05 DA 79 47 52 D1 24 B9 DE A7 F3 
Input key: E7 BF E0 AA AC F1 26 42 06 D6 59 44 F9 33 74 63 

请注意,IV总是16个空字节。

我终于发现了这个问题,这令人难以置信! 不是以这种方式创建解密程序:

ICryptoTransform decryptor = rijndael.CreateDecryptor(rijndael.Key, rijndael.IV);
我应该这样创建它:

ICryptoTransform decryptor = rijndael.CreateDecryptor(Sys.PrivateKey, iv);
如果将来有人遇到类似的问题,这里已经有了一个广义函数:

        public static String Decrypt(byte[] buff, byte[] key, byte[] iv)
        {
            using (System.Security.Cryptography.RijndaelManaged rijndael = new System.Security.Cryptography.RijndaelManaged())
            {
                rijndael.Padding = PaddingMode.PKCS7;
                rijndael.Mode = CipherMode.CBC;
                rijndael.KeySize = 128;
                rijndael.BlockSize = 128;
                ICryptoTransform decryptor = rijndael.CreateDecryptor(key, iv);
                System.IO.MemoryStream memoryStream = new System.IO.MemoryStream(buff);
                CryptoStream cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read);
                byte[] output = new byte[buff.Length];
                int readBytes = cryptoStream.Read(output, 0, output.Length);
                return System.Text.Encoding.UTF8.GetString(output, 0, readBytes);
            }
        }

希望能有所帮助。

我认为你应该尝试这样一个有效的解决方案,看看你做了什么不同的事情。但是,这不起作用。没有字符串,只有从TCP Recv解析的字节流
byte buff[]
。正如上面给出的示例(
Input bytes,Input key
),输入数据是绝对有效的,即使在上面提供的在线AES解密程序和Java客户端中,对它们进行解密也是有效的。解决了这个问题。只是不能接受自己的答案-就我个人而言,我会尝试使用。只需调用
TransformFinalBlock
就可以了,但请阅读API规范:“TransformFinalBlock是用于转换流中最后一个块或部分块的特殊函数。它返回一个包含剩余转换字节的新数组。返回一个新数组,因为添加填充时,在末尾返回的信息量可能大于单个块。”。仅使用此方法是黑客攻击,而不是编码。您会说,“注意,IV始终是16个空字节。“这是不安全的,实际上意味着您的第一个数据块是在ECB模式下加密的,而不是在CBC模式下加密的。为了安全起见,IV需要是随机的,并且每个消息都不同。您可能只需调用
CreateDecryptor()
,它就可以工作了,因为您已经在
rijndael
对象上设置了密钥和IV。
        public static String Decrypt(byte[] buff, byte[] key, byte[] iv)
        {
            using (System.Security.Cryptography.RijndaelManaged rijndael = new System.Security.Cryptography.RijndaelManaged())
            {
                rijndael.Padding = PaddingMode.PKCS7;
                rijndael.Mode = CipherMode.CBC;
                rijndael.KeySize = 128;
                rijndael.BlockSize = 128;
                ICryptoTransform decryptor = rijndael.CreateDecryptor(key, iv);
                System.IO.MemoryStream memoryStream = new System.IO.MemoryStream(buff);
                CryptoStream cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read);
                byte[] output = new byte[buff.Length];
                int readBytes = cryptoStream.Read(output, 0, output.Length);
                return System.Text.Encoding.UTF8.GetString(output, 0, readBytes);
            }
        }