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);
}
Penso che si dovrebbe giocare sul sicuro e chiamare 'hashStream.FlushFinalBlock()' 'dopo cryptStream.FlushFinalBlock()' –
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. –