像 MD5这样的散列函数如何是唯一的?

我知道 MD5有一些冲突,但这更多的是关于散列函数的高级问题。

如果 MD5将任意字符串散列为32位十六进制值,那么根据 鸽巢原理,这肯定不可能是唯一的,因为唯一的任意字符串比唯一的32位十六进制值多得多。

62306 次浏览

你是绝对正确的。但散列不是关于“独一无二”,而是关于“足够独一无二”。

(星期天似乎是散列函数。)

密码哈希函数被设计成具有非常、非常、非常低的重复率。显而易见的原因,你说,比率永远不可能为零。

维基百科页面的信息量很大。

您是对的,它不能保证唯一性,但是在32位十六进制值(16 ^ 32)中大约有3.402823669209387 e + 38个不同的值。这意味着,假设算法背后的数学给出了一个良好的分布,那么出现重复的可能性就非常小。你必须记住,当你考虑如何使用它的时候,复制是可能的。MD5通常用于确定某些内容是否已被更改(即它是校验和)。修改某些内容并产生相同的 MD5校验和的可能性非常小。

编辑: (给出最近的新闻 re: SHA1哈希) 上面的答案仍然有效,但是您不应该指望 MD5散列作为针对操作的任何类型的安全检查。SHA-1哈希值是碰撞可能性的2 ^ 32倍(超过40亿) ,并且已经证明可以设计一个输入来产生相同的值。(这是很久以前针对 MD5演示的)。如果您希望确保没有人恶意修改某些内容以产生相同的散列值,那么现在,您需要在 SHA-2获得可靠的保证。

另一方面,如果不在安全检查上下文中,MD5仍然有用。

可以认为,SHA-2散列的计算成本很低,因此无论如何都应该使用它。

正如 Mike (以及基本上所有其他人)所说的那样,它并不完美,但它确实起到了作用,而且碰撞性能确实取决于算法(其实算法相当不错)。

真正令人感兴趣的是对文件或数据的自动操作,以使不同数据保持相同的散列,请参阅 演示

正如其他人所回答的,散列函数根据定义不能保证返回唯一值,因为对于无限数量的输入有固定数量的散列。它们的关键特性是碰撞是 不可预测

换句话说,它们不容易可逆——因此,尽管可能有许多不同的输入会产生相同的散列结果(“冲突”) ,但找到其中任何两个在计算上都是不可行的。

从定义的性质来看,加密单向散列函数不是 注射器。 就哈希函数而言,“唯一”是毫无意义的。这些函数通过其他属性进行度量,这些属性会影响函数的强度,因为它们很难创建给定散列的预映像。例如,我们可能会关心有多少图像位受到改变一个位在前图像。我们可能会关心进行一个穷举法的难度(为给定的散列图像寻找一个 prie-image)。我们可能会关心找到冲突有多么困难: 找到两个具有相同散列图像的预图像,用于 生日袭击

正如其他人指出的那样,像 MD5这样的散列函数的目标是提供一种方便的方法来检查两个对象是否是等价的,而不需要知道它们最初是什么(密码)或者完整地比较它们(大文件)。

假设您有一个对象 O及其散列 h。您获得另一个对象 P,并希望检查它是否等于 O。这可能是一个密码,或者是您下载的一个文件(在这种情况下,您不会有 O,而是它的 h散列,很可能是 P附带的)。首先,对 P进行杂凑以得到 hP

现在有两种可能性:

  1. H和 hP是不同的。这肯定意味着 OP是不同的,因为对2个值/对象使用相同的散列必须产生相同的值。散列是确定性的。没有假阴性。
  2. H和 hP相等。正如你所说,由于鸽巢原理,这意味着不同的对象散列相同的值,可能需要采取进一步的行动。

    因为可能性的数目是如此之高,如果你对你的散列函数有信心,它可能足以说: “嗯,有1在2128碰撞的机会(理想情况下) ,所以我们可以假设 O = P。例如,如果您限制字符的长度和复杂性,这可能适用于密码。这就是为什么您看到存储在数据库中的密码哈希而不是密码本身的原因。 B.您可能会认为散列结果相等并不意味着对象相等,然后对 OP进行直接比较。你可能有一个假阳性。

所以,尽管你可能有假阳性匹配,你不会有假阴性。根据您的应用程序,以及是否期望对象始终相等或始终不同,散列可能是多余的步骤。

如果要散列的值比得到的散列长得多,那么很可能会出现冲突,但是对于大多数情况来说,冲突的数量仍然足够低(总共有 2 < sup > 128 可能的散列,所以理论上两个随机字符串产生相同散列的几率接近于1/1038)。

创建 MD5主要是为了进行完整性检查,因此它对最小的更改非常敏感。输入中的一个小小的修改将导致一个完全不同的输出。这就是为什么仅仅根据散列值很难猜测密码的原因。

虽然散列本身是不可逆的,但仍然可以通过纯粹的蛮力找到一个可能的输入值。这就是为什么当你使用 MD5存储密码哈希时,你应该确保添加一个 salt: 如果你在输入字符串中包含一个 salt,一个匹配的输入字符串必须包含完全相同的 salt 才能产生相同的输出字符串,因为否则与输出相匹配的原始输入字符串在自动加盐后将不能匹配(也就是说,你不能只是“反转”MD5并使用它来登录,因为反转的 MD5哈希很可能不是最初导致哈希创建的加盐字符串)。

所以散列并不是唯一的,但是身份验证机制可以使它足够唯一(这是一个有点似是而非的论点,用来代替加盐的密码限制: 产生相同散列的字符串集可能包含许多不遵守密码限制的字符串,所以用蛮力来反转散列更加困难——显然,加盐仍然是一个好主意)。

更大的哈希表示相同输入集的可能哈希集更大,因此重叠的几率更小,但是在处理能力提高到足以使强制 MD5变得不重要之前,对于大多数目的来说,它仍然是一个不错的选择。