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 CryptoStream
to 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 KeySize
property after setting the Key
causing 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 using
block.
在 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 没有犯这个错误,但这可能对其他人看到相同的错误有所帮助。