我应该选择哪种加密哈希函数?

Posted

技术标签:

【中文标题】我应该选择哪种加密哈希函数?【英文标题】:Which cryptographic hash function should I choose? 【发布时间】:2010-10-22 11:45:01 【问题描述】:

.NET 框架附带 6 种不同的哈希算法:

MD5:16 字节(散列时间 500MB:1462 毫秒) SHA-1:20 字节(1644 毫秒) SHA256:32 字节(5618 毫秒) SHA384:48 字节(3839 毫秒) SHA512:64 字节(3820 毫秒) RIPEMD:20 字节(7066 毫秒)

这些功能中的每一个都有不同的表现; MD5 最快,RIPEMD 最慢。

MD5的优点是适合内置的Guid类型; and it is the basis of the type 3 UUID。 SHA-1 hash is the basis of type 5 UUID. 这使得它们非常容易用于识别。

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

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

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

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

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();
    

【问题讨论】:

您提到 md5 符合 GUID(16 字节)格式的事实表明存在根本性的误解。散列不保证是唯一的,但很少见(如果在加密意义上使用,很难伪造)并且源自它是散列的东西,而 GUID 是唯一的但与内容无关它识别的东西。它们用于非常不同的目的。 更正它无关的,它只是一个方便的实现特定的事实。我知道您不能将无穷大放入 16 个字节中。您可以与任何散列算法发生冲突 Guid 在实践中也是唯一的,理论上如果你继续生成 Guid,最终你会得到重复。 您真的不应该将哈希值填充到 GUID 中,即使它适合。最简单的例子:同一个文件的两个副本应该有不同的 GUID,但相同的哈希值。人名的前 8 个字母也非常适合 16 个字节。 @user2332868 破坏 SHA-1 对 意外 冲突的概率没有影响。当恶意意图对您的使用构成威胁时,我认为盲目选择任何哈希函数都是错误的,您需要花时间针对您的具体情况进行风险/成本分析。 【参考方案1】:

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

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

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

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

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

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

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

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

【讨论】:

非常感谢您深入了解这一细节。这很有帮助。 对于某些应用程序,即使是非加密级哈希函数也可能是合适的。 OP 从未提及它是专门用于密码、质询-响应身份验证、访问令牌,还是仅用于索引一堆字符串/文件。另一方面,性能是 OP 关心的问题...【参考方案2】:

所有哈希函数都“损坏”

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

MD5/SHA1/Sha2xx 没有机会碰撞

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

但是……MD5坏了

有时它的损坏并不重要

目前在 MD5 上没有已知的pre-image or second pre-image attacks。

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

尽管如此,如果您需要抗原像性,当前的 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 碰撞在野外出现之前不会太久。

有关各种哈希函数的最新信息,请查看the hash function zoo。

但等等还有更多

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

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

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

【讨论】:

虽然 MD5 和 SHA-1 都被削弱了,但 MD5 比 SHA-1 弱得多,但只是稍微快了一点。已发现实际的 MD5 冲突并将其用于现实世界的漏洞利用(伪造 CA 证书),但据我所知,没有发现实际的 SHA-1 冲突(尽管操作数量已从蛮力大幅减少)。考虑到 MD5 的强度要低得多,如果 MD5 比 SHA-1 更早地出现第二次原像攻击,我不会感到惊讶。因此,我认为如果您需要速度而不是抗碰撞性,您应该使用 SHA-1,否则使用 SHA-2 系列之一。 @Brian 很清楚,在未来几年内,人们将能够对 SHA1 进行碰撞攻击,这实际上将使 SHA1 与 MD5 一样有用,CA 证书是一种碰撞攻击,同样几年后,人们将能够对 SHA1 CA 证书进行相同的攻击。攻击取决于恶意方创建 EVIL 和 GOOD 证书。没有已知的对 MD5 的原像攻击,并且存在碰撞攻击这一事实不会或多或少地导致原像攻击的可能性。 密码使用的哈希值远不如哈希值。如果您的盐是已知的,那么您的数据库将立即容易受到字典攻击;如果您的盐是程序性的,并且您的文件系统受到损害,那么您(再次)容易受到攻击;如果您的盐被省略,您将再次受到损害。无论如何,有问题的安全性是散列的内容。证书,我不会处理,因为我没有以程序员的身份处理它们(IE、创建、理解等)。 “破碎”一词在散列的上下文中具有特定的含义,并不是这个答案所强调的含义。这个答案只会引起混乱。 这是一个很好的答案,因为它注重实用性。哈希用于安全以外的事情(例如为非敏感数据生成缓存查找键或确定序列化对象是否已更改)。有针对性的攻击的机会几乎为零(永远不要说永远),即使攻击成功,也不会产生实质性影响。专注于实际(而非理论)影响的出色工作。【参考方案3】:

更新:

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

原答案:

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

    RIPEMD 已损坏,不应使用 as can be seen in this pdf MD-5 损坏,不应该使用,can be broken in 2 minutes with a laptop SHA-1 损坏,不应使用,is broken in principal, attacks are getting better by the week SHA-2 WEAK,未来几年可能会被破坏。 A few weaknesses have been found. 请注意,通常密钥大小越大,哈希函数越难破解。虽然密钥大小 = 强度并不总是正确的,但大多数情况下都是正确的。所以 SHA-256 可能比 SHA-512 弱。 绞纱没有已知的弱点,is a candidate for SHA-3。它是相当新的,因此未经测试。 It has been implemented in a bunch of languages. MD6 NO KNOWN WEAKNESSES,是 SHA-3 的另一个候选者。可能比 Skien 强,但在单核机器上速度较慢。像 Skien 一样,它未经测试。一些具有安全意识的开发人员正在使用它,mission critical roles。

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

【讨论】:

我不会把 Skein 和 MD6 放在列表中那么高的位置。 SHA-3 竞赛要到 2012 年底才能结束是有原因的。需要很长时间和很多眼睛才能确信哈希函数实际上可能是安全的,而这两个函数都不是已经存在足够长的时间了。 我同意你的观点,但我认为社区处于一个奇怪的位置。所有使用中的散列函数都危险地接近被破坏(也许,也许不是 SHA2 256-512),但我们必须等到 2012 年才能选择替代品。选择你的毒药:弱/损坏或未经测试(大多数 NIST 候选人没有公开超过 6 个月)?艰难的选择。 RIPEMD 坏了,但 RIPEMD-128/160/256 不同,并没有坏。 我不知道 Skein for .NET 的任何高性能实现。我遇到过 SkeinFish 和 nskein,两者都非常很慢。 我会等待使用 SHA-3 直到实际标准出现,至少如果您想真正遵循标准。算法本身的选项太多了。【参考方案4】:

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

【讨论】:

虽然我绝不是该领域的专家,但现在通过蛮力计算任意 MD5 哈希不是很接近可能吗? @mafu:这里的响应较晚,但可以通过蛮力计算任何哈希值。这可能需要很长时间。 @ItzWarty 我特别指的是所需的时间 - 因为 MD5 很短,我认为可以简单地在其上放置一个合理的计算源(E3,或者一个便宜的计算机网格)有几块显卡的机器,类似的东西)并且能够在几天内计算任意 MD5 哈希。 @mafu 对于 128 位散列,前映像攻击需要 2^127 次散列调用。这远非可行。 2^80 次调用是可行的,但已经非常昂贵。【参考方案5】:

看看BLAKE2算法是个好主意。

如前所述,它比 MD5 更快,并且至少与 SHA-3 一样安全。 several software applications也实现了,包括WinRar。

【讨论】:

它可能会更快,除非许多实现都有硬件支持,这使得 SHA-256 相当快。 我同意。截至 2019 年,Blake2b 是迄今为止发布的最佳通用哈希。比所有其他替代方案快得多,而且安全性不低(至少没有任何有意义的方式),并且只能在 336 字节的 ram 中执行(blake2s 为 168 字节),哦,它针对 little-endian CPU 进行了优化,这是当今系统中占主导地位的字节序。【参考方案6】:

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

【讨论】:

很多时候在讨论问题的解决方案时我提到我使用 MD5 来快速识别(散列字符串),他们说“但是 md5 坏了......不要使用它,使用 sha1”......我真的不同意这一点,我想知道是否有一些较弱的哈希从根本上破坏了它们,应该避免它们......例如正常数据产生冲突的实际工作案例 看到 MD5 为数百万人工作了 15 年,我怀疑如果哈希安全不重要,对您来说也可以。 @sambo MD5 几乎适用于任何情况,除非系统的实际安全/完整性取决于防止冲突。【参考方案7】:

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

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

【讨论】:

@Mike 我同意你的观点,这就是我在这个问题上所要挖掘的,是关于较弱的哈希函数从根本上被破坏以至于它们永远不应该被使用的东西。跨度> 此外,如果数据或数据所需的安全性的生命周期短于破解期(这些天 iirc 几分钟)MD5 绝对没问题。对情境有用但仍然有用才是重点。 @annakata - 请记住,您还必须避免在多条消息中重复使用密钥才能在这些情况下使用它。【参考方案8】:

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

【讨论】:

散列函数通常不使用键【参考方案9】:

以下是我给你的建议:

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

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

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

【讨论】:

这条评论已经很老了,看起来相当隐蔽,但是这一点 - RIAA 已经知道能够产生具有等效哈希的序列 - 突然出现在我面前,并且我很好奇这是什么背景。特别是 8 年前的 MD5 暴力破解比 2017 年要少一些,所以他们一定有一个很好的理由。

以上是关于我应该选择哪种加密哈希函数?的主要内容,如果未能解决你的问题,请参考以下文章

Python中的加密哈希函数

哈希(hash) - 哈希算法的应用

Hive的内置HASH()函数使用哪种哈希算法

证明与计算: 从加密哈希函数到一致性哈希

良好的加密哈希函数 [重复]

什么是区块链哈希算法?加密货币中哈希算法的应用有哪些?