所以我想知道哈希算法的各种实现之间是否存在重大差异,例如SHA系列算法。它们各有 3 个实现,其中 1 个在托管代码中,2 个围绕不同本机加密 API 的包装器,但是使用它们中的任何一个之间有什么重大区别吗?我可以想象,包装器版本可以具有更高的性能,因为它是在本机代码中执行的,但是 surley hey 都需要执行完全相同的计算,从而提供相同的输出,即 hey 是可以互换的。它是否正确?

例如,SHA512CNG 不能在 XP SP2 上使用(文档是错误的),但 SHA512MANAGED 可以。


@Maxim - 谢谢你,但不完全是我所要求的。我问的是,除了可能的性能之外,使用给定哈希算法的 Managed/CryptoServiceProvider/CNG 实现是否有任何差异。使用 .NET 3.5,您可以获得具有三种实现的所有哈希算法,因此

SHA512管理的SHA512CryptoServiceProvider SHA512CNG

后两者是本机 API 的包装器。例如,对于所有 SHAxxx 实现都是如此。

有帮助吗?

解决方案

一个区别是本机版本(至少其中一些)经过 FIPS 认证(即经美国政府批准),而托管版本则不然。如果您的代码恰好在配置为“仅限 FIPS”的 Windows 计算机上运行,​​则尝试使用托管版本将会失败。

大多数 Windows 计算机都没有以这种方式配置,但如果您要部署到面向政府或国防(或其他高度安全)的环境,您可能会遇到这种情况。

http://blogs.msdn.com/shawnfa/archive/2005/05/16/417975.aspx.

其他提示

Cng版本应该更快一些,但我刚刚编写了一个比较每个版本速度的小程序。 (我有一个客户询问MD5与SHA1的性能特征)

我很惊讶地发现MD5和SHA1之间几乎没有区别,但也很惊讶Cng和CryptoServiceProvider之间存在细微差别。

源代码非常直接,我添加了代表多次执行相同的迭代,所以我可以在一次运行期间在我的机器上进行平均以防万一发生任何奇怪现象。

通过以下呼叫拨打以下电话:

CalculateHash(1, 1024, new SHA1CryptoServiceProvider());

static long CalculateHash(UInt64 repetitions, UInt64 size, HashAlgorithm engine)
    {
        RandomNumberGenerator rng = RandomNumberGenerator.Create();

        byte[][] goo = new byte[repetitions][];
        for (UInt64 i = 0; i < repetitions; i++)
        {
            goo[i] = new byte[size];
            rng.GetBytes(goo[i]);
        }

        DateTime start = DateTime.Now;
        for (UInt64 i = 0; i < repetitions; i++)
        {
            engine.ComputeHash(goo[i]);
        }
        return DateTime.Now.Subtract(start).Ticks;
    }

我在一个越来越大的循环中运行它,以确定在使用大或小输入时是否有人摔倒了。这是循环,数据如下(我的计算机在2 ^ 28时用完了ram):

int loops = 32;
        UInt64 reps = 1;

        int width = 20;
        Console.WriteLine("Loop#".PadRight(6) +
                "MD5".PadRight(width) +
                "SHA1".PadRight(width) +
                "SHA1Cng".PadRight(width) +
                "SHA256".PadRight(width) +
                "SHA256Cng".PadRight(width));

        for (int i = 0; i < loops; i++)
        {
            UInt64 size = (UInt64)Math.Pow((double)2, (double)i);

            Console.WriteLine((i + 1).ToString().PadRight(6) +
                CalculateHash(reps, size, new MD5CryptoServiceProvider()).ToString().PadRight(width) +
                CalculateHash(reps, size, new SHA1CryptoServiceProvider()).ToString().PadRight(width) +
                CalculateHash(reps, size, new SHA1Cng() ).ToString().PadRight(width) +
                CalculateHash(reps, size, new SHA256CryptoServiceProvider()).ToString().PadRight(width) +
                CalculateHash(reps, size, new SHA256Cng()).ToString().PadRight(width));
        }

Loop# MD5         SHA1        SHA1Cng     SHA256      SHA256Cng
1     50210       0           0           0           0
2     0           0           0           0           0
3     0           0           0           0           0
4     0           0           0           0           0
5     0           0           0           0           0
6     0           0           0           0           0
7     0           0           0           0           0
8     0           0           0           0           0
9     0           0           0           0           0
10    0           0           10042       0           0
11    0           0           0           0           0
12    0           0           0           0           0
13    0           0           0           0           0
14    0           0           0           0           0
15    10042       0           0           10042       10042
16    10042       0           0           0           0
17    0           0           0           10042       10042
18    0           10042       10042       20084       10042
19    0           10042       10042       30126       40168
20    20084       20084       20084       70294       70294
21    30126       40168       40168       140588      140588
22    60252       70294       80336       291218      281176
23    120504      140588      180756      572394      612562
24    241008      281176      361512      1144788     1215082
25    482016      572394      723024      2289576     2420122
26    953990      1134746     1456090     4538984     4830202
27    1907980     2259450     2982474     9118136     9660404
28    3805918     4508858     5804276     18336692    19581900

我在SHA512上的 CNG managed 之间进行了快速而又脏的比较,这是使用下面代码的所有SHA算法AFAIK中最慢的。

    static void Main(string[] args)
    {
      int loops = 10000000;
      var data = Encoding.ASCII.GetBytes("123");

      var hashLoop = new Action<HashAlgorithm>((HashAlgorithm ha) =>
      {
        for (int i = 0; i < loops; i++)
          ha.ComputeHash(data);
      });

      var t1 = Task.Factory.StartNew(() =>
      {
        Time(hashLoop, new SHA512Managed());
      });
      var t2 = Task.Factory.StartNew(() =>
      {
        Time(hashLoop, new SHA512Cng());
      });

      Task.WaitAll(t1, t2);
      Console.WriteLine("Benchmark done!");
      Console.ReadKey();
    }
    static void Time(Action<HashAlgorithm> action, HashAlgorithm ha)
    {
      var sw = new Stopwatch();
      sw.Start();
      action(ha);
      sw.Stop();
      Console.WriteLine("{1} done in {0}ms", sw.ElapsedMilliseconds, ha.ToString());
    }

经过多次运行,我发现不同之处在于CNG比算法的托管版本快得多,大约 21.7%到49.5%

托管版本和 CNG 版本之间的另一个区别是支持的 .Net Framework 版本:例如

  • AES Managed 版本从 3.5 开始,而 CNG 从 4.6.2 开始
  • SHA512, 管理 从 1.1 开始并且 天然气 从 3.5 开始。

但是,我认为,如果我们不受框架版本的限制或支持旧版操作系统版本,我们应该使用 压缩天然气版本:

  • 后缀为 Cng 的哈希算法是唯一使用的算法 密码
  • 事实上,它可能需要更长的时间实际上是一个优势,因为它可以防止暴力攻击:在用户端,300ms 或 3ms 没有区别,而对于攻击者来说,这是 100 数量级!
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top