2010-09-01 81 views
14

什么是C#中的最佳解决方案计算的“对飞” MD5像未知长度的流的哈希?具体来说,我想从网络上收到的数据计算一个散列。我知道当发送者终止连接时我已经接收到了数据,所以我不知道这个长度。计算从未知长度的流在C#中的哈希

[编辑] - 现在我使用MD5,但这需要在数据第二遍后,它被保存并写入磁盘。我宁愿将它散列到网络中。

回答

43

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; 

这种模式适用于衍生自任何类型的其中包括MD5CryptoServiceProviderSHA1Managed

HashAlgorithm也定义了一个方法ComputeHash,它需要一个Stream对象;然而,这个方法会阻塞线程,直到流被使用。使用TransformBlock方法允许在数据到达时计算出“异步散列”,而无需使用线程。

+0

我看到了这些方法,但从来没有调查他们做了什么。对我感到羞耻。这看起来像会起作用。 – jjxtra 2010-09-01 19:13:26

7

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

1

Necromancing。

两个possibilitites在C#.NET核心:

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