原始算法会产生1个字节长的哈希,并且(当然)不适合密码学使用。
但是根据Wikipedia的说法,可以简单地通过增加密码的第一个字节来生成任何长度的Pearson哈希。哈希的下一个字节发送消息。
此外,如果编码数组中填充了实随机数,则可以保证产生的哈希的质量非常高。
因此,为什么此哈希函数没有得到广泛使用在密码算法中?
编辑1:
我用以下由https://www.random.org/lists生成的字节数组对皮尔逊哈希的雪崩效应进行了一些测试: br />
141, 227, 251,   2, 201, 179,  30,  63,  93, 145,  92,  46,   6,  95, 105,   1
 90, 112,  60,  84, 110, 205,   0, 253, 215, 118, 244, 218, 231,  31, 192,  67
189,  23,  66, 144,  59, 115, 248, 237, 216,  82, 217,  72, 147, 143, 125, 170
152, 154,  57,   4,  44, 131, 157, 111, 209, 185,  35,  81,  41, 182, 202, 176
113, 193, 114, 254,  39, 194,  94, 190,  37,  42,  15, 195, 188, 169,  12,   7
175,  88, 245, 127, 203, 135, 181, 178,  99, 164,  76, 235,  21,  86, 160, 243
223, 126, 136, 129,  77, 239, 132, 174, 122, 233,  87, 108,  47, 146, 158, 128
 97, 162, 219,  91, 229, 222, 104,  71, 150,  55, 242,  75, 151, 206, 119,  36
 58, 236, 117,  43,  74, 155, 246, 116, 153, 148,  68, 159, 210, 161,  19,  64
247, 186,  83,  29,   5, 249, 177, 196, 250, 197, 167, 230,  26, 134, 124, 240
 69, 149,  65,  62, 101,  38, 183,  45,  24, 166,  33, 123, 207, 107, 241, 191
208,  85,  78, 184,  32,  89,  20, 165,  27,  22,  11, 130,  98,  80,  17, 198
200, 211,  16, 100,  51, 232,   3,  96,  73, 187,  14,  53, 121, 199,  18, 103
228, 180, 156, 252, 168,  49,   8, 171,  79, 204,  10, 139,  40,  61, 220, 212
 13, 221, 109,  25, 255, 120,  70,  28,  48, 213, 234,  50, 138,   9,  52, 142
225, 172, 106,  54, 214, 163, 140,  34, 238, 224,  56, 226, 102, 137, 133, 173

更改消息的单个位后,哈希函数在不同情况下从生成的256位哈希值的110位更改为150位。
Edit2:
感谢对CodesInChaos的分析显然,如Wikipedia中所述,多字节哈希具有严重的缺陷,因为resu中的非重复字节并反转了第256个字节后的哈希的完全重复。这是因为下面的代码将以下行中的每个字节的h值清除为固定值:h = T[x[0] + j) % 256];
  for (j = 0; j < 8; j++) {
     unsigned char h = T[(x[0] + j) % 256];
     for (i = 1; i < len; i++) {
        h = T[h ^ x[i]];
     }
     hh[j] = h;
  }

但是此问题具有简单的解决方案-请勿重置该值内循环之后h的时间。
我尝试使用以下公式:h = T[((h+j)%256 ^ x[0])]。在我的测试中,它显示了结果中的重复字节,第256个字节后未重复哈希并且仍然具有很好的雪崩效果。修改后的函数的代码为(C#):
        byte h = 0;
        for (j = 7; j >=0; j--)
        {
            //h = T[(x[0] + j) % 256];
            h = T[((h + j)%256 ^ x[0])]; 
            for (i = x.Length-1; i > 0; i--)
            {
                h = T[h ^ x[i]];
            }
            hh[j] = h;
        }
        return hh;


评论

这样的哈希永远不会包含重复的字节。这是一个区别攻击,但它阻止了我一直在寻找的碰撞攻击。

密码分析很酷的练习:)

@CodesInChaos IMO,Pearson哈希可以包含重复的字节。为什么不呢?

@johnfound:如果您的字节数组实际上是一个排列,则可以向后运行哈希,证明如果输出中存在重复的字节,则它们将需要来自重复的初始字节-并“简单地增加消息的第一个字节对于下一个哈希字节”表示初始字节不会重复。

@HenningMakholm-哈希中的每个下一个字节实际上是不同输入消息的一个字节的Pearson哈希。只要一个字节的哈希具有很高的冲突率,那么散列中就可以有重复的字节。想象一下哈希长度超过256个字节。在这样的哈希中,您将在每个哈希值中获得重复的字节。

#1 楼

观察:

单个1字节的皮尔逊散列的行为类似于8位块密码,并使用消息作为密钥来加密初始状态。这意味着在给定固定消息的情况下,每种可能的初始状态都会产生不同的输出。这意味着合并的哈希将永远不会包含重复的字节。

没有此属性,哈希将在大约1.5 kB之后忘记初始状态,并且合并的哈希将由相同的字节组成,从而降低其质量。

永远不会产生相同的字节是一种微不足道的区别攻击,但是作为交换,您会得到一个不会偶然产生大量冲突的哈希。

“中间相遇”攻击找到前映像:

由于前一个状态与下一个状态之间的映射是双射的且可有效计算,因此,“中间相遇”攻击可以找到前图像-在$ 2 ^ {n / 2} $时间内n位哈希的图像,类似于如何通过中间相遇攻击破坏2DES。对于64位哈希,这是可行的。 SHA-3中使用的海绵构造也遭受类似的侵蚀,这就是为什么容量至少需要为所需的原像大小的两倍。

通过找到固定点来进行原像攻击:

我们定位的消息称为$ m_0 $。我们正在搜索后缀$ m $,以使$ h(m_0)= h(m_0 || m)$。这是$ m_0 $上的第二个原像,其中使用$ m $保留状态。

我们从$ n $短消息开始,我们将其称为字母。 $ n ^ 2 $个不同的2符号组合,其中$ 1/256 $的一部分将保留初始字节。我们尝试找到约$ n $个固定点,因此我们需要$ n \约256 $(实际上可能需要稍大的$ n $来补偿随机偏差)。

一旦第一个输出字节有足够的定点,我们将扩展到两个输出字节。为此,我们看一下由两个一个字节的定点组成的序列。所有这些组合也是一个字节的定点,而其中的$ 1/256 $是两个字节的定点。

重复此过程8次,将产生一个$ m $,该值保留了完整状态。由于每次迭代都会使消息长度加倍,因此我们最终得到的消息长度是单符号消息或短单符号消息(每个由一个或两个字节组成)的长度的256倍。位Pearson散列会产生相对较长的消息($ 2 ^ {16} $个符号或100-200kB)。您可以从$ n \ approx 256 ^ 2 $开始,同时固定两个字节的哈希,这将成本增加到$ \ approx 2 ^ {32} $哈希,这仍然是可行的。为了换取更高的运行时间,它会将消息长度减少回256个符号或500-1000字节。

如雨披所指出的那样,这种攻击很容易适应于第一个原图像。 >
此攻击的快速,肮脏的实现可在以下位置找到:https://gist.github.com/CodesInChaos/4a399a26b98221155a92

我的代码天真地枚举了所有$ n ^ 2 $组合,并且过滤掉产生所需结果的大约$ n $。反向运行哈希函数以执行中间相遇攻击,可以将这些$ n ^ 2 $哈希计算降低到大约$ n $哈希计算。这种优化使给定成本和消息大小的散列长度加倍,您可以破坏该散列。因此,中断128位哈希大约需要花费$ 2 ^ {16} $的哈希值,而中断256位哈希大约需要花费$ 2 ^ {32} $的哈希值,其中每条消息的大小约为1 kB。

您的“改进”版本:

上面的第二次映像前攻击无需更改攻击代码即可工作。只需将哈希函数替换为“改进”版本即可。

评论


$ \ begingroup $
好一个。将其转变为原像攻击似乎并不难;首先将第一个字节设置为所需的值,然后查找保留该第一个字节的$ n $序列,找到一个将第二个字节设置为所需值的序列,然后继续操作,直到设置完所有字节为止。 。
$ \ endgroup $
–雨披
16 Mar 15 '15:24



$ \ begingroup $
@poncho对该代码进行了概括,以包括类似的第一次映像前攻击。
$ \ endgroup $
– CodesInChaos
16 Mar 15 '16 at 17:37

$ \ begingroup $
对散列进行了一些更改(我用C#实现了我的汇编语言代码)后,我开始出现运行时错误:序列在第39行中不包含任何元素。是否可以解决该问题?整个代码在:pastebin.com/hbzZWspZ
$ \ endgroup $
– johnfound
16 Mar 15 '16 at 18:11

$ \ begingroup $
@johnfound您在哈希中向后运行j循环会破坏攻击代码。 (这并不意味着更改是对安全性的改进)
$ \ endgroup $
– CodesInChaos
16 Mar 15 '16 at 18:42

$ \ begingroup $
@CodesInChaos我了解。对我来说这是很好的锻炼。
$ \ endgroup $
– johnfound
16 Mar 15 '18:56



#2 楼

因为它不够安全。

哈希函数在很大程度上依赖于扩散(单个位的更改必须更改其他位的一半)和混乱(一个位的值应取决于其他位的值)位)。这也称为雪崩效应。

由于缺乏排列,所以我的第一个直觉是:它缺乏扩散性,并且对差分密码分析无能为力。我还猜想每8位数据包之间会有一个相关性:请参见Wikipedia提供的源代码中的第25行:

24       for (j = 0; j < 8; j++) {
25          unsigned char h = T[(x[0] + j) % 256];
26          for (i = 1; i < len; i++) {
27             h = T[h ^ x[i]];
28          }
29          hh[j] = h;
30       }
填充有真实的随机数,将确保产生的哈希值的质量很高。


这还不够:S-box必须经过安全设计(如果您引用的是随机数,到维基百科)。示例DES:如何选择具有密码分析抗性的值。此外,每个人的替代表必须相同。维基百科提供的表格的差异分析导致以下概率:

 00000101 => 00100010 : 10 / 256
 00100100 => 01100010 : 10 / 256
 00100100 => 11100110 : 10 / 256
 00011100 => 11100001 : 10 / 256
 00111111 => 10011011 : 10 / 256
 00100001 => 01011100 : 10 / 256
 01010010 => 10110111 : 10 / 256
 01011011 => 11010010 : 10 / 256
 01100011 => 11101110 : 10 / 256
 11001111 => 11110101 : 10 / 256
 11011000 => 10000100 : 10 / 256
 01110100 => 00101011 : 10 / 256
 01111011 => 00110111 : 10 / 256
 01111110 => 10000010 : 10 / 256
 01111111 => 11000011 : 10 / 256
 10110110 => 01000000 : 10 / 256
 11111001 => 00001101 : 10 / 256
 11101010 => 00001000 : 12 / 256


作为尺度,AES S盒(优化)概率永远不会高于4 / 256.

有关第二次原像攻击的信息,请参见CodeInChaos的答案。

评论


$ \ begingroup $
我使用随机数组(来自random.org)进行了一些测试,并在消息的单个更改位上始终获取114至152个更改位,以进行256位哈希。这似乎对雪崩效应非常有利。是不是
$ \ endgroup $
– johnfound
16 Mar 15 '16 at 11:44