解密 MD5 和 SHA:为什么你做不到






4.60/5 (7投票s)
我见过不少关于如何解密 SHA 和 MD5 以获得原始输入的问题,大多数都与“加密密码”有关,我想我应该尝试解释一下为什么答案是“你做不到”。
引言
我能理解为什么这似乎是个绝妙的主意:如果你使用 SHA 或 MD5,它们总是会生成一个固定长度的输出——128 位、256 位、512 位或 1024 位,这使得存储和传输都很容易;不像 DES 或 AES,它们会生成一个很长的字节流。所以如果你解密 SHA 或 MD5,你就能获得安全性加上惊人的压缩效果,这非常方便。那么……为什么像亚马逊或 Netflix 这样的流媒体服务不这样做呢?为什么硬盘驱动器的容量不是无限的,而是存储为 512 位的加密值呢?为什么网页不被压缩到 256 位呢?
不幸的是,事情不是这样的,本文将尝试解释原因。
什么是加密?
让我们从了解什么是加密开始。
在密码学中,加密是指将消息或信息进行编码,使其只有授权方才能访问,而未经授权者无法访问。加密本身并不能阻止干扰,但可以阻止窃听者理解其内容。在加密方案中,预期的信息或消息,称为明文,使用加密算法——一种密码——进行加密,生成只有在解密后才能读取的密文。
这意味着当你加密一条消息(无论是密码、短语、文档还是视频)时,你可以反转输出并获得原始信息。如果因为任何原因,当你解密加密数据时,你无法获得与开始时完全相同的内容,那么它就不是加密!
那么让我们试试
所以,让我们假设你可以解密 SHA 或 MD5 并获得原始输入,然后看看会发生什么。
为了在示例中简化,让我们发明一个名为 SHA-2Bit 的算法,它总是像 SHA256 一样产生一个 2 位的输出。
如果我们向 SHA-2Bit 输入 2 位值,我们会得到 2 位输出:算法内部是什么并不重要,就像 SHA256 一样——请记住,99.99% 的 SHA256 用户也不知道它是如何工作的,而且他们也根本不需要知道!
所以我们输入所有可能的两位值,并查看输出。
Input (Binary) Input (Decimal) Output (Binary) Output(Decimal)
00 0 11 3
01 1 00 0
10 2 10 2
11 3 01 1
每个输出都不同,这一点很重要:如果两个不同的输入生成相同的输出,那么我们就无法解密它,因为我们不知道我们最初使用的是哪一个输入。
这没问题:所以让我们取那些输出,看看如果我们通过在上面的输出列中查找它们来反向运行它们,我们会得到什么。
Output (Binary) Output (Decimal) Input (Binary) Input (Decimal)
11 3 00 0
00 0 01 1
10 2 10 2
01 1 11 3
所以这行得通——我们可以使用 SHA-2Bit 加密任何 2 位值,并成功解密它以获得原始输入。
Input (Binary) Encrypted (Binary) Output (Binary)
00 11 00
01 00 01
10 10 10
11 01 11
但是……如果我们输入一个三位值呢?这里我们遇到了一个问题,因为所有可能的两位输出都映射到一个单独的 2 位输入(而且它们必须是这样,否则就会出现重复,我们就无法解密它们)。那么我们能为 3 位输入输出什么 2 位值呢?我们可以看看十进制值,然后以此为基础进行处理。
Input (Binary) Input (Decimal) Output (Binary) Output (Decimal)
000 0 11 3
001 1 00 0
010 2 10 2
011 3 01 1
我想这不会有什么太大的区别(尽管在现实世界中,2 位的“3”和 3 位的“3”是有区别的)。
但是我们可以为其他三位数字生成什么值呢?
Input (Binary) Input (Decimal) Output(Binary) Output(Decimal)
000 0 11 3
001 1 00 0
010 2 10 2
011 3 01 1
100 4 ? ?
101 5 ? ?
110 6 ? ?
111 7 ? ?
我们尝试选择的任何两位值都已经被用来映射 2 位输入值,所以我们永远无法解密大于或小于 2 位的值。
所以……它不适用于 2 位输出
SHA256 也存在同样的问题:好吧,有 256 位,这给了我们 10^168(或 1 后面跟着 168 个零)个不同的值,但我们可以输入的 512 位数字的数量是它的两倍:而一个包含 33 个字符的文档已经超过了 256 位!
无论我们选择一个固定大小的输出,我们都无法将比该大小多一位、多一个字符或多一个字节的内容加密进去,因为我们绝对保证会产生重复的输出——而一个单一的重复值意味着我们无法保证在给定输出的情况下成功恢复原始输入。我们也许能得到**一些**东西,但它可能不是原始文档!
但是如果我使用加密密钥或盐:它就会起作用——对吧?
不。加密密钥是什么并不重要,因为在这个例子中我们甚至没有使用密钥——就像 SHA 和 MD5 不使用密钥一样!
这一点很重要:SHA 和 MD5 不使用密钥,因为它们不是加密算法:它们是**哈希**算法,区别在于加密可以被逆转,而哈希不行。任何生成固定大小输出的算法,其定义就是哈希,因为它会产生重复的值,而加密则不会,但为了确保这一点,它需要可变长度的输出。
盐也没用:它们用于改变原始输入,以便两个拥有相同密码的用户不会在“加密密码”表中生成相同的值。例如,为了防止所有密码为“Password”的人仅仅通过计算表中相同值的数量就可以被识别!
哈希算法的本质是丢弃信息以产生结果,就像加法一样:如果我将 2 和 7 相加,我总是得到 9——但你不能从 9 得到 2 + 7,因为 0 + 9、1+8、2+7、3+4、10+(-1)……等等都会得到相同的值。7 + 2、2+0+7……也是如此。
执行摘要
这就是为什么流媒体视频服务不只使用 SHA 来处理整个 MP4 电影,然后给你一个 256 位的视频:如果你能解密它并获得整个 1GB 的电影,相信我,它们会的!
哈希也不是压缩,因为压缩(实际上)是一种复杂的加密形式,它(非常努力地:非常非常努力地)试图生成一个比输入小得多的输出,但它依赖于实际数据及其“固有模式”来实现压缩。压缩算法唯一无法保证的是特定的输出大小,而对输入的一个看似微小的更改可能会导致输出大小发生很大的变化。
通常你会发现
- 固定大小的输出:哈希数据,无法恢复原始输入。
- 输出小于输入:压缩数据,可以恢复原始输入。
- 输出大于输入:加密数据,可以恢复原始输入。
警告!
是的,MD5 官方已经“失效”了,因为有一种方法可以逆转某些值到“可读输入”,但这只在少数情况下有效,并且不能保证恢复特定的原始输入。这并不意味着它已经变成了加密!你仍然不应该在新项目中使用它。
历史
- 2019-06-25:“SHA2”引用丢失 - 已更改为“SHA-2Bit”。非常感谢@bence98 的发现!
- 2019-06-25:已澄清 SHA-2Bit 输出到输入的“解码”。
- 2019-06-21:虚构的“SHA-2”算法更名为“SHA-2Bit”,以避免与真实的 SHA-2 算法混淆。感谢@xied75 (Dong Xie),并对造成的任何混淆表示歉意。
- 2019-06-20:由 Deeksha 整理。
- 2019-06-20:拼写错误
- 2019-06-20:原始版本