mobile wallpaper 1mobile wallpaper 2mobile wallpaper 3mobile wallpaper 4mobile wallpaper 5mobile wallpaper 6mobile wallpaper 7mobile wallpaper 8mobile wallpaper 9mobile wallpaper 10mobile wallpaper 11mobile wallpaper 12mobile wallpaper 13
6383 字
21 分鐘
密码学基础与应用
2026-04-27

第 4 章 密码学基础与应用#

4.1 学习目标#

  1. 理解对称 / 非对称加密、哈希、MAC、数字签名的作用边界与组合原则。
  2. 掌握主流算法(AES、ChaCha20、RSA、ECC、SHA-2/3、HMAC、Ed25519、Argon2)的使用场景与工程参数选择。
  3. 理解背后的数学:模算术、离散对数、椭圆曲线、格密码。
  4. 能复现并防御常见误用:ECB、GCM nonce reuse、Padding Oracle、低 e、共模攻击、长度扩展、时序攻击。
  5. 了解后量子密码(PQC)发展方向及 NIST 最新选型(ML-KEM、ML-DSA、SLH-DSA)。
  6. 会用 Python 手动实现 RSA / DH / HMAC / AES-GCM 以理解底层细节。

能力矩阵

能力域入门进阶精通
使用库AES-GCM 加密一段字符串正确 KDF + AEAD + 证书锁定设计跨语言/跨平台密码协议
分析题CTF 基本 RSA侧信道 / padding oracle实现自己的 Wycheproof 测试
协议阅读TLS 1.3 大致流程HKDF 推导链解读 Signal / Noise Protocol 规范

4.2 数论先修知识#

4.2.1 模算术基本定理#

  • 模运算:( a \equiv b \pmod n \Longleftrightarrow n \mid (a-b) )
  • 乘法逆元:若 ( \gcd(a,n)=1 ),存在唯一 ( a^{-1} ) 使 ( a \cdot a^{-1} \equiv 1 \pmod n )
  • 欧拉函数 ( \varphi(n) ):与 ( n ) 互素的正整数个数;( n=p q ) 则 ( \varphi(n) = (p-1)(q-1) )

4.2.2 费马小定理与欧拉定理#

  • 费马小定理:若 ( p ) 素、( \gcd(a,p)=1 ),则 ( a^{p-1} \equiv 1 \pmod p )
  • 欧拉定理:若 ( \gcd(a,n)=1 ),则 ( a^{\varphi(n)} \equiv 1 \pmod n )

RSA 正确性证明(核心一步):

[ m^{ed} \equiv m^{k\varphi(n)+1} \equiv (m^{\varphi(n)})^k \cdot m \equiv 1^k \cdot m \equiv m \pmod n ]

4.2.3 扩展欧几里得算法#

def ext_gcd(a, b):
if b == 0:
return a, 1, 0
g, x, y = ext_gcd(b, a % b)
return g, y, x - (a // b) * y
def modinv(a, n):
g, x, _ = ext_gcd(a % n, n)
if g != 1:
raise ValueError("not invertible")
return x % n

时间复杂度 ( O(\log \min(a,b)) )。

4.2.4 中国剩余定理 (CRT)#

若 ( n_1, \dots, n_k ) 两两互素,( N = \prod n_i ),则方程组

[ \begin{cases} x \equiv a_1 \pmod{n_1} \ \vdots \ x \equiv a_k \pmod{n_k} \end{cases} ]

在 ( \mathbb{Z}_N ) 下有唯一解:

[ x \equiv \sum_{i=1}^k a_i \cdot M_i \cdot M_i^{-1} \pmod N, \quad M_i = N / n_i ]

工程应用:RSA-CRT 优化——分别在 ( \pmod p ) 和 ( \pmod q ) 下计算,总耗时约为一次 ( \pmod{pq} ) 计算的 1/4

4.2.5 离散对数问题 (DLP)#

给定素数 ( p )、生成元 ( g )、( h = g^x \bmod p ),求 ( x ) 为 DLP。当前最好算法:

  • 通用:Pollard Rho ( O(\sqrt{q}) )(( q ) 为群阶)
  • 对素域:GNFS 子指数时间
  • 对 ECC:已知最快 Pollard Rho,仍为 ( O(\sqrt{q}) ) → 256-bit ECC ≈ 3072-bit RSA 安全

4.3 密码学三大支柱#

┌──── 对称加密 ───── 机密性(快,密钥共享难)
│ AES / ChaCha20 / SM4
密码学 ──── 非对称加密 ── 密钥交换 / 签名
│ RSA / ECC / Ed25519
└──── 哈希函数 ───── 完整性 / 指纹
SHA-256 / SHA-3 / BLAKE2 / SM3

组合原则

  • 想要 机密性 + 完整性:使用 AEAD(AES-GCM、ChaCha20-Poly1305)
  • 想要 密钥交换 + 机密性:ECDHE + AEAD(TLS 1.3 架构)
  • 想要 身份 + 抗否认:数字签名(Ed25519 / ECDSA)

4.4 对称加密#

4.4.1 分组密码 vs 流密码#

类型代表特点
分组密码AES-128/192/256、SM4固定块长(128 bit)
流密码ChaCha20、Salsa20、RC4(已废)生成密钥流 XOR

4.4.2 AES 算法内部结构#

AES-128 共 10 轮,每轮 4 个步骤:

State = 4×4 byte 矩阵
10 × (SubBytes → ShiftRows → MixColumns → AddRoundKey)
│ (最后一轮无 MixColumns)
Ciphertext

SubBytes(S-Box 替换)#

对状态每字节 ( a ),查 S-Box:首先求其在 GF(( 2^8 )) 上的乘法逆(用不可约多项式 ( x^8+x^4+x^3+x+1 )),再做仿射变换:

[ b_i = a_i \oplus a_{(i+4)\bmod 8} \oplus a_{(i+5)\bmod 8} \oplus a_{(i+6)\bmod 8} \oplus a_{(i+7)\bmod 8} \oplus c_i ]

其中 ( c = 0x63 )。

ShiftRows#

第 0 行不动,第 1/2/3 行左移 1/2/3 字节。

MixColumns#

每列被视作 GF(( 2^8 )) 上的 4 维向量,乘以矩阵:

[ \begin{pmatrix} 2 & 3 & 1 & 1 \ 1 & 2 & 3 & 1 \ 1 & 1 & 2 & 3 \ 3 & 1 & 1 & 2 \end{pmatrix} ]

乘法在 GF(( 2^8 )) 上进行(模 ( x^8+x^4+x^3+x+1 ))。

AddRoundKey#

状态与当前轮密钥按字节异或。

Key Schedule#

从 128-bit 主密钥生成 11 个 128-bit 轮密钥。每 4 个 word 生成一个新的 word,用到 RotWord、SubWord(S-Box)和 Rcon 常数。

4.4.3 工作模式深度#

模式描述安全性
ECB每块独立加密不安全,明显 pattern(企鹅图实验)
CBC上一块密文 XOR 下一块明文需要 IV;Padding Oracle 风险
CTR计数器 + 密钥流并行,IV 不能重用
GCMCTR + GHASH 认证推荐,AEAD
CCMCBC-MAC + CTR轻量,常用于 WiFi WPA2
XTS磁盘加密专用BitLocker、LUKS
OCB单 pass AEAD专利到期后可用,高性能
SIV抗 nonce reuse密钥派生+随机数兼容

4.4.4 GCM 深入#

GCM(K, IV, P, A):
J0 ← IV || 0^31 || 1 (12-byte IV 常见场景)
C ← CTR_K(J0+1, P) (counter 从 J0+1 开始)
H ← AES_K(0^128)
T ← GHASH_H(A || 0* || C || 0* || len(A) || len(C)) ⊕ AES_K(J0)
返回 (C, T)

其中 GHASH_H(X) 在 GF(( 2^{128} )) 上是:

[ Y_i = (Y_{i-1} \oplus X_i) \cdot H \pmod{x^{128}+x^7+x^2+x+1} ]

致命误用同一密钥下重复使用相同 nonce,两段密文 C1 ⊕ C2 = P1 ⊕ P2,同时可恢复认证密钥 H(Forbidden Attack,Joux 2006)。工程补偿:使用 SIV / nonce-random-128bit 或定期轮换密钥。

4.4.5 常见误用全谱#

  • ECB 加密头像 → 泄露结构
  • CBC + 固定 IV → 相同明文 = 相同密文
  • GCM 重用 nonce → 灾难级
  • Padding Oracle(POODLE、Lucky13)→ 逐字节解密
  • MAC-then-Encrypt(SSL 历史)→ 应改为 Encrypt-then-MAC 或 AEAD

4.4.6 Python AEAD 示例#

from cryptography.hazmat.primitives.ciphers.aead import AESGCM, ChaCha20Poly1305
import os
# AES-GCM
key = AESGCM.generate_key(bit_length=256)
aesgcm = AESGCM(key)
nonce = os.urandom(12)
ct = aesgcm.encrypt(nonce, b"plain", b"aad")
pt = aesgcm.decrypt(nonce, ct, b"aad")
# ChaCha20-Poly1305(无 AES-NI 时推荐)
key2 = ChaCha20Poly1305.generate_key()
chacha = ChaCha20Poly1305(key2)
nonce2 = os.urandom(12)
ct2 = chacha.encrypt(nonce2, b"plain", b"aad")
pt2 = chacha.decrypt(nonce2, ct2, b"aad")

4.4.7 Padding Oracle 攻击演示#

CBC 解密:( P_i = D_K(C_i) \oplus C_{i-1} )。若服务端对 padding 错误返回不同响应,攻击者逐字节改 C_{i-1} 直至最后一字节 padding 正确(0x01)→ 恢复 D_K(C_i) 最后一字节 → 逐位推完整 block。

def padding_oracle_decrypt_block(iv, block, oracle):
intermediate = bytearray(16)
for pad in range(1, 17):
for guess in range(256):
mod_iv = bytearray(16)
for k in range(pad - 1):
mod_iv[16 - 1 - k] = intermediate[16 - 1 - k] ^ pad
mod_iv[16 - pad] = guess
if oracle(bytes(mod_iv), block):
if pad == 1 and guess == iv[15]:
continue
intermediate[16 - pad] = guess ^ pad
break
return bytes(a ^ b for a, b in zip(intermediate, iv))

4.5 非对称加密#

4.5.1 RSA 加解密推导#

  • 选素数 ( p, q ),( n = pq )
  • 选 ( e ) 与 ( \varphi(n) = (p-1)(q-1) ) 互素(常取 65537)
  • ( d = e^{-1} \mod \varphi(n) )
  • 加密:( c = m^e \bmod n )
  • 解密:( m = c^d \bmod n )

密钥长度推荐:当前 ( n \geq 3072 \text{ bit} )(NIST SP 800-57,等效 128-bit 安全);2030 年后建议 4096-bit。

4.5.2 RSA-OAEP 填充#

直接 RSA 是确定性的(相同明文→相同密文,易被选择密文攻击),工程上须使用 OAEP:

seed (k0 bit 随机)
maskedDB = DB ⊕ MGF(seed, k - k0)
maskedSeed = seed ⊕ MGF(maskedDB, k0)
EM = 0x00 || maskedSeed || maskedDB
m_int = OS2IP(EM)
c = m_int^e mod n

其中 MGF 基于 SHA 构造。OAEP 提供 IND-CCA2 安全

4.5.3 RSA 经典攻击#

攻击条件
低 e 低 me=3 且 m < n^{1/3},直接开 3 次方
广播攻击同一 m 被 3 个不同 n 加密(e=3)→ CRT 合并 → 开方
共模攻击同一 m 用相同 n 但不同 e₁,e₂ 加密;若 gcd(e₁,e₂)=1 可恢复
Wienerd < n^{1/4}/3 时通过连分数恢复 d
Boneh-Durfeed < n^{0.292} 时格攻击
Coppersmith已知 p 的高 N/4 比特,可多项式恢复
Bleichenbacher 1998PKCS#1 v1.5 填充 oracle → 选择密文攻击
ROBOT (CVE-2017-6168)Bleichenbacher 变体,现代 TLS

4.5.4 手写 RSA(教学用途)#

import secrets
from sympy import isprime, nextprime
def gen_prime(bits):
while True:
n = secrets.randbits(bits) | (1 << (bits - 1)) | 1
if isprime(n):
return n
def gen_rsa(bits=2048):
p = gen_prime(bits // 2)
q = gen_prime(bits // 2)
n = p * q
phi = (p - 1) * (q - 1)
e = 65537
d = pow(e, -1, phi)
return (n, e), (n, d)
pub, priv = gen_rsa(2048)
m = int.from_bytes(b"hello", 'big')
c = pow(m, pub[1], pub[0])
m2 = pow(c, priv[1], priv[0])
print(m2.to_bytes(5, 'big'))

4.5.5 椭圆曲线密码(ECC)#

曲线方程(Weierstrass 形式):

[ y^2 = x^3 + ax + b \quad \text{over } \mathbb{F}_p ]

曲线上的点与”无穷远点” ( \mathcal{O} ) 构成 Abel 群。

点加运算(( P \neq Q ))#

[ \lambda = (y_Q - y_P) / (x_Q - x_P), \quad x_R = \lambda^2 - x_P - x_Q, \quad y_R = \lambda(x_P - x_R) - y_P ]

倍点(( P = Q ))#

[ \lambda = (3 x_P^2 + a) / (2 y_P), \quad \text{再用上式} ]

标量乘 ( kP )(Double-and-Add)#

def point_mul(k, P, curve):
R = None # 表示无穷远
Q = P
while k > 0:
if k & 1:
R = point_add(R, Q, curve)
Q = point_double(Q, curve)
k >>= 1
return R

常用曲线:

曲线说明
secp256k1比特币
secp256r1 (P-256)NIST 推荐
Curve25519 / Ed25519DJB 设计,抗侧信道,TLS 1.3
BLS12-381zk-SNARK / 聚合签名

4.5.6 Diffie-Hellman / ECDH#

公共参数:大素数 p、生成元 g
Alice: a 随机, A = g^a mod p
Bob: b 随机, B = g^b mod p
Alice 收到 B → 计算 K = B^a mod p
Bob 收到 A → 计算 K = A^b mod p

中间人攻击(MitM):需要认证 → TLS 证书、SSH 指纹、QR 码比较。

前向安全:一次性临时密钥(DHE / ECDHE)→ 私钥泄露也不能解过去的流量。

Logjam 回顾:512-bit DH 可被数域筛预计算攻破;2015 后浏览器强制 ≥ 1024,2020 后强制 ≥ 2048,TLS 1.3 禁用 DH < 2048 并推荐 ECDHE。

4.5.7 手写 DH#

import secrets
p = int("0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1..."[:770], 16) # RFC 3526 2048-bit
g = 2
a = secrets.randbelow(p - 2) + 2
A = pow(g, a, p)
b = secrets.randbelow(p - 2) + 2
B = pow(g, b, p)
K_A = pow(B, a, p)
K_B = pow(A, b, p)
assert K_A == K_B

4.5.8 数字签名算法#

算法基础特点
RSA-PKCS#1 v1.5RSA不可变填充,谨慎使用
RSA-PSSRSA推荐,概率性填充
DSA素域 DLPFIPS 186
ECDSAECC DLP短签名,TLS 常用
Ed25519EdDSA on Curve25519确定性、抗侧信道
SM2ECC over Fp中国国密
Dilithium (ML-DSA)格 Module-LWE后量子
FALCONNTRU 格紧凑签名
SLH-DSA (SPHINCS+)哈希无需数学假设

4.5.9 ECDSA 随机数事故#

ECDSA:对消息 ( m ) 签名

[ s = k^{-1} (H(m) + r \cdot d) \bmod n, \quad r = (kG).x ]

若 ( k ) 被重用两次(不同消息 ( m_1 \neq m_2 )),则:

[ d = \frac{s_1 H(m_2) - s_2 H(m_1)}{r(s_2 - s_1)} \bmod n ]

真实事故

  • Sony PS3:固件签名 k 恒为常数 → 私钥被 fail0verflow 泄露
  • Android Wallet 2013SecureRandom bug → 大量比特币被窃
  • TinyBTC 等 IoT 设备的熵源不足

防御:Ed25519 / 确定性 ECDSA(RFC 6979)。


4.6 哈希函数#

4.6.1 安全性质#

  • 抗原像:给定 h(x),难以找 x
  • 抗第二原像:给定 x,难以找 x’ 使 h(x’)=h(x)
  • 抗碰撞:难以找两个 x ≠ y 使 h(x)=h(y)(生日界 ( 2^{n/2} ))

4.6.2 主流算法#

算法输出状态
MD5128 bit碰撞已破(10 秒内)
SHA-1160 bit碰撞已破(SHAttered, 2017)
SHA-256 / 512256 / 512 bit推荐,Merkle-Damgård 结构
SHA-3(Keccak)可变推荐,海绵结构
BLAKE2 / BLAKE3可变高性能、树并行
SM3256 bit国密

4.6.3 Merkle-Damgård 构造#

Message → Padding → 分块 M_1, M_2, ..., M_t
IV → f(IV, M_1) = H_1 → f(H_1, M_2) = H_2 → ... → H_t
附加长度 → Final Hash

其中压缩函数 ( f: {0,1}^n \times {0,1}^b \to {0,1}^n ) 是核心。

长度扩展攻击:给定 H(secret || m)len(secret),可计算 H(secret || m || pad || m2) 而无需 secret。受影响:MD5、SHA-1、SHA-2。不受影响:SHA-3、BLAKE2、HMAC。

4.6.4 Sponge 构造(SHA-3)#

absorb 阶段:
S = 0
for block in M:
S[0:r] ^= block
S = Keccak-f(S)
squeeze 阶段:
out = S[0:r]
while 需要更多:
S = Keccak-f(S)
out += S[0:r]

抗长度扩展(因 capacity c 部分不向外暴露)。

4.6.5 HMAC#

[ \text{HMAC}(K, m) = H\big( (K’ \oplus \text{opad}) ,|, H((K’ \oplus \text{ipad}) ,|, m) \big) ]

其中 ( K’ ) 是密钥的规整化(过长则先 hash 再 pad)。抗长度扩展、抗某些 H 内部弱点。

4.6.6 口令哈希(慢哈希)#

bcrypt / scrypt / Argon2 ← 推荐(加盐 + 迭代 + 内存硬)
PBKDF2-HMAC-SHA256 ← FIPS 合规但易被 GPU 加速
MD5 / SHA1 / SHA256 ← 裸 hash 用于口令 = 错误

推荐:Argon2id(password, salt, m=64MB, t=3, p=4);bcrypt cost≥12;scrypt N=2^17

为何内存硬:GPU 擅长 SIMD 但内存带宽相对有限;Argon2 要求大块内存访问,使攻击者无法利用成千上万 GPU 线程。


4.7 MAC 与数字签名对照#

机制密钥提供不可否认
MAC(HMAC)对称完整性 + 源认证
数字签名(RSA/ECDSA)非对称完整性 + 源认证

4.7.1 时序攻击#

# 不安全
if mac_received == hmac(key, msg):
...

比较字符串的 == 一旦遇到不匹配字节立即返回,攻击者可通过耗时差距逐字节猜 MAC。

修复hmac.compare_digest(常量时间)。

import hmac as _hmac
if _hmac.compare_digest(mac_received, _hmac.new(key, msg, "sha256").digest()):
...

4.7.2 HMAC 抗攻击非形式化证明#

假设底层哈希 H 是 PRF(或接近);HMAC 的两次嵌套(inner + outer)等价于 NMAC,而 NMAC 在压缩函数为 PRF 的情况下是可证明安全的 MAC(Bellare, 1996)。


4.8 PKI、证书与现代协议组合#

4.8.1 证书链#

根 CA (离线) ──签发──▶ 中间 CA ──签发──▶ 服务器证书
浏览器/OS 信任根 CA
  • X.509 证书字段:Subject、Issuer、Public Key、SAN、Extensions
  • 吊销:CRL(列表)/ OCSP(在线查询)/ OCSP Stapling
  • CAA DNS 记录:限制哪家 CA 可签发本域证书
  • CT(Certificate Transparency):强制公开所有证书

4.8.2 Signal 端到端加密#

身份密钥 IK + 签名预共享密钥 SPK + 一次性预共享密钥 OPK
→ X3DH 协商根密钥
→ Double Ratchet 每条消息演进
→ 前向安全 + 后向安全
  • X3DH:Alice 用 Bob 的 IK/SPK/OPK 做 4 次 DH → 合并为共享密钥
  • Double Ratchet:DH Ratchet(每次换公钥)+ Chain Key Ratchet(KDF 链,每条消息推进)

4.8.3 TLS 1.3 密码套件#

TLS_AES_128_GCM_SHA256
TLS_AES_256_GCM_SHA384
TLS_CHACHA20_POLY1305_SHA256
TLS_AES_128_CCM_SHA256 (嵌入式)

注意此时套件只表示 对称算法 + 哈希,不再涵盖密钥交换(交换算法写在 supported_groups 扩展里)。

4.8.4 JWT 常见坑#

  • alg: none 绕过(服务端未校验 alg)
  • RS256 → HS256 混淆(服务端接受两种算法;攻击者用公钥当 HMAC 密钥)
  • kid 注入(SQL / 路径遍历)
  • jku / x5u 外连攻击者 JWKS
  • 弱 secret(secret123456)被 hashcat 秒破

4.8.5 HKDF 手写#

import hashlib, hmac
def hkdf_extract(salt: bytes, ikm: bytes, hash_name='sha256') -> bytes:
if salt is None:
salt = b'\x00' * hashlib.new(hash_name).digest_size
return hmac.new(salt, ikm, hash_name).digest()
def hkdf_expand(prk: bytes, info: bytes, length: int, hash_name='sha256') -> bytes:
hash_len = hashlib.new(hash_name).digest_size
blocks = (length + hash_len - 1) // hash_len
okm, t = b'', b''
for i in range(1, blocks + 1):
t = hmac.new(prk, t + info + bytes([i]), hash_name).digest()
okm += t
return okm[:length]

4.9 后量子密码(PQC)#

4.9.1 量子威胁#

  • Shor 算法(1994):多项式时间解整数分解与离散对数 → RSA/DH/ECC 全崩
  • Grover 算法:把对称加密暴力搜索从 ( 2^n ) 降到 ( 2^{n/2} ) → AES-128 → 约 64-bit 强度;推荐 AES-256

4.9.2 NIST PQC 选中算法(FIPS 203/204/205, 2024)#

类型算法基础难题
KEM(密钥封装)ML-KEM(原 Kyber)Module-LWE
签名ML-DSA(Dilithium)Module-LWE/SIS
签名SLH-DSA(SPHINCS+)哈希
签名FALCONNTRU

4.9.3 Kyber (ML-KEM) 核心#

基于 Module-LWE 困难问题:给定均匀 ( A )、短向量 ( s, e ),( t = A s + e );已知 ( (A, t) ) 难以恢复 ( s )。

KeyGen:
A ← random 3×3 polynomial matrix over R_q
(s, e) ← small
t = A s + e
pk = (A, t), sk = s
Encaps(pk):
m ← random 256-bit
r, e1, e2 ← small
u = A^T r + e1
v = t^T r + e2 + ⌈q/2⌋ · Decode(m)
return c=(u,v), K = H(m)
Decaps(sk, c):
w = v - s^T u # ≈ ⌈q/2⌋ · Decode(m) + small noise
m' = Round(w)
return K = H(m')

其中 ( R_q = \mathbb{Z}_q[X]/(X^{256}+1) ),( q = 3329 )。

4.9.4 工程部署#

  • Chrome 116+ (2023):TLS 中混合 X25519+Kyber768
  • Cloudflare, Google:内部 RPC 已普遍启用 PQC
  • OpenSSH 9.0+ (2022):默认启用 sntrup761x25519-sha512@openssh.com 混合 KEM
  • 签名尚未大规模部署,因尺寸较大(Dilithium5 签名 4627 B)

4.10 CVE 深度复盘汇总#

4.10.1 Heartbleed(已在 Ch02 详述)#

OpenSSL heartbeat 越界读——提醒 机密性依赖内存安全;后续 OpenBSD fork LibreSSL。

4.10.2 ROBOT (CVE-2017-6168 等)#

Bleichenbacher 1998 攻击的变体,现代 TLS 服务器实现对 RSA-PKCS#1 v1.5 填充错误响应差异仍然存在。攻击者构造选定密文,基于响应差异逐比特恢复会话密钥。修复:TLS 1.3 废弃 RSA 密钥交换。

4.10.3 DUHK (2017)#

Fortinet FortiOS 使用固定种子初始化 ANSI X9.31 RNG → VPN 会话密钥可被离线恢复。提醒:硬编码 RNG 种子 = 灾难。

4.10.4 Curveball (CVE-2020-0601)#

Windows crypt32.dll 在验证 ECC 签名时允许攻击者指定”生成元”而不校验 → 能伪造任意 CA 的签名。修复:强制生成元为曲线标准点。

4.10.5 Debian OpenSSL PRNG 缺陷 (2006-2008)#

Debian 维护者在审计时误删 MD_Update 调用 → 只有 PID 作为熵源 → 全球大量 SSH 密钥可枚举(约 32768 个)。教训:密码学代码不要随便”清理”。


4.11 工具速查#

任务工具
证书查看openssl x509 -in cert.pem -noout -text
私钥生成openssl genpkey -algorithm ED25519
哈希计算sha256sum / certutil -hashfile(Win)
口令破解hashcat -m 1800 hash.txt wordlist.txt
CTF cryptoRsaCtfTool / sage / gmpy2 / pycryptodome
TLS 扫描testssl.sh / sslscan / nmap --script ssl-*
JWT 解析https://jwt.io / jwt_tool.py
格攻击fpylll / sagemath / cvp
PQC 实验liboqs / oqs-provider(OpenSSL)

4.12 练习题#

  1. 证明 RSA 的解密正确性(含 ( \gcd(m,n) \neq 1 ) 的情形)。
  2. 给定 ( n = 97 \cdot 89 )、( e = 7 ),求 ( d ) 及 ( \varphi(n) )。
  3. 写一个 CTF 小脚本:已知 (n, e=3, c),( m < n^{1/3} ),直接开三次方恢复明文。
  4. 解释 GCM 为什么禁止在同一密钥下重复 nonce;若不小心重用了会泄露什么?
  5. 用 HMAC-SHA256 实现 TOTP(RFC 6238)。
  6. 对比 PBKDF2 与 Argon2 在 GPU 上的攻击开销估算。
  7. 解读 Ed25519 的签名为什么是确定性的,这对侧信道有什么好处?
  8. python-fpylll 实现一个小尺寸 Coppersmith 攻击:已知 RSA n, e=3, 明文的高位,恢复明文低位。
  9. 复现一个 Padding Oracle 的小 demo(自建 Flask 服务返回不同 HTTP code)。
  10. 阅读 TLS 1.3 HKDF 推导链,写出从 Handshake Secret 到 Client Application Traffic Secret 的 Label 链。

参考答案要点#

  1. 一般情形用 CRT:m^ed ≡ m (mod p)m^ed ≡ m (mod q) 合并。
  2. ( \varphi(n) = 96 \cdot 88 = 8448 ),( d = 7^{-1} \bmod 8448 ) 用扩欧。
  3. m = iroot(c, 3)[0]gmpy2.iroot)。
  4. 会让两段密文 C1⊕C2 = P1⊕P2,且可恢复 GHASH 认证密钥 H。
  5. TOTP = HOTP(K, ⌊T/30⌋),HOTP 基于 HMAC-SHA1 + 动态截断。
  6. Argon2 内存硬 → GPU 的高并发 ALU 优势失效;PBKDF2 可 GPU 高并发加速 1000x+。
  7. k 由 H(prefix || m) 确定,不依赖 RNG → 不会因弱 RNG 重用 k;侧信道上减少一个泄露源。
  8. 构造多项式 ( f(x) = (m_{high} + x)^3 - c ) 在 ( \bmod n ) 下解小根。
  9. Derive-Secret(Handshake Secret, "c hs traffic", ClientHello..ServerHello) 得 CHTS;Derive-Secret(Master Secret, "c ap traffic", ClientHello..server Finished) 得 CATS。

4.13 面试高频考点(附参考答案)#

Q1:为什么 ECB 不安全?举图像例子。

  • 相同明文块 → 相同密文块;加密企鹅图仍能看出轮廓。

Q2:AES-GCM 的 nonce 为什么不能重用?

  • CTR 密钥流决定于 (K, nonce),重用会泄露 P1⊕P2;同时 GHASH 认证密钥 H 可被恢复 → 任意伪造。

Q3:HMAC 为什么比 H(secret || m) 安全?

  • 抗长度扩展;Bellare 可证在 H 的压缩函数为 PRF 时 HMAC 是 PRF。

Q4:Diffie-Hellman 为什么会被中间人攻击?如何防御?

  • 无身份认证 → 中间人与双方各协商一把密钥;防御:证书、TOFU、口令短语比对、QR 码。

Q5:RSA 的 e=3 攻击场景?

  • m < n^{1/3} 直接开方;广播攻击(3 个不同 n 加密同一 m,CRT 合并);OAEP 填充不当也可能被 Manger 攻击。

Q6:什么是 Padding Oracle?举 CBC 例子。

  • 服务端对 padding 错误返回可区分响应 → 逐字节解密。

Q7:bcrypt vs Argon2,谁更推荐?为什么?

  • Argon2(内存硬 + 可并行参数),尤其是 Argon2id。

Q8:数字签名和 MAC 的本质区别?

  • 签名用非对称密钥 → 可公开验证 + 不可否认;MAC 用对称密钥 → 任一方都能生成。

Q9:TLS 1.3 相对 1.2 有什么安全升级?

  • 去 RSA 密钥交换(强制前向安全);禁用 CBC、RC4、SHA1、压缩;握手 1-RTT;0-RTT(可选);禁止重协商。

Q10:后量子密码工程迁移的主要挑战?

  • 密钥/签名尺寸变大(3~30×);CPU 开销增加;协议握手包过大 → TLS 分片;硬件 HSM 适配;混合部署过渡期风险。

4.14 补充:零知识证明与同态加密#

4.14.1 零知识证明 (ZKP) 基础#

三性质

  • 完备性:诚实证明者可让诚实验证者确信真命题。
  • 可靠性:作弊证明者无法以高概率让验证者相信假命题。
  • 零知识性:验证者除了命题为真外学不到额外信息。

Schnorr 离散对数零知识证明(交互式):

Prover 知道 x 使 y = g^x
1. Prover: 选 r 随机,计算 t = g^r,发 t
2. Verifier: 选挑战 c 随机
3. Prover: s = r + c·x (mod q),发 s
4. Verifier: 校验 g^s == t · y^c

Fiat-Shamir 启发式:把挑战 ( c ) 换成 ( c = H(g, y, t) ) 即可非交互化。

4.14.2 zk-SNARK / zk-STARK 对比#

属性zk-SNARK (Groth16)zk-STARK
依赖双线性对 + 椭圆曲线哈希 + FRI
抗量子
可信设置需要 trusted setup
证明大小~200 B~100 KB
验证速度毫秒级较慢

4.14.3 同态加密#

  • 部分同态(Paillier:加法)
  • 近似同态(BFV / BGV / CKKS)
  • 全同态(FHE,Gentry 2009)
  • 开源库:Microsoft SEALOpenFHEZama TFHE-rs
  • 典型应用:隐私 ML 推理、密文数据库查询

Paillier 加法同态 直观:

[ E(m_1) \cdot E(m_2) = E(m_1 + m_2), \quad E(m)^k = E(k m) ]


4.15 补充:常见误用 checklist#

  • 口令不加盐、不慢哈希 → 使用 Argon2id
  • 对称加密不带认证 → 使用 AEAD
  • CBC + 可预测 IV → IV 随机 + Encrypt-then-MAC 或 AEAD
  • ECDSA k 不随机 / 可重用 → 使用 Ed25519 或 RFC 6979
  • RSA 不填充 / v1.5 填充 → 使用 OAEP (加密) 或 PSS (签名)
  • 自定义密钥派生 → 使用 HKDF
  • 口令直接作为 AES 密钥 → PBKDF2/Argon2 派生
  • HMAC 比较用 == → 使用 hmac.compare_digest
  • JWT 信任 alg 字段 → 服务端固定 alg 白名单
  • TLS 证书未 pin → 高敏感应用启用证书 pin / CT 校验
  • DH 参数 < 2048 bit → ECDHE 或 ≥ 3072-bit DH
  • 日志中输出密钥/Token → 关键字过滤 + 最小化日志

4.16 补充:侧信道攻击#

4.16.1 时序攻击#

  • RSA:exp 过程中根据 d 每一位是否为 1 执行乘法 → 耗时差
  • 对比:AES T-table 实现中数组访问命中不同缓存行 → CacheAttack

4.16.2 功耗分析#

  • SPA (Simple Power Analysis):单次曲线即区分 “乘” vs “平方”
  • DPA (Differential Power Analysis):统计分析,需要成千次测量

4.16.3 故障注入#

  • 电压毛刺 / 时钟毛刺 → 让 CPU 跳过一条指令
  • 经典:BellcoreAttack,在 RSA-CRT 中注入错误使 ( s_p ) 错误 → 恢复 ( p )

4.16.4 缓存侧信道#

  • Flush+Reload:清 cache → 等受害者访问 → 重加载观察耗时
  • Prime+Probe:填 cache → 受害者访问 → 重测
  • 应用:KAISER / KPTI 防御 Meltdown 类攻击;RSA/AES 常数时间实现

4.16.5 防护#

  • 常数时间算法(opensslBN_consttimelibsodium
  • 硬件 HSM / SE(Secure Element)
  • 随机化 masking、shuffling
  • 指令级:crc32aesenc 的常数时间硬件支持

4.17 补充:随机数生成#

4.17.1 熵源#

  • 硬件:RDRAND、RDSEED(Intel)、ARMv8 RNDR、TPM RNG
  • 软件:中断计时、输入事件、磁盘延迟
  • Linux:getrandom(2)/dev/urandom(2.6 后合并熵池,现代正确实践)

4.17.2 CSPRNG 构造#

  • HMAC-DRBG / Hash-DRBG / CTR-DRBG(NIST SP 800-90A)
  • ChaCha20-DRBG(Linux 5.17+)

4.17.3 事故教训#

  • 已提 DUHK、Debian OpenSSL、Android SecureRandom
  • CVE-2023-20900 VMware CSP RNG 默认种子 → 虚机镜像批量使用同一种子 → TLS 密钥可碰撞

4.18 补充:国密算法速览#

  • SM2:基于 ECC over F_p256(国产素数曲线)的签名、密钥交换、加密。国标 GB/T 32918。
  • SM3:256-bit 哈希,结构类似 SHA-256,但带不同布尔函数。
  • SM4:128-bit 分组对称加密,32 轮非线性 Feistel。
  • SM9:基于身份的密码学(IBE / IBS)。
  • ZUC:LTE/5G 层序列密码。

合规侧:等保 2.0 / 密码法要求关键系统使用国密,金融、政务尤其严格。

4.18.1 SM4 Python 示例#

from gmssl import sm4
crypt_sm4 = sm4.CryptSM4()
key = b'0123456789ABCDEF'
crypt_sm4.set_key(key, sm4.SM4_ENCRYPT)
data = crypt_sm4.crypt_ecb(b'hello world12345')

生产不要用 ECB,改用 CBC / GCM 模式。


4.19 补充:实战场景与选型表#

4.19.1 文件/数据库加密#

  • 字段级:AES-256-GCM,每条记录独立 nonce + AAD=表名/列名
  • 全盘:LUKS2 + Argon2id;BitLocker + TPM;FileVault
  • KMS:AWS KMS / GCP Cloud KMS / HashiCorp Vault Transit
  • 包裹密钥 (DEK + KEK):数据用 DEK 加密,DEK 用 KEK(由 KMS 管理)加密

4.19.2 传输加密#

  • Web:TLS 1.3(或强制 TLS 1.2 with PFS cipher suites)
  • VPN:WireGuard > OpenVPN/IKEv2
  • gRPC:mTLS + SPIFFE ID
  • Kafka / Redis:支持 SASL_SSL 或 TLS over TCP

4.19.3 密钥管理#

  • 切勿把密钥硬编码进代码
  • 生产:KMS / HSM / Vault
  • 开发:环境变量 + dotenv,注意不提交到 Git
  • 轮换:定期 + 异常时强制;需要支持过渡期双密钥验证

4.19.4 密码学库选择#

语言推荐库
Pythoncryptography(高层 API),避免 pycrypto(已弃)
Gocrypto/*(官方) + golang.org/x/crypto
Rustringrustcrypto 组织、age-encryption.org/v1
JavaBouncy Castle、JCA/JCE
C/C++libsodium、OpenSSL 3、BoringSSL
Node.jsnode:cryptolibsodium-wrappers@peculiar/webcrypto

4.20 补充:CTF Crypto 套路整理#

题型关键词工具
RSA 小 ee=3, 明文短gmpy2.iroot
RSA 共模同 n,不同 eextended_gcd
RSA Wienerd 过小owiener
RSA Coppersmith部分已知sage .small_roots()
DLP 小范围p-1 平滑Pollard p-1 / rho
已知明密文AES/DES 参数未知暴力猜模式
LCG 预测随机数题sage 格方法
椭圆曲线反常#E(F_p) = pSmart 攻击
哈希碰撞MD5 collisionhashcash, chosen-prefix
格密码LLL, BKZfpylll / sage

4.21 补充:常见问答速记#

  • AEAD = Authenticated Encryption with Associated Data:在加密同时验证密文 + 关联数据(AAD)未被篡改。
  • IND-CPA vs IND-CCA2:前者抵抗选择明文攻击,后者额外抵抗自适应选择密文攻击。工业界默认目标是 IND-CCA2。
  • Forward Secrecy vs Post-Compromise Security:前向安全保障”私钥泄露不解过去”;后妥协安全(PCS/self-healing)保障”妥协之后可恢复”。Signal 的 Double Ratchet 同时提供两者。
  • Random Oracle Model:在证明中把哈希函数当理想均匀随机函数,方便分析;工程上不存在真正的 Random Oracle。
  • Standard Model:不依赖随机预言机;证明更强,但算法往往更复杂或效率更差。

4.22 补充:协议合规性要点#

  • FIPS 140-3:美政采购门槛;模块化认证 + 受控的算法清单。
  • Common Criteria (CC):国际通用标准,EAL 等级评估。
  • PCI-DSS:支付行业,对 KMS、传输加密、日志有明确要求。
  • GDPR / 《个人信息保护法》:加密是”合理技术措施”的核心之一。
  • CNCERT / CCRC 国密改造:国内金融、政务数据传输需 SM2/SM3/SM4 合规。

4.23 延伸阅读#

历史经典 CVE 速查(密码学相关)#

CVE描述
CVE-2014-0160OpenSSL Heartbleed 内存泄露
CVE-2017-3225DUHK 固定 RNG seed
CVE-2017-13099ROBOT (Bleichenbacher 复活)
CVE-2018-0737OpenSSL RSA 密钥生成定时通道
CVE-2019-1543OpenSSL ChaCha20-Poly1305 16KB 缓冲溢出
CVE-2020-1968Raccoon Attack 对 TLS-DH 的定时攻击
CVE-2022-3602 / CVE-2022-3786OpenSSL X.509 punycode 缓冲溢出
CVE-2023-0286OpenSSL X.400 类型混淆

教材#

  • Jean-Philippe Aumasson,《Serious Cryptography》
  • Ferguson, Schneier, Kohno,《Cryptography Engineering》
  • Katz, Lindell,《Introduction to Modern Cryptography (3rd Ed.)》
  • Dan Boneh, Victor Shoup,《A Graduate Course in Applied Cryptography》(免费在线)
  • Handbook of Applied Cryptography(HAC,免费 PDF)

在线课程#

标准 / 规范#

  • NIST SP 800-57 Part 1 Rev. 5 - Key Management
  • NIST FIPS 203 (ML-KEM), 204 (ML-DSA), 205 (SLH-DSA)
  • RFC 5869 (HKDF), RFC 8446 (TLS 1.3), RFC 8439 (ChaCha20-Poly1305)
  • RFC 6979 (Deterministic ECDSA)
  • ISO/IEC 11770 - Key Management

论文 / 博客#

  • Aviram et al., DROWN: Breaking TLS Using SSLv2, USENIX Security 2016
  • Adrian et al., Imperfect Forward Secrecy (Logjam), CCS 2015
  • Bernstein, Curve25519: new Diffie-Hellman speed records, PKC 2006
  • Biryukov, Dinu, Khovratovich, Argon2, PHC winner 2015
  • Real-World Cryptography(Wong, Manning 2021)
  • Cryptography Dispatches(Filippo Valsorda newsletter)
分享

如果這篇文章對你有幫助,歡迎分享給更多人!

密码学基础与应用
https://lemusakuya.com/posts/study-notes/network-security/04_密码学基础与应用/
作者
レム・咲く夜
發布於
2026-04-27
許可協議
CC BY-NC-SA 4.0

部分資訊可能已經過時

目錄