You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何修复基于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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 17:57:11