CNG、CryptoServiceProvider 和 HashAlgorithm 的托管实现
-
03-07-2019 - |
题
所以我想知道哈希算法的各种实现之间是否存在重大差异,例如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%