C#: ошибка AES: заполнение недопустимо и не может быть удалено. Тот же ключ и все, помогите
Я довольно новичок в C#, поэтому, пожалуйста, будьте терпеливы со мной. Я знаю, что этот вопрос задавали много раз, но я не мог найти ответа на свою проблему.
Я сохраняю некоторые данные, и перед записью в файл я конвертирую его в двоичный файл и храню его в массиве, который я шифрую, а затем пишу в файл. Я шифрую данные в кусках (32 байта). Точно так же я читаю данные в кусках по 32 байта, а затем расшифровываю эти данные, а затем это должно повторяться до конца файла. Но когда дело доходит до расшифровка возникает следующая ошибка:
Padding недействителен и не может быть удален.
Я использую тот же ключ и iv (hardcoded только до тех пор, пока я не получу его работу)
вот мой код шифрования, который работает без проблем:
//result
byte[] data = new byte[32];
//setup encryption (AES)
SymmetricAlgorithm aes = Aes.Create();
byte[] key = { 145, 12, 32, 245, 98, 132, 98, 214, 6, 77, 131, 44, 221, 3, 9,50};
byte[] iv = { 15, 122, 132, 5, 93, 198, 44, 31, 9, 39, 241, 49, 250, 188, 80, 7 };
ICryptoTransform encryptor = aes.CreateEncryptor(key, iv);
FileStream fStream = new FileStream(file, FileMode.OpenOrCreate, FileAccess.Write, FileShare.Read, 1024, false);
//prepare data to write (byte array 'data') ...
//encrypt
MemoryStream m = new MemoryStream();
using (Stream c = new CryptoStream(m, encryptor, CryptoStreamMode.Write))
c.Write(data, 0, data.Length);
data = m.ToArray();
fStream.Write(data, 0, data.Length);
и вот мой код расшифровки:
FileStream fStream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read, 4096, false);
//setup encryption (AES)
SymmetricAlgorithm aes = Aes.Create();
byte[] key = { 145, 12, 32, 245, 98, 132, 98, 214, 6, 77, 131, 44, 221, 3, 9, 50 };
byte[] iv = { 15, 122, 132, 5, 93, 198, 44, 31, 9, 39, 241, 49, 250, 188, 80, 7 };
ICryptoTransform decryptor = aes.CreateDecryptor(key, iv);
//result
byte[] data = new byte[32];
//loop for reading the whole file ...
int len = fStream.Read(data, 0, 32);
//decrypt
MemoryStream m = new MemoryStream();
using (Stream c = new CryptoStream(m, decryptor, CryptoStreamMode.Write))
c.Write(data, 0, data.Length); //The exception is thrown in this line
data = m.ToArray();
//using the decrypted data and then looping back to reading and decrypting...
Я пробовал все, что мог придумать (что не так много, потому что я очень новичок в криптографии), я искал везде, и я не смог найти решение своей проблемы. Я также помог себе с книгой C# в двух словах .
Если у кого есть идеи, почему это может произойти, я буду очень благодарна, потому что у меня нет идей.
Спасибо за ваше время и ответы.
изменить: Кажется, что размер зашифрованных данных составляет 48 байт (на 12 байт больше исходного). Почему это так? Я думал, что он добавляет только байты, если они не кратны размеру блока (16 байт, мои данные 32 байта). Данные всегда больше, и с постоянным увеличением (мне нужно знать, что для того, чтобы правильно прочитать и расшифровать).
примечание: Я не могу напрямую использовать другие потоки, потому что мне нужно иметь контроль над выходным форматом, и я считаю, что также безопаснее и быстрее шифровать в памяти.
3 ответов
на основе вашего редактирования:
EDIT: кажется, что размер зашифрованных данных составляет 48 байт (на 12 байт больше исходного). Почему это так? Я думал, что он добавляет только байты, если они не кратны размеру блока (16 байтов, мои данные-32 байта). Данные всегда больше, и с постоянным увеличением (мне нужно знать, что для того, чтобы правильно прочитать и расшифровать).
если зашифрованные данные составляют 48 байт, это на 16 байт больше, чем ваш оригинал матрица. Это имеет смысл, потому что алгоритм с pad данные, потому что по умолчанию pkcs7 в (даже если размер соответствует размеру блока, потому что он прокладывает далее кратно размеру блока). Если вы хотите сохранить ровно 32 байта, просто измените обивка to нет
aes.Padding = PaddingMode.None;
вы, похоже, рассматриваете длину открытого текста как длину зашифрованного текста. Это небезопасное предположение.
почему вы копируете между FileStream
и MemoryStream
, вы можете пройти FileStream
непосредственно шифратора/дешифратора.
в PKCS7 существует как минимум один байт заполнения (для хранения количества байтов заполнения). Таким образом, размер вывода будет Ceil16(input.Length + 1)
или (input.Length & ~15) + 1
.
короче говоря, AES шифрует сообщения в блоках по 16 байт. Если ваше сообщение не является даже кратным 16 байтам, алгоритм должен быть немного другим для последнего блока; в частности, последний блок должен быть "дополнен" значением, известным алгоритму как значение заполнения (обычно ноль, иногда что-то еще вроде значения символа пробела).
Вы делаете это сами, помещая данные в массив байтов фиксированной длины. Вы сами дополняли данные, но дешифратор теперь пытается удалить последний блок и получить значения байтов, которые он не распознает как заполнение, которое добавил бы его аналог шифратора.
ключ не для заполнения сообщения. Класс BitConverter можно использовать для приведения массивов байтов в Типы IConvertible и из них (типы значений и строки), а затем использовать его вместо сворачивания собственного массива байтов. Затем, когда вы расшифровываете, вы можете читать из потока дешифрования до длины зашифрованного текста, но не ожидайте в расшифрованном результате должно быть столько фактических байтов.