对称加密基础:AES算法要点归纳
讲字段级加密,绕不开AES。
它现在是全球标准。银行、云服务、物联网,都在用。
我个人习惯,只要项目没有特殊合规要求,对称加密默认选AES。为什么?因为它经过二十年公开检验,目前没有有效的攻击方式。
AES 是什么?不是新的,但很稳
AES 的前身叫 Rijndael 算法。2001年被美国NIST定为标准。
说白了,它就是一套用同一个密钥加密和解密的规则。速度快,硬件支持好。
来,看核心参数:
| 特性 | 值 |
|---|---|
| 数据块大小 | 128位(固定) |
| 密钥长度 | 128、192、256位 |
| 轮数 | 10(128位)、12(192位)、14(256位) |
| 支持操作模式 | ECB、CBC、CTR、GCM等 |
注意,数据块必须是128位。密钥越长,轮数越多,越安全。我司的支付系统在PCI-DSS合规改造时,统一要求AES-256。大家记住,AES-128 当前够用,但很多监管已经强制 AES-256 了。
内部到底干了什么?
这里我用一张图说明 AES-128 的加密流程。你看,它就四个基本操作,重复十轮。
搞懂这张图,AES就算入门了。
我一个个讲。你想想看,每次加密都要把数据切成128位的小块,然后对每个块跑十轮操作。
四个核心步骤,真正干活
1. 字节代换(SubBytes)
这一步的本质是查表。每个字节都通过S盒映射成另一个字节。S盒是设计好的非线性变换。它提供了混淆性。
嗯,S盒的实现细节我就不展开讲了。它在硬件里通常用查找表,在软件里也一样。关键是它抵抗线性攻击和差分攻击。
2. 行移位(ShiftRows)
把状态矩阵的每一行循环左移。第一行不移,第二行移1字节,第三行移2字节,第四行移3字节。
你可以想象成搬砖。每块数据在行之间交换位置。这就实现了扩散。
为什么要这么做? 如果不移位,每一列的变化影响不到其他列,加密就太弱了。
3. 列混合(MixColumns)
这步稍微数学一点。每列的四个字节,通过一个固定矩阵乘法得到新值。注意是在有限域GF(2⁸)上运算。
简单说,它让一列的四个字节互相影响。在项目中我见过有人把这个函数写错,结果密文解密后全是乱码。后来调试了一整天才发现是伽罗瓦域乘法实现有bug。
4. 轮密钥加(AddRoundKey)
把状态矩阵和轮密钥做XOR。
这一步很简单但至关重要。没它,加密就是一纸空文。密钥扩展算法保证每轮的密钥都不一样。
好,再看一眼流程图。
避坑指南: 我曾经在嵌入式项目里直接用AES原生算法加密固件包,结果发现每密文块长度和明文一样。后来一想,对了,AES是块加密,没加填充算法和认证模式。密码用对了,模式用错了,照样被攻破。
密钥扩展:不要直接用密钥硬编码
AES的总轮密钥位数 = 块大小 × (轮数+1)。
比如AES-128:128 × (10+1) = 1408位。
密钥扩展算法流程(概括版):
- 将原始密钥(16、24或32字节)放入前Nk个字。
- 每轮生成一个字(4字节):
- 如果 i mod Nk == 0:先循环左移,再S盒代换,然后与轮常数异或。
- AES-256还有额外的S盒操作。
- 将所有字排成阵列,用于每轮轮密钥加。
我踩过的一个坑,是大家在代码里把AES密钥直接当轮密钥用。结果呢?第一轮完了就没了。需要扩展出10轮(128位)或14轮(256位)的完整子密钥。
操作模式:你知道CBC和GCM的区别吗?
AES本身只定义块加密。实际使用时需要模式。
| 模式 | 特性 | 适用场景 |
|---|---|---|
| ECB | 相同明文块产生相同密文块 | 基本不用 |
| CBC | 需要初始化向量(IV),前后块关联 | 文件加密、数据库列 |
| CTR | 流式加密,可并行 | 高性能、网络传输 |
| GCM | AEAD,同时保证机密性和完整性 | 字段级加密、API令牌 |
我的建议是,能用GCM就别用CBC。GCM自带认证标签,可以检测篡改。你想想看,CBC模式下,如果攻击者改变了第一个块,后面所有块都变成乱码,但服务器可能误报、没有报错,数据已经损坏。GCM直接返回失败。
警告: ECB模式不要用于生产环境。我记得在PayPal的早期API里看到过ECB加密的漏洞——同一用户ID每次加密结果一样,攻击者直接通过密文比对就能知道用户重复提交。这就是EVE(类似CBC的漏洞)?不,这是ECB的先天性缺陷。
实践要点
- 密钥管理:不要硬编码密钥到代码里。使用KMS或HSM。
- IV要求:CBC和GCM的IV必须唯一。重复IV等于没加密。
- 填充方式:AES是块加密,明文长度不一定是16倍。PKCS#7填充最常见。
- 性能:AES-128比AES-256快约40%。但很多合规要求256。自已权衡。
来一组实际代码示例(Python),这是我常用来测试项目加密模块的片段:
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
import os
# 生成密钥和IV
key = os.urandom(32) # AES-256
iv = os.urandom(12) # GCM模式的nonce
# 构造加密器
cipher = Cipher(algorithms.AES(key), modes.GCM(iv))
encryptor = cipher.encryptor()
# 加密
plaintext = b"pay_password"
ciphertext = encryptor.update(plaintext) + encryptor.finalize()
# 获取认证标签
tag = encryptor.tag
# 解密
decryptor = Cipher(algorithms.AES(key), modes.GCM(iv, tag)).decryptor()
decrypted = decryptor.update(ciphertext) + decryptor.finalize()
print(decrypted) # 输出 b"pay_password"
这段代码我经常在微服务里做字段级加密的基准测试。
注意: GCM模式下,如果密文或tag被篡改,解密会抛出异常。不要忽略这个异常——它保护你的数据完整性。
说在最后
AES不是万能药。但它是对称加密领域最成熟的选项。只要密钥管理和模式选择不出错,它足够保护你的字段级数据。
我遇到过年轻工程师问:「AES会不会过时?」短期不会。它的安全性在可预见的未来内足够抵御量子计算机以外的威胁——记住,后量子时代才考虑替代。现在,专心把AES用对。