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


137

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

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

这些功能各自执行不同的功能。MD5是最快的,而RIPEMD是最慢的。

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

但是,MD5容易受到碰撞攻击,SHA-1也容易受到攻击,但程度较小。

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

我真的很想知道答案的具体问题是:

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

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

  • 在对文件名(或其他短字符串)进行哈希处理时,获得非恶意冲突的几率是多少?(例如,两个具有相同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();
    }

15
您提到的md5符合GUID(16字节)格式的事实表明存在基本的误解。不能保证哈希是唯一的,但是哈希是稀有的(如果从加密的意义上讲,很难伪造),并且哈希是从哈希中派生出来的,而GUID则是唯一的,但与哈希表的内容无关它标识的东西。它们用于非常不同的目的。
巴里·沃克

1
更正其无关的部分,只是方便实施的事实。我了解您无法将无穷大设置为16个字节。您可能会与ANY哈希算法发生冲突
Sam Saffron's

5
同样,Guid只是在实践中是唯一的,理论上,如果您继续生成Guid,最终会得到重复。
Sam Saffron

3
即使哈希适合,您也不应该将哈希填充到GUID中。最简单的示例:同一文件的两个副本应具有不同的GUID,但哈希相同。一个人的名字的前8个字母也很适合16个字节。
dbkk 2011年

2
@ user2332868 SHA-1的断开对意外碰撞的可能性没有影响。当恶意意图对您的使用构成威胁时,我认为盲目选择任何哈希函数是错误的,并且您需要花时间对您的特定案例进行风险/成本分析。
Andrey Tarantsov 2014年

Answers:


138

在密码学中,哈希函数提供三个单独的函数。

  1. 防冲突:某人找到两条散列相同的消息(任意两条消息)有多困难。
  2. 图像前抵抗力:给定一个散列,找到另一个散列相同的消息有多难?也称为单向哈希函数
  3. 第二次原像抵抗:给定一条消息,找到另一条散列相同的消息。

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

已经表明,MD5不是抗碰撞的,但是,这并不排除其在不需要抗碰撞的应用中的使用。确实,MD5仍经常用于较小的密钥大小和更快的速度的应用程序中。就是说,由于其缺陷,研究人员建议在新方案中使用其他哈希函数。

SHA1的一个缺陷是,理论上发现冲突的长度远远小于其长度的安全哈希函数所需的2 ^ 80步。攻击正在不断地进行修订,并且目前可以以〜2 ^ 63的步骤进行-仅在当前可计算性范围内。因此,NIST正在逐步淘汰SHA1,并指出应在2010年之后使用SHA2系列。

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

对于RIPEMD,除了要注意它不像SHA系列那样普遍使用之外,我不能对此发表过多评论,因此密码学研究人员没有对其进行仔细审查。仅出于这个原因,我建议在其上使用SHA函数。在实现中,您使用它的速度也似乎很慢,这使它的用处不大。

总之,没有一个最佳功能-这完全取决于您需要的功能。注意每个缺陷,您将最有能力为您的方案选择正确的哈希函数。


1
非常感谢您进入此详细级别。这非常有帮助。
joelc 2015年

1
对于某些应用程序,甚至非加密级哈希函数也可能是合适的。OP从未提及过它是专门用于密码,质询响应身份验证,访问令牌还是仅用于索引一堆字符串/文件。性能方面,在另一方面,对于OP关注...
塞瓦·阿列克谢耶夫

111

所有哈希函数都“中断”

鸽巢原理说,尝试努力,你将无法在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成为了一些头条新闻,一些人认为scrypt比bcrypt更有效,但我不知道.Net的实现。


虽然MD5和SHA-1均被削弱,但MD5比SHA-1弱得多,而速度却稍快。已经发现了实际的MD5冲突并将其用于实际攻击(伪造CA证书),但据我所知,没有发现实际的SHA-1冲突(尽管从蛮力中大大减少了操作次数)。考虑到MD5的弱点,如果MD5的第二次原像攻击比SHA-1的出现更快,我不会感到惊讶。因此,我认为如果需要速度而不是抗碰撞能力,则应使用SHA-1,否则应使用SHA-2系列之一。
布赖恩·坎贝尔

1
@Brian相当清楚,在未来几年内,人们将能够对SHA1进行碰撞攻击,这将有效地使SHA1像MD5一样有用。对SHA1 CA证书运行相同的攻击。攻击取决于恶意方创建的EVIL和GOOD证书。没有已知的对MD5的原始攻击,并且存在碰撞攻击的事实并没有使镜像前攻击或多或少地发生。
Sam Saffron

与您使用的是密码哈希相比,与密码使用的哈希相比,要少得多。如果您知道盐,那么您的数据库将立即受到字典攻击的攻击;如果您的程序存在问题,并且文件系统受到威胁,则您(再次)容易受到攻击;如果省略盐分,您将再次受到损害。无论如何,存在争议的安全性是散列了什么。证书,我不会处理,因为我没有以程序员的身份来对待它们(IE,创建,理解等)。
罗伯特·K

术语“破碎”在哈希的上下文中具有特定含义,而这并不是此答案强调的含义。这些答案只会引起混乱。
Joel McBeth 2014年

1
这是一个很好的答案,因为它注重实用性。哈希用于安全性以外的其他用途(例如为非敏感数据生成缓存查找键或确定序列化对象是否已更改)。定向攻击的机会几乎为零(永远不会说永不),即使攻击成功,也不会产生实质性影响。专注于实际(而非理论)影响的出色工作。
DVK 2016年

35

更新:

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

原始答案:

以最弱到最强的顺序,我会说:

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

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


5
我不会把Skein和MD6放在榜首。SHA-3竞赛要到2012年底才能完成,这是有原因的。要花很长时间和很多眼睛才能确信哈希函数实际上很可能是安全的,而这两个函数都不安全已经有足够长的时间了。
埃里克·伯内特

我同意您的观点,但我认为社区处于一个奇怪的位置。所有使用中的哈希函数都非常接近崩溃的危险(也许不是SHA2 256-512),但我们必须等到2012年才能选择一个替代函数。选择您的毒药:弱/残破或未经测试(大多数NIST候选人都没有公开超过6个月)?艰难的选择。
伊桑·海尔曼

5
RIPEMD已损坏,但RIPEMD-128 / 160/256不同,并且未损坏。
Bwooce

我不知道Skein for .NET的任何高性能实现。我遇到过SkeinFish和nskein,两者都很慢。
Cocowalla 2012年

1
我将等待使用SHA-3,直到出现实际的标准为止,至少在您要真正遵循标准的情况下。该算法本身有太多选择。
圣保罗Ebermann

3

在MD5的防御中,没有已知的方法来生成带有任意MD5哈希的文件。原作者必须事先计划好有工作上的冲突。因此,如果接收方信任发送方,则MD5可以。如果签名人是恶意的,则MD5将被破坏,但它不易受到中间人攻击。


1
虽然我绝不是该领域的专家,但如今利用蛮力计算任意MD5哈希值是否接近可行?
mafu 2012年

@mafu:此处的响应较晚,但是可以通过蛮力计算任何哈希值。这可能需要很长时间。
Warty 2013年

@ItzWarty我特别指的是所需的时间-由于MD5太短了,我认为可以简单地在上面放一个合理的计算源(E3,或者是便宜的计算机网格,一些机器带有一些图形卡,有些东西并能够在几天之内计算出任意MD5哈希值。
mafu 2013年

@mafu映像前攻击的128位哈希值花费2 ^ 127哈希值调用。这远非可行。2 ^ 80的调用是可行的,但已经非常昂贵。
CodesInChaos

2

实际使用哪个取决于您使用它的目的。如果您只想确保文件在传输过程中不会被损坏并且不关心安全性,则不妨精打细算。如果您需要数十亿美元的联邦救助协议的数字签名,并且需要确保它们不被伪造,那么就很难欺骗和拖延。


1
很多时候在讨论问题的解决方案时,我都提到我使用MD5进行快速标识(哈希字符串),他们说“但是md5坏了……不要使用它,请使用sha1”……我真的不赞成这样做,这在想如果从根本上破坏了一些较弱的哈希,应该避免使用它们……例如,正常数据会产生冲突的实际案例
Sam Saffron

鉴于MD5在15年来对数以百万计的人都有效,我怀疑如果哈希安全性不是至关重要的,那对您来说还可以。
mqp

2
@sambo MD5在几乎所有情况下都可以正常工作,除非系统的实际安全性/完整性取决于防止冲突。
Rex M

2

我想补充一下(在md5崩溃​​之前),尽管它对很多加密货币来说都是压倒性的,但我仍然广泛使用md5。

只要您不希望防止冲突(在hmac中也可以安全使用md5)并且确实想要速度(有时希望散列速度较慢),那么您仍然可以放心使用md5。


@Mike我同意您的意见,这就是我在研究这个问题时所想的事情,是关于较弱的哈希函数的内容,这些哈希函数从根本上被破坏以至于永远都不应使用它们。
Sam Saffron

除此之外,如果数据或数据的所需安全性的寿命短于破解周期(这些天数分钟),则MD5绝对可以。关键是在情况上有用,但仍然有用。
annakata

@annakata-请记住,您还必须避免在多条消息中重复使用密钥,以使其在这种情况下可用。
史蒂夫·威斯布鲁克

2

看看BLAKE2算法是一个很好的想法。

如描述的那样,它比MD5更快,并且至少与SHA-3一样安全。它还由包括WinRar在内的多个软件应用程序实现。


可能会更快,除非许多实现具有硬件支持,这使得SHA-256相当快。
zaph

我同意。截至2019年,Blake2b是迄今为止发布的最佳通用哈希值。比所有其他替代产品明显快得多,并且安全性同样高(至少没有任何有意义的方式),并且只能在336字节的ram中执行(对于blake2s为168),哦,它是针对低端CPU进行优化的,在当今系统中占主导地位的字节序。
hanshenrik

0

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


1
散列函数通常不使用键
伊桑·海尔曼

0

这是我对您的建议:

  1. 如果您预期会受到攻击,则可能应该忘记MD5。在线有很多彩虹表,并且像RIAA这样的公司已经知道能够产生具有相同哈希值的序列。
  2. 如果可以,请使用。在消息中包含消息长度会使得很难进行有用的哈希冲突。
  3. 一般而言,更多的比特意味着更少的碰撞(通过鸽洞原理),并且更慢,甚至可能更安全(除非您是能够发现漏洞的数学天才)。

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

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


这条评论很老,看起来似乎很埋头,但是这点- 众所周知RIAA能够产生具有等效哈希值的序列 -跳了起来,我很好奇这是什么背景。特别是8年前对MD5的暴力破解与2017年相比并不那么琐碎,因此他们一定有充分的理由。
i336_
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.