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

使用SQLite3开发密码管理器时遭遇cryptography.fernet.InvalidToken及Base64格式错误的排查求助

解决Fernet InvalidToken错误:修复密码管理器的SQLite存储逻辑

你遇到的InvalidToken错误,核心问题出在加密token的存储和读取过程中,你破坏了Fernet要求的原始二进制格式。之前用txt文件存储时能正常工作,是因为你直接读写二进制数据;但改用SQLite后,错误的字符串处理导致token格式损坏,最终解密失败。

问题根源分析

  1. 存储阶段:Fernet加密后的结果是bytes对象,你直接存入SQLite时,数据库会自动将其转换为类似b'gAAAAAB...'的字符串形式(带b'前缀和'后缀)。
  2. 读取阶段:你把查询结果转成字符串后手动切割,拿到的是b'gAAAAAB...'的字符串,再encode成bytes就变成了b"b'gAAAAAB...'"——这完全不是原始的加密token,自然无法通过Fernet的base64校验。

修复方案(两种可选)

方案1:将加密token转成字符串存储(推荐,兼容性好)

修改你的存储和解密逻辑,确保token始终保持正确的格式:

1. 更新加密存储函数submited

把加密后的bytes对象解码为utf-8字符串再存入数据库:

def submited():
    setPassword()
    usrinput = userInput.get()
    if os.path.isfile('data.db'):
        # 加密后解码为字符串,避免SQLite自动转换格式
        genPasswordEnc = f.encrypt(generatePassword.encode('utf-8')).decode('utf-8')
        c.execute("INSERT INTO passwords VALUES(?,?)", (usrinput, genPasswordEnc))
        conn.commit()
2. 更新解密函数see的循环部分

直接读取存储的字符串,转成bytes后解密,不要再做手动切割:

if os.path.isfile('data.db'):
    c.execute('SELECT * FROM passwords')
    password_list = c.fetchall()
    for item in password_list:
        # 直接取出存储的加密字符串,转成bytes
        encrypted_token = item[1].encode('utf-8')
        try:
            # 解密后转成字符串显示
            decrypt = f.decrypt(encrypted_token).decode('utf-8')
            listbox.insert(END, decrypt)
            print("Decrypted pass: ", decrypt)
        except Exception as e:
            print(f"解密失败: {e}")
            listbox.insert(END, f"[解密失败: {str(e)}]")

方案2:使用SQLite的BLOB类型存储二进制数据

如果想直接存储bytes对象,可以修改表结构为BLOB类型:

# 创建表时指定字段类型为BLOB
c.execute("""CREATE TABLE passwords (passwordTitle text, generatedPassword BLOB)""")

然后存储和解密时无需转码:

# 存储函数submited
def submited():
    setPassword()
    usrinput = userInput.get()
    if os.path.isfile('data.db'):
        # 直接存储加密后的bytes对象
        genPasswordEnc = f.encrypt(generatePassword.encode('utf-8'))
        c.execute("INSERT INTO passwords VALUES(?,?)", (usrinput, genPasswordEnc))
        conn.commit()

# 解密函数see的循环部分
if os.path.isfile('data.db'):
    c.execute('SELECT * FROM passwords')
    password_list = c.fetchall()
    for item in password_list:
        # 直接取出BLOB类型的bytes对象
        encrypted_token = item[1]
        try:
            decrypt = f.decrypt(encrypted_token).decode('utf-8')
            listbox.insert(END, decrypt)
            print("Decrypted pass: ", decrypt)
        except Exception as e:
            print(f"解密失败: {e}")
            listbox.insert(END, f"[解密失败: {str(e)}]")

为什么之前的txt文件能正常工作?

因为你直接读写二进制数据时,没有对token做任何字符串转换,保持了Fernet要求的原始base64二进制格式。而SQLite默认会把bytes转成字符串存储,这才导致了格式损坏。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 12:17:37