"Заполнение недопустимо и не может быть удалено" с помощью AesManaged
Я пытаюсь настроить простое шифрование / дешифрование при работе с AesManaged, но получаю исключение при попытке закрыть поток дешифрования. Строка здесь шифруется и дешифруется правильно, а затем я получаю CryptographicException "Заполнение было недопустимым и не может быть удалено" после того, как Console.WriteLine напечатает правильную строку.
Есть идеи?
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);
}
}
4 ответа
Хитрость заключается в использовании 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 и использовать http://msdn.microsoft.com/en-us/library/system.security.cryptography.rfc2898derivebytes.aspx для получения ключа и IV из пароля и соли.
смотрите также:
- AesManaged
Это исключение может быть вызвано несоответствием любого из нескольких параметров шифрования.
Я использовал интерфейс Security.Cryptography.Debug для отслеживания всех параметров, используемых в методах шифрования / дешифрования.
Наконец я узнал, что моя проблема в том, что я установил KeySize
свойство после установки Key
заставляя класс заново генерировать случайный ключ и не используя ключ, который я изначально настроил.
Я задокументирую то, с чем столкнулся. Я пытался прочитать поток памяти шифратора до закрытия 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, решило проблему. Как упоминал Чизо. Вам не нужно звонитьFlushFinalBlock()
если вы используете using
блок.
Никто не ответил, что на самом деле MemoryStream.GetBuffer возвращает выделенный буфер, а не реальные данные в этом буфере. В этом случае он возвращает 256-байтовый буфер, в то время как он содержит только 32 байта зашифрованных данных.
byte[] rawData = новый байт [rawPlaintext.Length];
Вам нужно прочитать длину буфера, который, вероятно, включает в себя необходимые отступы (IIRC, был несколько лет).
Как уже упоминалось, эта ошибка может возникнуть, если ключ /iv неправильно инициализирован для дешифрования. В моем случае мне нужно скопировать ключ и 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 не совершал эту ошибку, но это может быть полезно для других, видящих ту же ошибку.