📑 本页目录(点开跳转)
01 · 密码学到底在保护什么
⏱ 22 分钟 | ⭐ 建立整门学科的坐标系
🎯 一句话
大多数人以为密码学 = 加密 = 「让别人看不懂」。 但「看不懂」只是四个目标里的一个,而且经常是最不重要的那个。
🧱 一、四个安全目标(必须分开谈)
| 目标 | 一句话 | 没有它会怎样 |
|---|---|---|
| 机密性 Confidentiality | 别人看不到内容 | 你的密码被中间人读走 |
| 完整性 Integrity | 内容没被改过 | 转账金额从 100 被改成 10000 |
| 认证 Authentication | 对方确实是他 | 你在和钓鱼网站聊天 |
| 不可否认 Non-repudiation | 他事后赖不掉 | 签了合同说"不是我签的" |
⚠️ 关键:加密只提供第一个
一个只加密、不做认证的系统:
Alice ──[加密的转账指令]──► Bank
▲
│ 攻击者看不懂内容 ✅ 机密性有了
│ 但他可以【翻转密文里的某几个 bit】
│ 然后金额就变了 ❌ 完整性没有
🔑 这是整个领域最重要、也最常被忽略的一句话: 加密(Encryption)不提供完整性。
很多真实事故的根因就是有人以为"我都加密了还能怎样"。 🔗 第 11 章会讲怎么把两者正确地组合起来 —— 顺序还不能弄错。
💡 一个具体的例子:为什么加密挡不住篡改
用流密码加密(第 5 章):C = M ⊕ 密钥流
攻击者知道消息格式是 "转账金额:00100"
他不知道密钥流,但他可以:
C' = C ⊕ Δ (Δ 是他构造的一串 bit)
接收方解密得到:
C' ⊕ 密钥流 = (M ⊕ 密钥流 ⊕ Δ) ⊕ 密钥流 = M ⊕ Δ ⭐
→ 攻击者【完全不需要解密】,就能对明文做可控的修改
💥 这不是理论:这类"比特翻转攻击"打穿过真实的支付系统和 cookie 认证。
🔓 二、Kerckhoffs 原则:算法必须公开
系统的安全性应当只依赖于密钥的保密,而不依赖于算法的保密。
❌ 隐蔽式安全(Security through obscurity):
"我自己设计了一套加密算法,没人知道它怎么工作,所以很安全"
✅ Kerckhoffs 原则:
算法完全公开、任人研究,安全性只来自那把密钥
为什么必须这样:
| 理由 | 说明 |
|---|---|
| 算法迟早会泄露 | 反编译、内部人员、逆向工程 —— 密钥能换,算法不能换 ⭐ |
| 公开才能被审查 | 没被全世界攻击过的算法,"没人攻破"只是"没人看过" |
| 自己设计必翻车 | 这不是谦虚。专业密码学家设计的方案也经常在几年后被攻破 |
🔑 推论,请记住:永远不要自己设计密码算法,也不要自己实现标准算法。 用经过审计的库(libsodium、OpenSSL、你的语言的标准库)。
💡 为什么"自己实现标准算法"也不行:即使算法是对的, 实现也可能泄露侧信道信息(运行时间、功耗、缓存命中)—— 见下面第四节。
🎭 三、威胁模型:你在防谁?
"安全"这个词没有绝对含义 —— 必须先说清防的是谁、他能做什么。
攻击者能力从弱到强:
COA 仅知密文 只能看到密文
⊂
KPA 已知明文 知道一些「明文-密文」对
⊂
CPA 选择明文 ⭐ 能让你加密【他挑的】任意明文
⊂
CCA 选择密文 ⭐ 还能让你解密【他挑的】密文(挑战密文除外)
💡 为什么 CPA 不是"过分"的假设
看起来"攻击者凭什么能让你加密他挑的内容"?但现实中这太常见了:
| 场景 | 攻击者怎么做到的 |
|---|---|
| 你的服务器自动加密收到的请求 | 他直接发请求 |
| HTTPS 里浏览器加密他控制的 URL 参数 | 他发个链接给你点 |
| 加密的日志系统 | 他触发一个会被记录的事件 |
| 加密的数据库字段 | 他注册一个用户名 |
🔑 所以现代方案的最低门槛就是 IND-CPA(第 8 章会精确定义)。 达不到 CPA 安全的方案,直接出局。
💡 CCA 又是什么场景
攻击者能拿到「解密结果」的场景:
· 服务器解密后,如果格式不对会返回一个错误
→ 这个错误就泄露了解密的部分信息 ⭐
→ 这就是【padding oracle 攻击】的原理
· 解密后的内容被显示在页面上
· 解密失败和成功的【响应时间不同】
💥 真实事故:padding oracle 攻击曾打穿过 ASP.NET、Ruby on Rails、 以及大量使用 CBC 模式却不做认证的系统。 攻击者只靠"服务器返回的错误信息"就能完整解密任意密文。
🕰️ 四、还有一类攻击不在这个框架里:侧信道
前面讨论的都是【攻击者只能看到输入输出】
但真实设备会【漏出别的东西】:
├─ 运行时间 ← 比较密码时提前返回 = 泄露了对了几位 ⭐
├─ 功耗曲线 ← 能看出 RSA 在算平方还是乘法
├─ 电磁辐射
├─ 缓存命中 ← 著名的 AES 缓存计时攻击
└─ 声音 ← 真的有论文用麦克风提取过密钥
最常见也最容易避免的一个:时间侧信道
# ❌ 危险:一旦有一位不同就立刻返回
def check(a, b):
if len(a) != len(b): return False
for x, y in zip(a, b):
if x != y: return False # ⭐ 提前返回 = 泄露信息
return True
# ✅ 正确:恒定时间比较,不管哪里不同都跑完
import hmac
hmac.compare_digest(a, b) # ⭐ 用标准库的
💡 为什么提前返回是致命的:攻击者反复提交猜测, 测响应时间就能一位一位地把正确值试出来 —— 从 256^32 次降到 256×32 次。
🧭 五、这一章该带走的坐标系
拿到任何一个安全方案,问自己四个问题:
① 它提供【四个目标】里的哪几个? ← 加密只给机密性
② 它假设攻击者有什么能力?(COA/CPA/CCA) ← 达不到 CPA 直接出局
③ 安全性依赖什么? ← 只能是密钥,不能是算法保密
④ 实现层面有没有侧信道? ← 用恒定时间的标准库函数
🔑 这四个问题会贯穿整套教程。 后面每讲一个方案,都可以拿它们过一遍。
🔗 和站内其他章的关系
| 你可能已经知道的 | 这里的位置 |
|---|---|
| https 的小锁 | 机密性 + 认证,第 18 章讲完整流程 |
| "密码不要明文存" | 那用的是哈希,第 9 章 |
| 区块链"不可篡改" | 完整性,靠哈希链,第 20 章 |
| 电子签名的法律效力 | 不可否认性,第 17 章 |
| 智能体教程的沙箱与注入防护 | 同一种思维:假设对手是主动且聪明的 |
✅ 检查点
- 四个安全目标分别是什么?加密提供哪几个?
- 举例说明为什么"加密了"不等于"不能被篡改"。
- Kerckhoffs 原则说了什么?为什么算法必须公开?
- 为什么"自己实现标准算法"也不安全?
- CPA 攻击模型为什么不是过分的假设?举两个现实场景。
- padding oracle 攻击属于哪个攻击模型?它靠什么信息工作?
- 为什么密码比较必须用恒定时间函数?
👀 答案
- 机密性、完整性、认证、不可否认。加密只提供机密性这一个。
- 流密码下 C = M ⊕ 密钥流,攻击者构造 C' = C ⊕ Δ,接收方解密得到 M ⊕ Δ——完全不需要解密就能对明文做可控修改(比特翻转攻击)。
- 安全性应只依赖密钥的保密,不依赖算法的保密。因为①算法迟早泄露而密钥能换算法不能换 ②公开才能被全世界审查 ③自己设计必翻车。
- 因为即使算法逻辑正确,实现可能泄露侧信道信息——运行时间、功耗、缓存命中。
- 因为现实中攻击者太容易让你加密他选的内容:服务器自动加密收到的请求、浏览器加密他控制的 URL 参数、他注册一个用户名进加密的数据库字段、触发一条会被记录的日志。
- CCA(选择密文攻击)。它靠服务器返回的错误信息(padding 对不对)作为解密预言机,只用这一位信息就能完整解密任意密文。
- 因为提前返回会泄露"前几位对了",攻击者反复提交并测响应时间,能一位一位试出正确值——把 256³² 次降到 256×32 次。
🛑 可以停在这里
⚡ 走神救援
四个安全目标:机密性(看不到)、完整性(没被改)、认证(确实是他)、不可否认(赖不掉)。⭐最重要的一句:加密只提供机密性,不提供完整性——流密码下攻击者构造 C'=C⊕Δ,接收方解出 M⊕Δ,完全不用解密就能可控篡改明文(比特翻转攻击,打穿过真实支付系统)。Kerckhoffs 原则:安全只能依赖密钥、不能依赖算法保密(密钥能换,算法不能换)→ 推论:永远不要自己设计密码算法,也不要自己实现标准算法(实现会泄露侧信道)。威胁模型 COA⊂KPA⊂CPA⊂CCA,⭐CPA 不是过分假设——服务器自动加密请求、浏览器加密你控制的URL参数、注册一个用户名,都是让对方加密你选的内容;达不到 IND-CPA 的方案直接出局。CCA 的真实形态是 padding oracle——只靠"服务器返回的错误"就能完整解密,打穿过 ASP.NET 和 Rails。侧信道不在这个框架内:时间/功耗/缓存/声音;最常见的是比较密码时提前返回,必须用
hmac.compare_digest这类恒定时间函数。坐标系四问:提供哪几个目标 / 假设攻击者什么能力 / 安全依赖什么 / 有没有侧信道。
下一节 👉 02-古典密码为什么全倒了.md