import tkinter as tk from tkinter import filedialog, messagebox, ttk from Crypto.Cipher import AES from Crypto.Util.Padding import pad from Crypto.Random import get_random_bytes import os import base64 class VideoEncryptorGUI: def __init__(self, master): self.master = master master.title("视频加密工具") master.geometry("500x400") self.input_file_path = None # 创建GUI组件 self.label_title = tk.Label(master, text="视频文件加密工具", font=("Arial", 14, "bold")) self.label_title.pack(pady=10) self.btn_select = tk.Button(master, text="选择视频文件", command=self.select_file, width=20, height=2) self.btn_select.pack(pady=5) self.label_file = tk.Label(master, text="未选择文件", wraplength=400) self.label_file.pack(pady=5) # Key输入 self.label_key = tk.Label(master, text="AES密钥 (Base64编码或16/24/32字节字符串):") self.label_key.pack(pady=(10,0)) self.entry_key = tk.Entry(master, width=50) self.entry_key.pack(pady=5) # IV输入 self.label_iv = tk.Label(master, text="初始化向量IV (Base64编码或8字节字符串):") self.label_iv.pack(pady=(10,0)) self.entry_iv = tk.Entry(master, width=50) self.entry_iv.pack(pady=5) # 生成随机Key和IV按钮 self.btn_generate = tk.Button(master, text="生成随机密钥和IV", command=self.generate_key_iv, width=20) self.btn_generate.pack(pady=5) # 加密按钮 self.btn_encrypt = tk.Button(master, text="加密文件", command=self.encrypt_video, width=20, height=2, bg="#4CAF50", fg="white") self.btn_encrypt.pack(pady=10) self.status_label = tk.Label(master, text="", fg="blue") self.status_label.pack(pady=5) # 说明文本 help_text = "说明:输出文件将与输入文件同目录,扩展名为.hnv" self.label_help = tk.Label(master, text=help_text, fg="gray", font=("Arial", 9)) self.label_help.pack(pady=10) def select_file(self): """选择要加密的文件""" file_path = filedialog.askopenfilename( title="选择视频文件", filetypes=[("视频文件", "*.mp4 *.avi *.mov *.mkv"), ("所有文件", "*.*")] ) if file_path: self.input_file_path = file_path self.label_file.config(text=file_path) self.status_label.config(text="文件已选择,请设置密钥") def generate_key_iv(self): """生成随机的密钥和nonce""" # 生成随机密钥(32字节,AES-256)和nonce(8字节用于CTR模式) key = get_random_bytes(32) nonce = get_random_bytes(8) # AES CTR模式使用的nonce应该是8字节 # 转换为Base64编码字符串,显示在输入框中 key_b64 = base64.b64encode(key).decode('utf-8') nonce_b64 = base64.b64encode(nonce).decode('utf-8') self.entry_key.delete(0, tk.END) self.entry_key.insert(0, key_b64) self.entry_iv.delete(0, tk.END) self.entry_iv.insert(0, nonce_b64) self.status_label.config(text="已生成随机密钥和nonce,请妥善保存!") def encrypt_video(self): """加密视频文件""" if not self.input_file_path: messagebox.showerror("错误", "请先选择要加密的文件") return key_str = self.entry_key.get().strip() iv_str = self.entry_iv.get().strip() if not key_str or not iv_str: messagebox.showerror("错误", "请输入密钥和IV") return try: # 处理密钥:尝试Base64解码,否则使用字符串编码 # try: # key = base64.b64decode(key_str) # except: key = key_str.encode('utf-8') # 处理IV:尝试Base64解码,否则使用字符串编码 # try: # iv = base64.b64decode(iv_str) # except: iv = iv_str.encode('utf-8') # 确保密钥长度为16、24或32字节 # if len(key) not in [16, 24, 32]: # if len(key) < 16: # key = key.ljust(16, b'\0') # elif len(key) < 24: # key = key.ljust(24, b'\0') # elif len(key) < 32: # key = key.ljust(32, b'\0') # else: # key = key[:32] # 确保IV长度为16字节 # if len(iv) != 16: # if len(iv) < 16: # iv = iv.ljust(16, b'\0') # else: # iv = iv[:16] # 生成输出文件路径 file_dir = os.path.dirname(self.input_file_path) file_name = os.path.basename(self.input_file_path) file_base = os.path.splitext(file_name)[0] output_file = os.path.join(file_dir, f"{file_base}.hnv") # 执行加密 self.do_encryption(self.input_file_path, output_file, key, iv) self.status_label.config(text=f"加密成功!输出文件: {output_file}") messagebox.showinfo("成功", f"文件加密完成!\n输出文件: {output_file}") except Exception as e: messagebox.showerror("加密错误", f"加密过程中发生错误: {str(e)}") def do_encryption(self, input_path, output_path, key, iv): print(f"iv len: {len(iv)}") """ 执行加密操作 使用AES/CTR/NoPadding模式 """ try: # 创建CTR模式加密器 cipher = AES.new(key, AES.MODE_CTR, nonce=iv) with open(input_path, 'rb') as fin: with open(output_path, 'wb') as fout: # 将IV写入文件开头,解密时需要 fout.write(iv) # 逐块加密文件 while True: chunk = fin.read(4096) # 每次读取4KB if len(chunk) == 0: break encrypted_chunk = cipher.encrypt(chunk) fout.write(encrypted_chunk) except Exception as e: raise Exception(f"加密失败: {str(e)}") def main(): # 检查所需库是否已安装 try: from Crypto.Cipher import AES from Crypto.Util.Padding import pad from Crypto.Random import get_random_bytes except ImportError: print("正在安装所需库...") import subprocess import sys subprocess.check_call([sys.executable, "-m", "pip", "install", "pycryptodome"]) print("库安装完成,请重新运行程序") return # 创建主窗口 root = tk.Tk() app = VideoEncryptorGUI(root) root.mainloop() if __name__ == "__main__": main()