python-mini-projects 文件与文件夹加密实战:深入解析 AES-128 CFB 加密脚本 encrypt.py
【免费下载链接】python-mini-projectsA collection of simple python mini projects to enhance your python skills项目地址: https://gitcode.com/gh_mirrors/py/python-mini-projects
导读
本文围绕 python-mini-projects 仓库中的 Create_a_script_to_encrypt_files_and_folder 项目展开,系统讲解如何用一条命令行将单个文件或整个文件夹加密为.bin密文文件。文章不仅完整复刻原文档的使用方法,还深入 encrypt.py 的源码实现,剖析 AES-128 加密、CFB 分组模式、随机 IV 生成与落盘细节,并给出解密思路与已知限制,帮助读者真正掌握"脚本加密文件与文件夹"这一实战技能。
一、项目定位与整体设计
该迷你项目的核心诉求非常明确:在不引入复杂图形界面的前提下,用最少的代码实现对文件和文件夹的对称加密。从目录结构看,项目仅包含三个文件:
- README.md:说明脚本的调用方式与输出产物;
- encrypt.py:全部加密逻辑所在,共 39 行;
- requirements.txt:声明唯一依赖
pycryptodome==3.9.8。
加密方案上,脚本选用PyCryptodome库实现的AES 对称加密,配合CFB(Cipher Feedback,密码反馈)模式。AES 是当前使用最广泛的对称分组密码标准,CFB 模式则将分组密码转换为流密码的工作方式,对数据逐段异或加密,天然支持任意长度明文,无需像 ECB/CBC 那样进行 PKCS#7 填充,非常适合文件这种长度不固定的场景。
脚本对外暴露一个统一接口python encrypt.py <path>,内部根据路径类型自动分流:目录走目录遍历加密,普通文件走单文件加密,其余特殊文件(socket、FIFO、设备文件)则给出提示。
二、环境准备:安装加密依赖
脚本对第三方库的依赖极简,仅需 PyCryptodome。官方 requirements.txt 中锁定版本为:
pycryptodome==3.9.8安装命令:
pip install -r projects/Create_a_script_to_encrypt_files_and_folder/requirements.txt # 或直接 pip install pycryptodome==3.9.8安装完成后,脚本通过from Cryptodome.Cipher import AES与from Cryptodome import Random导入加密能力(PyCryptodome 同时提供Crypto与Cryptodome两种导入名,仓库中的 aes_encode.py 则使用Crypto前缀,二者指向同一套库)。该库支持 Python 2.6 到 3.x 的主流版本,仓库运行环境以 Python 3 为准(脚本中使用了sys.argv、os.walk等标准库)。
三、快速上手:命令行使用方式
原文档给出了完整的使用范式,核心命令格式为:
python encrypt.py path(file or folder)即第一个位置参数path既可以指向一个普通文件,也可以指向一个文件夹,脚本会自动识别。
3.1 加密单个文件
python encrypt.py test.txt运行后,加密产物test.txt.bin会生成在与原文件相同的位置("encrypted files will be generated in original location")。
3.2 加密整个文件夹
python encrypt.py ./testdir脚本会递归遍历testdir下的所有文件并逐一加密,每个文件都产出对应的.bin文件。控制台会打印每个正在处理的文件路径,例如:
testdir/a.txt is encrypting. testdir/sub/b.txt is encrypting.小提示:原 README 中的示例
python eccrypt.py ./testdir(folder)存在拼写笔误(eccrypt),实际可执行脚本名为encrypt.py,请以正确拼写运行。
四、源码级剖析:脚本的三条处理路径
encrypt.py 的整体结构非常清晰,入口逻辑位于文件末尾(第 33~39 行):
path = sys.argv[1] if os.path.isdir(path) and os.path.exists(path): encrypt_dir(path) elif os.path.isfile(path) and os.path.exists(path): encrypt_file(path) else: print("it's a special file(socket,FIFO,device file)")这里先用sys.argv[1]取出命令行传入的路径,再按优先级判断:
- 目录:
os.path.isdir(path)为真且路径存在 → 调用encrypt_dir(path); - 普通文件:
os.path.isfile(path)为真且路径存在 → 调用encrypt_file(path); - 其他情况:路径不存在或属于 socket、FIFO、设备文件等特殊类型 → 打印提示
it's a special file(socket,FIFO,device file)后退出。
注意os.path.isdir对不存在的路径返回False,因此脚本对"路径不存在"与"特殊文件"两种异常统一走了 else 分支,只在控制台给出一条提示,不会抛异常中断。
4.1 单文件加密:encrypt_file 的完整流程
encrypt_file 是核心加密函数,其流程可分四步:
def encrypt_file(path): # get the plaintext with open(path) as f: plain_text = f.read() # The key length must be 16 (AES-128), 24 (AES-192), or 32 (AES-256) Bytes. key = b'this is a 16 key' iv = Random.new().read(AES.block_size) mycipher = AES.new(key, AES.MODE_CFB, iv) ciphertext = iv + mycipher.encrypt(plain_text.encode()) # output with open(path + ".bin", "wb") as file_out: file_out.write(ciphertext[16:])第 1 步:读取明文。open(path)以文本模式读出文件全部内容。这里的隐含约束是:脚本面向文本文件设计(默认按系统编码解码文本,随后plain_text.encode()再编码为 UTF-8 字节流参与加密);对于二进制文件,直接以文本模式读取可能导致解码异常或数据损坏,这一点会在"已知限制"一节展开。
第 2 步:确定密钥。源码将密钥硬编码为 16 字节的b'this is a 16 key',对应AES-128。代码注释同时说明了 AES 对密钥长度的硬性要求:16 字节(AES-128)、24 字节(AES-192)或 32 字节(AES-256),超出或不足都会在AES.new()处抛出ValueError。
第 3 步:生成 IV 并加密。Random.new().read(AES.block_size)从系统安全随机源生成 16 字节(AES.block_size == 16)的初始向量 IV;随后以AES.MODE_CFB模式构造密码对象,将明文编码后的字节流加密,得到mycipher.encrypt(...)。ciphertext = iv + mycipher.encrypt(...)将 IV 拼接到密文头部,这是 CFB 模式的标准做法——解密时必须使用与加密时完全相同的 IV,因此 IV 需要随密文一起保存或传输。
第 4 步:写出密文。以二进制写模式打开path + ".bin",将ciphertext[16:]写入磁盘,即只写入去除 IV 头部后的纯密文流(第 30 行)。这一点值得注意,详见下文"IV 的保存"分析。
4.2 目录加密:encrypt_dir 的遍历逻辑
encrypt_dir 负责文件夹场景:
def encrypt_dir(path): for root, _, files in os.walk("."): for file in files: file_path = os.path.join(root, file) print(file_path + " is encrypting.") encrypt_file(file_path)它利用os.walk递归遍历目录树,对每个子目录下的每个普通文件拼接完整路径后调用encrypt_file逐一加密,并在控制台输出xxx is encrypting.的进度信息。
从源码结构看,这里有一个值得注意的实现细节:函数虽然接收了path参数,但os.walk(".")遍历的是进程的当前工作目录,而非传入的path。也就是说,python encrypt.py ./testdir实际加密的是"在 ./testdir 下运行时该目录内的所有文件",加密结果取决于执行命令时所在的目录。理解这一点有助于规避"加密了非预期文件"的误用场景。
五、加密原理详解:AES-128 + CFB 模式
5.1 为什么选 CFB 模式
AES 本身是分组密码,一次处理 16 字节。若直接对文件分块加密(ECB 模式),相同明文块会生成相同密文块,存在明显的模式泄露风险。CFB 模式通过"反馈链"将 AES 变为流式加密:用密钥加密上一个密文块(首块为 IV)得到密钥流,再与当前明文块异或产生密文块。其特性包括:
- 无需填充:明文长度可以是任意值,适合文本、配置等长度不定的文件;
- 解密可并行性较差但实现简单:解密同样按反馈链顺序进行;
- IV 的随机性直接影响安全性:IV 必须每次加密时重新生成(脚本通过
Random.new()每次随机生成,做法正确),否则相同密钥下相同明文会产生相同密文。
5.2 IV 的生成与保存问题
脚本生成 IV 的方式是标准的:Random.new().read(AES.block_size)从加密安全随机源(PyCryptodome 的Random模块基于操作系统熵源)读取 16 字节。问题出现在写盘环节——file_out.write(ciphertext[16:])将拼接好的iv + ciphertext中的 IV 部分(前 16 字节)丢弃了,落盘的.bin只包含纯密文流。
从源码结构可以推断:由于解密时需要用到加密时的 IV,而该 IV 未随.bin文件持久化,当前脚本产出的密文文件本身并不携带解密所需的完整参数。若要实现可逆的解密,需要额外保存 IV(例如将写入语句改为file_out.write(ciphertext),把 IV 一并落盘)。
5.3 密钥管理
脚本将密钥硬编码在源码中(b'this is a 16 key'),这是教学演示项目常见的简化做法,便于读者直接复现。但在真实生产场景中,硬编码密钥意味着任何拿到源码的人都能解密数据,密钥应通过环境变量、密钥文件或密钥管理系统注入,并按文件单独轮换。
六、解密思路:仓库内配套示例佐证
该目录本身未提供解密脚本,但 python-mini-projects 仓库中同主题的 Encrypt_and_decrypt_text 项目提供了可对照的解密实现 aes_encode.py,其核心解密逻辑为:
key = b'this is a 16 key' iv = ciphertext[:16] # 从密文头部取回 IV mydecrypt = AES.new(key, AES.MODE_CFB, iv) decrypttext = mydecrypt.decrypt(ciphertext[16:])对照这段代码可以清晰理解 CFB 解密所需的三个要素:
- 相同的密钥:与加密端一致的 16 字节密钥;
- 相同的 IV:从密文流头部截取前 16 字节(这正是"加密时将 IV 拼到密文前面"这一设计的原因);
- 相同的模式:
AES.MODE_CFB。
这从侧面印证了第五节的分析——aes_encode.py在解密前通过ciphertext[:16]取回 IV,而本项目的encrypt.py写盘时恰好截掉了这 16 字节,因此如需落地解密功能,建议参考该配套示例并修正 IV 的落盘策略。
七、已知限制与改进方向(基于源码推断)
综合源码实现,可以归纳出以下需要注意或可改进的点:
| 关注点 | 现状(源码依据) | 影响与建议 |
|---|---|---|
| 二进制文件支持 | open(path)以文本模式读取(encrypt.py) | 对图片、压缩包等二进制文件可能解码失败;建议改用open(path, "rb")直接操作字节流 |
| IV 持久化 | 写盘仅写ciphertext[16:](encrypt.py) | 密文文件不含 IV,无法独立解密;建议写入完整ciphertext |
| 密钥硬编码 | 密钥固定为b'this is a 16 key'(encrypt.py) | 仅适合教学演示;生产环境需外部注入并支持 AES-192/256 |
| 目录遍历基准 | os.walk(".")遍历当前工作目录(encrypt.py) | 实际加密范围与执行目录相关,建议改为os.walk(path)并补充"遍历到目录自身"的判断 |
| 文件编码 | 文本模式读取依赖系统默认编码 | 跨平台可能存在编码差异,建议显式指定encoding="utf-8" |
| 加密文件二次加密 | .bin会被再次识别为普通文件 | 重复运行会对已加密文件再加密,建议按扩展名过滤或跳过.bin |
八、总结
本项目的价值在于用极简的 39 行代码,完整演示了"文件 + 文件夹"两种粒度的 AES 对称加密实战:
- 一条命令即可上手:
python encrypt.py <file-or-folder>; - 加密产物为原路径下的
.bin文件,不破坏原始文件; - 技术上覆盖了 AES 密钥长度约束、CFB 无填充流式加密、随机 IV 生成与密文组装等核心知识点;
- 仓库配套的 aes_encode.py 提供了同密钥 CFB 解密的直接参考。
对于学习者而言,它是理解"脚本化批量加密"的最佳入门样例;若要投入真实使用,则需在二进制读取、IV 落盘与密钥管理三处做针对性增强,这也正是从"能跑的脚本"迈向"可用的工具"的关键一步。
【免费下载链接】python-mini-projectsA collection of simple python mini projects to enhance your python skills项目地址: https://gitcode.com/gh_mirrors/py/python-mini-projects
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考