我刚刚了解到,在P2P中广泛使用的THEX哈希树规范要求使用两种不同的哈希函数:一种用于叶节点(输入数据的哈希),另一种用于内部哈希(哈希的哈希)。 >

为了防止叶子哈希和
内部哈希之间的冲突,使用了不同的哈希结构来哈希叶子
节点和内部节点。相同的哈希算法用作每个结构的
基础,但是内部网络节点哈希的输入之前是网络字节顺序的单个'1'字节,
或0x01。 />单个'0'字节(或0x00)位于叶节点的哈希值之前。 BitTorrent的Merkle Hashes扩展仅对所有哈希使用未经修改的SHA-1。可以想见,这是为了简单起见而在安全性方面进行的折衷,但是在提案中​​未提及。 br />

#1 楼

如果对叶子节点和分支节点使用相同的标准哈希函数,则很容易产生冲突,甚至生成第二个原像。

例如,假设$ M $是一条比散列树的段大小,但(为简单起见)长度不超过两个段。然后将$ M $的哈希值计算为$$ H(M)= H_I(H_L(M_0)\,\ | \,H_L(M_1)),$$其中$ H_I $是内部哈希函数$ H_L $是叶哈希函数,$ M_0 $和$ M_1 $是$ M $的第一部分和第二部分。我们还假设哈希树的段大小至少是$ H_L $输出长度的两倍。

现在让$ M'= H_L(M_0)\, \ | \,H_L(M_1)$。由于假设$ M'$最多为一个段长,因此将其哈希计算为$$ H(M')= H_L(M')= H_L(H_L(M_0)\,\ | \,H_L( M_1))。$$如果$ H_L = H_I $,则$ H(M')= H(M)$,我们就发现了$ H(M)$的第二张原像。

评论


$ \ begingroup $
我意识到BitTorrent的简单默克尔树之所以不容易受到攻击的原因是,它们通过添加0叶(直到它们的数量达到2的幂)而被完全填充。另一方面,THEX允许不成对的叶子哈希将树“浮起”到原本应该内部哈希的位置。
$ \ endgroup $
–杰里米
2012年3月17日15:20



$ \ begingroup $
将段数填充到2的幂是无济于事的:请注意,在我的示例中,$ M $和$ M'$分别具有2和1个段。但是,只要末段长度严格大于内部哈希输入长度,就可以将最后一个段本身填充至全长就足以区分叶子哈希和内部哈希。 (但是请注意,如果没有足够仔细地进行填充,则可能会造成碰撞。)
$ \ endgroup $
–伊尔马里(Ilmari Karonen)
2012年3月17日15:32



$ \ begingroup $
糟糕!谢谢你的澄清。新的解释:在B​​itTorrent的上下文中树是安全的,因为它已经知道输入的总长度,因此攻击者无法根据需要添加或删除叶子。
$ \ endgroup $
–杰里米
2012年3月17日15:51



#2 楼

即使使用00填充,种子树散列本身也容易受到第二个前映像攻击。我不会重复Ilmari Karonen的回答,他已经很好地解释了这一部分。

但是它并不是用来单独识别数据的:内容文件集的原始发布者创建了一个所谓的Merkle torrent,它是一个洪流文件,其信​​息部分包含根哈希密钥,而不是片段密钥。


作为种子的唯一ID的信息哈希不仅基于树的根,还包括信息字典中保存的文件名和文件大小。

知道总数洪流的大小可防止此类攻击。我仍然不喜欢他们的设计决定,因为它很容易导致torrent客户端中的错误,而这些错误并不知道这个问题。例如,如果客户忘记验证片段的大小,而仅检查散列,它仍然很容易受到攻击。


IMO,这种设计在与安全性无关的方式上也存在缺陷。

特别地,哈希树仍然跨越文件边界。每个文件只有一个根会更好。但是我想他们试图保持尽可能接近原始格式。

,他们决定使用叶子大小作为计件大小。我会选择一个较小的恒定叶大小,而使块大小与叶大小无关。这将允许更改片段大小而无需更改哈希。