Я озадачен тем, что кажется причудой к классу .NET CryptoStream
: его метод Dispose()
читает после конца зашифрованного текста в поисках отступа, который не должен, и выдает CryprographicException
в результате.
Программа на C # ниже шифрует несколько байтов, изменяет размер массива зашифрованного текста, чтобы после конца зашифрованного текста было больше (бессмысленных) байтов, а затем пытается его расшифровать. Существенные моменты:
- Зашифрованный текст составляет 8 байтов, один блок шифрования 3DES. Поскольку я записываю только 6 байтов в
CryptoStream
и он использует PaddingMode.PKCS7
(по умолчанию), оставшиеся два байта в блоке заполняются значением заполнения 0x02.
- Размер массива зашифрованного текста впоследствии изменяется до 16 байтов, двух блоков 3DES. Второй блок - неинициализированная ерунда, недействительный вывод шифра.
- При расшифровке я читаю ровно 6 байтов из
CryptoStream
; Я не прошу его расшифровать в бессмысленную часть, и я не полагаюсь на то, что он распознает отступ, чтобы выяснить, когда он достигнет конца открытого текста.
Проблема в том, что когда вызывается расшифровка CryptoStream
Dispose()
(автоматически в конце блока using
), я получаю CryptographicException
с сообщением «Неверные данные». Его трассировка стека показывает, что он выполнял CryptoStream.FlushFinalBlock()
, и все 16 байтов были использованы из ciphertextStream
, а не только 8, соответствующих фактическим зашифрованным данным.
Если я удаляю строку, которая изменяет размер массива ciphertext
, программа работает правильно. И если я сделаю tripleDes.Padding = PaddingMode.None
перед расшифровкой, программа также будет работать правильно - но это в основном делает байты заполнения частью открытого текста, поэтому я бы предпочел этого не делать. Ясно, что проблема связана с дополнением; насколько я могу судить, он расшифровывает этот второй блок и ожидает, что в его конце будет найден допустимый отступ в стиле PKCS7
.
Поскольку я только читаю достаточно из CryptoStream
, чтобы потребовать расшифровки одного блока, и этот блок является правильно заполненным последним блоком, а затем я закрываю CryptoStream
, не читая больше, почему Поток думаете, что нужно прочитать другой блок и искать дополнительные отступы? Почему он даже пытается использовать больше входных данных как часть Dispose()
?
using System;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
namespace Test
{
class Program
{
static void Main(string[] args)
{
byte[] plaintext = { 0, 1, 2, 3, 4 };
using (SymmetricAlgorithm tripleDes = TripleDESCryptoServiceProvider.Create())
{
// Encrypt the plaintext
byte[] ciphertext;
using (MemoryStream ciphertextStream = new MemoryStream())
{
using (ICryptoTransform encryptor = tripleDes.CreateEncryptor())
{
using (CryptoStream cryptoStream = new CryptoStream(ciphertextStream, encryptor, CryptoStreamMode.Write))
{
cryptoStream.WriteByte((byte)plaintext.Length);
cryptoStream.Write(plaintext, 0, plaintext.Length);
cryptoStream.FlushFinalBlock();
}
}
ciphertext = ciphertextStream.ToArray();
}
// *** Add some non-ciphertext garbage to the end ***
Array.Resize(ref ciphertext, ciphertext.Length + 8);
// Now decrypt it again
byte[] decryptedPlaintext;
using (MemoryStream ciphertextStream = new MemoryStream(ciphertext, false))
{
using (ICryptoTransform decryptor = tripleDes.CreateDecryptor())
{
using (CryptoStream cryptoStream = new CryptoStream(ciphertextStream, decryptor, CryptoStreamMode.Read))
{
int length = cryptoStream.ReadByte();
decryptedPlaintext = new byte[length];
int i = 0;
while (i < length)
{
int bytesRead = cryptoStream.Read(decryptedPlaintext, i, (length - i));
if (bytesRead == 0) break;
else i += bytesRead;
}
} // CryptographicException: "Bad Data"
}
}
System.Diagnostics.Debug.Assert(decryptedPlaintext.SequenceEqual(plaintext));
}
}
}
}