"填充无效,无法删除"使用AesManaged

Tim*_*imK 29 .net c# encryption

我正在尝试使用AesManaged进行简单的加密/解密,但在尝试关闭解密流时我一直遇到异常.这里的字符串被正确加密和解​​密,然后在Console.WriteLine输出正确的字符串后,我得到CryptographicException"Padding无效且无法删除".

有任何想法吗?

MemoryStream ms = new MemoryStream();
byte[] rawPlaintext = Encoding.Unicode.GetBytes("This is annoying!");

using (Aes aes = new AesManaged())
{
  aes.Padding = PaddingMode.PKCS7;
  aes.Key = new byte[128/8];
  aes.IV = new byte[128/8];

  using (CryptoStream cs = new CryptoStream(ms, aes.CreateEncryptor(),
                                            CryptoStreamMode.Write))
  {
    cs.Write(rawPlaintext, 0, rawPlaintext.Length);
    cs.FlushFinalBlock();
  }

  ms = new MemoryStream(ms.GetBuffer());
  using (CryptoStream cs = new CryptoStream(ms, aes.CreateDecryptor(),
                                            CryptoStreamMode.Read))
  {
    byte[] rawData = new byte[rawPlaintext.Length];
    int len = cs.Read(rawData, 0, rawPlaintext.Length);
    string s = Encoding.Unicode.GetString(rawData);
    Console.WriteLine(s);
  }
}
Run Code Online (Sandbox Code Playgroud)

Che*_*eso 50

诀窍是使用MemoryStream.ToArray().我还更改了您的代码,以便CryptoStream在加密和解密时使用写入.并且您不需要CryptoStream.FlushFinalBlock()显式调用,因为您在using()语句中有它,并且将发生刷新Dispose().以下适用于我.

byte[] rawPlaintext = System.Text.Encoding.Unicode.GetBytes("This is all clear now!");

using (Aes aes = new AesManaged())
{
    aes.Padding = PaddingMode.PKCS7;
    aes.KeySize = 128;          // in bits
    aes.Key = new byte[128/8];  // 16 bytes for 128 bit encryption
    aes.IV = new byte[128/8];   // AES needs a 16-byte IV
    // Should set Key and IV here.  Good approach: derive them from 
    // a password via Cryptography.Rfc2898DeriveBytes 
    byte[] cipherText= null;
    byte[] plainText= null;

    using (MemoryStream ms = new MemoryStream())
    {
        using (CryptoStream cs = new CryptoStream(ms, aes.CreateEncryptor(), CryptoStreamMode.Write))
        {
            cs.Write(rawPlaintext, 0, rawPlaintext.Length);
        }

        cipherText= ms.ToArray();
    }


    using (MemoryStream ms = new MemoryStream())
    {
        using (CryptoStream cs = new CryptoStream(ms, aes.CreateDecryptor(), CryptoStreamMode.Write))
        {
            cs.Write(cipherText, 0, cipherText.Length);
        }

        plainText = ms.ToArray();
    }
    string s = System.Text.Encoding.Unicode.GetString(plainText);
    Console.WriteLine(s);
}
Run Code Online (Sandbox Code Playgroud)

此外,我猜您知道您将要显式设置AesManaged实例的模式,并使用System.Security.Cryptography.Rfc2898DeriveBytes 从密码和salt派生密钥和IV.

另见:
- AesManaged

  • 我有同样的问题,但使用RijndaelManaged(也是对称的)并且不知道发生了什么.事实证明,`MemoryStream.GetBuffer()`获得了*未刷新的*版本的数据,并且大多数最终的数据块都是null,这使我的填充变得混乱.`MemoryStream.ToArray()`获取真正的数组.非常感谢这个解决方案! (4认同)
  • 好好打电话给'Dispose`.我在处理CryptoStream之前调用了`ms.ToArray()`.在使用之外移动那条线为我固定它. (3认同)

ath*_*aki 24

此异常可能是由多个加密参数中的任何一个不匹配引起的.

我使用Security.Cryptography.Debug接口来跟踪加密/解密方法中使用的所有参数.

最后我发现我的问题是我KeySize在设置Key导致类重新生成随机密钥而不使用我最初设置的密钥之后设置了属性.

  • 我的问题是在设置密钥后设置KeySize,谢谢! (5认同)
  • +1非常感谢你,如果可以,我会投票给你100次.我花了一天多时间试图弄清楚为什么我无法正确解密,结果发现我在代码中的密钥之后设置了密钥大小. (2认同)

Jac*_*ck7 6

不管它的价值如何,我都会记录我所遇到的事情。我试图在 CryptoStream 关​​闭之前读取加密器内存流。我很天真,浪费了一天的时间来调试它。

    public static byte[] Encrypt(byte[] buffer, byte[] sessionKey, out byte[] iv)
    {
        byte[] encrypted;
        iv = null;
        using (AesCryptoServiceProvider aesAlg = new AesCryptoServiceProvider { Mode = CipherMode.CBC, Padding = PaddingMode.PKCS7 })
        {
            aesAlg.Key = sessionKey;
            iv = aesAlg.IV;
            ICryptoTransform encryptor = aesAlg.CreateEncryptor(sessionKey, iv);

            // Create the streams used for encryption.
            using (MemoryStream msEncrypt = new MemoryStream())
            {
                using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
                {
                    csEncrypt.Write(buffer, 0, buffer.Length);
                    
                    //This was not closing the cryptostream and only worked if I called FlushFinalBlock()
                    //encrypted = msEncrypt.ToArray(); 
                }

                encrypted = msEncrypt.ToArray();

                return encrypted;
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)

在 cypto 流关闭后移动读取的加密器内存流解决了该问题。正如奇索提到的。FlushFinalBlock()如果您正在使用该块,则无需调用using