3
<?php
function md7($text, $len)
{
  if($text)
  {
   $split = str_split(md5($text).md5(strlen($text)).md5($len), 5);
    foreach($split as $key=>$value)
    {
      $md5 = $md5.md5($value);
    }
    $split2 = str_split($md5);
    foreach($split2 as $kl=>$vl)
    {
      if($kl < $len)
      {
        $digest = $digest.$split2[$kl];
      }   
    }
    return $digest;
  }
} // end md7 function
?>

我创建了这个函数来使用 md5 和可变长度哈希,我相信这会减少发生冲突的机会,我已经测试了 MD5 冲突的示例,它不会为这个函数创建一个冲突,我相信这个函数不易受到彩虹表攻击。

4

3 回答 3

4

以下是一些明显的安全漏洞:

if($text)

两者都"0"返回""相同的哈希值。

foreach($split as $key=>$value)
{
  $md5 = $md5.md5($value);
}

您正在散列第一个散列的每个字母。$len <= 32这样一来,对于所有第一个字母相同的字符串,您就可以拥有完全相同的哈希值,md5($value)基本上将熵从 128 位降低到 4。这是所有 16 个哈希值的完整列表,其中 $len = 32:

8f14e45fceea167a5a36dedd4bea2543
92eb5ffee6ae2fec3ad71c777531578f
a87ff679a2f3e71d9181a67b7542122c
e4da3b7fbbce2345d7772b0674a318d5
c81e728d9d4c2f636f067f89cc14862c
8277e0910d750195b448797616e091ad
0cc175b9c0f1b6a831c399e269772661
45c48cce2e2d7fbdea1afc51c7c6ad26
4a8a08f09d37b73795649038408b5f33
e1671797c52e15f763380b45e841ec32
eccbc87e4b5ce2fe28308fd9f2a7baf3
c4ca4238a0b923820dcc509a6f75849b
8fa14cdd754f91cc6554c9e71929cce7
c9f0f895fb98ab9159f51fd0297e236d
1679091c5a880faf6fb5e6087eb1b2dc
cfcd208495d565ef66e7dff9f98764da

请注意,选择$len > 32. 您仍将只使用原始散列的第二个字母,这使您的熵增加了 4 位(现在最多 8 位),相当于 256 个不同的散列。

我很确定您需要 32^32 的长度才能匹配原始 md5 的熵。这是一个非常大的数字。


如果您想要安全性,请使用定义明确且经过良好测试的散列函数。PHP在散列函数中有一个sha1函数以及一堆其他函数。

哈希函数通常由加密社区创建和审查。它们比你能想出的几乎任何简单的 hack 都要好得多,所以不要实现你自己的散列函数,而是使用可用的散列函数之一。

于 2012-10-13T06:14:42.550 回答
3

除了你的函数不返回任何"""0",最终的哈希值只包含十六进制字符的 MD5 哈希值0–<code>9 和a–<code>f,它们是:

string(32) "cfcd208495d565ef66e7dff9f98764da"
string(32) "c4ca4238a0b923820dcc509a6f75849b"
string(32) "c81e728d9d4c2f636f067f89cc14862c"
string(32) "eccbc87e4b5ce2fe28308fd9f2a7baf3"
string(32) "a87ff679a2f3e71d9181a67b7542122c"
string(32) "e4da3b7fbbce2345d7772b0674a318d5"
string(32) "1679091c5a880faf6fb5e6087eb1b2dc"
string(32) "8f14e45fceea167a5a36dedd4bea2543"
string(32) "c9f0f895fb98ab9159f51fd0297e236d"
string(32) "45c48cce2e2d7fbdea1afc51c7c6ad26"
string(32) "0cc175b9c0f1b6a831c399e269772661"
string(32) "92eb5ffee6ae2fec3ad71c777531578f"
string(32) "4a8a08f09d37b73795649038408b5f33"
string(32) "8277e0910d750195b448797616e091ad"
string(32) "e1671797c52e15f763380b45e841ec32"
string(32) "8fa14cdd754f91cc6554c9e71929cce7"

如果我们使用相同的md7($c, 32)

NULL
string(32) "4a8a08f09d37b73795649038408b5f33"
string(32) "4a8a08f09d37b73795649038408b5f33"
string(32) "e1671797c52e15f763380b45e841ec32"
string(32) "0cc175b9c0f1b6a831c399e269772661"
string(32) "e1671797c52e15f763380b45e841ec32"
string(32) "c4ca4238a0b923820dcc509a6f75849b"
string(32) "c9f0f895fb98ab9159f51fd0297e236d"
string(32) "4a8a08f09d37b73795649038408b5f33"
string(32) "a87ff679a2f3e71d9181a67b7542122c"
string(32) "cfcd208495d565ef66e7dff9f98764da"
string(32) "45c48cce2e2d7fbdea1afc51c7c6ad26"
string(32) "a87ff679a2f3e71d9181a67b7542122c"
string(32) "c9f0f895fb98ab9159f51fd0297e236d"
string(32) "e1671797c52e15f763380b45e841ec32"
string(32) "c9f0f895fb98ab9159f51fd0297e236d"

再次,0返回NULL。但更有趣的是 { 1, 2, 8}, { 3, 5, 7} 和 { c, f} 的字符导致相同的哈希值。这是因为它们的 MD5 哈希值确实以相同的八位字节开头。当您使用这些散列来构建最终的 MD7 散列时,它们生成的散列的前 32 个十六进制字符也是相同的。

所以对于 ≤ 32 的长度,只有 16 个可能的 MD7 散列,对于 ≤ 64,有 16 2 个MD7 散列,依此类推。最大长度为 3·32·32=3072 并且可能的 MD7 哈希值的数量为 16 3·32

但是最后的 3072 个字符长的 MD7 哈希没有 16^192 熵。因为最后 1024 个字符是从已知的 MD7 哈希的长度推导出来的,所以只剩下 2048 个未知字符。

由于哈希循环可以反转,因此也可以获得文本及其长度的初始 MD5。

这是一个例子:

function md7_info($hash) {
    $hashlen = strlen($hash);

    $md5_to_hex = array();
    foreach (str_split('0123456789abcdef') as $c) $md5_to_hex[md5($c)] = $c;

    $md5_text = '';
    foreach (str_split(substr($hash, 0, 1024), 32) as $h) $md5_text .= $md5_to_hex[$h];

    $md5_textlen = '';
    foreach (str_split(substr($hash, 1024, 1024), 32) as $h) $md5_textlen .= $md5_to_hex[$h];

    return array($md5_text, $md5_textlen, $hashlen);
}

原始文本长度的MD5也可以反转。所以最后剩下的信息就是MD5和文本长度。没有获得更多的安全性。事实上,文本长度的知识确实揭示了额外的信息。

于 2012-10-13T07:23:58.793 回答
1

这里有一个问题可能值得考虑,但我无法轻松分析 md5 哈希。

让我们分两部分来考虑,前半部分接受输入,对其进行散列处理,并将其长度和返回的长度。我不确定与字符串连接的数组的效果是什么,但我会假设它只是为每个实例复制。

然后你遍历每一个并建立一个新的值:$md5 = $md5.md5($value). 鉴于您返回的字符串最多为 $len,这似乎是最大的弱点,因为您要返回字符串中的前 $len 个字节。

几个效果: $md5 主要取决于输入的开头。尝试类似的东西

md7("aaaaaaaaaaaaaaaaaaaaaaaa", 16)
md7("aaaaaaaaaaaaaaaaaaaaaaab", 16)

看看你是否得到类似的结果。我还没有尝试过,但我的直觉是你没有像你想要的那样正确混合整个输入。

于 2012-10-13T07:03:54.487 回答