MD5哈希值如何不可逆?

我一直想知道的一个概念是使用encryption散列函数和值。 我明白,这些函数可以生成一个独特的,几乎不可能扭转的哈希值,但这是我一直想知道的:

如果在我的服务器上,我在PHP中生成:

md5("stackoverflow.com") = "d0cc85b26f2ceb8714b978e07def4f6e" 

当你通过MD5函数运行相同的string时,你的PHP安装会得到相同的结果。 一个过程正在被用来产生一些价值,从一些初始值。

这是否意味着有一些方法来解构发生的事情并颠倒散列值?

这些function是什么使得产生的string不可能追溯?

input材料可以是无限长度,其中输出总是128位长。 这意味着无限数量的inputstring将会生成相同的输出。

如果你select一个随机数并除以2,而只剩下余数,则分别得到0或1 – 偶数或奇数。 是否有可能取0或1并获得原始数字?

如果像MD5这样的散列函数是可逆的,那么在数据压缩algorithm的历史中,这将是分水岭事件! 很容易看出,如果MD5是可逆的,那么任意大小的任意数据块都可以用128位表示,而不会丢失任何信息。 因此,无论原始消息的大小如何,您都可以从128位数字重build原始消息。

与这里强调的最高回答的答案相反,由大的(可能无限的)input大小和固定的输出大小之间的差异引起的密码散列函数的非注入性 (即,有几个string散列到相同的值) 不是重要的一点 – 实际上,我们更喜欢那些发生碰撞的散列函数。

考虑这个函数(用PHP表示法,作为问题):

 function simple_hash($input) { return bin2hex(substr(str_pad($input, 16), 0, 16)); } 

这附加了一些空格,如果string太短,然后将string的前16个字节,然后将其编码为hex。 它具有与MD5散列相同的输出大小(32个hex字符,如果我们省略bin2hex部分,则为16个字节)。

 print simple_hash("stackoverflow.com"); 

这将输出:

 737461636b6f766572666c6f772e636f6d 

这个函数也具有与Cody MD5的答案相同的非注入属性:我们可以传递任何大小的string(只要它们适合我们的计​​算机),它将只输出32位hex数字。 当然,它不能是内射的。

但是在这种情况下,find一个映射到同一个散列的string是很简单的(只hex2bin在你的散列上应用hex2bin就可以了)。 如果你的原始string的长度是16(如我们的例子),你甚至会得到这个原始的string。 即使你知道input的长度很短(除非我们find相匹配的东西,例如暴力攻击),否则这种types的MD5应该是不可能的。

密码散列函数的重要假设是:

  • 很难find产生给定散列的任何string(前像抵抗)
  • 很难find任何不同的string产生相同的哈希作为给定的string(第二原像电阻)
  • 很难find任何具有相同散列的string(碰撞抵抗)

很明显,我的simple_hash函数既不满足这些条件。 (实际上,如果我们限制input空间为“16字节的string”,那么我的函数变成内射的,因此甚至是可certificate的第二原像和抗碰撞)。

现在已经存在对MD5的碰撞攻击(例如,即使给定了相同的前缀,也可能产生一对string,这些string具有相同的散列,但是有相当多的工作,但不是不可能做太多的工作),所以你不应该使用对于任何关键的MD5。 目前还没有前期攻击,但攻击会变得更好。

回答实际的问题:

这些function是什么使得产生的string不可能追溯?

在Merkle-Damgard构造上build立的MD5(和其他散列函数)有效地执行的是将该消息用作密钥和某个固定值作为“明文”的encryptionalgorithm,使用所得到的密文作为散列。 (在此之前,input被填充和分块,每个块被用来encryption前一个块的输出,与其input异或以防止反向计算)。

现代的encryptionalgorithm(包括散列函数中使用的encryptionalgorithm)的制作方式使得难以恢复密钥,即使给出了明文和密文(或者甚至当对手select其中之一时)也是如此。 他们通常通过进行大量的位混洗操作来完成这一操作,每个输出位由每个关键位(几次)以及每个input位确定。 这样,只有在知道完整的键和input或输出的情况下,才能轻松地回溯内部发生的情况。

对于类似MD5的散列函数和preimage攻击(使用单块散列string,为了使事情更容易),您只有encryption函数的input和输出,而不是密钥(这是您正在查找的内容)。

科迪Brocious的答案是正确的。 严格地说,你不能“颠倒”一个散列函数,因为许多string映射到相同的散列。 但是请注意,find一个映射到给定散列的string,或者find两个映射到相同散列(即冲突 )的string,这对于密码分析者来说将是重大突破。 这两个问题的难度很大,为什么好的散列函数在密码学中是有用的。

MD5不会创build唯一的哈希值; MD5的目标是快速产生一个根据源头的微小变化而显着改变的值。

例如,

 "hello" -> "1ab53" "Hello" -> "993LB" "ZR#!RELSIEKF" -> "1ab53" 

(显然这不是真正的MD5encryption)

大多数哈希(如果不是全部的话)也是非唯一的; 相反,他们是独一无二 ,所以碰撞是非常不可能的,但仍然是可能的。

想一想散列algorithm的一个好方法就是考虑在Photoshop中调整图像的大小…假设您有一个5000×5000像素的图像,然后将其大小调整为32×32。 你有什么仍然是原始图像的代表,但它是小得多,并有效地“扔掉”图像数据的某些部分,以适应更小的尺寸。 所以如果你把这个32×32的图像重新调整到5000×5000,你会得到一个模糊的混乱。 但是,由于32×32的图像并不是那么大,理论上可以设想另一幅图像可以缩小以产生完全相同的像素!

这只是一个比喻,但它有助于理解哈希在做什么。

哈希碰撞比你想象的更有可能。 看看生日悖论 ,以便更好地理解这是为什么。

由于可能的input文件的数量大于128位输出的数量,因此不可能唯一地为每个可能的MD5散列赋值。

encryption散列函数用于检查数据完整性或数字签名(哈希是为了效率而签名的)。 因此,更改原始文档应该意味着原始散列不匹配已更改的文档。

有时使用这些标准:

  1. 前像抵抗:对于给定的散列函数和给定的散列,应该很难find具有该函数给定散列的input。
  2. 第二原像阻力:对于给定的散列函数和input,应该很难find具有相同散列的第二个不同的input。
  3. 碰撞阻力:对于一个给定的函数,应该很难find具有相同散列的两个不同的input。

select这些标准使得难以find与给定散列相匹配的文档,否则将可能通过将原始文档replace为与散列匹配的文档来伪造文档。 (即使replace是乱码,仅仅replace原文可能会导致中断。)

数字3意味着数字2。

对于MD5尤其如此,它已被certificate是有缺陷的: 如何打破MD5和其他散列函数 。

但这是彩虹桌的起点。 基本上这只是大量的散列值,然后将结果保存到磁盘。 然后反转位是“正好”在一个非常大的表中查找。

显然这只适用于所有可能的input值的一个子集,但是如果你知道input值的范围,可以计算它的input值。

中国科学家find了一种叫做“select前缀的碰撞”的方法来使两个不同的string发生冲突。

这里是一个例子: http : //www.win.tue.nl/hashclash/fastcoll_v1.0.0.5.exe.zip
源代码: http : //www.win.tue.nl/hashclash/fastcoll_v1.0.0.5_source.zip

正如大多数人已经说过的,MD5被devise用于将可变长度的数据stream散列成固定长度的数据块,所以单个散列被许多input数据stream共享。

但是,如果您需要从校验和中find原始数据,例如,如果您有密码散列并需要查找原始密码,那么只要Google(或您喜欢的任何search器)对于蛮力来说这个答案比它强。 我已经用这种方法成功找出了一些密码。

根据定义哈希(密码哈希)函数:不应该是可逆的,不应该有碰撞(尽可能less)。

regd你的问题:这是一种方法散列。 input(不考虑长度)将产生一个固定大小的输出(它将被基于algorithm填充(MD5的512比特边界))。 信息被压缩(丢失),实际上不可能通过反向转换生成。

有关MD5的更多信息:容易受到碰撞。 最近通过这篇文章, http://www.win.tue.nl/hashclash/Nostradamus/

打开encryption哈希实现(MD5和SHA)的源代码可以在Mozilla代码中find。 (免费图书馆)。

现在一天MD5哈希或任何其他散列是预先计算所有可能的string,并存储为方便访问。 虽然理论上MD5是不可逆的,但是使用这样的数据库,你可以找出哪个文本产生了一个特定的散列值。

例如,请尝试http://gdataonline.com/seekhash.php上的以下哈希代码来找出我用来计算哈希的文本;

 aea23489ce3aa9b6406ebb28e0cda430 

f(x)= 1是不可逆的。 哈希函数不是不可逆的。

这实际上是要求他们完成确定某人是否拥有散列数据的副本的function。 这带来了对暴力攻击的敏感性,这些攻击现在非常强大,特别是针对MD5。

在这里和那些有math知识,但知识less的知识的人也有困惑。 几个密码只是将数据与密钥stream异或,所以你可以说密文对应于这个长度的所有明文,因为你可以使用任何密钥stream。

然而,这忽略了由种子password产生的合理的明文比由种子产生的另一个明文更可能是更可能的Wsg5Nm^bkI4EgxUOhpAjTmTjO0F!VkWvysS6EEMsIJiTZcvsh@WI$IH$TYqiWvK!%&Ue&nk55ak%BX%9!NnG%32ftud%YkBO$U6o如果有人声称第二个可能性会被嘲笑的话。

以同样的方式,如果你试图在两个潜在的密码passwordWsg5Nm^bkI4EgxUO之间做出决定,那么做一些math家会让你相信的事情并不难。

理解所有最受投票的答案意味着最好的方法是实际尝试恢复MD5algorithm。 我记得几年前我试图恢复MD5cryptalgorithm,不是为了恢复原始的消息,因为它显然是不可能的,而只是生成一个消息,将产生与原始散列相同的散列。 至less在理论上,这将为我提供一种loginLinux设备的方法,该设备使用生成的消息(密码)将用户:密码存储在/ etc / passwd文件中,而不是使用原始密码。 由于这两个消息都具有相同的散列值,因此系统会将我的密码(从原始散列生成)视为有效。 这根本不起作用。 几个星期后,如果我没有记错的话,在最初的消息中使用盐会杀死我。 我不仅要产生一个有效的初始信息,而且要有一个有效的初始信息,这是我从来没有做过的。 但是我从这个实验中得到的知识很好。

我喜欢所有的各种论点。 显而易见,哈希值的真正价值仅仅是为诸如密码之类的string提供人类不可读的占位符。 它没有具体的增强安全效益。 假设攻击者利用哈希密码获得访问表,他/她可以:

  • 散列他/她自己select的密码,并将结果放在密码表中,如果他/她具有写入/编辑表的权限。
  • 生成通用密码的哈希值并testing密码表中是否存在类似的哈希值。

在这种情况下,弱密码不能仅仅由于散列而被保护。