代码之家  ›  专栏  ›  技术社区  ›  jjxtra

从C中长度未知的流计算哈希#

  •  18
  • jjxtra  · 技术社区  · 14 年前

    在C语言中,计算长度未知的流的“动态”md5哈希的最佳解决方案是什么?具体地说,我想从通过网络接收的数据中计算一个散列。我知道当发送者终止连接时,我已经完成了数据接收,所以我不知道提前的长度。

    [编辑]-现在我正在使用md5,在数据被保存并写入磁盘之后,我正在对其进行第二次传递。我宁愿把它从网络传来的时候放在适当的地方。

    5 回复  |  直到 5 年前
        1
  •  65
  •   Jeff Moser    12 年前

    开始:

    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 MD5CryptoServiceProvider SHA1Managed .

    哈希算法 ComputeHash 这需要一个 Stream 对象;但是,此方法将阻止线程,直到流被使用为止。使用 TransformBlock 这种方法允许在数据到达时计算“异步哈希”,而不使用线程。

        2
  •  13
  •   Michael come lately Nayeem    5 年前

    这个 System.Security.Cryptography.MD5 ComputeHash 方法 byte[] Stream . 退房 the documentation .

        3
  •  13
  •   Manfred    4 年前

    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都实现了idisposable,所以您需要使用 using(...){...}

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

        4
  •  9
  •   Dave    5 年前

    这似乎是一个完美的用例 CryptoStream ( docs ).

    标准接口 用于处理未知长度的数据库结果流,这些结果需要gzip压缩,然后与压缩文件的哈希一起通过网络传输。插入 标准接口

    基本方法如下所示:

    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();
    
        5
  •  3
  •   Stefan Steiger    6 年前

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