密码学在解决什么问题
1. 为什么要关心这个问题?
一个开发者用 AES 加密用户密码。另一个用 MD5 签名 API 请求。第三个用 RSA 加密几个 GB 的视频文件。
三个都是错的。
不是因为这些算法有问题,而是因为他们用错了工具。就像用锤子锯木头——锤子没问题,你只是用错了方式。
密码学不是一个单一的东西。它是一个工具箱,每个工具解决特定的问题。在需要哈希的地方用加密,或者在需要签名的地方用哈希,你的「安全」系统就变成了一个隐患。
2. 定义
密码学 是通过数学技术保护信息的科学。它为恰好四个基本安全问题提供解决方案:
- 机密性: 保守秘密
- 完整性: 检测未经授权的修改
- 认证: 验证身份
- 不可否认性: 防止否认行为
每个问题需要不同的工具。没有单一算法能解决全部四个问题。
3. 密码学安全的四大支柱
机密性:「只有预期的接收者能读取」
问题: 你想发送一条只有 Alice 能读取的消息,即使 Eve 截获了它。
解决方案: 加密
- 对称加密(AES、ChaCha20)
- 非对称加密(RSA、ECIES)
它不解决什么:
- 消息是否被篡改
- 发送者是否是他们声称的那个人
- 发送者是否能否认发送过它
# 机密性:AES 加密
ciphertext = aes_encrypt(plaintext, key)
# Eve 截获了密文但无法读取
# 但是:Eve 可以在不被检测的情况下修改密文!完整性:「这条消息没有被篡改」
问题: 你收到一条消息,需要验证它在传输过程中没有被修改。
解决方案: 哈希函数和 MAC
- 哈希函数(SHA-256、SHA-3)
- 消息认证码(HMAC)
它不解决什么:
- 保持消息内容的机密性
- 证明是谁发送的消息(对于没有密钥的哈希)
# 完整性:哈希验证
original_hash = sha256(message)
# 稍后...
if sha256(received_message) != original_hash:
raise TamperedMessageError()
# 但是:任何人都可以计算哈希——这不能证明是谁发送的!认证:「这条消息来自它声称的发送者」
问题: 你收到一条声称来自 Alice 的消息。你如何验证它真的来自她?
解决方案: 数字签名和 MAC
- 数字签名(RSA-PSS、ECDSA、EdDSA)
- HMAC(使用共享密钥)
区别:
- HMAC: 双方共享一个密钥。你知道它来自知道密钥的人。
- 数字签名: 只有私钥持有者能签名。你可以用公钥验证。
# 认证:数字签名
signature = sign(message, alice_private_key)
# 任何人都可以验证
is_authentic = verify(message, signature, alice_public_key)不可否认性:「发送者不能否认发送过这个」
问题: Alice 发给你一份合同。后来,她声称她从未发送过。你如何证明她发送过?
解决方案: 数字签名(仅限非对称!)
为什么 HMAC 不行: 使用 HMAC 时,双方共享同一个密钥。如果 Alice 有密钥,你也有密钥——你们任何一方都可能创建了这条消息。Alice 可以声称是你写的。
为什么数字签名可以: 只有 Alice 的私钥能创建有效的签名。如果签名用她的公钥验证通过,它一定来自她的私钥。她无法否认。
# 不可否认性:只有非对称签名提供这个
signature = sign(contract, alice_private_key)
# Alice 不能声称她没签——只有她的私钥能创建这个签名4. 算法-问题矩阵
| 问题 | 哈希 | HMAC | 对称加密 | 非对称加密 | 数字签名 |
|---|---|---|---|---|---|
| 机密性 | ❌ | ❌ | ✅ | ✅ | ❌ |
| 完整性 | ✅* | ✅ | ❌ | ❌ | ✅ |
| 认证 | ❌ | ✅ | ❌ | ❌ | ✅ |
| 不可否认性 | ❌ | ❌ | ❌ | ❌ | ✅ |
*哈希仅在你有原始哈希的可信副本时提供完整性验证。
5. 误用导致的常见灾难
灾难 1:加密密码
# 错误:用加密存储密码
encrypted_password = aes_encrypt(password, key)
database.store(encrypted_password)
# 问题:如果密钥被盗,所有密码立即暴露
# 另外:你为什么需要解密密码?正确做法: 用 bcrypt/argon2 哈希密码。你永远不需要恢复原始密码——你只需要验证。
灾难 2:用哈希实现机密性
# 错误:用哈希当"加密"
"secure_data" = sha256(sensitive_data)
# 问题:哈希是单向的,但是确定性的
# 相同输入 = 相同输出 = 可能进行模式分析
# 而且你永远无法恢复原始数据正确做法: 如果需要恢复数据,使用真正的加密。
灾难 3:用 HMAC 实现不可否认性
# 错误:用 HMAC 签合同
mac = hmac(contract, shared_secret)
# 问题:双方都有密钥
# Alice:"我没签这个——Bob 也有同样的密钥,他可能写的"正确做法: 对任何需要不可否认性的东西使用数字签名。
灾难 4:用 RSA 加密大数据
# 错误:用 RSA 加密大文件
encrypted_video = rsa_encrypt(video_file, public_key) # 极其慢!
# 问题:RSA 比 AES 慢约 1000 倍
# 另外:RSA 有消息大小限制正确做法: 使用混合加密——用 AES 加密数据,用 RSA 加密 AES 密钥。
6. 真实系统如何组合工具
现实世界的安全需要多个密码学原语协同工作。
HTTPS/TLS 握手
┌─────────────────────────────────────────────────────────┐
│ 1. 密钥交换(机密性 + 认证) │
│ - ECDHE 实现前向保密 │
│ - 服务器证书(RSA/ECDSA 签名) │
├─────────────────────────────────────────────────────────┤
│ 2. 数据传输(机密性 + 完整性) │
│ - AES-GCM 加密 │
│ - 内置认证标签(完整性) │
└─────────────────────────────────────────────────────────┘JWT(JSON Web Token)
┌─────────────────────────────────────────────────────────┐
│ Header.Payload.Signature │
├─────────────────────────────────────────────────────────┤
│ 签名提供: │
│ - 完整性:令牌不能被修改 │
│ - 认证:服务器可以验证发行者 │
├─────────────────────────────────────────────────────────┤
│ 签名不提供: │
│ - 机密性:Payload 是 Base64,不是加密的! │
└─────────────────────────────────────────────────────────┘7. 决策框架
选择密码学工具时,问:
你需要恢复原始数据吗?
├─ 否 → 考虑哈希
│ └─ 是密码吗?→ 使用 bcrypt/argon2
│ └─ 是用于完整性验证?→ 使用 SHA-256/SHA-3
│
├─ 是 → 你需要加密
│ └─ 谁持有密钥?
│ ├─ 同一方加密/解密 → 对称(AES)
│ └─ 不同方 → 非对称或混合
│
你需要证明是谁发送的吗?
├─ 可以接受共享密钥?→ HMAC
└─ 需要不可否认性?→ 数字签名8. 本章小结
三点要记住:
一个算法,一个问题。 加密提供机密性。哈希提供完整性。签名提供认证和不可否认性。不要混淆它们。
不可否认性需要非对称密码学。 如果双方共享密钥,都无法证明对方发送了消息。只有数字签名提供不可否认性。
真实系统组合多个原语。 HTTPS 同时使用密钥交换、加密和认证。理解哪个工具做什么,有助于你理解协议为什么这样设计。
9. 下一步
现在我们理解了密码学解决的四个问题。但我们多次提到「对称」和「非对称」加密却没有解释区别。
在下一篇文章中,我们将探讨:为什么我们需要两种完全不同类型的加密?它们的权衡是什么,真实系统如何组合使用它们?
