从C#中未知长度的流中计算哈希值

问题描述 投票:22回答:5

在C#中,用于计算“动态” md5(如未知长度的流的哈希)的最佳解决方案是什么?具体来说,我想根据通过网络接收的数据来计算哈希值。我知道当发送方终止连接时我已经完成了接收数据,所以我事先不知道长度。

[[编辑]-现在,我正在使用md5,但是在将数据保存并写入磁盘之后,这需要第二次传递数据。我宁愿将它从网络中散发出来。

c# hash cryptography stream
5个回答
53
投票

与其他哈希函数一样,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派生的任何类型,包括MD5CryptoServiceProviderSHA1Managed

HashAlgorithm还定义了采用ComputeHash对象的方法Stream;但是,此方法将阻塞线程,直到流被消耗为止。使用TransformBlock方法可以在数据到达时计算出“异步哈希”,而不会耗尽线程。


12
投票

System.Security.Cryptography.MD5类包含采用ComputeHashbyte[]Stream方法。签出the documentation


10
投票

进一步@ 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校验和的相同字符串。


4
投票

这似乎是CryptoStreamdocs)的完美用例。

我已经使用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();

1
投票

正在创新。

© www.soinside.com 2019 - 2024. All rights reserved.