从未知长度的C#中的流计算散列从未知长度的C#中的流计算散列(Compute a hash from

2019-05-12 01:48发布

什么是C#中的最佳解决方案计算的“对飞” MD5像未知长度的流的哈希? 具体而言,我想计算从网络上接收到的数据的哈希值。 我知道,当发送者终止连接我做了接收数据的,所以我不知道事先的长度。

[编辑] - 现在我使用MD5,但这需要在数据第二遍后,它被保存并写入磁盘。 因为它从网络中来,我宁愿哈希到位。

Answer 1:

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方法允许“异步散列”作为数据到达,而无需使用一个线程来计算。



Answer 2:

所述System.Security.Cryptography.MD5类包含一个ComputeHash方法,该方法它可以是一个字节[]或流。 瞧瞧吧http://msdn.microsoft.com/en-us/library/system.security.cryptography.md5_members.aspx



Answer 3:

继@彼得- 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(...){...}

在代码示例中的方法返回用于在天青Blob存储的MD5校验相同的字符串。



Answer 4:

这似乎是一个完美使用案例CryptoStream ( 文档 )。

我使用CryptoStream用于加工需要用gzip压缩,然后与压缩文件的哈希一起通过网络传输数据库结果的未知长流。 插入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();


Answer 5:

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


文章来源: Compute a hash from a stream of unknown length in C#