什么是AES?它为什么成为对称加密的“行业标准”
AES的全称是Advanced Encryption Standard(高级加密标准),是NIST(美国国家标准与技术研究院)在2001年选定的对称加密算法,用来取代安全性不足的DES(数据加密标准)。它能成为“行业标准”,核心原因有三个:

- 支持多密钥长度:AES允许使用128位、192位或256位密钥,其中128位密钥已能抵御当前所有已知的暴力破解(即使是量子计算机,破解128位密钥也需要约10^38次运算,这在可预见的未来都不可能实现);
- 软硬件实现高效:AES的设计基于字节操作,而非位操作,无论是在CPU、GPU还是嵌入式设备上,都能快速运行——比如128位AES加密的速度可达每秒数GB,适合大数据量场景(如磁盘加密、文件传输);
- 公开且经过严格验证:AES的算法细节完全公开,全球密码学家已经对它进行了20多年的攻击测试,至今没有发现致命漏洞(唯一的风险是“侧信道攻击”,但这是实现问题,不是算法本身的缺陷)。
作为对称加密算法,AES的核心特点是“同一密钥加解密”——加密者用密钥把明文变成密文,解密者用同样的密钥把密文恢复成明文。这种特性让它比非对称加密(如RSA)快得多,但也要求密钥必须安全传递(比如用RSA加密AES密钥,再用AES加密数据,这就是“混合加密”的常用模式)。
AES的核心原理:从S盒到轮变换的底层逻辑
AES的加密过程本质是“多轮变换”——把明文通过一系列固定操作(轮运算)转换成密文,每一轮的操作都由四个核心步骤组成:
1. 字节替代(SubBytes):用S盒做“非线性替换”
字节替代是AES中唯一的非线性操作(非线性才能让加密结果不可预测),它的工具是S盒(Substitution Box)——一个预定义的16×16的字节表,每个字节对应一个唯一的替换值。比如:
– 输入字节0x00
,查S盒得到0x63
;
– 输入字节0x12
,查S盒得到0xC9
。
你可以把S盒理解成“密码本”:每个明文字节都要换成S盒里的“暗号”,这样即使两个相同的明文字节,也会变成不同的密文字节(前提是它们在不同的轮次或位置)。
2. 行移位(ShiftRows):让行数据“错位”
行移位是对状态矩阵(AES把明文拆成4×4的字节矩阵)的行进行循环移位:
– 第1行(索引0):不变;
– 第2行(索引1):左移1位;
– 第3行(索引2):左移2位;
– 第4行(索引3):左移3位。
比如,假设行移位前的第二行是[0x12, 0x34, 0x56, 0x78]
,行移位后会变成[0x34, 0x56, 0x78, 0x12]
。这个操作的目的是混淆行内的字节顺序,让单个字节的变化影响整个行。
3. 列混淆(MixColumns):用多项式乘法“搅乱”列
列混淆是AES中最复杂的操作,它对状态矩阵的每一列进行有限域多项式乘法——用固定的多项式0x03x³ + 0x01x² + 0x01x + 0x02
(即字节0x03
、0x01
、0x01
、0x02
)乘以该列的每个字节,结果模0x11B
(即有限域GF(2^8)的本原多项式)。
举个简单的例子:假设某一列是[0x01, 0x02, 0x03, 0x04]
,列混淆后的值会变成[0x0B, 0x0E, 0x08, 0x04]
(具体计算可以查AES标准,但你不需要记住细节——关键是知道这个操作能让一个列的变化影响整个列的所有字节)。
4. 轮密钥加(AddRoundKey):用密钥“盖戳”
轮密钥加是把当前状态矩阵和轮密钥(从主密钥扩展来的子密钥)进行异或操作(相同为0,不同为1)。比如状态字节0x12
和轮密钥字节0x34
异或后得到0x26
。
这个操作的核心是把密钥信息注入每一轮的加密过程——没有轮密钥,即使知道前三个操作的细节,也无法恢复明文。
AES的加密流程:一步一步拆解轮运算
以最常用的128位密钥为例(对应10轮加密),AES的完整流程如下:
步骤1:准备状态矩阵和轮密钥
- 状态矩阵:把明文分成16字节的块(比如“Hello AES Encryption”会被分成多个16字节块),每个块组成4×4的矩阵(行优先,即第一个字节放在(0,0),第二个在(0,1),直到第16个在(3,3));
- 轮密钥扩展:用主密钥生成11个轮密钥(128位密钥需要11轮,每轮4个32位字,共44个字)——扩展算法会把主密钥“拉长”成多轮密钥,确保每一轮的密钥都不同。
步骤2:初始轮密钥加
把状态矩阵和第一轮密钥(轮密钥扩展的第一个结果)进行异或操作——这是加密的“起点”,让明文第一次和密钥结合。
步骤3:9轮完整轮运算
每一轮都依次执行:字节替代→行移位→列混淆→轮密钥加。比如:
– 第1轮:状态矩阵经过SubBytes→ShiftRows→MixColumns→AddRoundKey,得到第1轮后的状态;
– 第2轮:用第1轮的状态重复上述操作,直到第9轮。
步骤4:最后一轮运算
最后一轮(第10轮)的操作略有不同:字节替代→行移位→轮密钥加(去掉了列混淆)。这是因为列混淆是线性操作,最后一轮去掉它能让密文更难被分析(避免线性关系被利用)。
步骤5:输出密文
最后一轮后的状态矩阵就是密文——把它按行优先的顺序拼接起来,就是最终的密文字节流。
AES的常用模式:选对模式才能保证安全
AES本身是“分组加密算法”(只能加密固定长度的块,比如128位),但实际场景中,我们需要加密任意长度的数据(比如1KB的文件、1MB的图片),这时候就需要工作模式(Mode of Operation)——把分组加密扩展成流加密的规则。
常用的AES模式有以下几种,我用表格帮你对比它们的特点:
模式 | 核心特点 | 适用场景 | 安全风险 |
---|---|---|---|
ECB | 每个块独立加密 | 无重复的小数据(如密钥) | 相同明文块生成相同密文块→易被攻击(比如加密图片会保留轮廓) |
CBC | 前一个块的密文和当前块异或 | 文件加密、磁盘加密 | 需要随机IV(初始化向量)→IV重复会导致相同明文前16字节密文相同 |
CTR | 用计数器生成流密钥 | 实时数据(视频、音频) | 需要唯一计数器→计数器重复会泄露明文 |
GCM | 加密+认证(AEAD模式) | 网络通信(HTTPS、API) | 需要正确实现认证标签→标签泄露会导致密文被篡改 |
重点提醒:
– 永远不要用ECB模式——除非你想让攻击者一眼看出你的加密漏洞;
– 优先用GCM模式——它支持机密性+完整性+真实性(三个都满足才叫“安全”),而且性能比CBC+MAC(分开加密和认证)好得多。
AES的实战实现:用Python写一个简单的加密程序
理论讲得再多,不如写一行代码——我们用pycryptodome库(Python的加密库)实现一个AES-GCM模式的加密程序:
步骤1:安装依赖
pip install pycryptodome
步骤2:编写加密和解密代码
from Crypto.Cipher import AES
from Crypto.Random import get_random_bytes
from Crypto.Util.Padding import pad, unpad
def aes_gcm_encrypt(plaintext: str, key: bytes) -> tuple[bytes, bytes, bytes]:
"""用AES-GCM模式加密明文"""
# 生成12字节的IV(GCM模式推荐用12字节,性能最好)
iv = get_random_bytes(12)
# 创建AES加密器(GCM模式)
cipher = AES.new(key, AES.MODE_GCM, iv=iv)
# 填充明文(AES要求块大小为16字节)
padded_plaintext = pad(plaintext.encode(), AES.block_size)
# 加密:返回密文和认证标签(用于验证密文完整性)
ciphertext, tag = cipher.encrypt_and_digest(padded_plaintext)
return iv, ciphertext, tag
def aes_gcm_decrypt(iv: bytes, ciphertext: bytes, tag: bytes, key: bytes) -> str:
"""用AES-GCM模式解密密文"""
# 创建AES解密器
decipher = AES.new(key, AES.MODE_GCM, iv=iv)
try:
# 解密并验证标签(标签不对会抛出ValueError)
padded_plaintext = decipher.decrypt_and_verify(ciphertext, tag)
# 去除填充
plaintext = unpad(padded_plaintext, AES.block_size)
return plaintext.decode()
except ValueError:
return "密文被篡改或密钥错误!"
# 测试代码
if __name__ == "__main__":
# 生成128位密钥(16字节)
key = get_random_bytes(16)
plaintext = "这是一段需要加密的明文:AES-GCM模式测试"
# 加密
iv, ciphertext, tag = aes_gcm_encrypt(plaintext, key)
print("IV:", iv.hex())
print("密文:", ciphertext.hex())
print("认证标签:", tag.hex())
# 解密
decrypted_text = aes_gcm_decrypt(iv, ciphertext, tag, key)
print("解密结果:", decrypted_text)
代码说明:
- IV:初始化向量,GCM模式要求IV必须随机且唯一(用
get_random_bytes
生成); - 认证标签:GCM模式会生成一个16字节的标签,用于验证密文是否被篡改(解密时如果标签不对,会直接报错);
- 填充:AES要求明文长度是16字节的整数倍,
pad
函数会在明文末尾添加填充字节(比如添加x05
五次),unpad
会在解密后去除。
AES的安全注意事项:避开这些常见坑
AES本身是安全的,但错误的实现会让它变成“纸老虎”——以下是最容易踩的坑:
1. 密钥长度不要选太短
- 128位密钥:足够安全(抵御当前所有暴力破解);
- 192/256位密钥:适合高安全需求(比如政府、金融),但性能比128位慢约10%-20%;
- 不要用64位或更短的密钥——这和“裸奔”没区别。
2. IV必须随机且唯一
- CBC模式下,IV重复会导致相同明文生成相同密文(比如加密“Hello”两次,密文一样);
- GCM模式下,IV重复会导致密钥泄露(攻击者能恢复主密钥);
- 正确的做法:用
os.urandom
(Python)或SecureRandom
(Java)生成IV,不要用固定值(比如0x0000000000000000
)。
3. 不要用ECB模式加密重复数据
ECB模式的致命缺陷是“相同明文块生成相同密文块”——比如加密一张有重复图案的图片,加密后的图片会清晰保留原图案的轮廓(参考下图)。如果你需要加密重复数据,一定要用CBC、CTR或GCM模式。
4. 用AEAD模式代替“加密+MAC”
很多人习惯用“CBC模式加密+SHA-256生成MAC”(先加密再算认证码),但这种方式容易受到padding oracle攻击(攻击者通过修改密文的padding字节,推断出明文)。
正确的做法是用AEAD模式(Authenticated Encryption with Associated Data)——比如GCM、CCM,它们能同时实现加密和认证,而且避免了padding oracle攻击。
5. 密钥管理比算法更重要
AES的安全依赖于密钥的保密性——如果密钥泄露,即使算法再强也没用。以下是密钥管理的几个要点:
– 不要硬编码密钥在代码里(比如key = b"my_secret_key"
);
– 用密钥管理系统(KMS)存储密钥(比如AWS KMS、阿里云KMS、HashiCorp Vault);
– 定期轮换密钥(比如每6个月换一次)——即使密钥泄露,影响范围也会变小。
原创文章,作者:,如若转载,请注明出处:https://zube.cn/archives/244