/ / .NET CryptoStream чете миналия край на шифротекст в Dispose () и взривява - .net, криптиране, подложка, cryptostream

.NET CryptoStream чете миналия край на шифрова текста в Dispose () и издухва - .net, криптиране, подложка, cryptostream

Аз съм озадачен от това, което изглежда като прикритие на .NET CryptoStream клас: негови Dispose() Методът чете покрай края на шифротекста, който търси подложка, че не трябва да се изхвърля и хвърля CryprographicException като резултат.

Програмата C # по-долу криптира няколко байта,преоразмерява масива на шифровия текст, така че след края на шифротекста има повече (глупости) байтове и след това се опитва да го дешифрира. Основните точки са:

  • Шифровият текст е 8 байта, един 3DES шифров блок. Тъй като пиша само 6 байта в CryptoStream и използва PaddingMode.PKCS7 (по подразбиране), останалите два байта в блока са запълнени с стойността за допълване 0x02.
  • Последователно шифровият масив се преоразмерява на 16 байта, два блока 3DES. Вторият блок е неинициализиран безсмислица, невалиден изход за шифър.
  • Когато дешифрирам, прочетох точно 6 байта от CryptoStream; Аз съм не моли го да декриптира в безсмислената част, а аз не разчитайки на това, разпознавайки подложката, за да разбере кога е достигнала края на открития текст.

Проблемът е, че когато дешифрирането CryptoStreamDispose() се извиква (автоматично в края на using блок), получавам CryptographicException със съобщението "Bad Data". Проследяването на стека показва, че се изпълнява CryptoStream.FlushFinalBlock(), и всичките 16 байта са били използвани от ciphertextStream, а не само 8, съответстващи на действителните криптирани данни.

Ако премахна линията, която преоразмерява ciphertext масив, програмата работи правилно. И ако го направя tripleDes.Padding = PaddingMode.None преди дешифрирането, програмата също работиправилно - но това основно прави байта на подложката част от обикновен текст, така че аз по-скоро не го правя. find valid PKCS7стилизираща подложка в края му.

Тъй като аз само чета достатъчно от. \ T 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));
}
}
}
}

Отговори:

3 за отговор № 1

Вие съзнателно добавяте боклук до края на потока и след това се чудите защо потокът се задушава на боклука.

В криптографията всичко трябва да се провери много внимателно, за да се гарантира товаедин нападател не се опитва нещо подъл. Ако укажете PKCS7 запълване, тогава потокът е прав, за да провери за PKCS7 подложка в края и правото да хвърли изключение, ако не намери правилното подложка в края на потока.

Потокът няма начин да знае, че действителниятCyphhertext завършва в средата на потока, а не в края. Как очаквате да знае? В crypto правилото е да се маркират всички и всички аномалии, а дефектната подложка в (очевидния) край на потока е нещо, което документацията ще ви каже, причинява изключение.