2011-01-18 16 views
11

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); 
}
+0

creo que debe jugar a lo seguro y lo llaman 'hashStream.FlushFinalBlock()' 'después cryptStream.FlushFinalBlock()' –

+2

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. –

Respuesta

30

CryptoStream lo hace por usted.

SHA256 hashAlg = new SHA256Managed(); 
CryptoStream cs = new CryptoStream(_out, hashAlg, CryptoStreamMode.Write); 
// Write data here 
cs.FlushFinalBlock(); 
byte[] hash = hashAlg.Hash; 
+0

[Se eliminó el comentario - código de formato] –

+0

@ soren.bendtsen por favor márquelo como respuesta para que sepamos que ha resuelto su problema ... – Eli

4

Usted puede hacer bloque por bloque de hash transforma usando HashAlgorithm.TransformBlock. Esto puede ser envuelto en una implementación de Stream, por lo que podría tener un HashStream como lo sugiere. Recuerde llamar al TransformFinalBlock antes de obtener el valor hash.

HashAlgorithm es abstracto, por lo que debe elegir la implementación concreta que desee. Hay MD5, la familia SHA y otros para elegir.

+1

¿Conoces una buena implementación de la envoltura Sync/async Stream para calcular hash durante la lectura o la escritura? – MuiBienCarlota

Cuestiones relacionadas