前言

存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美化下界面。

运行截图

加密前:

image-20250418221625073.png

image-20250418221625073.png

加密后:

image-20250418221721880.png

解密:

image-20250418221754376.png

关键组件分析

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自动化办公教程》祝你效率翻倍

标签: none