我正在尝试使用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);
}
}
答案 0 :(得分:49)
诀窍是使用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从密码和盐派生出Key和IV。
另见:
- AesManaged
答案 1 :(得分:23)
此异常可能是由多个加密参数中的任何一个不匹配引起的。
我使用Security.Cryptography.Debug接口来跟踪加密/解密方法中使用的所有参数。
最后我发现我的问题是我在设置KeySize
之后设置Key
属性,导致类重新生成随机密钥而不使用我最初设置的密钥。 / p>
答案 2 :(得分:1)
byte [] rawData = new 字节[rawPlaintext.Length];
你需要读取缓冲区的长度,这可能包括必要的填充(IIRC,已经有几年了)。
答案 3 :(得分:1)
没有人回答,实际上MemoryStream.GetBuffer返回分配的缓冲区,而不是此缓冲区中的实际数据。在这种情况下,它返回256字节的缓冲区,而它只包含32字节的加密数据。
答案 4 :(得分:0)
为了说明它的价值,我将记录所面对的事情。我试图在关闭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;
}
}
}
移动在关闭cypto流之后读取的加密器内存流可以解决此问题。正如Cheeso所说。如果您使用的是FlushFinalBlock()
块,则无需调用using
。
答案 5 :(得分:0)
正如其他人所提到的,如果密钥/ iv未正确初始化以进行解密,则可能发生此错误。就我而言,我需要从一些较大的缓冲区中复制key和iv。这是我做错的事情:
不起作用 :(填充无效,无法删除)
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);
作品:
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;
OP并没有犯此错误,但这可能对其他看到相同错误的人有所帮助。