一句话版本
AES 把每个字节看成有限域 F28=F2[x]/(x8+x4+x3+x+1) 里的一个元素。它的 S 盒就是"求乘法逆元,再做一个仿射变换";列混合(MixColumns)就是一次多项式乘法。
用代数结构而不是随手画的表格来设计,能让 AES 对已知攻击给出可证明的抵抗力。
全文分三层:
- 通俗理解:混淆与扩散,AES 每一轮在干什么
- 实际用处:AES 无处不在,以及为什么它不怕量子计算机
- 数学原理:F28 的构造、S 盒、MixColumns,附 FIPS 197 标准里的手算例子
第一层:通俗理解
1.1 对称加密要做两件事
香农在 1949 年提出,好的分组密码要同时做到:
- 混淆(confusion):密文和密钥的关系要尽量复杂、非线性,不能列个线性方程组就解出来。
- 扩散(diffusion):明文改动一位,密文要有一半左右的位跟着变("雪崩效应")。
AES 就是一台把这两件事反复做 10 到 14 轮的机器。
1.2 AES 的一轮
AES 把 16 字节的数据排成 4×4 的方阵,每一轮做四步:
| 步骤 |
做什么 |
作用 |
| SubBytes |
每个字节查 S 盒替换 |
混淆:唯一的非线性步骤 |
| ShiftRows |
第 i 行循环左移 i 格 |
扩散:把字节打散到不同列 |
| MixColumns |
每一列乘一个固定矩阵 |
扩散:一列中每个字节影响全列 |
| AddRoundKey |
和本轮子密钥异或 |
引入密钥 |
做两轮之后,任意一个输入字节就已经影响到全部 16 个输出字节。
1.3 为什么要用有限域
字节有 256 种取值。我们想对字节做"乘法"和"除法",结果还得是一个字节。普通整数乘法会溢出,模 256 又不是域(2×128≡0,有零因子,不能除)。
办法是把字节看成系数为 0 或 1 的多项式,在模一个不可约多项式的意义下做运算。这样 256 个字节恰好构成一个域:能加减乘除,每个非零元都有逆元。
第二层:实际用处
AES 是 2001 年美国 NIST 通过公开竞赛选出的标准(原名 Rijndael,两位比利时密码学家设计)。今天它几乎无处不在:
- HTTPS 里的数据加密(AES-GCM)
- 手机和电脑的全盘加密(iOS、Android、BitLocker、FileVault)
- Wi-Fi WPA2/WPA3、VPN、压缩包加密
- 加密货币钱包文件、密码管理器
硬件加速:Intel、AMD 的 AES-NI 指令和 ARM 的加密扩展直接在芯片里实现一轮 AES,速度可达每秒数 GB。
量子计算机:AES 没有 RSA 那样的代数陷门,Shor 算法用不上;Grover 算法只能把暴力搜索从 2128 降到约 264。所以用 AES-256 就足够应对,详见《后量子密码》。
真正的风险在实现
AES 本身二十多年来没有实际可行的攻击。出事的都是用法:ECB 模式(相同明文块得到相同密文块,"加密后企鹅图依然清晰可见")、GCM 模式重复使用 nonce、查表实现带来的缓存时间侧信道。
第三层:数学原理
3.1 构造 F28
取 F2={0,1}(加法是异或)。多项式
m(x)=x8+x4+x3+x+1
在 F2 上不可约,所以 (m(x)) 是 F2[x] 的极大理想,商环
F28=F2[x]/(m(x))
是一个有 28=256 个元素的域(抽象代数:F[x]/(f) 是域当且仅当 f 不可约)。
一个字节 b7b6⋯b0 对应多项式 b7x7+⋯+b1x+b0。例如 0x57 =010101112 对应 x6+x4+x2+x+1。
- 加法:系数逐位模 2 相加,就是异或。
- 乘法:多项式相乘,再模 m(x) 取余。实现上就是"乘 x = 左移一位,溢出了就异或
0x1B"。
3.2 手算例子:乘法
{57} · {83} = {C1}(FIPS 197 原文例子)
{57} =x6+x4+x2+x+1,{83} =x7+x+1。
先做普通多项式乘法(系数模 2):
(x6+x4+x2+x+1)(x7+x+1)=x13+x11+x9+x8+x6+x5+x4+x3+1.
再模 m(x):用 x8≡x4+x3+x+1 反复降次,最后得到
x7+x6+1=110000012=C1.
(已用 Python 验算。)
3.3 S 盒 = 求逆 + 仿射变换
对每个字节 a:
- 求逆:b=a−1 in F28(规定 0−1=0);
- 仿射变换:把 b 看成 F28 中的向量,算 s=Mb⊕63,M 是一个固定的 8×8 循环矩阵:
si=bi⊕bi+4⊕bi+5⊕bi+6⊕bi+7⊕ci(下标模 8, c=63).
S(53) = ED(FIPS 197 原文例子)
- 逆元:
{53} 的逆是 {CA},可以验证 {53}·{CA} = {01}
- 仿射变换后得到
{ED}
另外 S(00) = 63:0 求"逆"仍是 0,只剩下常数 63。(已用 Python 验算。)
为什么用求逆:x↦x−1 在 F28 上是高度非线性的。Nyberg(1993)证明了这类映射对差分攻击和线性攻击有接近最优的抵抗力:任意输入差分最多以 4/256 的概率产生某个特定输出差分。
为什么还要加仿射变换:纯求逆的代数结构太"干净",可能被代数攻击利用(比如插值攻击),而且 0 和 1 是不动点。仿射变换打乱这种结构,并保证 S 盒没有不动点和"反不动点"。
3.4 MixColumns = 模 x4+1 的多项式乘法
每一列的 4 个字节看成系数在 F28 中的三次多项式 a(y)=a3y3+a2y2+a1y+a0,然后
a(y)↦c(y)⋅a(y)mod(y4+1),c(y)=03y3+01y2+01y+02.
因为 y4≡1,这是一个循环卷积,写成矩阵就是
c0c1c2c3=02010103030201010103020101010302a0a1a2a3.
注意 y4+1=(y+1)4 在特征 2 下可约,所以这个商环不是域,但 c(y) 与 y4+1 互素,因此可逆,解密时乘它的逆 c−1(y) 即可。
这个矩阵还是一个 MDS 矩阵(和 Reed–Solomon 纠错码里的 MDS 码是同一个概念):输入和输出中非零字节的总数至少是 5。这保证了扩散的速度,也是 AES 设计者"宽轨迹策略"的核心。
总结
| 层次 |
要点 |
| 直觉 |
混淆靠 S 盒,扩散靠 ShiftRows 和 MixColumns,反复十几轮 |
| 代数 |
字节 = F2[x]/(m(x)) 的元素;不可约多项式给出域 |
| 设计 |
S 盒 = 求逆 + 仿射,抵抗差分 / 线性攻击;MixColumns 是 MDS |
| 工程 |
算法本身很稳;风险在模式误用和侧信道;AES-256 可抗量子 |