3. 对称加密基础:AES算法原理与工作模式简介
聊字段级加密,绕不开对称加密。
而对称加密里,AES就是那个“黄金标准”。
你想想看,从你的手机聊天记录,到银行的交易数据,背后可能都有AES在撑着。我刚开始接触密码学时,也觉得这东西特别神秘——一串乱码就能保证安全?
后来自己动手写过几次,才明白它为什么这么牛。说白了,就是简单、快、靠谱。
3.1 为什么是AES?它解决了什么问题?
在AES出现之前,有个叫DES的老算法。它用了很多年,但后来被证明不够安全了——密钥太短,容易被暴力破解。
我入行时还见过一些老旧系统在用DES,说实话有点慌。于是NIST(美国国家标准与技术研究院)搞了个竞赛,从15个候选算法里挑出了Rijndael,也就是现在的AES。
AES的核心优势:
- 安全可靠:至今没有有效的攻击手段能彻底破解它
- 性能出色:硬件和软件实现都很快
- 标准化:全球通用,合规性无脑选它就行
AES不是一次加密所有数据,而是把数据切成固定大小的“块”。它只处理128位(16字节)的块。如果你的数据不够16字节,就得补位(padding),这个后面会讲。
3.2 AES算法核心:SPN网络
AES的内部结构,可以理解成一套“替换-置换”的循环,学名叫SPN网络(Substitution-Permutation Network)。
它不像Feistel网络那样分左右两半。AES每一轮都直接操作整个数据块。这带来的好处是——扩散效果更好,更抗分析。
我记得第一次画AES的流程图时,脑子差点绕进去。但其实它只有4个操作反复循环:
- 字节代换(SubBytes):用一个固定查表(S盒),把每个字节替换成另一个字节。这是一个非线性操作,用来抵抗线性分析。
- 行移位(ShiftRows):把4x4的状态矩阵的行,分别向左循环移位不同的偏移量。这是为了扩散。
- 列混合(MixColumns):用一个矩阵乘法,把每一列的4个字节混合起来。这是为了混淆。
- 轮密钥加(AddRoundKey):把当前状态跟这一轮的轮密钥做异或。这是把密钥真正“揉”进数据里。
一个小技巧:解密就是逆向操作,顺序相反,并且要用逆S盒和逆列混合。很多人在实现时把行移位和列混合搞反了顺序——我曾经也犯过,跑出来的结果跟标准向量对不上,排查了一下午。
3.3 密钥扩展:从短密钥到多个轮密钥
AES支持3种密钥长度:128位、192位、256位。不同的密钥长度,对应的加密轮数也不同。
| 密钥长度 | 轮数 | 状态矩阵大小 |
|---|---|---|
| AES-128 | 10轮 | 4x4 字节 |
| AES-192 | 12轮 | 4x4 字节 |
| AES-256 | 14轮 | 4x4 字节 |
加密开始时,我们只有一把原始密钥。但每一轮都需要一个不同的轮密钥。这就需要密钥扩展:从初始密钥派生出所有轮密钥。
我个人的习惯是:在字段级加密场景里,如果对性能要求没那么苛刻,尽量选AES-256。虽然多几轮计算,但安全裕度更大,心里踏实。
3.4 工作模式:怎么用AES去加密任意长度数据?
AES本身只是个“块密码”,它只能加密128位的数据块。但你不可能所有数据都正好128位吧?
所以就有了工作模式——解决两个问题:
- 怎么处理超过128位的数据
- 怎么保证同样的数据加密后不产生同样的密文(防模式识别)
下面这几种模式,你在实际开发中大概率会遇到:
3.4.1 ECB模式(电子密码本)
最简单。把数据切块,每块独立加密。问题是:相同明文块 → 相同密文块。
我曾经在客户的项目里见过有人用ECB加密头像图片。结果密文里还能看出图片的轮廓!因为每个像素块加密后,颜色分布没变。这太危险了。
警告:除非你确定数据里的每一个块都不重复,并且安全性要求极低,否则不要在生产环境里用ECB。它不提供语义安全。
3.4.2 CBC模式(密码分组链接)
每个明文块在加密前,先跟上一块的密文做异或。这样同样的明文块在不同的位置上,会得到不同的密文。
但CBC有一个麻烦:它需要随机初始向量(IV)。IV的长度等于块大小(128位)。而且IV必须随机、唯一。
问题是:CBC不能并行解密。因为解密时依赖前一块的密文。不过字段级加密的数据量通常不大,这倒不是大问题。
3.4.3 CTR模式(计数器模式)
这是我最喜欢的模式。不直接加密明文,而是加密一个递增的计数器,再把结果跟明文异或。
好处太多了:
- 可并行计算:每个计数器块可以同时加密
- 不需要填补:数据长度可以是任意值
- 支持随机访问:解密时只计算需要的块
在实际字段级加密中,我建议优先考虑CTR模式。它的实现简洁,效率高,而且在现代CPU上有硬件加速支持。
3.4.4 GCM模式(伽罗瓦/计数器模式)
GCM = CTR + 认证标签。加密的同时生成一个MAC(消息认证码),保证密文没被篡改。
在字段级加密里,如果你需要同时保证机密性和完整性,GCM是首选。比如加密后要把数据存到数据库里,GCM能发现有没有人偷偷改过你的数据。
# 用Python的cryptography库做GCM加密
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
import os
# 密钥必须是32字节(256位)
key = AESGCM.generate_key(bit_length=256)
aesgcm = AESGCM(key)
# 随机生成96位nonce
nonce = os.urandom(12)
# 加密明文(附加认证数据AAD是可选的)
ciphertext = aesgcm.encrypt(nonce, b"这是一段字段数据", b"")
print(ciphertext.hex())
# 解密
plaintext = aesgcm.decrypt(nonce, ciphertext, b"")
print(plaintext)
经验之谈:我真的建议你在生产环境中使用AES-GCM而不是AES-CBC+HMAC。GCM把加密和认证合为一体,减少了很多容易出错的组合步骤。很多人为了省事,自以为组合对了,结果留下的漏洞比预期的多。
3.5 工作模式对比:选哪个?
为了方便你决策,我把常用模式的关键特性列了一张表:
| 模式 | 并行性 | 需要IV/nonce | 需要填补 | 认证保护 | 推荐场景 |
|---|---|---|---|---|---|
| ECB | 是 | 否 | 是 | 否 | 不推荐 |
| CBC | 仅解密 | 是(随机IV) | 是 | 否 | 兼容老旧系统时使用 |
| CTR | 是 | 是(随机nonce) | 否 | 否 | 高性能加密 |
| GCM | 是 | 是(随机12字节nonce) | 否 | 是 | 字段级加密首选 |
3.6 实战建议:字段级加密中的AES配置
在实际的字段级加密项目里,我通常按这个标准来配置:
- 算法:AES-256
- 工作模式:GCM或CTR
- 密钥管理:密钥不要硬编码在代码里,用密钥管理服务(KMS)或安全硬件模块(HSM)
- IV/nonce管理:每个加密操作都生成一个新的随机值。保证不重用同一个IV+密钥组合
- 认证数据:在GCM里把字段名或实体ID作为AAD传入,这样可以绑定密文到具体字段
嗯,这里还要提醒一点:你加密的字段如果很短(比如手机号11位),用什么模式区别不大。但如果是长文本字段,CTR或GCM会明显比CBC快。
3.7 本章知识结构
下面这张图,帮你把AES的加解密流程和模式之间的关系理清楚:
图中左半部分画的是AES加密的全流程——从明文进来,经过密钥扩展和N轮替换-置换,最终输出密文。右半部分则是加密后选择工作模式的决策树,提醒你不同模式有不同的侧重点。
好了,这章的内容就到这儿。AES的原理和模式搞清楚了,下一块知识我们就能直接上手加密实战了。