使用Fernet开发密码管理器遇多记录解密错误:Signature did not match digest
密码管理器Fernet解密异常问题
我正在开发一款密码管理器应用,计划用Fernet加密密码后写入文件,需要时读取解密。当前代码在secrets.txt只有一条记录时能正常运行,但多条记录时会抛出“Signature did not match digest”错误,最终触发cryptography.fernet.InvalidToken异常。
现有代码
key = Fernet.generate_key() password = '123456789' write_record("facebook","ali",password,key) read_record(key) def write_record(site,account,password,key): f = Fernet(key) token = f.encrypt(bytes(password,'utf-8')) with open ('secrets.txt','a') as file: file.write(f"{site},{account},{str(token)}\n") def read_record(key): f = Fernet(key) with open ('secrets.txt','r') as file: lines = file.readlines() for line in lines: line = line.strip().replace('\n', '') print("line is "+line) token = line.split(",")[2] print(token) token = token[2:-1] token = token.encode() print(token) print(f.decrypt(token))
报错信息
line is facebook,ali,b'gAAAAABkLyRCekwyD5p5MMmaNxee6quDhlv9zx5e6Qghfv6jjubsGtP5m5F8YaB1LEPBq90-ab1VxK5oqOHmNStNbulSBMCtXQ==' b'gAAAAABkLyRCekwyD5p5MMmaNxee6quDhlv9zx5e6Qghfv6jjubsGtP5m5F8YaB1LEPBq90-ab1VxK5oqOHmNStNbulSBMCtXQ==' b'gAAAAABkLyRCekwyD5p5MMmaNxee6quDhlv9zx5e6Qghfv6jjubsGtP5m5F8YaB1LEPBq90-ab1VxK5oqOHmNStNbulSBMCtXQ==' Traceback (most recent call last): File "/usr/lib/python3/dist-packages/cryptography/fernet.py", line 119, in _verify_signature h.verify(data[-32:]) File "/usr/lib/python3/dist-packages/cryptography/hazmat/primitives/hmac.py", line 74, in verify ctx.verify(signature) File "/usr/lib/python3/dist-packages/cryptography/hazmat/backends/openssl/hmac.py", line 75, in verify raise InvalidSignature("Signature did not match digest.") cryptography.exceptions.InvalidSignature: Signature did not match digest. During handling of the above exception, another exception occurred: Traceback (most recent call last): File "/home/mido/Desktop/project.py", line 44, in <module> main() File "/home/mido/Desktop/project.py", line 8, in main read_record(key) File "/home/mido/Desktop/project.py", line 32, in read_record print(f.decrypt(token)) File "/usr/lib/python3/dist-packages/cryptography/fernet.py", line 80, in decrypt return self._decrypt_data(data, timestamp, time_info) File "/usr/lib/python3/dist-packages/cryptography/fernet.py", line 137, in _decrypt_data self._verify_signature(data) File "/usr/lib/python3/dist-packages/cryptography/fernet.py", line 121, in _verify_signature raise InvalidToken cryptography.fernet.InvalidToken
secrets.txt内容
facebook,ali,b'gAAAAABkLyRCekwyD5p5MMmaNxee6quDhlv9zx5e6Qghfv6jjubsGtP5m5F8YaB1LEPBq90-ab1VxK5oqOHmNStNbulSBMCtXQ==' facebook,ali,b'gAAAAABkLySj1RzbJMCFYrDJw8a2dNyfYMlwyiq1be818DwzU7RCWnEiUFGDS2I5DHNt7jmFf2mEm_q40h95HGfeSExTNumd-A=='
问题原因与修复方案
问题根源
写入文件时用str(token)把Fernet加密后的bytes对象转成了带b'...'格式的字符串,读取时仅通过截取[2:-1]去掉首尾标识,但这种处理方式会破坏加密token的字节完整性,导致解密时签名验证失败——哪怕单条记录看似能运行,也是偶然适配,本质是不可靠的字符串转义处理。
Fernet token本身是base64编码的字节流,正确做法是直接将其解码为纯字符串,避免多余格式字符。
修复后的代码
写入函数修改
将str(token)替换为token.decode('utf-8'),直接把bytes类型的token转成纯base64字符串:
def write_record(site,account,password,key): f = Fernet(key) token = f.encrypt(bytes(password,'utf-8')) with open ('secrets.txt','a') as file: file.write(f"{site},{account},{token.decode('utf-8')}\n")
读取函数修改
无需再截取字符串,直接将读取到的字符串编码为bytes即可,同时增加异常处理和记录校验:
def read_record(key): f = Fernet(key) with open ('secrets.txt','r') as file: lines = file.readlines() for line in lines: line = line.strip() # strip已包含去除换行符,无需额外replace parts = line.split(",", 2) # 限制拆分次数,避免token中意外出现逗号(Fernet token本身不含逗号,但更严谨) if len(parts) != 3: print(f"无效记录:{line}") continue site, account, token_str = parts token = token_str.encode('utf-8') try: decrypted_pwd = f.decrypt(token).decode('utf-8') print(f"站点:{site},账号:{account},密码:{decrypted_pwd}") except cryptography.fernet.InvalidToken: print(f"解密失败,无效token:{token_str}")
额外优化建议
- 每次运行生成新
key会导致旧记录无法解密,实际使用中需将key安全存储(比如用用户主密码派生后加密保存),而非每次生成新key。 - 推荐使用Python内置的
csv模块处理记录读写,避免手动拼接字符串可能出现的分隔符冲突问题。
内容的提问来源于stack exchange,提问作者ali nasser
相关产品推荐
相关产品推荐

