🏠 总目录📚 本教程 01 · 到底在保护什么 ← →
📑 本页目录(点开跳转)

01 · 密码学到底在保护什么

⏱ 22 分钟 | ⭐ 建立整门学科的坐标系


🎯 一句话

大多数人以为密码学 = 加密 = 「让别人看不懂」。 但「看不懂」只是四个目标里的一个,而且经常是最不重要的那个。


🧱 一、四个安全目标(必须分开谈)

目标 一句话 没有它会怎样
机密性 Confidentiality 别人看不到内容 你的密码被中间人读走
完整性 Integrity 内容没被改过 转账金额从 100 被改成 10000
认证 Authentication 对方确实是他 你在和钓鱼网站聊天
不可否认 Non-repudiation 他事后赖不掉 签了合同说"不是我签的"

⚠️ 关键:加密只提供第一个

关键信息

🔑 这是整个领域最重要、也最常被忽略的一句话: 加密(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 模式却不做认证的系统。 攻击者只靠"服务器返回的错误信息"就能完整解密任意密文。


🕰️ 四、还有一类攻击不在这个框架里:侧信道

关键信息

最常见也最容易避免的一个:时间侧信道

# ❌ 危险:一旦有一位不同就立刻返回
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

a = b"correct-token-value"
b = b"correct-token-valuX"             # 只差最后一个字节
print("朴素比较:", check(a, b))        # False —— 但它在第几位不同就返回,时间会泄露
print("恒定时间:", hmac.compare_digest(a, b))   # ⭐ 用标准库的,一样是 False

💡 为什么提前返回是致命的:攻击者反复提交猜测, 测响应时间就能一位一位地把正确值试出来 —— 从 256^32 次降到 256×32 次。


🧭 五、这一章该带走的坐标系

操作步骤

  1. 拿到任何一个安全方案,问自己四个问题:
  2. 它提供【四个目标】里的哪几个? ← 加密只给机密性
  3. 它假设攻击者有什么能力?(COA/CPA/CCA) ← 达不到 CPA 直接出局
  4. 安全性依赖什么? ← 只能是密钥,不能是算法保密
  5. 实现层面有没有侧信道? ← 用恒定时间的标准库函数

🔑 这四个问题会贯穿整套教程。 后面每讲一个方案,都可以拿它们过一遍。


🔗 和站内其他章的关系

你可能已经知道的 这里的位置
https 的小锁 机密性 + 认证,第 18 章讲完整流程
"密码不要明文存" 那用的是哈希,第 9 章
区块链"不可篡改" 完整性,靠哈希链,第 20 章
电子签名的法律效力 不可否认性,第 17 章
智能体教程的沙箱与注入防护 同一种思维:假设对手是主动且聪明的

✅ 检查点

  1. 四个安全目标分别是什么?加密提供哪几个?
  2. 举例说明为什么"加密了"不等于"不能被篡改"。
  3. Kerckhoffs 原则说了什么?为什么算法必须公开?
  4. 为什么"自己实现标准算法"也不安全?
  5. CPA 攻击模型为什么不是过分的假设?举两个现实场景。
  6. padding oracle 攻击属于哪个攻击模型?它靠什么信息工作?
  7. 为什么密码比较必须用恒定时间函数?
👀 答案
  1. 机密性、完整性、认证、不可否认。加密只提供机密性这一个。
  2. 流密码下 C = M ⊕ 密钥流,攻击者构造 C' = C ⊕ Δ,接收方解密得到 M ⊕ Δ——完全不需要解密就能对明文做可控修改(比特翻转攻击)。
  3. 安全性应只依赖密钥的保密,不依赖算法的保密。因为①算法迟早泄露而密钥能换算法不能换 ②公开才能被全世界审查 ③自己设计必翻车。
  4. 因为即使算法逻辑正确,实现可能泄露侧信道信息——运行时间、功耗、缓存命中。
  5. 因为现实中攻击者太容易让你加密他选的内容:服务器自动加密收到的请求、浏览器加密他控制的 URL 参数、他注册一个用户名进加密的数据库字段、触发一条会被记录的日志。
  6. CCA(选择密文攻击)。它靠服务器返回的错误信息(padding 对不对)作为解密预言机,只用这一位信息就能完整解密任意密文。
  7. 因为提前返回会泄露"前几位对了",攻击者反复提交并测响应时间,能一位一位试出正确值——把 256³² 次降到 256×32 次。

🛑 可以停在这里

⚡ 走神救援

先记住这几件事

下一节 👉 02-古典密码为什么全倒了.md

打卡记录保存在你的浏览器里,首页能看到总进度