结论:cryptography库+aes-gcm比pycryptodome+cbc更安全省心,尤其适合文件加解密;因gcm同时提供加密与完整性认证,且nonce必须每次随机生成(推荐12字节)、不可复用,salt也须随机且随密文保存,密钥应通过scrypt等kdf派生,大文件需分块处理以防内存溢出。

直接说结论:用 cryptography 库 + AES-GCM 模式,比 pycryptodome + CBC 更安全、更省心,尤其适合文件级加解密。
为什么别用硬编码 IV 或固定 salt
常见错误是把 iv 写死成 b'0102030405060708',或每次用同一个 salt。这会导致相同明文生成相同密文,攻击者可做“确定性加密”分析——比如你反复加密“salary.xlsx”,别人只要看到两次密文一样,就知道内容没变。
- IV(nonce)必须每次随机生成,且 GCM 模式下绝不能复用;12 字节是推荐长度,不是 16
- salt 必须随密文一起保存(通常前置),否则无法从密码还原出正确密钥
- 别用
hashlib.sha256(password).digest()直接当密钥——它不抗暴力穷举,也不防彩虹表
用 Scrypt 衍生密钥比 PBKDF2 更稳妥
Scrypt 在内存消耗和计算成本上比 PBKDF2HMAC 更难被 GPU/ASIC 硬件加速破解,对用户密码保护更强。参数 n=2**14 是当前较平衡的起点:太小不安全,太大卡顿。
- 必须用新
salt = os.urandom(16),每次加密都不同 -
length=32对应 AES-256,别写成 16(那是 AES-128) - 密钥派生后不能缓存或日志打印,哪怕只调试一次
加密时写入顺序决定解密能否成功
文件开头怎么组织字节,解密时就得严格按同样顺序读取。典型结构是:salt(16B)→ nonce(12B)→ ciphertext → tag(16B)。GCM 的 tag 是完整性校验码,缺了就无法验证是否被篡改。
- 写入时用
f_out.write(nonce)前,得先写salt;否则解密函数读前 16 字节会误当成salt,实际却是nonce - GCM 模式下,
encryptor.finalize()返回的是tag,必须和密文一起落盘 - 不要把
tag存在单独文件里——它和密文是一体的,分离即失效
大文件必须分块读写,否则 OOM
一次性 f.read() 整个 2GB 文件,Python 进程内存直接飙到 3GB+,尤其在低配机器上必崩。AES-GCM 支持流式加解密,但需手动处理 padding(GCM 本身不需填充)和 chunk 边界。
- 建议缓冲区设为
64 * 1024(64KB),兼顾 IO 效率与内存压力 - 加密器
encryptor.update(chunk)可多次调用,最后finalize()得到 tag - 解密时同样分块
decryptor.update(),但tag必须等全部密文读完再传给decryptor.finalize()
最易被忽略的一点:GCM 的 nonce 虽然只需 12 字节,但若你把它和 salt 都写进文件头,就必须确保解密端能精确切分——少读 1 字节,后续全错。这不是逻辑 bug,是字节布局 bug,调试时很难一眼看出。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











