ChatGPT解决这个技术问题 Extra ChatGPT

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

.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 UUIDSHA-1 hash is the basis of type 5 UUID. 这使得它们非常容易用于识别。

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

D
DonCarleone

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

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

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

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

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

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

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

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


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

所有哈希函数都“损坏”

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、创建、理解等)。
术语损坏在散列的上下文中具有特定的含义,这不是这个答案所强调的含义。所有这些答案都会引起混乱。
这是一个很好的答案,因为它侧重于实用性。哈希用于安全以外的事情(例如为非敏感数据生成缓存查找键或确定序列化对象是否已更改)。有针对性的攻击的机会几乎为零(永远不要说永远),即使攻击成功,也不会产生实质性影响。专注于实际(而不是理论)影响的出色工作。
E
Ethan Heilman

更新:

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

原答案:

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

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

我个人会使用 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,直到实际标准出现,至少如果您想真正遵循标准。算法本身有太多的选择。
r
rlbond

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


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

看看 BLAKE2 算法是个好主意。

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


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

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


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

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

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


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

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


哈希函数通常不使用键
U
Unknown

以下是我给你的建议:

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

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

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


这条评论非常古老,似乎相当隐蔽,但这一点——众所周知,RIAA 能够产生具有等效散列的序列——突然出现在我身上,我很好奇这是什么背景。特别是 8 年前的 MD5 暴力破解比 2017 年要少一些,所以他们一定有一个很好的理由。