不能直接用 encrypt() 处理整个文件,因为aes要求输入为长度合规的完整字节块,加载10gb文件会内存溢出;cbc等模式需全局填充且无法并行,而ctr模式每块独立、支持流式加密,需配合随机nonce、递增计数器及明文头部(32字节魔数+nonce+版本号)实现安全分块加密。

为什么不能直接用 encrypt() 处理整个文件?
因为 AES 等对称加密函数(如 pycryptodome 的 AES.new().encrypt())要求输入是完整、长度合规的字节块。读入 10GB 文件到内存再加密,会直接触发 MemoryError 或让系统开始疯狂 swap。更糟的是,某些模式(如 CBC)还需要填充(padding),而填充必须基于**全部数据长度**——你根本没法在流式处理中提前知道总长。
必须用分块 + 流式模式:选 CTR 或 OFB,别碰 CBC
CBC 模式依赖前一块密文,无法真正并行分块;且解密时必须从头开始,无法随机访问。而 CTR 把 AES 当作伪随机数生成器,加密 = 明文 ⊕ AES(Nonce + Counter),每块独立可算。实操建议:
- 用
Counter类(来自pycryptodome)构造递增计数器,起始值存进文件头 - Nonce 随机生成 16 字节(AES-128),和计数器高位拼接,确保每文件唯一
- 每块大小设为
64 * 1024(64KB),太小增加调用开销,太大仍占内存 - 避免手动拼接
nonce + counter字节——用Counter.new(nbits=128, initial_value=...)更安全
文件头怎么设计才不破坏流式结构?
不能把元数据塞进加密流中间,否则解密错位。标准做法是「明文头部 + 加密主体」:
- 头部固定 32 字节:
0x454E43525950544544("ENCRYPTED" ASCII)+ 16 字节随机nonce - 头部不加密,解密端先读 32 字节校验魔数、提取
nonce,再初始化CTR模式 - 切忌把文件总长写进头部——
CTR不需要它;也不用存块数,EOF 就是结束信号 - 头部末尾留 1 字节版本号(如
0x01),方便以后升级格式
实际代码里最容易漏掉的三件事
很多人写完逻辑能跑通,但一换环境或大文件就失败。关键细节:
- 打开文件必须用
rb/wb模式,文本模式会悄悄改换行符,导致解密错乱 - 加密后立即
out_file.flush(),尤其配合os.fsync(),防止断电丢最后一块 -
Counter初始化时,initial_value必须是整数(不是 bytes),且要保证高位不溢出——推荐用int.from_bytes(nonce, 'big') & 0xFFFFFFFFFFFFFFF0清零低 4 位,留给计数器递增空间
流式加密没「一步到位」的封装,每个环节都得自己掐住边界。最常出问题的不是算法,而是 nonce 复用、文件模式错误、或计数器跨块没续上——这些地方一旦错,解密出来的就是彻底乱码,连报错都不会有。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











