简介:这是一款用Python编写的文件加密解密工具,面向需要保护敏感数据的企业或个人用户,以及希望研究文件加解密机制与密钥管理的开发者。工具在思路上与勒索病毒相似,加密后会自动修改文件扩展名,使原始数据无法直接访问,但用途是安全地加密与解密文件。密钥统一保存在SQL Server数据库中,由encryption_key字段记录,使用前需自行创建空库,连接失败时可借助msodbcsql工具排查;运行后会在当前目录生成db_config配置文件,用于保存数据库连接信息。资源包共11个文件,约22MB,包含加密工具与解密工具两个exe主程序、msodbcsql.msi数据库驱动安装包、bat启动脚本、html说明页面、url快捷入口及jpg图片等,覆盖从环境准备到实际加解密的完整环节。目前已有113人学习下载,适合想了解密钥数据库存储方案、扩展名自动修改逻辑与连接排错思路的读者参考,使用时需注意密钥备份与数据库安全配置,避免数据永久丢失。
1. 拆开这个 Python 文件加密解密工具:它到底像不像勒索病毒
第一次拿到加解密工具_20250418_084555.zip的时候,我盯着目录里那两个加密工具.exe和解密工具.exe看了半天。做安全的同行都懂,一个会「自动改扩展名、把密钥写进数据库」的 Python 工具,行为特征和勒索病毒几乎一模一样——区别只在于:勒索病毒不给你密钥,而这个工具把密钥老老实实存进了 SQL Server 的encryption_key字段里。这就是它最反直觉的地方:它用勒索病毒的思路做数据保护,但把「后悔药」留在了你自己的数据库里。
这个工具适合谁?一类是手里有敏感文件、又不想依赖第三方云盘加密的从业者;另一类是正在学 Python 文件 IO、想找一个「能跑起来、有真实数据库交互」的项目练手的人。它用 Python 写核心逻辑,用 SQL Server 存密钥,用msodbcsql.msi解决连接驱动问题,运行时在当前目录生成db_config配置文件。整套流程不复杂,但坑集中在数据库连接和密钥管理这两块。下面我按「先搞懂它怎么运作 → 再动手跑通 → 最后说清楚哪里会翻车」的顺序拆一遍。
2. 加密逻辑与密钥落库:为什么密钥要单独存数据库
2.1 文件加密的典型流程与扩展名改写机制
这个工具的核心动作可以拆成三步:读文件 → 加密内容 → 改扩展名。加密本身用的是对称加密思路(Python 生态里常见的是cryptography库的 Fernet 或者 AES),密钥由工具生成,加密完成后把密文写回原文件,然后把文件名后缀替换成一个自定义标记。原文说「加密过后也是自动修改尾椎」,这里的「尾椎」就是扩展名——改掉之后,双击打不开,系统也不知道该用什么程序打开,等于给文件加了一层「伪装壳」。
为什么非要改扩展名?因为单纯加密内容、不改名字的话,用户很容易误点,触发解密流程或者报错。改掉扩展名相当于一个物理隔离:你看到.xxx就知道这是加密态,不会手贱去双击。常见做法是把原扩展名也记录进数据库或者文件名里,解密时再还原回去。如果工具没记录原扩展名,解密后就只能得到一个无后缀文件,得手动改回来——这是第一个要留意的细节。
2.2 密钥为什么存 SQL Server 而不是本地文件
把密钥写进 SQL Server 的encryption_key字段,而不是塞在本地.key文件里,这个选型有它的道理。本地密钥文件一旦被拷走,加密就形同虚设;而数据库可以独立做权限控制、备份、审计。对于企业场景,数据库通常有独立的账号体系和网络隔离,密钥放在里面比放在工具同目录安全得多。
代价是:工具强依赖数据库可用性。数据库连不上,加密解密全废。所以原文才强调「先自行创建空库」「连接不上用 msodbcsql 工具」。msodbcsql.msi是微软的 ODBC 驱动安装包,Python 通过pyodbc连接 SQL Server 时,底层就靠这个驱动。没有它,pyodbc.connect()会直接抛Data source name not found之类的错误。
2.3 建库建表与 db_config 生成
工具运行时会生成db_config文件,里面存的是数据库地址、库名、账号、密码这类连接信息。这个文件是明文还是加密,原文没细说,但从「工具会在当前目录下面创建一个 db_config 文件」来看,它大概率是工具首次运行时让你填连接参数,然后落盘复用。
建表 SQL 我一般会这样写,字段名对齐原文的encryption_key:
-- 在 SQL Server 里先建一个空库,比如 FileCrypto -- 然后建密钥表,encryption_key 存密钥,file_path 记录加密过的文件 CREATE TABLE crypto_keys ( id INT IDENTITY(1,1) PRIMARY KEY, encryption_key NVARCHAR(512) NOT NULL, -- 密钥本体 file_path NVARCHAR(1024) NOT NULL, -- 被加密文件的原始路径 original_ext NVARCHAR(32), -- 原始扩展名,解密时还原用 created_at DATETIME DEFAULT GETDATE() );encryption_key用NVARCHAR(512)是为了兼容 Fernet 生成的 base64 密钥(44 字符)以及未来可能的更长密钥。original_ext这个字段是我建议加的——原文没提,但如果不存原始扩展名,解密后你还得靠猜。file_path存绝对路径,避免工具换目录后找不到对应关系。
提示:建库时字符集和排序规则保持默认即可,密钥是 base64 字符串,不涉及中文排序问题。
3. 环境搭建与连接排错:从 msodbcsql 到 pyodbc 的完整链路
3.1 安装 ODBC 驱动与 Python 依赖
Windows 上先双击msodbcsql.msi装驱动,装完可以在「ODBC 数据源管理器」的「驱动程序」标签页里看到ODBC Driver 17 for SQL Server或类似条目。版本号不用纠结,17 和 18 都能用,关键是 Python 侧连接字符串里的DRIVER=要和实际装的名字对上。
Python 依赖装这几个:
# 数据库连接 pip install pyodbc # 加密算法(Fernet 是对称加密,适合文件场景) pip install cryptography # 如果工具用了 pandas 处理批量文件列表,按需装 pip install pandaspyodbc是 SQL Server 在 Python 里最稳的连接方式,pymssql也能用但在 Windows 上坑更多。cryptography的 Fernet 自带时间戳和签名,解密时能校验密文有没有被篡改,比裸 AES 省心。
3.2 连接字符串怎么写、db_config 怎么配
连接字符串是排错的重灾区。一个能跑通的模板:
import pyodbc conn_str = ( "DRIVER={ODBC Driver 17 for SQL Server};" "SERVER=127.0.0.1,1433;" # 地址,端口 "DATABASE=FileCrypto;" # 你建的空库名 "UID=sa;" # 登录账号 "PWD=YourStrongPassword;" # 密码 "TrustServerCertificate=yes;" # 本地自签证书时必加 ) conn = pyodbc.connect(conn_str) cursor = conn.cursor() cursor.execute("SELECT encryption_key FROM crypto_keys")SERVER如果是本机默认实例,写127.0.0.1或localhost都行;命名实例要写成主机名\实例名。TrustServerCertificate=yes是本地开发环境的后悔药——不加的话,SQL Server 自签证书会导致 SSL 握手失败,报SSL Provider: certificate verify failed。生产环境应该换成受信任证书,但本地调试先加上省事。
db_config文件我一般让工具用 JSON 存,方便手改:
{ "server": "127.0.0.1,1433", "database": "FileCrypto", "uid": "sa", "pwd": "YourStrongPassword", "driver": "ODBC Driver 17 for SQL Server" }工具启动时读这个文件拼连接串。如果连接失败,先确认三件事:SQL Server 的 TCP/IP 协议有没有启用(在「SQL Server 配置管理器」里开)、1433 端口有没有放行、账号密码对不对。
3.3 加密与解密的最小可运行脚本
把核心逻辑抽出来,一个能跑的最小版本:
from cryptography.fernet import Fernet import pyodbc, os, json # 读配置 with open("db_config", "r", encoding="utf-8") as f: cfg = json.load(f) conn = pyodbc.connect( f"DRIVER={{{cfg['driver']}}};SERVER={cfg['server']};" f"DATABASE={cfg['database']};UID={cfg['uid']};PWD={cfg['pwd']};" "TrustServerCertificate=yes;" ) cur = conn.cursor() def encrypt_file(path): key = Fernet.generate_key() # 生成密钥 f = Fernet(key) with open(path, "rb") as fp: data = fp.read() enc = f.encrypt(data) # 加密 new_path = path + ".enc" # 改扩展名 with open(new_path, "wb") as fp: fp.write(enc) os.remove(path) # 删原文件 cur.execute( "INSERT INTO crypto_keys (encryption_key, file_path, original_ext) VALUES (?,?,?)", key.decode(), path, os.path.splitext(path)[1] ) conn.commit() return new_path def decrypt_file(enc_path): cur.execute("SELECT encryption_key, file_path FROM crypto_keys WHERE file_path = ?", enc_path.replace(".enc", "")) row = cur.fetchone() if not row: raise ValueError("数据库里没有这个文件的密钥记录") f = Fernet(row[0].encode()) with open(enc_path, "rb") as fp: dec = f.decrypt(fp.read()) with open(row[1], "wb") as fp: # 还原原始文件名 fp.write(dec) os.remove(enc_path)Fernet.generate_key()每次加密生成独立密钥,存进encryption_key字段。os.path.splitext取原始扩展名存库,解密时用row[1]还原路径。注意decrypt如果密钥不对会抛InvalidToken,这是 Fernet 的签名校验在起作用,比裸 AES 多一层保护。
注意:
os.remove(path)删原文件这一步很危险,测试时先用副本跑,确认解密能还原再上真实文件。
4. 避坑与常见问题排查:密钥、驱动、扩展名这三处最容易翻车
4.1 现象:pyodbc 报「Data source name not found」
原因:msodbcsql.msi没装,或者装了但连接字符串里的DRIVER=名字和实际驱动名不一致。Windows 上驱动名带版本号,比如ODBC Driver 17 for SQL Server,少一个空格都连不上。
解决:去「ODBC 数据源管理器 → 驱动程序」标签页复制准确名字,粘进连接字符串。如果列表里根本没有 SQL Server 相关驱动,重新跑一遍msodbcsql.msi,装完重启命令行再试。
4.2 现象:加密成功但解密报 InvalidToken
原因:encryption_key字段存进去的时候被截断了,或者取出来的时候编码不对。NVARCHAR(512)存 base64 密钥够用,但如果建表时手滑写成VARCHAR(32),密钥后半截就丢了。
解决:先SELECT LEN(encryption_key) FROM crypto_keys看长度,Fernet 密钥固定 44 字符。短了就是字段长度问题,改表结构重来。另外 Python 侧key.decode()存、row[0].encode()取,编码要对称。
4.3 现象:解密后文件打不开,提示格式损坏
原因:加密时读文件用了文本模式("r")而不是二进制模式("rb"),换行符被转换,密文和原文对不上。或者解密时写回用了"w"而不是"wb"。
解决:文件加密全程用二进制模式,open(path, "rb")和open(path, "wb")。这个坑我踩过不止一次,尤其是处理图片和压缩包的时候,文本模式一进去就废。
4.4 现象:数据库连上了,但加密到一半报连接超时
原因:批量加密大量文件时,每个文件都commit一次,数据库连接被频繁占用;或者连接字符串没设超时,网络抖动直接卡死。
解决:批量场景改成攒一批再commit,或者用连接池。pyodbc.connect(conn_str, timeout=10)设个超时,别让它无限等。另外db_config里的密码如果含特殊字符(比如;),连接字符串拼接会断,建议用pyodbc.connect的关键字参数传,别手拼字符串。
4.5 现象:换台机器跑,db_config 里的地址连不上
原因:db_config里写的是127.0.0.1,换机器后数据库不在本机;或者 SQL Server 没开远程访问。
解决:db_config里的server改成数据库实际 IP,SQL Server 配置管理器里启用 TCP/IP 并确认监听端口。跨网段还要看防火墙。这个文件本身是明文配置,别把它和加密文件一起打包发出去,等于把钥匙和锁一起送人。
5. 进阶:密钥轮换、批量处理与一个验证解密完整性的技巧
跑通基础流程之后,有几个进阶点值得补上。第一个是密钥轮换:长期用同一批密钥有风险,可以定期生成新密钥、重新加密文件、更新encryption_key字段。做法是遍历crypto_keys表,对每条记录用旧密钥解密、新密钥加密、更新字段,整个过程包在一个事务里,中途失败就回滚。
第二个是批量处理的性能。几百个文件逐个commit会很慢,我一般改成每 50 个文件commit一次,并且把cursor.fast_executemany打开(如果用的是executemany插入)。文件 IO 本身是瓶颈,可以考虑用线程池读文件、单线程写数据库,避免数据库连接竞争。
第三个是一个验证解密完整性的小技巧:加密前先算原文件的 SHA256,存进数据库单独一个字段;解密后再算一次,比对一致才认为还原成功。这样即使 Fernet 的签名校验通过了,也能确认文件内容没在传输或存储环节被改动。加这个字段的 SQL:
ALTER TABLE crypto_keys ADD file_hash NVARCHAR(64);加密时hashlib.sha256(data).hexdigest()存进去,解密后重新算一遍比对。多这一步,心里踏实很多。
最后一个习惯:每次动真实文件之前,先拿一个测试目录跑一遍加密→解密→比对哈希的完整闭环。我早期图省事直接对工作目录下手,结果有一次密钥字段长度建错,加密完解不回来,只能从备份恢复。从那以后我每次改完连接配置或者表结构,都强制走一遍「加密一个测试文件 → 查库确认密钥落库 → 解密 → 比对 SHA256」这个流程,确认无误再碰真实数据。希望这个习惯也能帮到你。
本文还有配套的精品资源,点击获取