Python还能这么用?U盘加密工具保护你的秘密
前言
存u盘里内容(老师)不想让别人知道,那就写个u盘加密工具来守护它把!
何为u盘加密?
加密U盘是指对U盘内容有加解密保护功能的U盘。市面上的加密U盘主要有三类:A.假加密,仅仅是隐藏文件,设个密码,仅仅验证身份,实际存储内容没有任何变化。B.软加密,内置或附带软件,对数据进行加密,一般用AES,也可分加密区及非加密区。C.硬件加密,内置硬件加密,透明加密,无形之中,完成加密,读取时验证,有的具有一些特殊功能,例如将加密应用于硬盘,插上U盘显示明码,拔下显示就是加密信息。
柿子要挑软的捏,那我们就从软加密入手吧。
核心功能概述
1、使用Fernet对称加密(基于AES-128-CBC),常用的对称加密方式。
2、使用SHA-256哈希存储密码,PBKDF2派生加密密钥
3、加密后将原文件删除,解密后恢复原始文件结构,这样可以隐藏源文件。
4、基于Tkinter的简单GUI界面,简单,但是界面不是很美观,后期可以用ttkbootstrap美化下界面。
运行截图
加密前:
加密后:
解密:
关键组件分析
1. 密钥管理机制
def hash_password(self, password):
"""对密码进行哈希"""
return hashlib.sha256(password.encode()).hexdigest()
def derive_key(self, password):
"""从密码派生加密密钥"""
kdf = PBKDF2HMAC(
algorithm=hashes.SHA256(),
length=32,
salt=self.salt,
iterations=self.config["encryption_settings"]["key_iterations"],
)
key = base64.urlsafe_b64encode(kdf.derive(password.encode()))
return key
- 使用PBKDF2密钥派生函数,通过多次迭代(默认100,000次)增强安全性
- 使用固定盐值(
self.salt = b'USBEncryptionSalt123'
),简化密钥管理但降低了安全性 - 密码验证使用SHA-256哈希,存储在配置文件中
2. 文件加密流程
def encrypt_usb(self, password):
# ...
# 创建Fernet加密器
key = self.derive_key(password)
fernet = Fernet(key)
# 打开加密数据文件
with open(self.data_file, 'wb') as data_file:
# 写入文件数量
data_file.write(struct.pack("<I", total_files))
# 加密并写入每个文件
for i, file_path in enumerate(files_to_encrypt):
# 读取文件内容
with open(file_path, 'rb') as f:
file_data = f.read()
# 获取相对路径
rel_path = os.path.relpath(file_path, self.usb_root)
rel_path_bytes = rel_path.encode('utf-8')
# 加密文件内容
encrypted_data = fernet.encrypt(file_data)
# 写入路径长度、路径和加密数据
data_file.write(struct.pack("<I", len(rel_path_bytes)))
data_file.write(rel_path_bytes)
data_file.write(struct.pack("<Q", len(encrypted_data)))
data_file.write(encrypted_data)
# 删除原文件
os.remove(file_path)
# ...
- 所有文件内容被加密并集中存储在一个单一的加密数据文件(
.usbenc_data.bin
)中 - 文件结构信息(相对路径)也被保存,以便解密时恢复原始目录结构
- 使用二进制格式存储,包含文件数量、路径长度、路径、加密数据长度和加密数据
3. 文件解密流程
def decrypt_usb(self, password):
# ...
# 创建Fernet解密器
key = self.derive_key(password)
fernet = Fernet(key)
# 打开加密数据文件
with open(self.data_file, 'rb') as data_file:
# 读取文件数量
total_files = struct.unpack("<I", data_file.read(4))[0]
# 解密并写入每个文件
for i in range(total_files):
# 读取路径长度和路径
path_len = struct.unpack("<I", data_file.read(4))[0]
rel_path = data_file.read(path_len).decode('utf-8')
# 读取加密数据长度和数据
data_len = struct.unpack("<Q", data_file.read(8))[0]
encrypted_data = data_file.read(data_len)
# 解密数据
decrypted_data = fernet.decrypt(encrypted_data)
# 确保目标目录存在
file_path = os.path.join(self.usb_root, rel_path)
os.makedirs(os.path.dirname(file_path), exist_ok=True)
# 写入解密后的文件
with open(file_path, 'wb') as f:
f.write(decrypted_data)
# ...
- 从加密数据文件中读取并解析文件结构信息和加密内容
- 使用相同的密钥解密数据,并按照原始路径恢复文件
- 解密完成后删除加密数据文件
4. 配置管理
def load_config(self):
"""加载或创建配置文件"""
default_config = {
"is_encrypted": False,
"password_hash": "",
"last_access": "",
"encryption_settings": {
"key_iterations": 100000,
}
}
if os.path.exists(self.config_file):
try:
with open(self.config_file, 'r') as f:
self.config = json.load(f)
except:
self.config = default_config
else:
self.config = default_config
self.save_config()
- 使用JSON格式存储配置信息
- 跟踪加密状态、密码哈希、上次访问时间和加密设置
- 配置文件存储在U盘根目录的隐藏文件中(
.usbenc_config.json
)
5. 密码修改机制
def change_password(self):
# 先验证当前密码
current_pwd = simpledialog.askstring("验证当前密码", "请输入当前密码:", show="*", parent=self.root)
# ...
# 如果U盘已加密,需要先解密到临时目录
temp_dir = None
if self.config["is_encrypted"]:
temp_dir = self.decrypt_to_temp(current_pwd)
# ...
# 更新密码哈希
self.config["password_hash"] = self.hash_password(new_password)
self.save_config()
# 如果有临时解密的文件,需要用新密码重新加密
if temp_dir:
success = self.encrypt_from_temp(new_password, temp_dir)
# ...
- 修改密码时,先验证当前密码
- 如果U盘已加密,需要先解密到临时目录,再用新密码重新加密
- 更新配置文件中的密码哈希
6. 线程处理
def encrypt_usb(self, password):
# ...
# 在后台线程中执行加密操作
def encrypt_thread():
# 加密操作...
# 启动加密线程
threading.Thread(target=encrypt_thread).start()
- 使用后台线程处理耗时的加密/解密操作,避免UI冻结
- 通过进度条向用户展示操作进度
- 线程完成后通过
after
方法安全地更新UI
7. 文件过滤机制
# 跳过隐藏文件和目录
dirs[:] = [d for d in dirs if not d.startswith('.')]
for file in files:
if file.startswith('.'):
continue
# 跳过程序自身和配置文件
file_path = os.path.join(root, file)
if file_path == os.path.abspath(sys.argv[0]) or \
file_path == self.config_file or \
file_path == self.data_file:
continue
- 排除隐藏文件和目录(以
.
开头) - 排除程序自身、配置文件和加密数据文件,确保程序正常运行
发布成exe运行文件
pyinstaller -F -w --icon=tt.ico .\u盘加密工具.py
关注@运维躬行录,在聊天框输入【u盘加密】,可免费领取打包文件及《python自动化办公教程》祝你效率翻倍