把任意数据压成一枚固定长度的指纹。它不是加密,却撑起了完整性、密码存储、数字签名和整个区块链。
对称密码解决了"锁数据",但密码学还有另一半天空,和加密毫无关系,却同样无处不在。你 App 里的文件校验、密码存储、APK 签名、Git commit id、区块链的每一个区块——底层都是同一个东西:加密哈希函数。
这是初学者最常见的混淆,先钉死它:
| 加密 | 哈希 | |
|---|---|---|
| 有密钥吗 | 有 | 没有 |
| 可逆吗 | 可以(用密钥解密) | 不可逆(单向) |
| 输出长度 | 随输入变化 | 固定(如 SHA-256 永远 256 位) |
| 目的 | 保密 | 指纹 / 完整性 |
哈希函数 H 把任意长度的输入压成固定长度的输出(叫哈希值、摘要、指纹)。它没有密钥,不可逆——你没法从指纹还原出原始数据。它的价值不在于藏住数据,而在于给数据一个几乎独一无二、且改一点就面目全非的标识。
任何函数都能把数据压短(比如"取首字节"),但那不是加密哈希。密码学级别的哈希必须扛得住攻击,具体是三条:
① 抗原像(Preimage resistance):给定哈希值 h,找不到任何输入 m 使 H(m)=h。——单向性。这是"密码存储"的地基(第 13 章)。
② 抗第二原像(Second-preimage):给定一个 m₁,找不到另一个 m₂ 使 H(m₁)=H(m₂)。——你改不了文件却保持指纹不变。
③ 抗碰撞(Collision resistance):找不到任意一对 m₁≠m₂ 使 H(m₁)=H(m₂)。——这条最难满足,也最先被攻破(第 11 章的生日攻击专治它)。
再加一条工程上的直觉性质:雪崩效应——输入改动哪怕一个比特,输出也要有大约一半的比特翻转,且翻转看起来完全随机、毫无规律。这正是第 3 章"扩散"思想在哈希里的化身,也是"指纹独一无二"的来源。
下面的 Demo 用 SHA-256 实时哈希你的输入。上面一行是原文,下面一行是"只改动一个字符"的版本;两个 256 位哈希逐比特对比,不同的位标红,并统计翻转比例。你会发现:无论改动多微小,总有接近 50% 的比特翻转——而且你完全无法从"我改了什么"预测"哪些位会翻"。
| 算法 | 输出 | 状态 | 说明 |
|---|---|---|---|
| MD5 | 128 位 | 已死 | 2004 年碰撞被找到,现在几秒就能造碰撞。仅可做非安全校验(如文件去重)。 |
| SHA-1 | 160 位 | 已死 | 2017 年 Google "SHAttered" 造出实际碰撞。已从 TLS/证书中淘汰。 |
| SHA-256 / SHA-512 | 256 / 512 位 | 主力 | SHA-2 家族,当前默认选择。区块链、TLS、签名都在用。 |
| SHA-3 (Keccak) | 可变 | 现代 | 结构与 SHA-2 完全不同(海绵结构),作为"备胎标准"。以太坊用其变体 Keccak-256(第 23 章)。 |
| BLAKE2 / BLAKE3 | 可变 | 高速 | 比 SHA-2 更快,安全性优秀,越来越流行。 |
SHA-256 属于 Merkle–Damgård 结构:把消息切成 512 位的块,维护 8 个 32 位寄存器作为"内部状态",逐块地把当前状态和消息块通过一个压缩函数搅拌(64 轮加法、位移、XOR、逻辑运算)。最后一块之前要做填充:补一个 1 位、若干 0,最后 64 位写上原始消息长度。记住"末尾写长度"这个细节——第 12 章的长度扩展攻击,钻的就是这个结构的空子。
这三条性质一旦到手,应用就像多米诺骨牌一样铺开——本书后半程几乎每一章都在用它:
哈希是单向的,但它没有密钥,任何人都能计算。所以"把手机号 SHA-256 一下再存/上传"并不能保护隐私——手机号空间很小,攻击者把所有可能的号码挨个哈希一遍(彩虹表),几秒就能反查出来。哈希保护的是完整性,不是机密性。要保密请用加密,要防猜解请加盐并用慢哈希(第 13 章)。
哈希看起来坚不可摧,但它有一条数学上无法回避的软肋——而且这条软肋比大多数人的直觉要脆弱得多。为什么一个 256 位的哈希,抗碰撞强度其实只有 128 位?答案藏在一个关于生日的古老悖论里。下一章揭晓。