AES.new() 加密字符串会失败,因为 AES 是分组密码,需手动处理块对齐、填充、模式选择和密钥合规性;常见错误源于密钥长度(16/24/32字节)、IV长度(CBC需16字节)、明文填充及ECB禁用等未严格满足。

直接用 AES.new() 加密字符串会失败,因为 AES 是分组密码,必须处理块对齐、填充、模式选择和密钥合规性——这些都不是自动完成的。
为什么 AES.new(key, AES.MODE_CBC, iv) 常报错或静默出错?
常见错误包括 ValueError: IV must be 16 bytes long、ValueError: Invalid key size 或解密后出现乱码/报 ValueError: Padding is incorrect。根本原因是 pycryptodome 不做任何输入校验:传入 15 字节密钥、17 字节 IV、未填充明文,它都可能不抛错但结果不可逆。
- 密钥必须严格为
16(AES-128)、24(AES-192)或32字节(AES-256),不能是任意长度字符串 - IV 必须恰好
16字节(CBC/ECB)或12字节(GCM),且每次加密必须全新生成 - 明文必须填充到块大小(
AES.block_size == 16)的整数倍;pad()和unpad()必须成对使用 - ECB 模式绝对禁用——相同字段(如
"enabled": true)加密后字节完全一致,暴露结构
如何把口令字符串安全转成 AES 密钥?
用户记忆的密码(如 "my-secret-2026")不能直接当密钥用:长度不对、熵不足、易被暴力破解。必须用密钥派生函数(KDF)拉伸处理。
- 用
hashlib.pbkdf2_hmac('sha256', password.encode(), salt, 100_000)生成 32 字节密钥(适配 AES-256) -
salt必须随机且唯一,每次加密都重生成(如get_random_bytes(16)),并和密文一起保存 - 硬编码 salt 或复用 salt = 等于削弱 KDF 效果;用固定迭代次数(如
100_000)保证抗暴力能力 - 环境变量中只存原始口令(
os.getenv('CONFIG_PASSPHRASE')),绝不存派生后的密钥
推荐用 GCM 模式而非 CBC 处理配置项
配置信息常含布尔、数字、路径等短字段,CBC 下位翻转攻击可精准篡改(如把 "false" 改成 "true"),而 GCM 自带完整性校验,解密时 tag 不匹配直接报错,防篡改能力更强。
立即学习“Python免费学习笔记(深入)”;
- GCM 初始化用
AES.new(key, AES.MODE_GCM, nonce=nonce),nonce长度建议12字节(兼容性好),同样需每次随机生成 - 加密返回
ciphertext和tag,二者缺一不可;解密时必须传入完整nonce + ciphertext + tag - 切勿复用 nonce:同一密钥下两次相同 nonce → 攻击者可恢复密钥 → 全量密文失效
- Base64 编码时把
nonce + ciphertext + tag拼接再编码,解码后按固定长度拆分(如 nonce=12, tag=16)
最易被忽略的是密钥生命周期管理:配置加密不是“加一次就完事”。IV/nonce 可随密文公开,但 salt、passphrase、KMS 凭据这些必须严格隔离;本地开发可用环境变量,生产务必走 Vault 或 KMS —— 否则加密等于给门装了锁,钥匙却贴在门框上。


















