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

使用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 14:19:55