2011-01-18 14 views
11

Attualmente sto creando un formato di file crittografato che deve essere firmato. Per questo ho bisogno di calcolare il codice hash del contenuto che ho scritto su un flusso.Calcolare l'hash durante la scrittura nello stream

Nel framework .net esistono numerosi algoritmi di hash che possono essere utilizzati e funzionano correttamente, ma mi richiede di elaborare lo stream tre volte.

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

Questo è bene se è codificato in un file, ma se è criptato a una destinazione di rete, i byte non sono più disponibili.

Quindi in pratica ho bisogno di elaborare i dati solo una volta. Su CodeProject c'è un article che ha implementato CRC32 come Stream che calcola il codice CRC32 ogni volta che vi sono dati scritti.

Qualcosa di simile:

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

Ovviamente CRC32 non è un alogorithm hash, ma sarebbe bello avere qualcosa di simile a un HashStream che prende un HashAlgorithm. HashStream aggiornerebbe il valore hash ogni volta che viene chiamata write/read.

Qualcosa di simile:

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

lettura dei file dovrebbe funzionare in modo simile, in modo che quando hai letto il file (non compresa l'hash), l'hash del contenuto di lettura è già stato calcolato.

È possibile costruire qualcosa come questo utilizzando i componenti esistenti .net framework?

Modifica:

Grazie Peter! Non sapevo che CryptoStream potesse prendere un algoritmo hash. Così, per la crittografia e hashing, allo stesso tempo, avrei potuto fare qualcosa di simile:

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

Penso che si dovrebbe giocare sul sicuro e chiamare 'hashStream.FlushFinalBlock()' 'dopo cryptStream.FlushFinalBlock()' –

+2

ho provato, ma ha generato un'eccezione. Apparentemente FlushFinalBlock viene chiamato anche sui flussi di base. Anche se è dichiarato come Stream. System.NotSupportedException Messaggio = Il metodo FlushFinalBlock() è stato chiamato due volte su un CryptoStream. Può essere chiamato solo una volta. –

risposta

30

È fatto per te da CryptoStream.

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

[Commento rimosso - codice formato] –

+0

@ soren.bendtsen contrassegnarlo come risposta in modo che sappiamo che è stato risolto il problema. – Eli

4

Si può fare blocco per blocco hash trasforma utilizzando HashAlgorithm.TransformBlock. Questo può essere incluso in un'implementazione Stream, quindi potresti avere un HashStream come suggerisci. Ricordarsi di chiamare TransformFinalBlock prima di ottenere il valore hash.

HashAlgorithm è astratto, quindi ovviamente è necessario scegliere l'implementazione concreta che si desidera. Ci sono MD5, la famiglia SHA e altri tra cui scegliere.

+1

Conoscete una buona implementazione del wrapper Stream sincrono/asincrono per calcolare l'hash durante la lettura o la scrittura? – MuiBienCarlota

Problemi correlati