加密原理(下):哈希算法、数字签名、消息认证码
上一章我们把对称加密、非对称加密家族认了个遍。但说实话,只靠加密还远远不够。
你想想看——你把文件用AES加密了,结果在传输过程中被人篡改了一个字节,接收方解密后得到的是一堆乱码。你根本不知道它被改过。所以我们需要另外三样东西:哈希算法、数字签名、消息认证码。这三兄弟才是把「防篡改」和「身份确认」补齐的关键。
一、哈希算法:数据的「指纹」
哈希算法也叫散列函数。它能把任意长度的输入,压缩成固定长度的输出。这个输出就是“哈希值”,或者说“摘要”。
我的一个口头禅:哈希是单向的。你没法从摘要反推出原文,就像你没法从一个人的指纹还原出他的脸。我踩过坑吗?有次在项目中用了MD5做备份校验,后来发现MD5已经被找到碰撞方法——两个不同文件能算出同样的MD5。太危险了。从那以后我全线换成了SHA-256。
| 算法 | 输出长度(位) | 安全性等级 | 我推荐用吗? |
|---|---|---|---|
| MD5 | 128 | 已破解(碰撞) | ❌ 别用 |
| SHA-1 | 160 | 理论脆弱 | ❌ 已废弃 |
| SHA-256 | 256 | 安全 | ✅ 首选 |
| SHA-3 | 可变 | 安全 | ✅ 可用 |
二、消息认证码(MAC):有人和你共享密钥
哈希没问题,但如果有人在传输途中同时改了原文和哈希值,接收方拿新哈希对新原文一算——咦,竟然也对得上?
所以我们需要一个钥匙。消息认证码(MAC)就是哈希 + 共享密钥。发方用原文和一个双方事先约定好的密钥,一起丢进MAC算法,产出MAC标签。收方用同样的密钥和原文重新算一遍,结果一样就说明既没被篡改,而且确实是拥有密钥的那位发的。
最常见的是HMAC(Hash-based MAC)。比如HMAC-SHA256。我个人习惯在API签名校验里用HMAC——简单、快、不需要公钥基础设施。
// 伪代码示例:HMAC计算
key = "shared_secret_123"
message = "POST /api/order data=xxx"
mac = HMAC-SHA256(key, message)
// 把mac附在请求头里
// 服务端用同样的key和message算一遍,比对
三、数字签名:签名是你的身份证
数字签名用非对称加密来对哈希值做签名。私钥签名,公钥验证。这样一来:
- 只有持有私钥的人能生成签名——身份唯一
- 任何篡改原文都会导致哈希值对不上——防篡改
- 签名者事后无法抵赖——因为私钥只有他自己有
我记得刚接触HTTPS时,一直搞不懂为什么证书需要用CA签名。后来想通:CA用自己的私钥对网站的公钥做数字签名,浏览器拿到证书后用内置的CA公钥验签,确认这个公钥确实属于该网站。整个过程就是数字签名在撑腰。
常用签名算法:RSA-PSS、ECDSA。速度上ECDSA比RSA快,而且密钥长度更短。
| 特性 | 消息认证码 (MAC) | 数字签名 |
|---|---|---|
| 密钥类型 | 对称密钥 | 非对称密钥对 |
| 抗抵赖性 | ❌ 没有 | ✅ 有 |
| 性能 | 快 | 慢(尤其签名) |
| 典型场景 | API鉴权、短消息校验 | 证书、合同、代码签名 |
四、三者如何协作?一张图看清
这几个东西到底怎么串起来的?我画了一张日常搬运的逻辑图。你看一遍就懂了。
五、避坑指南:我曾犯过的错
- 以为哈希就是加密:我初期把哈希和加密混着叫,跟甲方说“把密码加密存起来”,结果数据库里哈希的密码没法解密。后来老老实实改口说“哈希存储”。千万别搞混,哈希不可逆。
- 用了太短的哈希:有位同事为了省计算时间,坚持用MD5做文件完整性校验——被我们劝回来了。SHA-256虽然慢一丁点,但安全才是第一位的。
- 数字签名≠加密:签名是“私钥签,公钥验”,加密是“公钥加密,私钥解密”。我被刚入行者问过“签名不也能加密吗?”其实签名过程里确实涉及加密运算,但目的完全不同——签名的输出是可公开验证的凭证,不是用来隐藏原文的。