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("文件未找到")
修复说明
- 密钥完整性:保留完整的44字节Fernet密钥,避免格式错误。
- 简化编码逻辑:移除冗余的Base64编码操作,直接使用Fernet原生输出格式。
- 单一压缩处理:仅通过
lzma.open处理压缩,避免双重压缩导致的数据混乱。 - 明确数据分割:使用
b'|||'作为密钥与加密数据的分隔符,确保分割逻辑可靠。
内容的提问来源于stack exchange,提问作者Admrail Hiccup
相关产品推荐
相关产品推荐

