跳转至

密码学哈希

Theory

计算哈希值

我们使用 sha256sum 工具来计算给定输入的 SHA-2 256 哈希值。SHA-2 的其他变体由 sha224sumsha256sumsha384sumsha512sum 提供。

要对你随后输入到终端的文本进行哈希,请使用 sha256sum。该文本用你的终端的文本编码进行编码,然后发送给该工具。要完成输入,发出 Ctrl+D。注意,包含一个换行符(由 Enter 产生)会使输入不同。

要对一个文件进行散列,使用 sha256sum file_name

回顾 SHAttered 的碰撞攻击

碰撞攻击是指人们试图产生一个与给定数据具有相同哈希值的不同数据。

研究人员已经破解了 SHA-1。在 SHAttered 项目中使用了一种比蛮力快得多的方法来构建碰撞攻击。我们将对其结果进行研究。

使用这些命令来下载攻击结果:

wget https://shattered.io/static/shattered-1.pdf
wget https://shattered.io/static/shattered-2.pdf

然后使用这些命令来计算两个文件的 SHA-1 哈希值:

sha1sum shattered-1.pdf
sha1sum shattered-2.pdf

输出应该是:

$ sha1sum shattered-1.pdf
38762cf7f55934b34d179ae6a4c80cadccbb7f0a  shattered-1.pdf
$ sha1sum shattered-2.pdf
38762cf7f55934b34d179ae6a4c80cadccbb7f0a  shattered-2.pdf

现在,想象你信任 SHA-1 哈希值 38762cf7f55934b34d179ae6a4c80cadccbb7f0a,因为文件的作者给了你这个哈希值。然后收到了 shattered-2.pdf,计算了它的 SHA-1 哈希值;因为你认为没有人可以创建另一个具有相同的哈希值的文件,所以你信任了 shattered-2.pdf。你就可能成为了碰撞攻击的受害者。我们可以使用 SHA-2 256 哈希算法进一步验证这两个文件是不同的:

$ sha256sum shattered-1.pdf
2bb787a73e37352f92383abe7e2902936d1059ad9f1ba6daaa9c1e58ee6970d0  shattered-1.pdf
$ sha256sum shattered-2.pdf
d4488775d29bdef7993367d541064dbdda50d383f89f0aa13a6ff2e0894ba5ff  shattered-2.pdf

或者简单地使用 diff shattered-1.pdf shattered-2.pdf 来比较文件的原内容。

这就是 SHA-1 碰撞的证明。请注意,这不是用普通的暴力获得的;SHA-1 算法中的一个聪明的发现使研究人员能够设计一个快 10 万倍的攻击算法。这就是为什么 SHA-1 应该被淘汰了。

文件格式和内容修改

你可以发现 shattered-1.pdfshattered-2.pdf 都是有效的 PDF 文件,只在非常有意的位置进行了修改。这提示我们,这种攻击可以按照意图修改内容。事实上,这正是攻击的全部意义所在。

许多文件格式(包括 PDF)指定了未使用的位置。当文件被支持的程序打开时,这些位置的数据被忽略。然而,所有的数据都对哈希值有贡献。为了进行攻击,攻击者首先修改感兴趣的内容,然后用所有可能的字符串填充这些未使用的位置,以碰撞散列值。

通常情况下,有足够的组合供攻击者尝试,因为哈希值很短:SHA-1 只有 20 字节长,甚至 SHA-2 512 也只有 64 字节长。如果我们假设 SHA-2 512 从输入到输出的映射是「均匀密集的」,那么我们应该期望在所有可能的 64 字节字符串的未使用位置找到一个碰撞。如果有 65 个字节的可用空间,那么我们应该期望 256 次碰撞。这被证明是非常可行的,因为大多数文件格式有足够多的未使用的空间来进行这种修改。尽管如此,加密哈希函数的不可逆转性和混沌性将使攻击无法以可接受的速度计算出来。

模拟一次性密码生成器

流行的一次性密码(OTP)规范是基于加密哈希值。一个 OTP 程序每隔固定的时间就会产生一个不同的代码,而且只有这个代码在这段时间内有效。OTP 通常被用来提供认证的第二个因素。

让我们模拟一个 OTP 过程。

首先,服务器确定一个秘密并将其显示给用户。让我们使用秘密 He110!(UTF-8 字符串)作为我们的例子。

然后,假设客户端和服务器都同步了他们的时钟,他们计算出从 1970 年 1 月 1 日(格林尼治标准时间)半夜 12:00 开始,已经过去了多少个 30 秒。在我们的例子中,让我们使用 54646121 这个值。

然后,我们将这两块数据结合起来,进行哈希运算。如果我们简单地将这两个字符串连接成 He110!54646121 并使用 sha256sum,那么我们得到的哈希值是 c927ef15ac1d090bac6c3a9860242ddf2170b53aedaaac8f78c7e71cd3c6d11c。我们进一步将其减少到前 3 个字节 c927ef,这样就很容易在 30 秒内输入。(这也使得几乎不可能用暴力破解该秘密。)

30 秒后,两端将各自生成一个新的哈希值,使用共享的秘密和新的时间编号。只要服务器和客户端的时钟同步,他们将继续生成相同的哈希值。如果像「c927ef」这样的 OTP 被泄露,不知道秘密的攻击者就不能继续产生与服务器相同的哈希值。因此,保护 OTP 的秘密是很重要的,这就是为什么 OTP 工具总是隐藏它们。