关于c#:我应该选择哪种加密哈希函数?

Which cryptographic hash function should I choose?

.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类型;它是类型3 UUID的基础。sha-1哈希是类型5 UUID的基础。这使得它们很容易用于识别。

但MD5易受碰撞攻击,SHA-1也易受攻击,但程度较低。

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

我很想知道答案是什么:

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

  • 里佩姆比沙伊好多少?(如果更好的话)它的计算速度慢了5倍,但散列大小与sha1相同。

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

这是我使用的基准:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
    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不具有抗碰撞性,但是,这并不排除它在不需要抗碰撞性的应用中的应用。实际上,MD5通常仍用于密钥大小和速度较小的应用程序中。也就是说,由于它的缺陷,研究人员建议在新的场景中使用其他哈希函数。

    sha1有一个缺陷,它允许在理论上远远小于2^80步的范围内发现冲突,这是一个安全哈希函数所需要的长度。攻击正在不断地被修改,目前可以用大约2^63个步骤来完成——仅仅是在当前可计算的范围内。出于这个原因,NIST正在逐步停止使用SHA1,并指出SHA2系列产品应在2010年之后使用。

    sha2是在sha1之后创建的一个新的哈希函数家族。目前还没有针对sha2函数的已知攻击。sha256、384和512都是sha2家族的一部分,只是使用了不同的密钥长度。

    我不能对ripemd作太多评论,只是要注意到它不像sha家族那样常用,因此没有被密码研究人员仔细研究过。仅出于这个原因,我建议在上面使用sha函数。在您正在使用的实现中,它看起来也相当慢,这使得它不那么有用。

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


    所有哈希函数都是"中断的"

    鸽子洞原则说,尽你所能的努力,你不能在2个洞里容纳超过2只鸽子(除非你把鸽子切掉)。同样,在2^128插槽中不能容纳2^128+1个数字。所有散列函数都会产生一个有限大小的散列,这意味着如果搜索"有限大小"+1个序列,则始终可以找到冲突。这样做是不可行的。不适用于MD5和Skein。

    MD5/Sha1/Sha2xx没有发生碰撞的机会

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

    但是…MD5被破坏

    有时候,它破碎的事实并不重要。

    目前,MD5上没有已知的预映像或第二个预映像攻击。

    那么,你可能会问,MD5的缺点是什么?第三方可以生成2条消息,其中一条消息是邪恶的,另一条消息是好的,两条消息的哈希值相同。(碰撞攻击)

    尽管如此,如果您需要预成像电阻,当前的RSA建议不要使用MD5。当涉及到安全算法时,人们倾向于谨慎行事。

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

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

    重复这个,我之后,没有机会MD5碰撞,恶意碰撞可以仔细设计。尽管到目前为止,MD5上还没有已知的预映像攻击,但安全专家的观点是,在需要防御预映像攻击的地方不应使用MD5。Sha1也是如此。

    请记住,并非所有的算法都需要防御预图像或碰撞攻击。以一个简单的例子为例,在你的硬盘上搜索重复的文件。

    • 如果需要加密安全的哈希函数,请使用基于sha2xx的函数。

    没有人发现任何Sha512碰撞。曾经。他们真的很努力。就这一点而言,从来没有人发现过任何Sha256或384碰撞。.

    • 除非用于互操作性场景,否则不要使用sha1或ripemd。

    Ripmed没有收到与Shax和MD5收到的相同数量的审查。Sha1和Ripemd都很容易受到生日攻击。它们都比.NET上的MD5慢,并且具有令人尴尬的20字节大小。使用这些函数是毫无意义的,忘记它们吧。

    sha1碰撞攻击降低到2^52,在sha1碰撞消失之前不会太久。

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

    但是等等还有更多

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

    问题是,如果攻击者得到了数据库的一个转储文件,他可以非常有效地使用蛮力猜测密码。他尝试的每一个组合只需要几毫秒的时间,而且他可以每秒尝试数十万个密码。

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


    更新:

    时过境迁,我们有一个沙三队的冠军。我建议你使用凯卡(又名Sha3)来赢得Sha3比赛。

    原始答案:

    从最弱到最强,我会说:

  • ripemd坏了,不应该像本pdf中看到的那样使用。
  • MD-5坏了,不应该使用,可以用笔记本电脑在2分钟内坏掉。
  • sha-1坏了,不应该使用,原则上是坏的,每周攻击都会好转。
  • 沙二弱,可能会在未来几年被打破。发现了一些弱点。注意,通常键的大小越大,哈希函数就越难破坏。虽然键大小=强度并不总是正确的,但大多数情况下都是正确的。所以sha-256可能比sha-512弱。
  • 斯金没有已知的弱点,是沙三的候选人。它是全新的,因此未经测试。它已经用一系列语言实现。
  • MD6没有已知的弱点,是另一个候选的SHA-3。可能比皮肤强壮,但在单核机器上慢。就像滑雪板一样,它是未经测试的。一些有安全意识的开发人员正在使用它,扮演关键任务的角色。
  • 就我个人而言,我会使用MD6,因为人们永远不会太多疑。如果速度是一个真正的问题,我会看skein,或sha-256。


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


    我想插话(在MD5被撕开之前),我仍然广泛使用MD5,尽管它在大量加密方面有着压倒性的破坏性。

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


    你到底用哪一个取决于你用它做什么。如果你只是想确保文件在传输过程中不会被破坏,也不会那么担心安全性,那就快速而小型地进行吧。如果你需要数十亿美元的联邦救助协议的数字签名,并且需要确保它们不是伪造的,那就去努力欺骗和放慢速度。


    看一看布莱克2阿尔戈雷姆是个好主意。

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


    以下是我的建议:

  • 如果您预测攻击,您可能应该忘记MD5。在线上有很多彩虹表,像RIAA这样的公司已经知道可以用等价的哈希产生序列。
  • 如果可以的话,用盐。将消息长度包含在消息中可能会使有用的哈希冲突变得非常困难。
  • 作为一般经验法则,更多的比特意味着更少的碰撞(根据鸽子洞原理),更慢,也许更安全(除非你是一个数学天才,能发现漏洞)。
  • 请参阅本文,详细介绍如何在31秒内与台式IntelP4计算机创建MD5冲突的算法。

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


    我不是这方面的专家,但我跟上了安全社区的步伐,那里的很多人都认为MD5散列已被破坏。我想说,使用哪一个取决于数据的敏感性和特定的应用程序。只要密钥是好的和强的,您就可以用一个稍微不安全的散列来摆脱它。