使用Bouncy Castle计算文件的哈希值

时间:2012-08-21 17:52:20

标签: c# .net cryptography bouncycastle

我正在查看Bouncy Castle,了解其哈希算法的性能与.NET Framework的性能相比,它看起来并不太好; MD5的实现速度比.NET慢大约6倍,而SHA256的实现速度比.NET慢大约3倍。

所以我想确保我正确使用Bouncy Castle,因为文档几乎不存在。这就是我正在做的事情:

using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Digests;

public byte[] Hash(string filename)
{
  IDigest hash = new Sha256Digest();

  byte[] result = new byte[hash.GetDigestSize()];

  using (var fs = new FileStream(filename, FileMode.Open, FileAccess.Read, 
    FileShare.Delete | FileShare.ReadWrite))
  {
    byte[] buffer = new byte[4092];
    int bytesRead;

    while ((bytesRead = fs.Read(buffer, 0, buffer.Length)) > 0)
    {
      hash.BlockUpdate(buffer, 0, bytesRead);
    }

    hash.DoFinal(result, 0);
  }

  return result;
}

修改

为了比较,以下是我如何使用.NET:

public byte[] Hash(string filename)
{
  byte[] hashBytes;
  HashAlgorithm hash = new SHA256CryptoServiceProvider();

  using (var fs = new FileStream(filename, FileMode.Open, FileAccess.Read, 
    FileShare.Delete | FileShare.ReadWrite))
  {
    try
    {
      hashBytes = hash.ComputeHash(fs);
    }
    finally
    {
      hash.Clear();
    }
  }

  return hashBytes;
}

4 个答案:

答案 0 :(得分:3)

您应该检查的第一件事是您是IO绑定还是CPU限制。如果你受CPU限制,那么我怀疑 Bouncy Castle。如果你受IO限制,可能是.NET对IO更加智能。首先,您可能希望将缓冲区大小从4K增加到(比方说)64K。试一试吧。这是一个非常容易的改变。更难的改变是使用异步IO,以便在您散列已经获得的数据时读取下一个缓冲区的未散列数据。

答案 1 :(得分:1)

虽然这两种算法可能差异很大,您可能会遇到3-6倍的差异,但问题很可能是由于I / O差异造成的。通过将FileStream传递给.NET实现,它有可能在内部做一些聪明的事情来实现更好的I / O性能(例如并发哈希和读取),而你在Bouncy Castle示例中没有这样做。

要对此进行测试,您可以:

  1. 让你的两个例子尽可能相似(这就是我要做的)。您可以在.NET HashAlgorithm中使用TransformBlock和TransformFinalBlock,它将更类似于您的Bouncy Castle测试。

  2. 尝试对Bouncy Castle代码进行I / O优化,看看是否可以实现.NET实现的性能。

  3. 但这可能没有实际意义。如果.NET实现满足您的需求,它可能最适合您的应用程序。看起来它可能已经内置了一些性能特征,你必须手动添加到Bouncy Castles实现。

答案 2 :(得分:1)

  1. 似乎您正在正确使用它。

    • 如果不确定,请通过将散列与.NET进行比较来测试代码 哈希。
    • 您还可以测试不同的块大小,看看它们是否 提高代码的性能。 4092可能不是最佳大小 对于较大的流。另外,请尝试使用2的倍数的块大小。
  2. 您对两个实现之间的性能差异也很正确。 我的最新测试表明,在c#nuget上的Bouncy Castle MD5哈希比.NET哈希慢约X2。

MD5 hashing times (milliseconds)

答案 3 :(得分:0)

我知道这个问题已经很老了,但是目前,.NET和Bouncy Castle的MD5算法实现都能获得相同的速度。

但是,我没有在读取文件时计算哈希,而是在上一步中读取了完整的文件竞争然后对它进行哈希处理:

    var md5Digest = new MD5Digest();
    var hash = new byte[md5Digest.GetDigestSize()];

    md5Digest.BlockUpdate(buffer, 0, buffer.Length);
    md5Digest.DoFinal(hash, 0);

    // Once used, mark buffer content to be garbage collected.
    buffer = null;

(我很清楚,将完整的文件内容存储在内存中可能不是很方便)。