CNG,CryptoServiceProvider和HashAlgorithm的Managed实现

24

我在想这些哈希算法的各种实现之间是否有重大差异,以SHA系列算法为例。它们都有3种实现方法,一种是托管代码,另外两种是使用不同本地加密API的包装器,但它们之间是否有重大区别呢?我可以想象包装版本可能具有更高的性能,因为它在本地代码中执行,但它们肯定需要执行完全相同的计算,从而提供相同的输出,即它们可以互换。这是正确的吗?

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


@Maxim - 谢谢你,但不完全符合我的要求。我想知道使用给定哈希算法的Managed/CryptoServiceProvider/CNG实现除性能之外是否有任何区别。在.NET 3.5中,您可以获得所有哈希算法及其三个实现,因此:

SHA512Managed SHA512CryptoServiceProvider SHA512Cng

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


我曾经注意到本地包装器实现之一(加密,忘记是哪一个)在XP SP1和SP2中产生了不同的结果。那是很久以前,当时我正在使用的是.Net 1.1,因此我转而使用托管实现,更“可移植”。 - faulty
据我所知,封装实现(CryptoServiceProvider 和 CNG 版本)在 XP SP2 上无法工作,尽管 MSDN 文档声称它们可以。我尝试了一下,但是抛出了异常。 - TheCodeJunkie
3
以下是一些有用的链接,它们提供了关于加密类不同版本及其支持情况的表格总结:http://mytenpennies.wikidot.com/blog:cryptography-in-dot-nethttp://geeklyeverafter.blogspot.com/2010/12/net-encryption-part-2.html - luksan
4个回答

18

一个区别是本地版本(至少其中一些)是FIPS认证的(即被美国政府批准),而托管版本则没有。如果你的代码恰好在配置为“仅限FIPS”的Windows机器上运行,则使用托管版本将会失败。

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

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


.NET Core中的CNG版本在哪里?CNG和CryptoServiceProvider版本之间有什么区别吗? - afruzan

4
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时已经耗尽了内存):

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

1
DateTime并不是精确的,使用Stopwatch进行时间测量,它使用高分辨率性能计数器! - BerndK

1

我在下面的代码中对CNGmanaged在SHA512上进行了一个快速而简单的比较,这是我所知道的所有SHA算法中最慢的。

    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%

有趣的事实是,为了保护您免受暴力破解攻击,您实际上希望您的哈希算法变慢。对于用户来说,300毫秒或3毫秒没有区别,但对于攻击者来说,这是一个100数量级的差距! - Ioanna
你并不总是希望它变慢。例如,在进行数据快速比较时,您希望碰撞几率较低。 - rollsch

1
受支持的.Net Framework版本是Managed和CNG版本之间的另一个区别:例如,
  • AES Managed版本从3.5开始,而CNG版本从4.6.2开始;
  • SHA512,Managed从1.1开始,Cng从3.5开始。
然而,我认为如果我们不受框架版本或支持旧操作系统版本的限制,我们应该使用CNG版本
  • 后缀为Cng的哈希算法是唯一使用bcrypt的算法;
  • 它可能需要更长时间的事实实际上是一个优点,因为它可以防止暴力攻击:对于用户来说,300ms或3ms没有区别,而对于攻击者来说,这是100数量级的顺序!

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接