如何修复基于Fernet加密的Python解密函数InvalidToken错误?
问题:Fernet解密时出现InvalidToken错误(提示密钥错误)
问题根源
加密过程中使用os.urandom(16)生成随机salt,但未将salt与加密内容一同保存。解密时重新生成新的随机salt,导致相同密码推导的密钥不一致,无法完成解密。此外,解密函数中获取标题的逻辑错误,使用了窗口初始化时的空标题值,而非用户当前输入的标题。
修复步骤
- 加密时,将salt用base64编码为字符串,和标题、加密消息一起写入文件
- 解密时,从文件中读取对应标题的salt和加密消息,用相同的KDF参数重新推导密钥
- 修改解密函数中获取标题的逻辑,实时读取输入框的标题内容
修改后的完整代码
from tkinter import * from tkinter import messagebox import base64 import os from cryptography.fernet import Fernet, InvalidToken from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC window = Tk() window.title("Secret Notes") window.minsize(width=400, height=400) window.config(padx=20, pady=20) title_label = Label(text="Enter the Title") title_label.config(fg="black", padx=10, pady=10) title_label.pack() title_entry = Entry(width=30) title_entry.focus() title_entry.pack() secret_label = Label(text="Enter the Secret Message") secret_label.config(fg="black", padx=10, pady=10) secret_label.pack() secret_text = Text(width=30, height=10) secret_text.pack() masterkey_label = Label(text="Enter the Key") masterkey_label.config(fg="black", padx=10, pady=10) masterkey_label.pack() masterkey_entry = Entry(width=30, show="*") masterkey_entry.pack() desktop_path = os.path.join(os.path.join(os.environ['USERPROFILE']), 'Desktop') def save_and_encrypt(): title = title_entry.get() secret = secret_text.get("1.0", END).strip() # 去掉末尾换行 streaky = masterkey_entry.get() if len(title) == 0 or len(secret) == 0 or len(streaky) == 0: messagebox.showerror(title="Error", message="Please fill in all fields.") else: password = streaky.encode() salt = os.urandom(16) kdf = PBKDF2HMAC( algorithm=hashes.SHA256(), length=32, salt=salt, iterations=480000, ) key = base64.urlsafe_b64encode(kdf.derive(password)) f = Fernet(key) encrypted_text = secret.encode() token1 = f.encrypt(encrypted_text) # 将salt编码为base64字符串以便存储 salt_b64 = base64.b64encode(salt).decode() with open(os.path.join(desktop_path, "encrypted_notes.txt"), "a") as file: file.write(f"Title: {title}\n") file.write(f"Salt: {salt_b64}\n") file.write(f"Encrypted Message: {token1.decode()}\n") # 直接存储字符串而非bytes file.write("\n") messagebox.showinfo(title="Completed", message="Your note has been saved and encrypted.") def decrypt_notes(): # 实时获取用户输入的标题和密钥 target_title = title_entry.get() master_key = masterkey_entry.get() if len(target_title) == 0 or len(master_key) == 0: messagebox.showerror(title="Error", message="Please enter title and master key.") return # 读取加密文件 try: with open(os.path.join(desktop_path, "encrypted_notes.txt"), "r") as file: lines = file.readlines() except FileNotFoundError: messagebox.showerror(title="Error", message="No encrypted notes found.") return # 查找对应标题的salt和加密消息 salt_b64 = None encrypted_message = None for i in range(0, len(lines), 4): # 现在每条笔记占4行:title、salt、encrypted、空行 if i + 2 >= len(lines): break title_line = lines[i].strip() if title_line == f"Title: {target_title}": salt_b64 = lines[i+1].strip().split("Salt: ")[1] encrypted_message = lines[i+2].strip().split("Encrypted Message: ")[1] break if encrypted_message is None or salt_b64 is None: messagebox.showerror(title="Error", message="Note not found.") return # 解密流程 try: password = master_key.encode() # 解码salt salt = base64.b64decode(salt_b64) kdf = PBKDF2HMAC( algorithm=hashes.SHA256(), length=32, salt=salt, iterations=480000, ) key = base64.urlsafe_b64encode(kdf.derive(password)) f = Fernet(key) decrypted_message = f.decrypt(encrypted_message.encode()).decode() messagebox.showinfo(title="Decrypted Message", message=decrypted_message) except (InvalidToken, ValueError): messagebox.showerror(title="Error", message="Decryption failed. Incorrect master key.") except Exception as e: messagebox.showerror(title="Error", message=f"Unexpected error: {str(e)}") save_button = Button(text="Save & Encrypt",command=save_and_encrypt) save_button.config(padx=1, pady=1) save_button.pack(padx=(10, 0), pady=(10, 0)) decrypt_button = Button(text="Decrypt",command=decrypt_notes) decrypt_button.config(padx=1, pady=1) decrypt_button.pack(padx=(10, 0), pady=(10, 0)) window.mainloop()
内容的提问来源于stack exchange,提问作者Barış Tüzün
相关产品推荐
相关产品推荐

