99

我一直想知道的一个概念是加密哈希函数和值的使用。我知道这些函数可以生成一个唯一且几乎不可能反转的哈希值,但这是我一直想知道的:

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

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

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

这是否意味着有某种方法可以解构正在发生的事情并反转哈希值?

这些函数是什么使生成的字符串无法回溯?

4

16 回答 16

215

输入材料可以是无限长的,输出总是 128 位长。这意味着无限数量的输入字符串将生成相同的输出。

如果您选择一个随机数并将其除以 2,但只记下余数,您将得到 0 或 1——分别为偶数或奇数。是否可以取那个 0 或 1 并得到原始数字?

于 2008-12-01T07:19:56.063 回答
53

如果像 MD5 这样的哈希函数是可逆的,那么这将是数据压缩算法历史上的一个分水岭!很容易看出,如果 MD5 是可逆的,那么任意大小的任意数据块可以仅用 128 位表示,而不会丢失任何信息。因此,无论原始消息的大小如何,您都可以从 128 位数字重构原始消息。

于 2008-12-01T09:22:00.123 回答
34

与此处最受赞成的答案所强调的相反,由大(可能无限)输入大小和固定输出大小之间的差异引起的密码散列函数的非注入性(即有几个字符串散列到相同的值)不是重要的一点——实际上,我们更喜欢那些冲突尽可能少发生的哈希函数。

考虑这个函数(在 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 结构的散列函数)有效地做的是应用加密算法,将消息作为密钥,将某个固定值作为“纯文本”,使用生成的密文作为散列。(在此之前,输入被填充并分割成块,每个块用于加密前一个块的输出,与输入进行异或以防止反向计算。)

现代加密算法(包括散列函数中使用的算法)的制作方式使得很难恢复密钥,即使在明文和密文(甚至当对手选择其中之一时)也是如此。他们通常通过执行大量位混洗操作来做到这一点,每个输出位由每个关键位(几次)以及每个输入位确定。这样,如果您知道完整的密钥以及输入或输出,您就可以轻松地追溯内部发生的事情。

对于类似 MD5 的散列函数和原像攻击(使用单块散列字符串,以使事情更容易),您只有加密函数的输入和输出,但没有密钥(这就是您要寻找的)。

于 2011-08-22T18:00:41.413 回答
18

Cody Brocious 的回答是正确的。严格来说,您不能“反转”散列函数,因为许多字符串都映射到同一个散列。然而,请注意,要么找到一个映射到给定哈希的字符串,要么找到两个映射到同一个哈希的字符串(即冲突),对于密码分析者来说将是重大突破。这两个问题的巨大困难是好的散列函数在密码学中有用的原因。

于 2008-12-01T07:32:59.997 回答
12

MD5 不会创建唯一的哈希值;MD5 的目标是快速生成一个值,该值会根据对源的微小更改而发生显着变化。

例如,

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

(显然这不是真正的 MD5 加密)

大多数哈希(如果不是全部)也是非唯一的;相反,它们足够独特,因此碰撞是极不可能的,但仍有可能。

于 2008-12-01T07:41:05.893 回答
8

考虑哈希算法的一个好方法是考虑在 Photoshop 中调整图像的大小……假设您有一个 5000x5000 像素的图像,然后将其调整为 32x32。您所拥有的仍然是原始图像的表示,但它要小得多,并且有效地“丢弃”了图像数据的某些部分以使其适合较小的尺寸。因此,如果您将 32x32 图像的大小重新调整为 5000x5000,您将得到的只是一团模糊的混乱。然而,由于 32x32 图像并没有那么大,理论上可以想象另一个图像可以缩小尺寸以产生完全相同的像素!

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

于 2008-12-13T11:26:27.873 回答
4

哈希冲突的可能性比您想象的要大得多。看看生日悖论,以更好地理解为什么会这样。

于 2008-12-01T07:49:05.177 回答
4

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

加密散列函数用于检查数据完整性或数字签名(为提高效率而对散列进行签名)。因此,更改原始文档应该意味着原始哈希与更改后的文档不匹配。

有时会使用这些标准:

  1. 原像抗性:对于给定的散列函数和给定的散列,应该很难找到具有该函数给定散列的输入。
  2. 第二原像抗性:对于给定的散列函数和输入,应该很难找到具有相同散列的第二个不同的输入。
  3. 碰撞阻力:对于给定的函数,应该很难找到具有相同哈希的两个不同输入。

选择这些标准是为了使找到与给定哈希匹配的文档变得困难,否则就有可能通过将原始文档替换为与哈希匹配的文档来伪造文档。(即使替换是胡言乱语,仅仅替换原件也可能导致中断。)

数字 3 意味着数字 2。

尤其是 MD5,它已经被证明是有缺陷的: 如何破解 MD5 和其他哈希函数

于 2008-12-02T14:17:38.760 回答
2

但这就是彩虹桌发挥作用的地方。基本上它只是大量单独散列的值,然后将结果保存到磁盘。然后反转位“只是”在一个非常大的表中进行查找。

显然,这仅适用于所有可能输入值的子集,但如果您知道输入值的范围,则可以计算它。

于 2008-12-01T07:47:34.820 回答
2

中国科学家发现了一种称为“选择前缀冲突”的方法,可以在两个不同的字符串之间产生冲突。

下面是一个例子: 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

于 2012-03-13T06:07:36.080 回答
2

了解所有投票最多的答案意味着什么的最佳方法是实际尝试还原 MD5 算法。我记得几年前我试图恢复MD5crypt算法,不是为了恢复原始消息,因为这显然是不可能的,而只是为了生成一条可以产生与原始哈希相同的哈希的消息。至少从理论上讲,这将为我提供一种登录 Linux 设备的方法,该设备使用生成的消息(密码)而不是使用原始消息(密码)将 user:password 存储在 /etc/passwd 文件中。由于两条消息将具有相同的结果散列,因此系统会将我的密码(从原始散列生成)识别为有效。那根本行不通。几周后,如果我没记错的话,盐的使用在最初的消息中杀了我。我不仅要生成一个有效的初始消息,而且还要生成一个加盐的有效初始消息,这是我永远无法做到的。但是我从这个实验中得到的知识很好。

于 2017-02-15T16:53:15.740 回答
1

正如大多数人已经说过的那样,MD5 设计用于将可变长度数据流散列为固定长度的数据块,因此许多输入数据流共享单个散列。

但是,如果您确实需要从校验和中找出原始数据,例如,如果您有密码的哈希值并且需要找出原始密码,那么只需 google(或您喜欢的任何搜索器)哈希值通常会更快答案比暴力破解它。我已经使用这种方法成功找到了一些密码。

于 2008-12-03T10:42:37.540 回答
0

根据定义,密码散列函数不应该是可逆的,并且应该具有尽可能少的冲突。

关于您的问题:这是一种单向哈希。输入(与长度无关)将生成固定大小的输出,该输出将基于算法(MD5 的 512 位边界)进行填充。信息被压缩(丢失)并且实际上不可能从反向变换中生成。

有关 MD5 的附加信息:它容易受到碰撞。我最近浏览了这篇文章, http://www.win.tue.nl/hashclash/Nostradamus/

加密哈希实现(MD5 和 SHA)的开源代码可以在 Mozilla 代码中找到。(免费图书馆)。

于 2008-12-01T08:14:20.790 回答
0

现在每天 MD5 散列或任何其他散列都会为所有可能的字符串预先计算并存储以便于访问。虽然理论上 MD5 是不可逆的,但使用这样的数据库,您可能会发现哪个文本产生了特定的哈希值。

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

aea23489ce3aa9b6406ebb28e0cda430
于 2009-05-30T15:04:55.760 回答
0

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

这实际上是他们完成确定某人是否拥有散列数据的未损坏副本的功能所必需的。这带来了蛮力攻击的敏感性,如今这些攻击非常强大,尤其是针对 MD5。

在具有数学知识但对密码破译知识很少的人中,这里和其他地方也存在混淆。几个密码只是简单地将数据与密钥流进行异或运算,因此您可以说密文对应于该长度的所有明文,因为您可以使用任何密钥流。

但是,这忽略了从种子产生的合理明文password比种子产生的另一个明文的可能性要大得多,Wsg5Nm^bkI4EgxUOhpAjTmTjO0F!VkWvysS6EEMsIJiTZcvsh@WI$IH$TYqiWvK!%&Ue&nk55ak%BX%9!NnG%32ftud%YkBO$U6o以至于任何声称第二种可能性的人都会被嘲笑。

同样,如果您要在两个潜在的密码password和之间做出决定Wsg5Nm^bkI4EgxUO,这并不像某些数学家让您相信的那么难。

于 2013-02-19T22:45:24.920 回答
-5

我喜欢各种不同的论点。很明显,散列值的真正价值只是为诸如密码之类的字符串提供人类不可读的占位符。它没有特定的增强安全优势。假设攻击者获得了使用散列密码访问表的权限,他/她可以:

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

在这种情况下,弱密码不能仅仅因为它们被散列而受到保护。

于 2014-09-23T21:38:55.400 回答