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

Python聊天程序加密解密功能故障排查求助

聊天记录加密压缩导入导出故障排查与修复

问题描述

开发聊天程序时,实现聊天记录加密压缩保存与加载功能后,export_history和import_history方法出现异常:解密时抛出"Fernet key must be 32 url-safe base64-encoded bytes."或"InvalidToken"错误,未添加加密压缩前功能正常。

错误原因分析

  • 密钥截断错误:Fernet生成的密钥是44字节的URL-safe Base64字符串(对应24字节原始二进制数据,Base64编码后固定长度为44),但导入时错误截取前32字节,导致密钥格式无效或不完整。
  • 冗余Base64编码:导出时对Fernet加密结果额外执行base64.b64encode,但Fernet的encrypt方法本身已返回URL-safe Base64格式数据,重复编码导致导入时无法正确解密。
  • 双重压缩处理:导出时先调用lzma.compress,再用lzma.open写入文件,lzma.open本身会自动处理压缩,双重压缩导致数据格式混乱。
  • 无明确数据边界:直接拼接密钥和加密数据,依赖固定长度分割易因数据内容变化导致分割错误。

修复后的代码

export_history方法

def export_history(self, filename='chat_history.json.enc'):
    # Fernet密钥本身就是合法的URL-safe Base64格式,直接使用
    cipher = Fernet(self.key)
    # 聊天记录转JSON后加密,Fernet.encrypt返回URL-safe Base64字节串
    encrypted_data = cipher.encrypt(json.dumps([msg.to_dict() for msg in self.messages]).encode('utf-8'))
    # 用明确分隔符区分密钥与加密数据,避免分割错误
    file_data = self.key + b'|||' + encrypted_data
    
    # 直接通过lzma.open写入,自动处理压缩,无需额外编码和压缩操作
    with lzma.open(filename, 'wb') as file:
        file.write(file_data)

import_history方法

def import_history(self, filename='chat_history.json.enc'):
    try:
        with lzma.open(filename, 'rb') as file:
            decompressed_data = file.read()
            
            # 按分隔符分割密钥和加密数据,仅分割一次避免数据内包含分隔符的情况
            key, encrypted_data = decompressed_data.split(b'|||', 1)
            
            try:
                # 直接用提取的完整密钥初始化Fernet
                cipher = Fernet(key)
                decrypted_data = cipher.decrypt(encrypted_data)
                data = json.loads(decrypted_data.decode('utf-8'))
                
                self.messages = [ChatRoomMessage.ChatRoomMessage(
                    msg['sender'], 
                    msg['content'], 
                    datetime.datetime.fromisoformat(msg['timestamp'])
                ) for msg in data]
                self.key = key

            except InvalidToken as e:
                print(f"解密错误: {e}")
            except ValueError as e:
                print(f"数据格式错误(无有效分隔符): {e}")

    except FileNotFoundError:
        print("文件未找到")

修复说明

  1. 密钥完整性:保留完整的44字节Fernet密钥,避免格式错误。
  2. 简化编码逻辑:移除冗余的Base64编码操作,直接使用Fernet原生输出格式。
  3. 单一压缩处理:仅通过lzma.open处理压缩,避免双重压缩导致的数据混乱。
  4. 明确数据分割:使用b'|||'作为密钥与加密数据的分隔符,确保分割逻辑可靠。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 13:13:09