C# “填充无效,无法删除”使用 AesManaged
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/604210/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
"Padding is invalid and cannot be removed" using AesManaged
提问by TimK
I'm trying to get simple encryption/decryption working with AesManaged, but I keep getting an exception when trying to close the decryption stream. The string here gets encrypted and decrypted correctly, and then I get the CryptographicException "Padding was invalid and cannot be removed" after Console.WriteLine prints the correct string.
我正在尝试使用 AesManaged 进行简单的加密/解密,但是在尝试关闭解密流时我不断收到异常。此处的字符串已正确加密和解密,然后在 Console.WriteLine 打印正确的字符串后,我得到 CryptographicException“填充无效且无法删除”。
Any ideas?
有任何想法吗?
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);
}
}
采纳答案by Cheeso
The trick is to use MemoryStream.ToArray().
I also changed your code so that it uses the CryptoStreamto Write, in both encrypting and decrypting. And you don't need to call CryptoStream.FlushFinalBlock()explicitly, because you have it in a using()statement, and that flush will happen on Dispose(). The following works for me.
诀窍是使用MemoryStream.ToArray(). 我还更改了您的代码,以便它CryptoStream在加密和解密时都使用to Write。而且您不需要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);
}
Also, I guess you know you will want to explicitly set the Modeof the AesManaged instance, and use System.Security.Cryptography.Rfc2898DeriveBytesto derive the Key and IV from a password and salt.
另外,我猜您知道您将要显式设置AesManaged 实例的模式,并使用System.Security.Cryptography.Rfc2898DeriveBytes从密码和盐派生密钥和 IV。
see also:
- AesManaged
另见:
- AesManaged
回答by leppie
byte[] rawData = new byte[rawPlaintext.Length];
byte[] rawData = new byte[rawPlaintext.Length];
You need to read the length of the buffer, that probably includes the necessary padding (IIRC, been a few years).
您需要读取缓冲区的长度,其中可能包括必要的填充(IIRC,已经有几年了)。
回答by athina.bikaki
This exception can be caused by a mismatch of any one of a number of encryption parameters.
此异常可能是由多个加密参数中的任何一个不匹配引起的。
I used the Security.Cryptography.Debuginterface to trace all parameters used in the encrypt/decrypt methods.
我使用Security.Cryptography.Debug接口来跟踪加密/解密方法中使用的所有参数。
Finally I found out that my problem was that I set the KeySizeproperty after setting the Keycausing the class to regenerate a random key and not using the key that I was initially set up.
最后我发现我的问题是我KeySize在设置Key导致类重新生成随机密钥后设置了属性,而不是使用我最初设置的密钥。
回答by Nickolay Olshevsky
Nobody answered, that actually MemoryStream.GetBuffer returns the allocated buffer, not the real data in this buffer. In this case it returns 256-byte buffer, while it contains only 32 bytes of encrypted data.
没有人回答,实际上 MemoryStream.GetBuffer 返回分配的缓冲区,而不是该缓冲区中的真实数据。在这种情况下,它返回 256 字节的缓冲区,而它只包含 32 字节的加密数据。
回答by Hyman7
For whats its worth, I'll document what I faced. I was trying to read the encryptor memory stream before the CryptoStream was closed. I know it was naive and I wasted a day debugging it.
对于它的价值,我将记录我所面临的情况。我试图在 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;
}
}
}
Moving the encryptor memory stream read after the cypto stream was closed solved the problem. As Cheeso mentioned. You don't need to call the FlushFinalBlock()if you're using the usingblock.
在 cypto 流关闭后移动读取的加密器内存流解决了问题。正如 Cheeso 提到的。FlushFinalBlock()如果您正在使用该using块,则不需要调用。
回答by Robert Hegner
As others have mentioned, this error can occur if the key/iv is not correctly initialized for decryption. In my case I need to copy key and iv from some larger buffer. Here's what I did wrong:
正如其他人所提到的,如果密钥/iv 未正确初始化以进行解密,则可能会发生此错误。在我的情况下,我需要从一些更大的缓冲区复制 key 和 iv 。这是我做错的地方:
Does not work:(Padding is invalid and cannot be removed)
不起作用:(填充无效且无法删除)
aes.Key = new byte[keySize];
Buffer.BlockCopy(someBuffer, keyOffset, aes.Key, 0, keySize);
aes.IV = new byte[ivSize];
Buffer.BlockCopy(someBuffer, ivOffset, aes.IV, 0, ivSize);
Works:
作品:
var key = new byte[keySize];
Buffer.BlockCopy(someBuffer, keyOffset, key, 0, keySize);
aes.Key = key;
var iv = new byte[ivSize];
Buffer.BlockCopy(someBuffer, ivOffset, iv, 0, ivSize);
aes.IV = iv;
The OP did not make this mistake, but this might be helpful for others seeing the same error.
OP 没有犯这个错误,但这可能对其他人看到相同的错误有所帮助。

