Рассчитать хеш при записи в поток - PullRequest
12 голосов
/ 18 января 2011

В настоящее время я создаю зашифрованный формат файла, который необходимо подписать.Для этого мне нужно вычислить хеш-код содержимого, которое я записал в поток.

В .net Framework есть множество алгоритмов хеширования, которые можно использовать, и это прекрасно работает, но для этого требуетсяобработать поток три раза.

byte[] content = new byte[] { 0, 1, 2, 3, 4, 5, 6 };

using (Stream fileStream = File.Open("myfile.bin", FileMode.Create))
{
    //Write content
    fileStream.Write(content, 0, content.Length);
}

byte[] hashValue = null;
using (Stream fileStream = File.Open("myfile.bin", FileMode.Open))
{
    HashAlgorithm hash = SHA256.Create();
    hashValue = hash.ComputeHash(fileStream);
}

using (Stream fileStream = File.Open("myfile.bin", FileMode.Append))
{
    fileStream.Write(hashValue, 0, hashValue.Length);
}

Это нормально, если он зашифрован в файл, но если он зашифрован в сеть назначения, байты больше не доступны.

Такв основном мне нужно обрабатывать данные только один раз.В CodeProject есть статья , в которой CRC32 реализован в виде потока, который вычисляет код CRC32 каждый раз, когда в него записываются данные.

Что-то вроде:

byte[] content = new byte[] { 0, 1, 2, 3, 4, 5, 6 };

using (FileStream fileStream = File.Create("myfile.bin"))
using (Stream crcStream = new CRCStream(fileStream)) //Takes a base stream
{
    //Write content
    crcStream.Write(content, 0, content.Length); 

    //Write checksum
    fileStream.Write(crcStream.WriteCRC, 0, 4);
}

Очевидно, что CRC32 не является алгоритмом хеширования, но было бы неплохо иметь что-то вроде HashStream, которое принимает HashAlgorithm.HashStream будет обновлять значение хеша каждый раз, когда вызывается запись / чтение.

Что-то вроде:

byte[] content = new byte[] { 0, 1, 2, 3, 4, 5, 6 };

HashAlgorithm hashAlgo = SHA256.Create();

using (FileStream fileStream = File.Create("myfile.bin"))
using (HashStream hashStream = new HashStream(hashAlgo, fileStream))
{
    //Write content to HashStream 
    hashStream.Write(content, 0, content.Length);

    //Write checksum
    fileStream.Write(hashStream.HashValue, 0, hashAlgo.HashSize / 8);
}

Чтение файлов должно работать аналогичным образом, поэтому, когда вы прочитали файл(не включая хеш), хэш прочитанного содержимого уже рассчитан.

Возможно ли создать что-то подобное, используя существующие компоненты .net Framework?

Редактировать:

Спасибо, Питер!Я не знал, что CryptoStream может использовать HashAlgorithm.Поэтому для шифрования и хеширования одновременно я мог бы сделать что-то вроде этого:

byte[] content = new byte[] { 0, 1, 2, 3, 4, 5, 6 };

SymmetricAlgorithm cryptoSymetric = Aes.Create();
HashAlgorithm cryptoHash = SHA256.Create();

using (FileStream file = new FileStream("Crypto.bin", FileMode.Create, FileAccess.Write))
using (CryptoStream hashStream = new CryptoStream(file, cryptoHash, CryptoStreamMode.Write))
using (CryptoStream cryptStream = new CryptoStream(hashStream, cryptoSymetric.CreateEncryptor(), CryptoStreamMode.Write))
{
    cryptStream.Write(content, 0, content.Length);
    cryptStream.FlushFinalBlock();

    byte[] hashValue = cryptoHash.Hash;

    file.Write(hashValue, 0, hashValue.Length);
}

Ответы [ 2 ]

36 голосов
/ 18 января 2011

Это сделано для вас CryptoStream.

SHA256 hashAlg = new SHA256Managed();
CryptoStream cs = new CryptoStream(_out, hashAlg, CryptoStreamMode.Write);
// Write data here
cs.FlushFinalBlock();
byte[] hash = hashAlg.Hash;
4 голосов
/ 18 января 2011

Вы можете делать хэш-преобразования с блоками, используя HashAlgorithm.TransformBlock . Это может быть включено в реализацию Stream, так что вы можете иметь HashStream, как вы предлагаете. Не забудьте вызвать TransformFinalBlock перед получением значения хеш-функции.

HashAlgorithm является абстрактным, поэтому, конечно, вам нужно выбрать конкретную реализацию, которую вы хотите. Можно выбрать из MD5, семейства SHA и других.

...