【问题标题】:Simple enquiry on hash algorithm哈希算法的简单查询
【发布时间】:2011-12-14 16:14:35
【问题描述】:

从下面列出的链接阅读文章后:

http://news.ycombinator.com/item?id=910203

我现在正在尝试证明和理解为什么下面列出的哈希是不安全的,程序员不应该练习。

H(k || m) --> SHA1("secret-key" + "name=bob,withdraw=$200")

H(m || k) --> SHA1("name=bob,withdraw=$200" + "secret-key")

根据文章所述,第一个示例完全被致命地破坏了。 SHA1(以及 MD5 和许多其他哈希)是共享一种称为 Merkle-Damgaard 的通用设计的机器,这意味着它们以块长度的块处理消息,并使用这些块来置换内部状态。输出 SHA1 是该状态的“最终”内容。但是没有什么可以真正“确定” SHA1 状态。如果您在线路上看到 SHA1 值,您可以继续使用 附加数据 启动 Merkle-Damgaard 机器。 这意味着您可以创建带有任意数据的新消息,这些数据看起来是真实的。这种攻击非常容易实施;大约需要 20 行 Ruby 代码。

第二个例子也坏了,它是这篇博文的主题。如果您在消息之后添加密钥,您将无法继续使用数据驱动哈希,因为您无法猜测的秘密在它的末尾。

我在 C# 中编写了一个简单的哈希函数,试图证明作者声称的内容,但不知何故,无论我添加/填充或在消息的后面/前面添加什么,我似乎都无法做到。

        string strRet;
        // hash contains the SHA 1 value of SHA1 (key + temp)
        string hash = "ce0037fbbff7a1b68b5794bd73dcc7d63338f115";

        try
        {
            string key = "password";
            string temp = "name=bob,withdraw=$200";

            for (int i = 0; i < 1000; i++)
            {
                byte[] buffer = Encoding.ASCII.GetBytes(temp);
                SHA1CryptoServiceProvider cryptoTransformSHA1 = new SHA1CryptoServiceProvider();
                strRet = BitConverter.ToString(cryptoTransformSHA1.ComputeHash(buffer)).Replace("-", "");
                strRet = strRet.ToLower();
                MessageBox.Show(strRet);

                if (strRet.Equals(hash))
                {
                    MessageBox.Show("Hash are equal !");
                    MessageBox.Show(temp);
                }

                temp = key + temp + "2";
            }

            MessageBox.Show("The End !");

        }
        catch (Exception)
        {
            MessageBox.Show("There is a Error !");
        }

有人可以通过提供一个指定的示例来指导我,我可以散列、理解和证明作者在文章中对这两种散列方法的主张。提前感谢您提供的任何帮助。

【问题讨论】:

  • 回复:“我在 C# 中编写了一个简单的哈希函数,试图证明作者声称的内容,但不知何故,无论我添加/填充或在消息的后面/前面添加什么,我似乎都无法做到这一点” ——用简单的语言向我们准确解释您认为作者所声称的内容。您可能无法证明作者的主张,因为您没有正确理解该主张。您的代码似乎与所提出的声明没有任何关系。
  • 感谢您的意见。我实际上正在使用算法,在阅读了这篇文章后,我正在考虑使用 HMAC,因为现在我正在使用的 2 算法是不安全的?因此,我编写了上面列出的一个简单的 c 语言代码。据我了解,在不知道密钥的情况下,攻击者可以通过某种方式获得身份验证,这就是我想要证明的。总而言之,我试图理解并证明为什么使用这两种方法是不安全的?
  • 来自 Wiki 由于算法的块和迭代结构以及没有额外的最终步骤,所有 SHA 函数都容易受到长度扩展和部分消息冲突攻击。 [9]这些攻击允许攻击者通过扩展消息并在不知道密钥的情况下重新计算哈希来伪造仅由密钥散列 - SHA(message | | key) 或 SHA(key | | message) 签名的消息。防止这些攻击的最简单改进是哈希两次 - SHAd(message) = SHA(SHA(0b | | message)) (0b - 零块,长度等于哈希函数的块大小)。任何 expln ?

标签: c# hash cryptography sha


【解决方案1】:

让我们退后一步。首先,H(k|m) 是什么意思?这是干什么用的?

这里的目标如下。 Alice 和 Bob 共享一个密钥。他们如何分享它,我们不知道。不知何故,爱丽丝和鲍勃商定了一个秘密密钥,而其他人都不知道。

爱丽丝希望给鲍勃发消息。 Alice 不关心是否有人可以阅读该消息,但 Alice 非常关心 Bob 知道 Alice 写了该消息。

他们提出了以下方案。 Alice 将创建一条消息,该消息由密钥和消息的其余部分组成。然后她会对整个事情进行哈希处理。然后,她将不带密钥的消息连同哈希一起发送给 Bob。

Bob 尝试验证消息是否来自 Alice。他将密钥放在消息前面并对其进行哈希处理。如果 Bob 得到相同的哈希值,那么 Bob 就知道发送消息的人拥有密钥。他知道不是他,所以一定是爱丽丝。

此方案不安全。马洛里希望向鲍勃发送一条虚假信息,并欺骗他认为这是来自爱丽丝的。

有一天,Alice 拿到她的密钥“123SesameStreet”和一条消息“亲爱的 Bob,我爱你!”,然后她将它们一起附加到“123SesameStreet,亲爱的 Bob,我爱你!”她将其散列到“398942358092”并发送散列和消息“亲爱的鲍勃,我爱你!”给鲍勃。

Mallory 在消息到达 Bob 之前拦截了它。 Mallory 不知道密钥,但她知道消息和哈希。 Mallory 将 SHA1 算法设置为状态为 398942358092,然后运行字符“开个玩笑我讨厌你!”,并从 92358023934 中得到一个哈希值。现在 Mallory 发送新的哈希值和消息“亲爱的 Bob,我爱你!开玩笑的,我恨你!给鲍勃。

这项工作的精确度如何?这是交易。基本上,SHA1 的工作原理就像这个过于简化的草图:

int hash = 0;
foreach(char c in message)
    hash = MakeNextHash(hash, c);

也就是说,你从零开始。然后你散列第一个字符和数字 0。然后你散列 那个散列第二个字符。这会产生一个新的哈希值。然后你用第三个字符散列 that ,做第三个散列。继续这样做,直到你的字符用完为止;你做的最后一个哈希是整个消息的哈希。

真正的 SHA1 算法使用大于单个字符的块和大于 int 的状态,但基本上就是这样。它一次一个块地转换一堆状态,使用前一个状态作为下一个状态的输入。

所以如果我告诉你“这是一个字符串 M。此外,字符串 KM 具有哈希 H(K|M)。”那么显然你可以为任何 Z 计算出 KMZ 的哈希 H(K|M|Z),即使你不知道 K。你就说:

int hash = HKM;
foreach(char c in Z)
    hash = MakeNextHash(hash, c);

结果是 H(K|M|Z),即使你不知道 K。

所以,你知道这是怎么回事。 Bob 将密钥添加到消息中,并通过 SHA1 算法运行它,然后他得到正确的哈希值。所以他已经验证了消息是来自 Alice,而实际上有一半来自 Mallory。

这就是为什么钥匙必须放在最后的原因。您必须将密钥放在消息之后,而不是之前。你会想。事实证明,虽然现在的攻击不像密钥优先方案那样微不足道,但它仍然不安全。 H(m|k) 方案也不好。

为什么不呢?

假设 Mallory 截获了一条消息 M 和一个哈希 H,即 H(M|K),其中 K 是密钥。她阻止消息到达。

Mallory 很容易计算 H(M)。困难的部分是马洛里推导出破坏性消息 N 使得 H(N) = H(M)。她是如何做到的,我们还不知道,但人们普遍认为存在这种技术,只是我们还没有找到。

Mallory 知道 H(N|K) 与 H(M|K) 相同,原因与之前相同——因为要计算 H(N|K),我们要做的是:

int hash = HN;
foreach(char c in key)
    ....

计算 H(N|K)。 Mallory 不需要知道 K 来生成消息 N,使得 H(N|K) 是 H(M|K)。

所以,现在 Mallory 将 N 和 H(M|K) / H(N|K) ——它们是同一个东西——发送给 Bob。 Bob 将 K 附加到 N,并验证消息来自 Alice,而实际上它来自 Mallory。

情况变得更糟。假设 Mallory 捕获了一百万条消息 M1、M2……和一百万条在 Alice 和 Bob 之间传递的哈希 H(M1|K)、H(M2|K)……。 Mallory 需要制作一条消息 N,以使 H(N) 与 H(M1)、H(M2)、H(M3) 中的 任何 匹配……她的工作变得轻松了一百万倍。她找到这样的消息 N 使得 H(N) 匹配,例如 H(M1234),然后将 N 和 H(M1234|K) 发送给 Bob。 Bob 没有注意到他之前看到过该哈希,并认为这是来自 Alice 的消息。

情况变得更糟。让我们稍微改变一下方案,看看它会变得更糟。 Carol 有一条消息,她想通过 Alice 发送给 Bob。消息 M 是“嘿 Bob,这是 Carol。让你和我和 Alice 下周一起吃午饭。如果 Alice 同意,她会用她的身份验证器向你发送这条消息。” Carol 不知道密钥 K,但 Alice 知道。 Alice 同意消息 M,因此她计算 H(M|K) 并将 M 和 H(M|K) 发送给 Bob。

现在马洛里想制造麻烦,所以她搜索两条消息 B(良性)和 D(危险),使得 H(B) 等于 H(D),并且 Alice 会同意 B,但不会同意 D。这比搜索匹配来自 Alice 的 given 消息的消息 N 容易得多,因为现在 Mallory 可以选择 both 消息。发现碰撞的工作要容易几个数量级。

Mallory 找到这两条消息并将 B 发送给 Alice。 Alice 同意该消息,计算 H(B|K),并将 H(B|K) 和 B 发送给 Bob。 Mallory 截获消息 B 并将其替换为 D。H(B|K) 和 H(D|K) 与之前的推理相同。 Bob 收到消息 D 并验证 H(D|K) 与他发送的哈希值匹配,因此他知道 Alice 批准了该消息,即使她没有。

目前还没有人找到一种方法让 SHA1 可靠地产生这样的碰撞,但几乎每个人都相信我们会解决这个问题。

故事的第一个寓意是不要将这些技术中的任何一种用作消息验证器。第一个是微不足道的,第二个很可能会在我们的一生中被打破。

第二个道德是永远不要让潜在的攻击者选择您将使用您的密钥处理的消息。

【讨论】:

  • 再次感谢您的意见。但是文章中也指出,将您的密钥放在消息之后也可以被破坏。我能理解你从哪里看的。我所做的是当用户尝试访问我的服务器时,我将根据存储在他/她的 PC 上的 cookie 向他提供某些信息。我的程序将创建一个 cookie SHA1(日期 || 一个秘密密码)。根据我会给他额外信息的日期,我想知道用户如何编辑 cookie 并获取额外信息。我看过的一些文章vnsecurity.net/t/length-extension-attack
  • 因为我已经完成了以下 SHA1(日期 || 密码)。我想知道用户如何更改 cookie 以从我的服务器获取更多信息。正如文章中所述,它可以在不知道秘密密码的情况下完成。我的实际问题是什么?
  • @埃里克。 1 最后一个问题我很好奇 Mallory 如何将 SHA 1 状态设置为 398942358092 并运行角色“开个玩笑我恨你!”,并从 92358023934 中获取哈希值?
  • 等等,如果message + key 很容易被入侵,我们应该用什么来签署消息?
  • @NickJohnson:马洛里通常是一个姓氏。当用作名字时,它可以是男性名字,但自 1980 年代以来,当“Mallory Keaton”是流行情景喜剧“Family Ties”中的一个角色时,它在美国绝大多数是女性名字。在加密草图中用作规范攻击者时,马洛里(以及夏娃和爱丽丝!)几乎总是被描述为女性。
【解决方案2】:

您可以链接http://rdist.root.org/2009/10/29/stop-using-unsafe-keyed-hashes-use-hmac/,这是此声明的来源。

它说这个哈希方案比它需要的要弱,并不是说它实际上可以用 SHA-1 破解。

只有当底层哈希函数有任何弱点(第一次攻击的第二个原像,第二次攻击的冲突)时,这个方案才容易受到攻击。据我所知,SHA-1 没有发现其中任何一个的实际漏洞,而 MD5 在第二次攻击的情况下被破坏。

由于冲突是哈希函数中最容易发现的漏洞,因此除非必要,否则最好使用不易受到冲突攻击的构造。这就是推荐使用 HMAC 的原因。

【讨论】:

  • 感谢您的意见。在早期研究时,我已经遇到了那方面。
  • SHA-1 还没有被破坏,但它已经到了那里。如果要使用哈希,SHA-2 会更安全。
  • MD5 存在允许这种攻击的问题,它被用来伪造 SSL 证书。虽然 SHA1 基于与 MD5 (Merkle-Damgaard) 相同的结构,这意味着它将来可能会出现类似的故障。您应该使用 SHA2 系列算法之一,RIPEMD160 或 Whirlpool。见:en.wikipedia.org/wiki/MD5#Collision_vulnerabilities
猜你喜欢
  • 2016-02-17
  • 2015-07-21
  • 2012-07-05
  • 2016-06-23
  • 2015-08-16
  • 1970-01-01
  • 2017-12-01
  • 2012-06-03
  • 2013-01-02
相关资源
最近更新 更多