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

在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派生的任何类型,包括MD5CryptoServiceProviderSHA1Managed

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

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

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

Necromancing。

C#.NET Core中的两种可能性:

 private static System.Security.Cryptography.HashAlgorithm GetHashAlgorithm(System.Security.Cryptography.HashAlgorithmName hashAlgorithmName) { if (hashAlgorithmName == System.Security.Cryptography.HashAlgorithmName.MD5) return (System.Security.Cryptography.HashAlgorithm) System.Security.Cryptography.MD5.Create(); if (hashAlgorithmName == System.Security.Cryptography.HashAlgorithmName.SHA1) return (System.Security.Cryptography.HashAlgorithm) System.Security.Cryptography.SHA1.Create(); if (hashAlgorithmName == System.Security.Cryptography.HashAlgorithmName.SHA256) return (System.Security.Cryptography.HashAlgorithm) System.Security.Cryptography.SHA256.Create(); if (hashAlgorithmName == System.Security.Cryptography.HashAlgorithmName.SHA384) return (System.Security.Cryptography.HashAlgorithm) System.Security.Cryptography.SHA384.Create(); if (hashAlgorithmName == System.Security.Cryptography.HashAlgorithmName.SHA512) return (System.Security.Cryptography.HashAlgorithm) System.Security.Cryptography.SHA512.Create(); throw new System.Security.Cryptography.CryptographicException($"Unknown hash algorithm \"{hashAlgorithmName.Name}\"."); } protected override byte[] HashData(System.IO.Stream data, System.Security.Cryptography.HashAlgorithmName hashAlgorithm) { using (System.Security.Cryptography.HashAlgorithm hashAlgorithm1 = GetHashAlgorithm(hashAlgorithm)) return hashAlgorithm1.ComputeHash(data); } 

或者与BouncyCastle:

 private static Org.BouncyCastle.Crypto.IDigest GetBouncyAlgorithm( System.Security.Cryptography.HashAlgorithmName hashAlgorithmName) { if (hashAlgorithmName == System.Security.Cryptography.HashAlgorithmName.MD5) return new Org.BouncyCastle.Crypto.Digests.MD5Digest(); if (hashAlgorithmName == System.Security.Cryptography.HashAlgorithmName.SHA1) return new Org.BouncyCastle.Crypto.Digests.Sha1Digest(); if (hashAlgorithmName == System.Security.Cryptography.HashAlgorithmName.SHA256) return new Org.BouncyCastle.Crypto.Digests.Sha256Digest(); if (hashAlgorithmName == System.Security.Cryptography.HashAlgorithmName.SHA384) return new Org.BouncyCastle.Crypto.Digests.Sha384Digest(); if (hashAlgorithmName == System.Security.Cryptography.HashAlgorithmName.SHA512) return new Org.BouncyCastle.Crypto.Digests.Sha512Digest(); throw new System.Security.Cryptography.CryptographicException( $"Unknown hash algorithm \"{hashAlgorithmName.Name}\"." ); } // End Function GetBouncyAlgorithm protected override byte[] HashData(System.IO.Stream data, System.Security.Cryptography.HashAlgorithmName hashAlgorithm) { Org.BouncyCastle.Crypto.IDigest digest = GetBouncyAlgorithm(hashAlgorithm); byte[] buffer = new byte[4096]; int cbSize; while ((cbSize = data.Read(buffer, 0, buffer.Length)) > 0) digest.BlockUpdate(buffer, 0, cbSize); byte[] hash = new byte[digest.GetDigestSize()]; digest.DoFinal(hash, 0); return hash; }