我一直试图确切地理解长度扩展攻击如何在SHA-1上工作。我将在下面详细介绍我到目前为止所了解的内容,以便传达我的理解,并希望就我要去哪里出了错。

让我们假设这是一条信息$ m $,将秘密$ s $附加到其后,并计算SHA-1哈希。如果$ \ textrm {len}(m)+ \ textrm {len}(s)$不是块大小的倍数,则向其中添加一定量的填充以使其为倍数,并使用本质上是$ s || m || \ textrm {padding} $。

现在SHA-1内部使用5个寄存器-它接收一个块,生成新的寄存器值,转动曲柄,接收另一个块,生成新的寄存器值,转动曲柄...等等直到最后当所有块都用完后,寄存器值将被串联并吐出。

假定攻击者知道$ m $的某个值,并且他也知道哈希键。在这种情况下,当处理$ {s || m || \ textrm {padding} $时,他知道5个寄存器的状态。还假设攻击者知道$ s $的长度,以便他可以预测

这是我感到困惑的地方。从到目前为止的内容来看,攻击涉及获取已知的哈希,添加一定数量的填充,然后添加值但是,在创建哈希表中填充是否已经用完了?为什么在攻击中使用填充?

评论

一直想问一样但忘了!难道这是对某些博客的回应,它不清楚地解释了Stripe的CTF挑战的第七级?

#1 楼

SHA-1按512位块(64字节)处理数据。对于给定的输入消息m,它首先附加一些位(至少65,最多576),以使总长度为512的倍数。让我们将p称为附加位(即填充)。填充位仅取决于m的长度(这些位包括该长度的编码,但是它们不取决于位的值)。

被填充的消息m || p为分成连续的512位块,然后依次处理。 SHA-1使用内部压缩函数(这是传统术语);它还具有由五个32位字组成的运行状态。压缩功能分别将两个160和512位的值作为输入,并输出160位。处理过程如下:


运行状态被初始化为固定的常规值(在SHA-1规范中给出)。
对于每个输入块,评估压缩功能,输入当前运行状态和输入块;函数的输出是新的运行状态。
处理完最后一个块后的运行状态是哈希输出。

所以,现在是长度扩展攻击。假设您给我一个哈希值h,该值是根据消息m计算得出的,而消息m对我来说是未知的。我知道m的长度,但不知道它的内容。由于我知道m的长度,因此我可以轻松计算出您使用的填充p。然后我想象一个消息m',它以m || p开头;也就是说,m'= m || p || z,其中z是我可以任意选择的位序列。我现在将继续计算m'的SHA-1哈希,即使我不知道它的一部分(它以m开头,我也不知道)。

当在m'上计算SHA-1时,首先用p'填充后者,这取决于m'的长度(我知道)。生成的流为m || p || z || p'。然后,一对一地处理512位块。我不知道最初的步骤,因为我不知道m。但是,我可以想象自己正在这样做。在某些时候,我将精确地到达p字符串的末尾(因为m || p的长度是512的倍数)。此时的运行状态的值是多少?好吧,这正是您给我的哈希值h!因此,我可以停止想象。我可以在此时,在z的开头,使用您的哈希值h作为运行状态的值,开始SHA-1(m')的SHA-1计算。

这就是核心它的。我可以使用SHA-1(m)来计算SHA-1(m'),即以m的内容开头的消息,而我却不知道m就可以这样做。 SHA-1的此属性(适用于其他Merkle-Damgård哈希函数,例如MD5或SHA-256)与通常的哈希函数安全功能(对碰撞,原像和第二原像的抵抗)没有矛盾,但是它表明SHA-1不是一个随机的Oracle。

它对攻击者有什么用?好吧,请考虑以下消息认证代码的(有缺陷的)构造:对于给定的密钥k和要保护d的数据,将SHA-1(k || d)计算为MAC值。这种方案在存在长度扩展攻击的情况下被打破:如果我作为攻击者看到消息d的MAC,那么我可以为扩展了d的消息d'计算MAC——而我可以在没有知道k || d(因此,尤其是不知道密钥)。这使我可以使用有效的MAC伪造消息。

长度扩展攻击是为什么从哈希函数构建MAC时,我们需要更复杂的东西,即HMAC(这是安全的)。

评论


$ \ begingroup $
由于您不知道m,如何想象以m || p开头的消息?您是说我用h(m)|| p || z喂SHA-1吗?
$ \ endgroup $
–好奇
2012年10月10日10:23



$ \ begingroup $
我用大脑想象。那就是想象的重点:我不必真正做到这一点。如果我知道m,则可以构建更大的消息。我的答案结尾给出了应用程序:我不知道MAC密钥,但是我仍然可以通过想象自己知道消息并计算我将获得的MAC值来伪造一条消息。
$ \ endgroup $
–托马斯·波宁(Thomas Pornin)
2012年10月10日上午11:11

$ \ begingroup $
确实有很多文字,很难理解。如果您稍后再说明自己,将会有所帮助。
$ \ endgroup $
–史密斯·约翰斯(Sm​​it Johnth)
13年5月30日在21:55



$ \ begingroup $
问题:HMAC-SHA-1和HMAC-SHA2family可以防止长度扩展,并且更好。但是,作为SHA-512的替代方案,由于攻击者不再具有完整的内部状态,将其仅截断N个字节就可以防止长度扩展吗?如果是这样,那么对于N的哪个值甚至可能值得?当然,我认为HMAC还可以带来其他好处。
$ \ endgroup $
–反弱密码
2014年2月23日在7:39

$ \ begingroup $
作为攻击者,我们没有在任何地方使用$ p $填充,所以攻击者是否有必要知道$ m $的长度?在不知道$ m $长度的情况下,攻击者还可以计算$ H(m || p || z)$,不是吗?
$ \ endgroup $
– Mehran Torki
16-4-18在19:17



#2 楼

理解哈希扩展攻击的关键是要理解哈希输出不仅是生成哈希的机器的输出,还是直到该点为止的机器状态。换句话说,仅散列输出就包含足够的信息,供您继续使用并将更多内容附加到散列输入。
要注意的是,由于散列适用于固定大小的块,因此如果数据大小不正确沿着这些块边界之一正确排列,将用零填充直到它填满为止。因此,我们必须在攻击中考虑到这一点。 (是的,SHA-1还有其他填充规则,为简单起见,我们将忽略它们)
一个例子
假设您的超级安全身份验证协议是接收给定的消息,并为其添加密码,并将散列的结果作为“签名”发送。我只需知道您的哈希输出就可以计算您的字符串的哈希值加上其他字符串。
因此,可以说我对字符串count=1&price=100.2具有“签名”,但我想将价格更改为1。我知道您的解析算法将较早的值替换为较新的值,并且不会阻塞嵌入式null。因此,从理论上讲,我可以计算所需字符串count=1&price=100.2&price=1.0的哈希值。
但是我不能只是将字符串附加到您的字符串中并期望它可以工作。我必须考虑填充。为了简单起见,我们假设块大小为10。 (nb:“•” = null)
   123456789|123456789|123456789|123456789|             <- ruler
A: [mysecurepassword]count=1&price=100.2                
B: [mysecurepassword]count=1&price=100.2•••

表面上我有字符串A的哈希,但是我真正拥有的是字符串B的哈希-在末尾附加了三个空。
所以我不必发送字符串count=1&price=100.2&price=1,而必须发送字符串count=1&price=100.2•••&price=1.0
要生成我的签名,我只需使用您给我的签名初始化哈希引擎,添加&price=1.0并输出结果。
当然,SHA-1的规则与我假装的10字节哈希有些不同,但是原理仍然适用,只是让字节对齐即可。

评论


$ \ begingroup $
极好的答案。我想我现在明白了
$ \ endgroup $
–ogogmad
2015年5月3日14:33



$ \ begingroup $
+1表示状态并修改哈希函数的初始状态(初始化向量)
$ \ endgroup $
–chrisamanse
16-09-5 13:53

$ \ begingroup $
“并且它不会阻塞嵌入的null”->如果不可能嵌入null,是否可以避免长度扩展攻击?
$ \ endgroup $
–chux-恢复莫妮卡
17年1月26日在2:39