146

.NET 框架附带 6 种不同的散列算法:

  • MD5:16 字节(哈希 500MB 的时间:1462 毫秒)
  • SHA-1:20 字节(1644 毫秒)
  • SHA256:32 字节(5618 毫秒)
  • SHA3​​84:48 字节(3839 毫秒)
  • SHA512:64 字节(3820 毫秒)
  • RIPEMD:20 字节(7066 毫秒)

这些功能中的每一个都执行不同的操作;MD5 是最快的,RIPEMD 是最慢的。

MD5的优点是适合内置Guid类型;它是类型 3 UUID 的基础SHA-1 哈希是类型 5 UUID 的基础。这使得它们非常容易用于识别。

然而,MD5 容易受到碰撞攻击,SHA-1 也容易受到攻击,但程度较轻。

在什么情况下我应该使用哪种哈希算法?

我真的很想看到答案的具体问题是:

  • MD5不可信吗?在正常情况下,当您使用没有恶意的 MD5 算法并且没有第三方有任何恶意时,您会期望任何冲突(意味着两个任意字节 [] 产生相同的哈希)

  • RIPEMD 比 SHA1 好多少?(如果它更好的话)它的计算速度慢了 5 倍,但哈希大小与 SHA1 相同。

  • 散列文件名(或其他短字符串)时发生非恶意冲突的几率是多少?(例如 2 个具有相同 MD5 哈希的随机文件名)(使用 MD5 / SHA1 / SHA2xx) 一般来说,非恶意冲突的几率是多少?

这是我使用的基准:

    static void TimeAction(string description, int iterations, Action func) {
        var watch = new Stopwatch();
        watch.Start();
        for (int i = 0; i < iterations; i++) {
            func();
        }
        watch.Stop();
        Console.Write(description);
        Console.WriteLine(" Time Elapsed {0} ms", watch.ElapsedMilliseconds);
    }

    static byte[] GetRandomBytes(int count) {
        var bytes = new byte[count];
        (new Random()).NextBytes(bytes);
        return bytes;
    }
    

    static void Main(string[] args) {

        var md5 = new MD5CryptoServiceProvider();
        var sha1 = new SHA1CryptoServiceProvider();
        var sha256 = new SHA256CryptoServiceProvider();
        var sha384 = new SHA384CryptoServiceProvider();
        var sha512 = new SHA512CryptoServiceProvider();
        var ripemd160 = new RIPEMD160Managed();

        var source = GetRandomBytes(1000 * 1024);

        var algorithms = new Dictionary<string,HashAlgorithm>();
        algorithms["md5"] = md5;
        algorithms["sha1"] = sha1;
        algorithms["sha256"] = sha256;
        algorithms["sha384"] = sha384;
        algorithms["sha512"] = sha512;
        algorithms["ripemd160"] = ripemd160;

        foreach (var pair in algorithms) {
            Console.WriteLine("Hash Length for {0} is {1}", 
                pair.Key, 
                pair.Value.ComputeHash(source).Length);
        }

        foreach (var pair in algorithms) {
            TimeAction(pair.Key + " calculation", 500, () =>
            {
                pair.Value.ComputeHash(source);
            });
        }

        Console.ReadKey();
    }
4

9 回答 9

145

在密码学中,散列函数提供三个独立的函数。

  1. 碰撞阻力:某人找到两条哈希相同的消息(任意两条消息)有多难。
  2. 原像阻力:给定一个哈希值,找到另一个哈希值相同的消息有多难?也称为单向哈希函数
  3. 第二个原像阻力:给定一条消息,找到另一条哈希相同的消息。

这些属性是相关但独立的。例如,碰撞阻力意味着第二原像阻力,但反之则不然。对于任何给定的应用程序,您将有不同的要求,需要这些属性中的一个或多个。用于保护服务器密码的散列函数通常只需要原像抗性,而消息摘要需要这三个功能。

已经证明 MD5 不耐碰撞,然而,这并不排除它在不需要耐碰撞的应用中的使用。事实上,MD5 仍然经常用于较小的密钥大小和速度有好处的应用程序中。也就是说,由于其缺陷,研究人员建议在新场景中使用其他哈希函数。

SHA1 有一个缺陷,理论上它允许在远少于其长度的安全散列函数所需的 2^80 步中发现冲突。攻击不断被修改,目前可以在 ~2^63 步内完成 - 仅在当前的可计算性范围内。出于这个原因,NIST 正在逐步淘汰 SHA1 的使用,并指出 SHA2 系列应该在 2010 年之后使用。

SHA2 是在 SHA1 之后创建的一个新的哈希函数系列。目前没有针对 SHA2 函数的已知攻击。SHA256、384 和 512 都是 SHA2 系列的一部分,只是使用了不同的密钥长度。

RIPEMD 我不能过多评论,只是要注意它不像 SHA 系列那样常用,因此没有受到密码学研究人员的仔细审查。仅出于这个原因,我建议使用 SHA 函数。在您使用的实现中,它似乎也很慢,这使得它不太有用。

总之,没有一个最好的功能——这完全取决于你需要它做什么。请注意每个缺陷,您将能够最好地为您的场景选择正确的哈希函数。

于 2009-04-29T06:30:15.247 回答
116

所有哈希函数都“损坏”

鸽笼原则说,尽你所能,你不能在 2 个洞里放超过 2 只鸽子(除非你把鸽子剪掉)。同样,您不能在 2^128 个插槽中放置 2^128 + 1 个数字。所有哈希函数都会产生有限大小的哈希,这意味着如果您搜索“有限大小”+ 1 个序列,您总能找到冲突。这样做是不可行的。不适用于 MD5 和Skein

MD5/SHA1/Sha2xx 没有机会碰撞

所有的散列函数都有冲突,这是不争的事实。偶然遇到这些碰撞相当于赢得了星际彩票。也就是说,没有人中了星际彩票,这只是彩票的运作方式。您永远不会遇到意外的 MD5/SHA1/SHA2XXX 哈希。每个字典中的每个单词,每种语言中的每个单词,都会散列到不同的值。整个星球上每台机器上的每个路径名都有不同的 MD5/SHA1/SHA2XXX 哈希值。我怎么知道的,你可能会问。好吧,正如我之前所说,从来没有人中过星际彩票。

但是……MD5坏了

有时,它坏掉的事实并不重要

就目前而言,没有已知的对 MD5的原像或第二原像攻击。

那么,您可能会问,MD5 有什么问题?第三方有可能生成 2 条消息,其中一条是 EVIL,另一条是 GOOD,它们的哈希值相同。(碰撞攻击

尽管如此,如果您需要抗原像性,当前的 RSA 建议是不要使用 MD5。在涉及安全算法时,人们倾向于谨慎行事。

那么我应该在 .NET 中使用什么哈希函数呢?

  • 如果您需要速度/大小并且不关心生日攻击或原像攻击,请使用 MD5。

在我之后重复这个,没有机会 MD5 碰撞,可以精心设计恶意碰撞。尽管迄今为止在 MD5 上没有已知的前映像攻击,但安全专家的说法是,不应在需要防御前映像攻击的地方使用 MD5。SHA1 也一样

请记住,并非所有算法都需要防御原像或碰撞攻击。以第一次搜索 HD 上的重复文件为例。

  • 如果您想要加密安全的散列函数,请使用基于 SHA2XX 的函数。

没有人发现任何 SHA512 冲突。曾经。他们真的很努力。就此而言,没有人发现任何 SHA256 或 384 冲突。.

  • 不要使用 SHA1 或 RIPEMD,除非它用于互操作性场景。

RIPMED 没有受到与 SHAX 和 MD5 一样多的审查。SHA1 和 RIPEMD 都容易受到生日攻击。它们都比 .NET 上的 MD5 慢,并且只有 20 字节大小。使用这些功能毫无意义,忘记它们。

SHA1 碰撞攻击下降到 2^52,在 SHA1 碰撞在野外出现之前不会太久。

有关各种散列函数的最新信息,请查看散列函数 zoo

但是等等还有更多

拥有一个快速的散列函数可能是一个诅咒。例如:哈希函数的一个非常常见的用法是密码存储。本质上,您计算密码的哈希值和已知的随机字符串(以阻止彩虹攻击)并将该哈希值存储在数据库中。

问题是,如果攻击者得到数据库的转储,他可以非常有效地使用暴力破解密码。他尝试的每个组合只需要几分之一毫秒,他每秒可以尝试数十万个密码。

为了解决这个问题,可以使用bcrypt算法,它的设计速度很慢,因此如果使用 bcrypt 攻击系统,攻击者的速度将大大减慢。最近scrypt出现了一些头条新闻,并且被一些人认为比 bcrypt 更有效,但我不知道 .Net 实现。

于 2009-05-03T13:59:15.243 回答
36

更新:

时代变了,我们有了 SHA3 赢家。我建议使用SHA3 竞赛的 keccak(又名SHA3)获胜者。

原答案:

按照从弱到强的顺序,我会说:

  1. RIPEMD BROKEN,不应该使用,如本 pdf 所示
  2. MD-5 BROKEN,永远不要使用,可以用笔记本电脑在 2 分钟内打破
  3. SHA-1 BROKEN,永远不应该使用,原则上被破坏,攻击每周都在变好
  4. SHA-2 WEAK,未来几年可能会被打破。发现了一些弱点。请注意,通常密钥大小越大,哈希函数越难破解。虽然密钥大小 = 强度并不总是正确的,但大多数情况下都是正确的。所以 SHA-256 可能比 SHA-512 弱。
  5. Skein NO KNOWN WEAKNESSES,是 SHA-3 的候选者。它是相当新的,因此未经测试。它已经以多种语言实现。
  6. MD6 NO KNOWN WEAKNESSES,是 SHA-3 的另一个候选者。可能比 Skien 强,但在单核机器上速度较慢。像 Skien 一样,它未经测试。一些具有安全意识的开发人员正在以任务关键型角色使用它。

我个人会使用 MD6,因为人们永远不会太偏执。如果速度是一个真正的问题,我会考虑 Skein 或 SHA-256。

于 2009-05-01T01:45:15.337 回答
3

在 MD5 的辩护中,没有已知的方法可以生成具有任意 MD5 散列的文件。原作者必须提前计划进行工作冲突。因此,如果接收方信任发送方,MD5 就可以了。如果签名者是恶意的,MD5 就会被破坏,但不知道它是否容易受到中间人攻击。

于 2009-04-29T05:10:05.780 回答
3

看看BLAKE2算法是个好主意。

如前所述,它比 MD5 更快,并且至少与 SHA-3 一样安全。它也由几个软件应用程序实现,包括 WinRar。

于 2016-08-21T21:33:58.300 回答
2

您使用哪一个实际上取决于您使用它的目的。如果您只是想确保文件在传输过程中不会损坏并且不太担心安全性,请选择快速和小型。如果您需要数十亿美元的联邦救助协议的数字签名,并且需要确保它们不是伪造的,那么请努力欺骗和放慢速度。

于 2009-04-29T02:53:04.643 回答
2

我想插话(在 md5 被撕裂之前)我仍然广泛使用 md5,尽管它对于很多加密货币来说是压倒性的破坏。

只要您不关心防止碰撞(您仍然可以安全地在 hmac 中使用 md5)并且您确实想要速度(有时您想要更慢的哈希),那么您仍然可以自信地使用 md5。

于 2009-04-29T02:53:54.253 回答
0

我不是这类事情的专家,但我跟上安全社区的步伐,那里的很多人认为 md5 哈希已损坏。我会说使用哪一个取决于数据的敏感程度和特定的应用程序。只要密钥良好且强大,您就可以摆脱安全性稍差的哈希值。

于 2009-04-29T02:54:47.713 回答
0

以下是我给你的建议:

  1. 如果您预期攻击,您可能应该忘记 MD5。网上有很多彩虹表,众所周知,像 RIAA 这样的公司能够生成具有等效哈希的序列。
  2. 如果可以,请使用盐。在消息中包含消息长度会使产生有用的哈希冲突变得非常困难。
  3. 作为一般经验法则,更多位意味着更少的冲突(根据鸽巢原理)并且更慢,并且可能更安全(除非您是可以发现漏洞的数学天才)。

请参阅此处查看论文,该论文详细介绍了使用台式 Intel P4 计算机在 31 秒内创建 md5 冲突的算法。

http://eprint.iacr.org/2006/105

于 2009-04-29T02:57:41.013 回答