哈希算法的进化:从 MD5 到 SHA-3

55 阅读 2753 字 · 约 10 分钟

密码学家设计 MD5(Message-Digest Algorithm 5,消息摘要算法第五版)的时候,觉得 128 位够长了——2¹²⁸ 种可能,暴力穷举要算到宇宙热寂。1992 年发布,全世界用上了。

这个设计,只撑了十二年。

2004 年,王小云团队在国际密码学会议上公布了 MD5 的碰撞方法。不需要 2¹²⁸ 次尝试,只需要 2⁴⁰ 次——一个普通机房跑几天就能找到。两个不同文件,同一个 MD5 值。密码学里最不该发生的事,发生了。

鸽巢原理:无限输入 → 有限输出

这次攻破不是意外,是数学上的必然。哈希函数把任意长度的输入压缩成固定长度的输出——输入有无限多种可能,输出只有有限种。鸽子比洞多,必有两只进同一个洞。区别只在于:你是算到宇宙热寂才碰上一对,还是设计上就有漏洞让人几步就找到了。

MD5 属于后者。


MD5:被一张假证书判了死刑

2008 年,一群研究者用 MD5 碰撞造了一张假的 CA 证书。CA(Certificate Authority,证书颁发机构)证书是什么?是你浏览器信任的根——你的银行网站、邮箱、网银,全凭它说「这个网站是真的」。CA 用 MD5 给证书签名,攻击者构造了两份内容不同但 MD5 值相同的证书:一份是「我是一家中等公司,给我签个名」,一份是「我有权签发任何域名」。哄着 CA 在真证书上盖了章,把签名挪到假证书上——假证书瞬间合法。

浏览器没有报警。证书链检查全部通过。攻击者能冒充任何网站,你的 HTTPS 锁定图标绿着,对面坐的是别人。

这不是理论攻击,是工程上已经能造的假证书。MD5 立刻被判死刑——TLS 证书禁用、代码签名禁用、密码存储换 bcrypt。一个用了十六年的算法,一夜之间变成「别碰」。

但 MD5 没有死透。至今还有人在用 MD5 做文件校验、做去重——「我不防恶意攻击,我只想快速校验」。这是它唯一的容身之地:不防碰撞,只防意外。


SHA-1:多活了十年,死法一样

SHA-1 是 MD5 的继任者——NSA(美国国家安全局)设计的,160 位输出,比 MD5 宽了 32 位。设计上更复杂,轮次更多,理论上更难碰撞。

哈希函数怎么工作:分块 → 压缩 → 迭代

但 SHA-1 底层的压缩结构还是老的那一套——Merkle-Damgård 结构:消息切成小块,逐块喂进压缩函数,前一轮的输出是下一轮的输入。迭代到最后一轮,吐出来的就是哈希值。这个结构本身没有漏洞,但 SHA-1 用的内部函数太窄了——160 位,在那个算力爆炸的年代,不再是安全的。

2017 年,Google 联手荷兰的研究机构发布了 SHAttered:两份内容不同的 PDF,SHA-1 值完全一样。花了 6500 年的 CPU 时间加 110 年的 GPU 时间——不是轻松算出来的,是终于有人愿意花这个钱算了。

哈希算法的进化:被攻破一次,就加长一截

这笔账单的意义不是「SHA-1 被攻破了」,是「攻击成本从不可行降到了可行」。2017 年花十几万美金就能算出来,再过五年呢?再过十年?SHA-1 的寿命是算力替你倒数的。Google 的演示不是为了炫技,是告诉整个行业:SHA-1 的迁移窗口关上之前,赶紧走。

Git 还在用 SHA-1 标识 commit。Linus Torvalds 说过「Git 用 SHA-1 不是为了安全,是为了完整性」,但 Git 社区自己也在规划迁移 SHA-256。旧系统拖得越久,升级越疼。


SHA-2:加长就是加安全

SHA-1 被攻破的逻辑很简单:160 位不够长。SHA-2 的回应也很简单:加长。

SHA-2 是一整个家族——SHA-224、SHA-256、SHA-384、SHA-512,四个成员,主要差别在输出长度。底层结构一样,还是 Merkle-Damgård——SHA-224/256 用 512 位分块、64 轮压缩,SHA-384/512 用 1024 位分块、80 轮压缩,核心思路没变。

SHA-256 输出 256 位,SHA-512 输出 512 位。找一对碰撞有多难?生日悖论给出答案:碰撞的难度只有输出位长的一半——SHA-1 要 2⁸⁰ 次尝试,SHA-256 要 2¹²⁸ 次。2¹²⁸ 是 10³⁸ 这个量级,全世界所有计算机从诞生算到今天,加起来也差得远。至于 2²⁵⁶ 的原像攻击(给定哈希值反推输入),那是 10⁷⁷ 的量级——宇宙里原子总数大约 10⁸⁰,只差三个数量级,更不用想。

加长不改变结构,但改变碰撞的门槛。 从 160 位到 256 位,不是多了 96 位,是碰撞难度乘了 2⁴⁸。算力翻倍、量子计算成熟——在可预见的未来,依然摸不到 2¹²⁸ 的边。

现在 TLS 证书、比特币、代码签名——全在 SHA-256 的地盘上。它不完美(结构上还是老的那套),但 够用。


SHA-3:不是继任者,是备胎

SHA-2 够用,为什么还要设计 SHA-3?因为「够用」的前提是整个密码学界没找到 SHA-2 的漏洞。万一找到了呢?万一明天有人发现 SHA-256 的压缩函数有结构缺陷呢?整个互联网的安全底座压在 SHA-2 上,没有备选。

美国国家标准与技术研究院(NIST)在 2007 年公开征集 SHA-3,全世界密码学家提交了 64 个候选。三轮筛选,2012 年选出冠军:Keccak——一个完全不同的底层结构:海绵函数。

Merkle-Damgård 是「分块→逐块压缩→迭代」。海绵函数是「吸收→挤压」:先把所有数据吸进海绵里(吸收阶段),再用力挤出一段固定长度的摘要(挤压阶段)。结构全换,不共享 SHA-2 的任何 DNA。这意味着:攻击 SHA-2 的技巧,对 SHA-3 不成立。

SHA-3 不是「更安全」,是「安全来源不同」。 你的系统用 SHA-256 做主哈希,用 SHA-3 做备选——万一 SHA-2 被攻破,备胎马上转正。一个网站不会因为一个哈希算法被攻破而全线崩塌。

这就是密码学校计的底线:不赌单点,每个关键环节都有独立的后路。


怎么选

MD5 被攻破了,SHA-1 被攻破。SHA-2 还站着,SHA-3 等着接班。选哈希算法不是问「哪个最先进」,是问 你的使用场景,攻击者是谁。

  • 你只做文件去重、数据校验,不防恶意——MD5 够了。快,简单,生态全认。别拿它做安全性验证(防篡改),防篡改用 SHA-256。
  • 你用的是旧系统,只认 SHA-1——能迁就迁。Git 还有时间,但 SHA-1 的迁移窗口在收窄。拖到最后一刻,挨一刀。
  • 你是新系统,做 TLS、代码签名——SHA-256,没别的。256 位是当前性价比最高的选择——安全,快,生态全认。512 位更安全但更慢,大部分场景不需要。
  • 你存密码——别用 SHA-256 直接哈希密码。密码专用算法 bcrypt、scrypt、Argon2 故意算得慢,拖慢暴力破解。SHA-256 太快了,一秒能算几百万次——密码被撞开的代价是速度差。
  • 你追求最高安全,要考虑后量子时代——SHA-3。它不是「更好」,是「不一样」。不和 SHA-2 共用一个底层,攻击不共享。

大部分人选 SHA-256,大部分场景够用。SHA-3 是备胎,存着,暂时用不上——就像 SHA-2 够用之前,SHA-3 已经在等它的位置。