在C#中计算来自未知长度的流的哈希

jjx*_*tra 22 c# hash cryptography stream

在C#中计算"动态"md5的最佳解决方案是什么,就像未知长度的流的哈希一样?具体来说,我想根据通过网络收到的数据计算哈希值.我知道当发件人终止连接时我已收到数据,所以我不知道提前的长度.

[编辑] - 现在我正在使用md5,但这需要在保存并写入磁盘后再次传递数据.当它从网络进入时,我宁愿哈希它.

Ste*_*ary 54

与其他哈希函数一样,MD5不需要两次传递.

开始:

HashAlgorithm hasher = ..;
hasher.Initialize();
Run Code Online (Sandbox Code Playgroud)

每个数据块到达时:

byte[] buffer = ..;
int bytesReceived = ..;
hasher.TransformBlock(buffer, 0, bytesReceived, null, 0);
Run Code Online (Sandbox Code Playgroud)

要完成并检索哈希:

hasher.TransformFinalBlock(new byte[0], 0, 0);
byte[] hash = hasher.Hash;
Run Code Online (Sandbox Code Playgroud)

此模式适用于派生自HashAlgorithm,包括MD5CryptoServiceProvider和的任何类型SHA1Managed.

HashAlgorithm还定义了一个ComputeHash获取Stream对象的方法; 但是,此方法将阻塞线程,直到消耗流.使用该TransformBlock方法允许在不使用线程的情况下到达时计算的"异步散列".

  • 它不适合从网络接收流并仅使用 API CopyTo 方法将流发送(复制)到文件系统的情况。CryptoStream 解决了这个问题。 (2认同)

Pet*_*eld 13

System.Security.Cryptography.MD5类包含一个ComputeHash方法,该方法接受byte []或Stream.请访问http://msdn.microsoft.com/en-us/library/system.security.cryptography.md5_members.aspx查看


Man*_*red 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;
   }
}
Run Code Online (Sandbox Code Playgroud)

由于流和MD5都实现了IDisposible,因此您需要使用 using(...){...}

代码示例中的方法返回与Azure Blob存储中的MD5校验和相同的字符串.


Dav*_*ave 10

这似乎是CryptoStream( docs )的完美用例。

我曾用于CryptoStream处理未知长度的数据库结果流,这些结果需要 gzip 压缩,然后与压缩文件的散列一起通过网络传输。CryptoStream在压缩器和文件写入器之间插入 a允许您即时计算散列,以便在写入文件后立即准备就绪。

基本方法如下所示:

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();
Run Code Online (Sandbox Code Playgroud)