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

使用cryptography模块开发密码管理器时遇InvalidToken解密错误求助

密码管理器APM触发cryptography.fernet.InvalidToken错误排查

问题描述

开发一款名为APM的密码管理器时,执行find google命令后触发cryptography.fernet.InvalidToken错误,错误位于APMDatabase类decrypt方法第44行(decrypted = fernet.decrypt(original)),谷歌搜索未找到有效解决方案。

报错回溯

hello, thank you for using APM. enter 'help' for help. enjoy!
> find google
"google", "google.com", "AntispleneticMoonlighty", "#{6P=,U{;%^AMO+", "number- 1"

Traceback (most recent call last):
  File "D:\CODING\Python\APM.py", line 80, in <module>
    db.decrypt()
  File "D:\CODING\Python\APM.py", line 44, in decrypt
    decrypted = fernet.decrypt(original)
  File "C:\Users\Anton\AppData\Local\Programs\Python\Python310\lib\site-packages\cryptography\fernet.py", line 85, in decrypt
    timestamp, data = Fernet._get_unverified_token_data(token)
  File "C:\Users\Anton\AppData\Local\Programs\Python\Python310\lib\site-packages\cryptography\fernet.py", line 121, in _get_unverified_token_data
    raise InvalidToken
cryptography.fernet.InvalidToken
Press any key to continue . . .

精简代码

import PGL
from cryptography.fernet import Fernet
import os
import logging as lg


class APMDatabase:
    def __init__(self, keyfile_path, database_path):
        global start
        self.keyfile_path = keyfile_path
        self.database_path = database_path
        print(start)

    def read_key(self):
        with open(self.keyfile_path, "rb") as keyfile:
            return keyfile.read()

    def encrypt(self):
        key = self.read_key()
        fernet = Fernet(key)
        with open(self.database_path, "rb") as file:
            original = file.read()
        encrypted = fernet.encrypt(original)
        with open(self.database_path, "wb") as encfile:
            encfile.write(encrypted)

    def decrypt(self):
        key = self.read_key()
        fernet = Fernet(key)
        with open(self.database_path, "rb") as file:
            original = file.read()
        decrypted = fernet.decrypt(original)            # 错误发生行
        with open(self.database_path, "wb") as decfile:
            decfile.write(decrypted)
   
    def find(self, name):
        db.decrypt()
        with open(self.database_path, "r") as database:
            content = database.readlines()
            for i in content:
                if name in i:
                    print(i)
                    return i
        db.encrypt()        
    
    
db = APMDatabase(
    keyfile_path="D:\\CODING\\Python\\APMKEY.APMKEY",
    database_path="D:\\CODING\\Python\\APMDatabase.APMDATA",
)

while True:
   db.decrypt()
   number = len((open("D:\\CODING\\Python\\APMDatabase.APMDATA")).readlines())
   db.encrypt()
   
   query = input("> ")
   
   elif "find" in query:
       data = query.split(" ")[1]
       if data == "(all)":
           try:
               db.find('"')
           except:
                lg.error("404")
       try:
           db.find(data)
       except:
           lg.error("404")

问题分析与解决建议

核心问题

  1. 数据库状态不一致:主循环中每次输入前都会执行「解密->读取行数->加密」,而find方法又会执行「解密->读取内容->加密」。如果中间出现异常导致加密步骤未执行,或者重复加密,会导致数据库内容变为密文的密文,后续解密时触发InvalidToken。
  2. 全局实例引用错误:find方法中使用全局db实例调用decrypt/encrypt,而非当前实例的self,可能导致操作对象混乱。
  3. 文件句柄泄漏:主循环中读取行数时直接open文件未关闭,可能导致文件锁定或状态异常。

修复步骤

  1. 修正实例引用:将find方法中的db.decrypt()和db.encrypt()改为self.decrypt()和self.encrypt():
    def find(self, name):
        self.decrypt()
        with open(self.database_path, "r") as database:
            content = database.readlines()
            for i in content:
                if name in i:
                    print(i)
                    return i
        self.encrypt()
    
  2. 优化文件读取逻辑:主循环中用with语句安全读取行数,避免文件未关闭:
    while True:
        db.decrypt()
        with open("D:\\CODING\\Python\\APMDatabase.APMDATA", "r") as f:
            number = len(f.readlines())
        db.encrypt()
        
        query = input("> ")
        # 后续逻辑...
    
  3. 验证密钥有效性:确认APMKEY.APMKEY中的密钥是Fernet格式的有效密钥(URL-safe base64编码的32字节字符串)。可通过以下代码验证:
    from cryptography.fernet import Fernet
    
    with open("D:\\CODING\\Python\\APMKEY.APMKEY", "rb") as f:
        key = f.read()
    try:
        # 检查是否为合法Fernet密钥
        Fernet(key)
        print("密钥有效")
    except ValueError:
        print("密钥无效,请重新生成Fernet密钥")
    
  4. 恢复数据库(若已损坏):如果数据库被重复加密,可尝试手动解密恢复:
    from cryptography.fernet import Fernet
    
    key = b"替换为你的密钥内容"
    fernet = Fernet(key)
    with open("D:\\CODING\\Python\\APMDatabase.APMDATA", "rb") as f:
        data = f.read()
    try:
        decrypted = fernet.decrypt(data)
        with open("恢复的数据库.txt", "wb") as f:
            f.write(decrypted)
        print("数据库恢复成功")
    except Exception as e:
        print(f"恢复失败:{e}")
    
  5. 添加异常处理:在decrypt方法中添加异常捕获,避免程序直接崩溃并记录日志:
    def decrypt(self):
        try:
            key = self.read_key()
            fernet = Fernet(key)
            with open(self.database_path, "rb") as file:
                original = file.read()
            decrypted = fernet.decrypt(original)
            with open(self.database_path, "wb") as decfile:
                decfile.write(decrypted)
        except Exception as e:
            lg.error(f"解密失败: {str(e)}")
            raise  # 可根据需求选择是否抛出异常
    

内容的提问来源于stack exchange,提问作者Anton Chernyshov

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 07:10:17