Crypto 3 - 现代密码学基础
Crypto 3 - 现代密码学基础
密码学基础
针对加密算法的攻击
首先来回顾一下密码学中常见的攻击手段:
- 从已掌握信息的角度, 分为:
- 已知密文攻击 (Ciphertext-only, COA): 最弱的攻击, 攻击者只有密文;
- 已知明文攻击 (Known-plaintext attack, KPA): 攻击者拥有部分密文和与之对应的明文对;
- 选择明文攻击 (Chosen-plaintext attack, CPA): 攻击者可以任意选择明文, 然后获得对应的密文对;
- 选择密文攻击 (Chosen-ciphertxt attack, CCA): 攻击者可以任意选择密文, 然后获得对应的明文对;
- 从攻击手段来看, 大致有:
- 统计分析攻击: 利用明文 (或语言) 固有的统计特性 (字母/字母对/词频、重复模式、重合指数等) 从密文中推断密钥或明文。属于密码分析经典方法, 常用于对抗简单替换/置换类密码或当加密未能完全掩盖明文统计特征时。
例如考虑 字典/凯撒 密码, 对一段英文原文进行加密得到的密文, 由于英语的语言特性, 元音字母会大量出现且字母 e 会高频率出现在单词结尾, 通过字母频率、双字母频率、重合指数破译。 在现代密码学中, 对于少部分格式保持的加密或者未压缩明文, 仍然能通过统计分析推断字段值;
- 数学/代数分析攻击: 主要是针对现代公钥与现代分组密码, 数学攻击通常利用 “算法内部的确定性结构或参数弱点”, 把问题化为数论/代数/格/方程求解问题;
例如, Hastad 的广播攻击 (针对 RSA)
成熟可用的加密算法或协议必须在已知攻击模型下被设计/分析/实测以抵抗主要攻击 (穷举/统计/代数/选择明文/选择密文/侧信道等), 并且在工程层面实现恰当、可替换 (crypto agility) 。
密码学安全目标
通常用以下几类明确定义的安全目标来衡量:
信息论安全
在理论上对任何计算能力无条件安全, (但代价极高, 通常不可行); 如 OTP;
计算安全性
这类安全是在已知算法与计算能力下不可行地破解;
计算安全性通常基于困难问题: 例如 AES 的抗穷举性基于密钥足够长, RSA 因式分解的数学困难;
实现层与部署安全
抗侧信道、随机数质量、正确的密钥管理、避免常见坑等;
注意, 即使算法在数学上安全, 错误的实现 (例如经典的弱随机数, 可预测随机数, 秘钥泄露等) 仍然会使系统被攻破;
分组密码
分组密码又称为流密钥密码或对称密码。使用分组密码对明文加密时, 首先对明文分组, 每组长度相同, 然后对每组明文分组, 每组长度相同, 然后对每组明文分别加密的到等长的密文。
DES
DES分组长度为64比特, 使用56比特秘钥对64比特的明文进行16轮加密, 得到64比特的密文串。其中, 秘钥为64比特, 实际使用56比特, 另外8位用作奇偶校验。
更具体来说, 实际上 64 bit 是被切割为了 8 组, 每组有 7 位数据位和 1 位校验位, 至于为什么是 7 + 1 的组合, 主要是历史兼容性; DES 被设计的时代通信硬件通常按 8 bit 处理; 校验码不参与加密, 仅用于保证传输无误 (一般默认是奇校验);
加密过程
DES 采用对偶算法, 也就是:
$$
f=f^{-1}
$$
- 预处理: 初始置换 $IP$
$$
IP(M) = (L_0,R_0)
$$
- $M$ 为初始明文;
- 16 轮加密
$$
L_i = R_{i-1} \
R_i = L_{i-1} \bigoplus f(R_{i-1},K_i) \
i=1, 2, … , 16 \
$$
- 其中 $L_i, R_i$ 分别是第 $i$ 轮加密的左半部分和右半部分; $K_i$ 为第 $i$ 轮使用的子密钥, 由主密钥通过置换和循环位移生成;
- 逆置换 $IP^{-1}$
$$
{IP}^{-1}(R_{16},L_{16}) = C
$$
- $C$ 为最终密文;
秘钥计算
去除校验位 + 置换选择 1
64 位秘钥分为 8 组, 然后去掉末尾 (奇偶校验), 剩余的部分 56 位做重排, 然后分为左右两部分 $(C_0,D_0)$; 显然各为 28 位;
循环左移 (Left Shifts)
每一轮秘钥 $(C_i,D_i)$ 生成都由上一轮的秘钥循环左移获得:
$$
(C_i,D_i) = (LeftShift(C_{i-1}), LeftShift(D_{i-1}))
$$
当 $i$ 为 $1, 2, 9, 16$ 时, 位移两位, 其余为 1 位;
置换选择2
将 $(C_i,D_i)$ 拼接为 56 位, 然后按照 PC-2 表选择其中 48 位, 也就是按 指定表重新排列, 这 48 位就是第 $i$ 轮使用的 子密钥 $K_i$:
$$K_i = PC_2(C_i,D_i)$$
- 注意, PC2 (Permutation Choice 2) 是一张固定表
DES 安全性
- 秘钥长度问题: DES 密钥长度仅有 64 位, 理论需要穷举 72,057,594,037,927,936 次, 在现代计算机的 GPU 集群中可以在几分钟内完成穷举, 因此 DES 已经被认为在计算上不安全;
- 弱密钥和半弱密钥: 当秘钥为某些特殊值时, 会导致子密钥满足某些数学性质:
- 弱密钥: 非常少见 (例如
0x0101010101010101), 会导致所有子密钥全部相等 (Feistel 结构坍缩):
- 弱密钥: 非常少见 (例如
$$E_K(E_K(M)) = M$$
- 半弱密钥: 用一个密钥加密, 再用另一个秘钥解密, 会得到原文; 也就是说, 加密的时候, 前半段加密过程, 正好会被后半段加密过程给 “反向加密” 掉;
$$E_{K_A}(E_{K_B}(M)) = M$$
经典半弱密钥:
0x01FE01FE01FE01FE-0xFE01FE01FE01FE01
3DES
经典 DES 存在秘钥位数不足, 已经可被穷举计算的问题, 3DES 继承了 DES 的思想 (核心算法结构不变, 但是执行多次, 并扩宽长度) 并扩展了其规模:
3DES 实际是 重复执行三次 DES 的加解密操作。
- 模式一: 双密钥 3DES
$$C = E_{K_1}(D_{K_2}(E_{K_1}(M)))$$
第一次加密用 $K_1$, 第二次解密用 $K_2$, 第三次加密用 $K_1$; 总秘钥长度为 $K_1$ 与 $K_2$ 相加, 即 128 位, 去掉奇偶校验位 (28(7-1) = 112) 为 112 位;
当 $E_{K_1}=E_{K_2}$时, $E_{K_1}(D_{K_1}(E_{K_1}(M))) = M$, 此时退化到普通 DES, 满足历史兼容性;
- 模式二: 三秘钥 3DES
$$C = E_{K_1}(D_{K_2}(E_{K_3}(M)))$$
同理, 三次秘钥均不同, 则为三秘钥; 更安全, 但显然计算开销也更大;
这两种 3DES 可以抵御现代穷举计算攻击。
AES
AES 整体是基于一定数域上的模运算, 数学原理和安全性等在上一篇密码学博客中有写: 手撕 AES-256
安全性总结
分组密码本质上就是相对固定的 分组-模式运算-置换-查表-重组 流程; 很显然, 这些操作都是为了增加熵值, 而其中最主要的熵增部分就是查表 (或者说, 字节代换), 这个流程结合其他的分组, 置换等, 会使得熵值指数级增长, 从而保证对差分分析和线性分析有高度抗性;
因此, 字节代换用的这张表, 也就是 S盒 的设计非常重要; 首先, 它是一个非线性的多对一映射, 引入了 非线性和混淆
接下来是 P盒 (置换) 和 E盒 (扩展):
- E 盒扩展人为制造重复的比特位输入, 保证不同的 S 盒输入间有重叠, 制造跨位相关性; (一对多的映射)
- P 置换将 S 盒的 32 位输出打乱, 实现扩散 (Diffusion), 属于一对一映射;
在这几个步骤的加持下, 即使只改动一位的明文或秘钥, 密文也平均有一半的变化, 这就是雪崩效应;
可用性总结
由于分组密码加密和解密使用同一组秘钥, 其数学过程满足 Feistel 结构, 也就是对称可用; 加密与解密几乎完全对称, 任意非线性函数都可以嵌入, 仍能可逆, 这种结构让分组密码在已知秘钥进行明文/密文求解, 但求解秘钥就在计算上不可行;
序列密码
序列密码又称为流密码, 序列码是明文流和秘钥流按顺序逐比特进行异或运算, 序列密码中的关键是保持通信双方精确同步。
$$
C_i = P_i \bigoplus K_i
P_i = C_i \bigoplus K_i
$$
其中 $C_i, P_i, K_i$ 分别为密文, 明文和秘钥流的第 i 位; 由于异或操作的特性, 所有的流密码在加密和解密上都是完全对称的;
一轮序列/流密码绝对不能重用, 考虑以下情景:
$$C_1 = P_1 \bigoplus K$$
$$C_2 = P_2 \bigoplus K$$那么攻击者一旦拿到两个密文, 直接异或, 就可以得到明文:
$$ C_1 \bigoplus C_2 = (P_1 \bigoplus K) \bigoplus (P_2 \bigoplus K) = P_1 \bigoplus P_2 $$
由于流密码的加密解密过程及其简单, 因此其速度极快;
现代序列密码流程
考虑 Alice 和 Bob 正在进行加密会话, 双方先分发相同的流秘钥 (主密钥), 然后每次传输时将随机数 (明文, 包含在被签名部分中防止篡改) + 明文 一同发送给对方。
流秘钥需要定期更新 (Rekey), 且过程中的随机数和流秘钥需要保持唯一性;
如果流密码长期复用, 那么可能通过统计分析找出密钥流模式 (即使已经有随机数参与): 因此秘钥更新仍然是必要的; 现代协议会使用 Session Key 定期刷新, 这与 TLS 的机制和思想是相同的;
线性反馈移位寄存器 - LFSR
线性反馈移位寄存器是流密码中常见的伪随机序列发生器, 用于生成流密钥 (而非随机数);
通过线性反馈函数, 不断移位产生一个看似随机但实际上可预测的二进制序列。
核心思想
假设寄存器长度为 $n$, 每次输出寄存器的末位, 下一步的最高位由之前若干位经过 异或(XOR, $\bigoplus$) 获得;
数学原理
LFSR 的数学本质是有限状态机 (Finite State Machine), 所有运算发生在有限域 $GF(2)$:
设寄存器状态为:
$$
S_t = [S_1, S_2, … S_t-n+1]
$$
定义一个反馈多项式:
$$
f(x) = 1 + c_1x + c_2x^2 + … + c_nx^n
$$
其中 $c_i \in {0,1}$, 更新规则 (反馈函数):
$$
s_{t+1} = (c_1s_{t+n-1} \bigoplus c_2s_{t+n-2} \bigoplus … \bigoplus c_ns_{t})
$$
形象理解 (白痴级别)
这是我能想到的最简单, 形象, 白痴的理解!
我们可以把整个 LFSR 算法得出的结果视为一个长度为 (假设) $t$, 假(设 $n = 4$) 的由 0 和 1 组成的有限数列,初始状态:
1 | 0, 0, 1, 1 |
由反馈函数 (或者状态转移方程) 算得 $t$ 个时刻后的序列:
假设反馈方程为 $$s_{t+4}=s_t \bigoplus s_{t+1}$$
1 | t = 2 |
要知道此时的寄存器状态, 等于将一个长度为 $n, (n=4)$ 的滑块从左往右移动了 $t, t=2$ 位, 也即是:
1 | t = 2 |
被框柱的部分就是 $t=2$ 时刻的寄存器完整状态;
安全性
LFSR 显然并不 “安全”, 其输出看似随机, 实则在数学上完全线性可预测; 也就是说, 只要攻击者截获足够的输出位, 例如 $2n$ 个, 那么就可以建立一个线性方程组, 直接解出反馈多项式和初始状态, 直接预测整个 LFSR 序列;
因此 LFSR 本身的设计并非为了安全, 而是为了:
- 高速低成本的产生 “伪随机序列”;
- 提供周期性良好, 均匀分布 的比特流;
- 在序列密码中作为基础安全 (线性, 结合一些非线性的组件提高安全性)
现代加密通常使用 LFSR + 多个其他非线性组合函数如 S 盒代换来提高安全性, 这个思想在分组密码中也被广泛运用;
RC4
RC4 是一种基于置换的流密码, 用 256 元素的数组 S[0, 1, ..., 255] 来维护状态
数学原理
RC4 的数学原理是动态置换状态机 (permutation-based FSM):
$$
S_{t+1} = \pi_i (S_t)
$$
其中$\pi_i$是一个由密钥和当前状态决定的置换映射。
密钥调度算法 KSA:
用密钥初始化状态表 ($S$):
1
2
3
4
5
6for i = 0..255:
S[i] = i
j = 0
for i = 0..255:
j = (j + S[i] + K[i mod keylen]) mod 256
swap(S[i], S[j])这一步能够打乱或者置换初始的序列
伪随机生成算法 PRGA:
1
2
3
4
5
6
7i = j = 0
while True:
i = (i + 1) mod 256
j = (j + S[i]) mod 256
swap(S[i], S[j])
t = (S[i] + S[j]) mod 256
output S[t]每执行一次循环就产生一个字节的密钥流;
安全性问题
RC4 的状态长度 256, 状态空间理论可达 256! , 并且在软件和硬件上都可以快速运行, 看起来不能被穷举攻破;
但是 RC4 存在一些严重的数学问题:
- 密钥初期输出存在偏差 (前几百字节强相关);
- 输出字节的分布不均匀 (具有一些统计特征, 可能被分析);
- 相同密钥重用会泄露明文差分;
- 被攻击者收集足够多加密数据后, 可通过 Fluhrer-Mantin-Shamir, FMS 攻破还原密钥 (根本原因);
所以现代 TLS 明确禁止使用 RC4。
形象理解
在刚才的 LFSR 滑块模型基础上, RC4 就是将简单的滑块平移替换为乱序洗牌的滑块, 每次随机交换两张牌, 再根据结果抽一张输出。
ZUC - 祖冲之算法
ZUC 是一种面向流密码安全通信的现代流密码算法, 由中国提出并作为 3GPP LTE (4G 通信) 的标准加密算法使用。
算法结构
1 | graph TD |
(1) LFSR - 线性骨架
规模为 16 个寄存器单元, 每个寄存器 31 bit, 更新公式, 相对于传统 LFSR 具有更复杂的空间状态和抗线性分析性:
$$
s_{t+16} = \left( 2^{15} s_{t+15} + 2^{17} s_{t+13} + 2^{21} s_{t+10} + 2^{20} s_{t+4} + (1+2^8) s_t \right) \mod (2^{31}-1)
$$
(2) 位重组 - 局部置换 + 拼接
从 LFSR 的若干单元中抽取特定位, 组成 4 个 32-bit:
1 | X0 = 高16位(s15) || 低16位(s14) |
这一步起到局部置换 + 拼接的作用;
(3) F 函数 - 非线性变换
F 函数承担了非线性混淆的角色, 与 AES 的 SubBytes 相似, 实现上有区别:
之后 ZUC 会进行 L1/L2 线性散列变换, 这一步类似于 AES 中的列混合;
1 | W = (X0 ⊕ R1) + R2 (mod 2^32) |
长话短说:AES 是字节级非线性 + 列扩散, ZUC 是字节级非线性 + 字扩散;
(4) 初始化 - 核心安全保证机制
初始化的目的: 不直接输出秘钥流, 尽可能屏蔽 LFSR 中的线性特征; 降低不同秘钥/IV 可能导致输出不均, 从而被统计分析的可能性;
因此, 初始化主要做三件事:
- 不直接输出秘钥流;
- 经过 32 轮”加优” (Warm-up);
- 每一轮都将 F 函数输出反作用于 LFSR 内部;
1 | for i in range(32): |
F 函数的输出会向 LFSR 做反馈;
这种反向注入或者反馈调节会稀释初始状态的偏差, 并使得 LFSR 的结果趋于均匀。
这一步的数学原理比较复杂, 从结果来看, 其结果的比特序列趋近于独立同分布 (i.i.d.), 已经没有明显偏差;
可以这么直观地理解:
原始的 LFSR 状态像是一堆按规律排列的沙子,
F 函数相当于 “搅拌器”,
初始化阶段就是 “搅拌 32 次”,
使沙子均匀分布后再开始 “取样输出”。
总结
ZUC 属于通信中的工程级安全设计, ZUC 算法的特点: 在硬件上高效实现、流特征均匀、密钥恢复攻击困难、周期超长。 目前 ZUC 仍然非常安全。
哈希函数
哈希函数已经是老朋友了, 简单来说, 哈希函数构造了一个多对一映射: 哈希函数将无限的输入转化为了 (定长) 有限的输出, 根据这一个特征, 哈希函数用于数据完整性、数字签名、消息认证等。
$$
x=h(m)
$$
哈希函数是一个单向函数, 主要需要满足单向性和抗碰撞性(不能简单的由输出找到一个可能的输入);
针对哈希函数的攻击
(1) 穷举碰撞, 例如生日攻击, 产生足够多的明文攻击计算哈希值直到找到碰撞点, MD5 是常见的攻击对象;
(2) 利用散列函数的代数结构进行分析攻击: 中间相遇攻击、修正分组攻击和差分分析攻击等。
(3) 还有一些辅助攻击手段, 例如彩虹表攻击, 需要指出的是, 彩虹表不是简单的空间换时间, 而是一种折中的优化手段。简单的理解其作用, 就是在已知哈希算法和少量明文的信息 (长度, 字符集如是否仅含小写字母和数字) 的情况下快速从密文恢复出可能的明文;
重要参考: 知乎: 什么是彩虹表?;
腾讯云: 深入浅出理解彩虹表
MD5 与 SHA-1算法
MD5算法
消息分组长度为512比特, 生成128比特的摘要。
SHA-1 算法
的输入是长度小于2^64-1比特的任何消息, 输出160比特
美国国家安全局与国家标准合作, 提出数字安全标准 DDS 及其算法标准 DSA 。DDS 数字签名标准的核心是数字签名算法 DSA, 该算法中杂凑函数采用SHA-1。
需要指出的是 MD5 和 SHA-1 的抗碰撞性已经不足, 现在应用更广泛的是 SHA-256, MD5 通常只用作文件校验等非常简单无需担心碰撞的场景。
SM3 算法
SM3 算法是国家密码管理局半步的安全密码杂凑算法, 把长度为len($ 1 < len < 2^64$)比特的消息经过填充和迭代压缩, 生成长度为256比特的消息摘要。
可用于数字签名和验证, HMAC的生成与认证, 以及随机数的生成。
HMAC
消息验证的关键, 是消息摘要函数, 通常搭配非对称加密作为消息认证机制出现。
非对称加密 (公钥-私钥加密)
在之前的 RSA 专题博客中已经写过, 这里不再赘述;
现代加密三大体系对比
| 类别 | 工作方式 | 优点 | 缺点 | 常见应用 |
|---|---|---|---|---|
| 分组密码 (Block Cipher) | 将明文分成固定长度的分组 (如 AES 128-bit) , 每组使用相同或轮秘钥加密。 | ✅ 高安全性 ✅ 抗统计攻击 ✅ 可硬件加速 |
⚠️ 处理延迟高 (块为单位) ⚠️对流数据需模式/填充 |
AES、DES、SM4, 磁盘/数据库加密、VPN |
| 流密码 (Stream Cipher) | 明文按位/字节与伪随机密钥流异或加密。密钥流通常由 LFSR、ChaCha20 等生成 | ✅ 高速、低延迟 ✅ 可边加密边传输 (实时流) ✅ 实现简单 |
⚠️ 密钥流必须唯一, 重用会泄露 ⚠️ 通常需要安全随机数生成器 |
RC4 (已淘汰) 、ChaCha20、LTE/5G 数据流加密 |
| 非对称加密 (Public Key / Private Key) | 使用公钥加密, 私钥解密 (或签名验证) ; 无需共享私钥 | ✅ 便于秘钥分发 ✅ 支持数字签名/认证 ✅ 可以和对称加密混合使用 |
⚠️ 运算慢, 效率低 ⚠️ 适合加密小数据或传输对称秘钥 |
RSA、ECC、Diffie-Hellman、TLS 密钥协商 |
秘钥分发与传输
痛点: 对称秘钥在通信双方间必须共享 → 传输过程中可能被窃听或篡改;
解决方式:
- 公私钥机制: 用对方公钥加密对称秘钥, 只有对方私钥能解密;
例如, 通信中使用分组密码来加密消息, 提高效率, 而传递或更新分组密码的主密钥时, 使用非对称加密如 RSA 来传递;
密钥协商协议 (Diffie-Hellman / ECDH): 双方共同计算共享秘钥, 避免了明文传输。这个思想在区块链中被沿用, 也就是后来的安全多方计算;
数字签名/证书验证: 防止中间人篡改;
学密码学真的很累..

























































