Actualmente estoy creando un formato de archivo encriptado que necesita ser firmado. Para esto necesito calcular el código hash del contenido que he escrito en una transmisión.Calcular hash al escribir en la corriente
En el .NET Framework hay numerosos algoritmos de hash que se pueden usar, y funciona bien, pero me requiere procesar la transmisión tres veces.
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);
}
Esto está bien si está codificada en un archivo, pero si está encriptada a un destino de red, los bytes ya no están disponibles.
Básicamente, solo necesito procesar los datos una vez. En CodeProject hay un article que ha implementado CRC32 como un flujo que calcula el código CRC32 cada vez que hay datos escritos en él.
Algo así como:
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);
}
Obviamente CRC32 no es un alogorithm hachís, pero sería bueno tener algo así como un HashStream que toma un HashAlgorithm. HashStream actualizaría el valor hash cada vez que se llama a escritura/lectura.
Algo así como:
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);
}
La lectura de los archivos deben trabajar de manera similar, por lo que cuando haya leído el archivo (sin incluir el hash), el hash del contenido de lectura ya ha sido calculado.
¿Es posible construir algo como esto usando los componentes existentes de .net frameworks?
Editar:
Gracias Peter! No sabía que CryptoStream podría tomar un algoritmo HashAlgorithm. Así que para el cifrado y hash al mismo tiempo, podría hacer algo como esto:
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);
}
creo que debe jugar a lo seguro y lo llaman 'hashStream.FlushFinalBlock()' 'después cryptStream.FlushFinalBlock()' –
he intentado eso, sino que inició una excepción. Aparentemente FlushFinalBlock también se invoca en transmisiones base. Aunque está declarado como Stream. System.NotSupportedException Mensaje = El método FlushFinalBlock() se invocó dos veces en un CryptoStream. Solo se puede llamar una vez. –