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

时间:2010-09-01 19:05:37

标签: c# hash cryptography stream

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

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

5 个答案:

答案 0 :(得分:49)

与其他哈希函数一样,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方法允许在不使用线程的情况下到达时计算的“异步散列”。

答案 1 :(得分:10)

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

答案 2 :(得分:8)

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

答案 3 :(得分:2)

这似乎是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();

答案 4 :(得分:1)

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;
}