2009-03-02 49 views
26

我试图使用AesManaged获得简单的加密/解密,但在尝试关闭解密流时我不断收到异常。这里的字符串被正确加密和解​​密,然后在Console.WriteLine打印正确的字符串后,我得到CryptographicException“填充无效且无法删除”。“填充无效,无法删除”使用AesManaged

任何想法?

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

回答

44

诀窍是使用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); 
} 

另外,我想你知道你将要明确设置AesManaged实例的Mode,并使用System.Security.Cryptography.Rfc2898DeriveBytes推导从密码和盐的密钥和IV。

也参见:
- AesManaged

+4

我有同样的问题,但使用RijndaelManaged(也对称),并不知道发生了什么。结果是`MemoryStream.GetBuffer()`得到了一个* unflushed *版本的数据,并且大部分最后的数据块都是空的,这与我的填充有关。 `MemoryStream.ToArray()`获取真正的数组。非常感谢这个解决方案! – Codesleuth 2009-12-17 15:23:36

+0

这是迄今为止我所见过的最好的/最小的实现。 – tmanthey 2013-05-25 09:37:05

1

字节[] RAWDATA =新 字节[rawPlaintext.Length];

您需要读取缓冲区的长度,这可能包括必要的填充(IIRC,几年)。

21

此异常可以通过多个加密参数中的任一个的不匹配引起的。

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

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

1

没有人回答,实际上MemoryStream.GetBuffer返回分配的缓冲区,而不是此缓冲区中的实际数据。在这种情况下,它返回256字节的缓冲区,而它只包含32字节的加密数据。

相关问题