使用MD5.Create和MD5CryptoServiceProvider有什么区别?

48
在.NET框架中,似乎有几种计算MD5哈希的方法,但是有一些我不理解的地方;这些有什么区别?它们之间有什么不同之处?他们似乎产生了相同的结果:
    public static string GetMD5Hash(string str)
    {
        MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();
        byte[] bytes = ASCIIEncoding.Default.GetBytes(str);
        byte[] encoded = md5.ComputeHash(bytes);

        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < encoded.Length; i++)
            sb.Append(encoded[i].ToString("x2"));

        return sb.ToString();
    }

    public static string GetMD5Hash2(string str)
    {
        System.Security.Cryptography.MD5 md5 = System.Security.Cryptography.MD5.Create();
        byte[] bytes = Encoding.Default.GetBytes(str);
        byte[] encoded = md5.ComputeHash(bytes);

        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < encoded.Length; i++)
            sb.Append(encoded[i].ToString("x2"));

        return sb.ToString();
    }

我认为这个也应该被提及为正确答案的重要部分,因为它还提供了关于更近期版本的见解! - That Marc
4个回答

37

System.Security.Cryptography.MD5.Create() 实际上是创建一个 MD5CryptoServiceProvider。这就是为什么你看到相同的结果。

查看定义,MD5 是基类且为抽象类。我猜他们添加了公共的 create 函数以便于使用。

public sealed class MD5CryptoServiceProvider : MD5 { }

public abstract class MD5 : HashAlgorithm { }

请查看这些定义。

MD5 表示所有 MD5 哈希算法实现都继承的抽象类。

MD5CryptoServiceProvider 使用加密服务提供程序(CSP)提供的实现来计算输入数据的 MD5 哈希值。此类不能被继承。


2
你是否认为MD5.Create()方法是一种工厂方法,它今天可能会返回一个MD5CryptoServiceProvider实例,但在未来的版本中具有返回任何类型的MD5实现的灵活性?它的返回类型是MD5,因此如果你想让你的程序使用最新的实现,那么请使用MD5.Create()方法。 - Ben
C#如何返回一个抽象类的实例?我认为抽象类的整个目的就是不能被实例化,但它的继承子类可以。 - silkfire
MD5.Create() 返回一个 MD5CryptoServiceProvider 而非 MD5 抽象类。 - Jason Rowe

10
正如Jason Rowe所提到的(请投票支持他的答案,这只是一个警告),在功能上没有区别。但是,如果您考虑MD5Managed(或任何名称中带有Managed的加密类),则存在差异。当通过组策略启用符合FIPS标准的加密算法时,无法使用以“Managed”命名的类。

7
您也可以通过以下任一方式创建MD5CryptoServiceProvider对象:
(MD5CryptoServiceProvider) HashAlgorithm.Create("MD5");
(MD5CryptoServiceProvider) HashAlgorithm.Create("System.Security.Cryptography.MD5");
由于MD5是标准算法,而不是它们的代码相同,因此所有MD5类返回相同的哈希值。
但是创建MD5CryptoServiceProvider对象的方式并不是唯一的选择。
运行Windows的美国政府计算机必须启用FIPS模式。该模式确保使用的加密代码经过NIST验证。
各种.NET加密类通常存在多个版本。其中一个版本使用纯.NET代码,而其他版本调用Win32 API加密函数。
各种Win32加密API如下:
- Windows NT 4加密API:CAPI(CryptoAPI)。我理解CSP(Cryptographic Service Provider)是在CryptoAPI之上的加密API。 - Windows Vista加密API:CNG(Cryptography Next Generation)
Microsoft表示,加密服务提供程序已弃用,并可能在未来的Windows版本中被删除,并称CNG是CryptoAPI的长期替代品。
.NET加密类名称通常具有以下后缀:
- "CryptoServiceProvider"表示调用CryptoAPI Win32 API的类。 - "Cng"表示调用CNG Win32 API的类。 - "Managed"表示纯.NET代码类。
某些Win32 API可能无法符合FIPS标准,而且出于未公开的原因,微软没有请求或无法获得加密.NET纯代码的FIPS验证。
不符合FIPS标准的类会在启用FIPS模式的计算机上引发CryptographicException。这在它们的文档中提到。
因此,如果您的程序不打算在美国政府电脑上运行,则可以自由使用最快的类。
关于MD5,正如类名所示,MD5CryptoServiceProvider类应调用即将过时的CryptoAPI,并符合FIPS标准,而MD5Cng类调用CNG API并不符合FIPS标准。这表明,在未来的Windows版本中,MD5可能无法在美国政府计算机上使用。实际上,MD5.NET类的文档建议将MD5替换为SHA256或SHA512。
有关微软关于FIPS的含糊立场的更多信息,请参见:
https://blogs.technet.microsoft.com/secguide/2014/04/07/why-were-not-recommending-fips-mode-anymore/

MD5CryptoServiceProvider是从.NET Framework 1.1版本开始存在的。在Windows XP时期,MD5CryptoServiceProvider类被添加进来了。当时底层的Win32 CNG API并不存在。因此,MD5.Create方法在算法选择上没有选择余地,而微软可能还没有计划在Windows上实现CNG。自CNG被添加到Vista后,MD5Cng才存在于.NET Framework 3.5中。

与MD5CryptoServiceProvider相比,以下是大致执行时间(时间越短越好):
MD5Cng: x 1.08(.NET Framework 3.5)
SHA256CryptoServiceProvider: x 2.5(.NET Framework 3.5)
SHA256Cng: x 2.4(.NET Framework 3.5)
SHA256Managed: x 4.8(.NET Framework 1.1)

这些意外的结果显示,SHA256Managed .NET纯代码实现速度较慢。
当SHA256Managed实现时,表现更好的Windows Vista CNG并不存在。

在流上执行要比在字节数组上执行总是略快一些。

用于验证本帖是否被外部代理修改的哈希值为:
1c84TiredWithMSDNwrittenByAncientEgyptians4cfebef40b0ae0a906b97c7


说得好!我很高兴尽管旧的帖子和答案被标记为上面已经被接受,但出于某种原因我仍然向下滚动并认识到今天有些新的和非常有用的东西! :) - That Marc

3

我的两分钱。

MD5增加了一些开销,MD5CryptoServiceProvider相比较慢

我刚刚进行了一个小型压力测试,生成了300k个字符串的哈希值:

MD5CryptoServiceProvider: 00:00:01.1750834
MD5: 00:00:01.6398959

减慢了近1.5倍。
PS. 在一台i7核心的笔记本电脑上测试。

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