使用SQLite3开发密码管理器时遭遇cryptography.fernet.InvalidToken及Base64格式错误的排查求助
解决Fernet InvalidToken错误:修复密码管理器的SQLite存储逻辑
你遇到的InvalidToken错误,核心问题出在加密token的存储和读取过程中,你破坏了Fernet要求的原始二进制格式。之前用txt文件存储时能正常工作,是因为你直接读写二进制数据;但改用SQLite后,错误的字符串处理导致token格式损坏,最终解密失败。
问题根源分析
- 存储阶段:Fernet加密后的结果是
bytes对象,你直接存入SQLite时,数据库会自动将其转换为类似b'gAAAAAB...'的字符串形式(带b'前缀和'后缀)。 - 读取阶段:你把查询结果转成字符串后手动切割,拿到的是
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
相关产品推荐
相关产品推荐

