不能直接用AES.new()加密明文,因为AES是分组密码,要求明文长度为16字节整数倍且需填充(如PKCS7),ECB模式不安全,CBC需随机IV、GCM更优但nonce不可复用;密钥须严格16/24/32字节,推荐PBKDF2派生;IV必须每次随机生成并随文传输,密钥须环境变量或KMS管理;GCM提供认证加密,解密必须校验tag,nonce复用将导致密钥泄露。

为什么不能直接用 pycryptodome 的 AES.new() 加密明文?
因为 AES 是分组密码,原始明文长度必须是 16 字节(AES-128)的整数倍,且 ECB 模式极度不安全——相同明文块加密后完全一致,会暴露数据模式。实际中必须搭配填充(如 PKCS7)和安全模式(如 CBC、GCM)。pycryptodome 不自动处理填充,也不校验密钥/IV 长度是否合规,直接调用 AES.new(key, AES.MODE_CBC, iv) 很容易触发 ValueError: IV must be 16 bytes long 或静默加密失败。
实操建议:
立即学习“Python免费学习笔记(深入)”;
图片提示词生成器?不止如此。 马甲系统 —— 把脑海中的画面,翻译成AI能理解的专业表达。 用得越多,它越懂你:首次需要多问几句确认方向,用久了几乎一说就懂。 用得越多,它越快:缓存机制让后续对话越来越省。 RAG进化:成功案例持续入库,越跑越聪明。 输入「新手指南」查看完整功能介绍
- 始终显式使用
PKCS7填充:用pad(data, block_size=16)补齐,解密后用unpad(padded_data, block_size=16)剥离 - CBC 模式下,
iv必须随机生成且每次不同,不能复用;GCM 模式更优(自带认证),但要求nonce同样不可复用 - 密钥必须是 16/24/32 字节(对应 AES-128/192/256),不能直接传字符串;推荐用
hashlib.pbkdf2_hmac('sha256', password.encode(), salt, 100_000)衍生密钥
如何安全地生成和保管 AES 密钥与 IV?
把密钥硬编码在代码里、或存在配置文件中,等于没加密。IV 虽可公开,但必须唯一且不可预测;密钥则必须隔离存储。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 运行时从环境变量读密钥(如
os.getenv('AES_KEY')),并确保该变量只对当前进程可读;生产环境用密钥管理服务(如 AWS KMS、HashiCorp Vault)获取密钥 - IV 每次加密都重新生成:
iv = get_random_bytes(16),然后和密文一起保存(如base64.b64encode(iv + cipher_text)),无需保密 - 绝对不要用时间戳、计数器或固定值当 IV —— 这会导致 CBC 下的“确定性加密”,极易被重放或字节翻转攻击
为什么 GCM 模式比 CBC 更适合现代应用?
CBC 只提供机密性,不验证完整性;攻击者可在密文上做位翻转,解密后得到可控的错误明文(比如把 “false” 改成 “true”)。GCM 同时提供加密和认证标签(auth_tag),解密时必须校验该标签,否则直接报错。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 优先选
AES.MODE_GCM,初始化时传入nonce(等价于 IV,但长度通常为 12 字节):cipher = AES.new(key, AES.MODE_GCM, nonce=nonce) - 加密后必须保存
cipher.nonce和auth_tag,缺一不可;解密时需完整传入三者:cipher = AES.new(key, AES.MODE_GCM, nonce=nonce); cipher.decrypt_and_verify(ciphertext, auth_tag) - GCM 对 nonce 复用极其敏感:一旦重复,密钥可能被直接恢复。务必用
get_random_bytes(12)生成,别用time.time()或自增 ID
Python 中最简可用的 AES-GCM 封装长什么样?
不依赖额外框架、不省略关键校验、能直接复制进项目跑通的最小可靠实现。
from Crypto.Cipher import AES
from Crypto.Random import get_random_bytes
from base64 import b64encode, b64decode
def encrypt_gcm(plaintext: str, key: bytes) -> str:
nonce = get_random_bytes(12)
cipher = AES.new(key, AES.MODE_GCM, nonce=nonce)
ciphertext, tag = cipher.encrypt_and_verify(plaintext.encode(), b'')
return b64encode(nonce + tag + ciphertext).decode()
def decrypt_gcm(encoded: str, key: bytes) -> str:
raw = b64decode(encoded)
nonce, tag, ciphertext = raw[:12], raw[12:28], raw[28:]
cipher = AES.new(key, AES.MODE_GCM, nonce=nonce)
return cipher.decrypt_and_verify(ciphertext, tag).decode()
注意:b'' 是附加认证数据(AAD),若需额外绑定上下文(如用户 ID、时间窗口),可传入非空字节串;密钥长度必须严格为 32 字节(AES-256),否则 AES.new() 会静默截断或报错。
真正麻烦的从来不是写几行加密代码,而是密钥生命周期管理、nonce 生成策略、错误处理粒度(比如认证失败该返回 400 还是 403)、以及是否允许降级到无认证模式——这些地方一松懈,前面所有加密都形同虚设。

















