与此处最受支持的答案相反,由大(可能无限)的输入大小和固定的输出大小之间的差异引起的加密哈希函数的非注入性(即,有多个字符串哈希到相同的值)不是重要的一点 –实际上,我们更喜欢哈希函数,在这些哈希函数中,冲突很少发生。
考虑以下功能(以PHP表示法为问题):
function simple_hash($input) {
return bin2hex(substr(str_pad($input, 16), 0, 16));
}
如果字符串太短,则会附加一些空格,然后使用字符串的前16个字节,然后将其编码为十六进制。它具有与MD5哈希相同的输出大小(32个十六进制字符,或者如果省略bin2hex部分,则为16个字节)。
print simple_hash("stackoverflow.com");
这将输出:
737461636b6f766572666c6f772e636f6d
此功能也具有与Cody针对MD5的回答所强调的相同的非内射性:我们可以传入任何大小的字符串(只要它们适合我们的计算机),并且它只会输出32个十六进制数字。当然不能是内射的。
但是在这种情况下,找到映射到相同哈希的字符串很简单(只需将其应用于hex2bin
您的哈希即可)。如果您的原始字符串的长度为16(如我们的示例所示),您甚至会得到此原始字符串。即使您知道输入的长度很短,MD5也不应该有这种情况(除非尝试所有可能的输入,直到找到匹配的输入,例如蛮力攻击)。
密码哈希函数的重要假设是:
- 很难找到产生给定哈希值(原像电阻)的任何字符串
- 很难找到产生与给定字符串相同的哈希值的任何其他字符串(第二个像前电阻)
- 很难找到具有相同散列的任何一对字符串(抗冲突性)
显然,我的simple_hash
职能不满足这些条件。(实际上,如果我们将输入空间限制为“ 16字节字符串”,那么我的函数会变得内射,因此甚至可以证明其具有第二原像抗性和抗碰撞性。)
现在存在针对MD5的碰撞攻击(例如,即使有给定的相同前缀,也可能产生具有相同哈希值的一对字符串,需要做很多工作,但不是不可能做很多工作),因此您不应该使用MD5适用于任何关键问题。尚无原像攻击,但攻击会变得更好。
要回答实际问题:
这些函数使生成的字符串无法回溯是什么原因?
MD5(和其他基于Merkle-Damgard构造的哈希函数)有效地执行的工作是,使用所得的密文作为哈希,应用一种加密算法,将消息作为密钥,并将某个固定值作为“纯文本”。(在此之前,将输入填充并拆分为块,每个块用于加密前一个块的输出,并对其输入进行XOR运算,以防止进行反向计算。)
现代加密算法(包括哈希函数中使用的算法)的制作方式使得即使在给定明文和密文(甚至当对手选择其中之一)的情况下也很难恢复密钥。他们通常通过执行许多位混洗操作来做到这一点,即每个输出位由每个关键位(多次)以及每个输入位确定。这样,如果您知道完整的键以及输入或输出,就只能轻松地追溯内部发生的事情。
对于类似MD5的哈希函数和原图像攻击(使用单块哈希字符串,使事情变得更容易),您只有加密函数的输入和输出,而没有密钥(这就是您要寻找的)。