在C#中,用于计算“动态” md5(如未知长度的流的哈希)的最佳解决方案是什么?具体来说,我想根据通过网络接收的数据来计算哈希值。我知道当发送方终止连接时我已经完成了接收数据,所以我事先不知道长度。
[[编辑]-现在,我正在使用md5,但是在将数据保存并写入磁盘之后,这需要第二次传递数据。我宁愿将它从网络中散发出来。
与其他哈希函数一样,MD5不需要两次通过。
开始:
HashAlgorithm hasher = ..;
hasher.Initialize();
当每个数据块到达时:
byte[] buffer = ..;
int bytesReceived = ..;
hasher.TransformBlock(buffer, 0, bytesReceived, null, 0);
要完成并获取哈希:
hasher.TransformFinalBlock(new byte[0], 0, 0);
byte[] hash = hasher.Hash;
此模式适用于从HashAlgorithm
派生的任何类型,包括MD5CryptoServiceProvider
和SHA1Managed
。
HashAlgorithm
还定义了采用ComputeHash
对象的方法Stream
;但是,此方法将阻塞线程,直到流被消耗为止。使用TransformBlock
方法可以在数据到达时计算出“异步哈希”,而不会耗尽线程。
System.Security.Cryptography.MD5
类包含采用ComputeHash
或byte[]
的Stream
方法。签出the documentation。
进一步@ peter-mourfield的答案,这是使用ComputeHash()
的代码:
private static string CalculateMd5(string filePathName) {
using (var stream = File.OpenRead(filePathName))
using (var md5 = MD5.Create()) {
var hash = md5.ComputeHash(stream);
var base64String = Convert.ToBase64String(hash);
return base64String;
}
}
由于流和MD5都实现了IDisposible,因此您需要使用using(...){...}
代码示例中的方法返回用于Azure Blob存储中MD5校验和的相同字符串。
这似乎是CryptoStream
(docs)的完美用例。
我已经使用CryptoStream
处理了未知长度的数据库结果流,这些结果需要压缩后再通过网络与压缩文件的哈希一起传输。在压缩器和文件编写器之间插入CryptoStream
,可让您即时计算哈希值,以便在写入文件后立即准备好。]
基本方法如下:
var hasher = MD5.Create();
using (FileStream outFile = File.Create(filePath))
using (CryptoStream crypto = new CryptoStream(outFile, hasher, CryptoStreamMode.Write))
using (GZipStream compress = new GZipStream(crypto, CompressionMode.Compress))
using (StreamWriter writer = new StreamWriter(compress))
{
foreach (string line in GetLines())
writer.WriteLine(line);
}
// at this point the streams are closed so the hash is ready
string hash = BitConverter.ToString(hasher.Hash).Replace("-", "").ToLowerInvariant();
正在创新。