哈希不是加密

工具相关 ·

在技术交流里,「把这段文字加密成 SHA-256」是一个出现频率很高的说法,但它从根上是错的。SHA-256 不是加密算法,也无法解密。这个说法之所以顽固,是因为它背后的混淆会导致实际的设计错误——有人真的把哈希当成加密来用,结果做出无法还原的数据存储方案。

加密是可逆的,哈希是不可逆的

加密的本质是一次可逆的变换:用密钥把明文变成密文,再用密钥把密文变回明文。它的前提是存在一个逆运算,而且只有持有密钥的人才能执行这个逆运算。AES、DES、SM4 都属于这一类,它们的共同点是都需要密钥,而且都能解密。

哈希的本质是一次单向压缩:把任意长度的输入映射成固定长度的输出。它是不可逆的——不是「很难」,而是设计上就没有保留还原所需的信息。哈希函数会把大量不同的输入映射到同一个输出(这就是碰撞的由来),所以从输出反推输入在信息论层面就是不可能的。

两个概念对应两种完全不同的用途。加密用于保护数据的机密性*,让不该看到的人看不到;哈希用于校验数据的*完整性,确认内容有没有被改动。

一个具体的对比

用同一个字符串 hello 分别做加密和哈希,差别立刻显现。

用 AES 加密,需要指定密钥和模式,得到一段密文。拿同样的密钥和模式解密,能还原出 hello。换一个密钥,密文完全不同。

用 SHA-256 哈希,得到 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824。这个结果没有任何办法还原回 hello,也没有密钥可以用。但对任何输入 hello 的人,算出的结果都是这一串。

这个固定性正是哈希的用途所在:如果两段数据的哈希相同,就可以认定它们内容一致。

「MD5 解密」网站做的是什么

既然哈希不可逆,那些声称能解密 MD5 的网站又是怎么回事?

它们的做法是预先计算并存储。后台维护一张巨大的对照表,记录常见口令和它们的哈希值。用户提交一个哈希值,网站去表里查,查到就返回对应的原文,查不到就显示「未收录」。

所以它们做的不是解密,是查表。对于常见弱口令(123456、password、admin 这类),命中率很高;对于随机的长口令,基本查不到。

这也解释了为什么加盐能有效对抗这种攻击:盐改变了输入,导致预先算好的表对不上号。但如前面所说,盐挡不住针对单个账号的暴力尝试,因为攻击者可以现场计算。

哈希的三种正确用法

第一是完整性校验。计算文件的哈希值,传输后重新计算并比对,确认内容没有被改动。这是哈希最传统的用途。

第二是内容寻址。用内容的哈希作为标识,天然实现去重,同时保证「同样的标识对应同样的内容」。Git 的对象存储、容器镜像的分层、内容分发网络的缓存键都属于这一类。

第三是消息认证。把哈希和密钥结合起来,形成 HMAC,用来确认消息来源。前面说过,裸哈希不能当签名用,因为它没有身份信息。

口令存储是个例外情况

有人会问:既然哈希不可逆,那用哈希存密码不是正合适吗?

方向是对的,但算法选错了。口令存储需要的不是「不可逆」,而是「每次验证都很贵」。MD5、SHA-1、SHA-256 这些通用哈希都太快,攻击者每秒能尝试数十亿次,弱口令很快就被穷举出来。

所以口令存储必须使用专门设计的慢哈希:Bcrypt、Argon2、PBKDF2。它们同样不可逆,但通过可调的代价参数把单次计算变得昂贵,从而把暴力破解的成本抬到不可接受的水平。

这是一个典型的例子:同样是「用哈希」,不同场景对哈希的要求完全不同,选错算法就会留下漏洞。

检查清单

  • 加密可逆、需要密钥;哈希不可逆、没有密钥,两者用途不同
  • 「SHA-256 加密」是错误说法,正确表述是「SHA-256 哈希」或「摘要」
  • 声称能解密 MD5 的网站是查预计算表,不是数学还原
  • 哈希的典型用途是完整性校验、内容寻址、消息认证
  • 口令存储要用慢哈希,通用哈希太快,不适合这个场景
  • 判断一个算法是否适用,先想清楚要解决的是机密性、完整性还是认证问题
阅读 11