使用functools.partial迭代解密文件时触发cryptography.fernet.InvalidToken错误
使用Fernet分段解密时触发InvalidToken错误的修复方案
问题背景
用functools.partial迭代读写文件做加解密,加密函数encryypt()运行正常,但解密decryypt()时抛出cryptography.fernet.InvalidToken错误,已确认密钥和Fernet实例一致,问题出在迭代读写的逻辑上。
原代码
key = Fernet.generate_key() print(key) cypher = Fernet(key) def encryypt(): with open('file.pdf', 'rb') as f, open('file2.pdf', 'wb') as target_f: for _bytes in iter(partial(f.read, 10*2048), ''): encrypt_data = cypher.encrypt(_bytes) target_f.write(encrypt_data) if not _bytes:break target_f.close() def decryypt() : with open('file2.pdf', 'rb') as ff, open('file3.pdf', 'wb') as target_ff: for __bytes in iter(partial(ff.read, 10*2048), ''): decrypt_data = cypher.decrypt(__bytes) target_ff.write(decrypt_data) if not __bytes:break encryypt() decryypt()
报错信息
Traceback (most recent call last): File "C:\Users\#\#\.venv\Lib\site-packages\cryptography\fernet.py", line 134, in _verify_signature h.verify(data[-32:]) cryptography.exceptions.InvalidSignature: Signature did not match digest. During handling of the above exception, another exception occurred: Traceback (most recent call last): File "c:\Users\#\#\Bin2\Start\test.py", line 43, in <module> decryypt() File "c:\Users\#\#\Bin2\Start\test.py", line 39, in decryypt decrypt_data = cypher.decrypt(__bytes) ^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Users\#\#\.venv\Lib\site-packages\cryptography\fernet.py", line 91, in decrypt return self._decrypt_data(data, timestamp, time_info) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Users\#\#\.venv\Lib\site-packages\cryptography\fernet.py", line 152, in _decrypt_data self._verify_signature(data) File "C:\Users\#\#\.venv\Lib\site-packages\cryptography\fernet.py", line 136, in _verify_signature raise InvalidToken cryptography.fernet.InvalidToken
问题根源
- 哨兵值类型不匹配:
iter(partial(f.read, ...), '')中,二进制文件读取返回bytes类型,哨兵用字符串''永远不会匹配,导致循环多处理一次空字节块,写入无效加密数据。 - Fernet Token完整性被破坏:Fernet加密后的每个结果是独立的、格式固定的Token,不能拆分或拼接后解密。原代码解密时按固定字节数读取,会把多个Token混在一起或截断单个Token,导致
decrypt()无法识别有效签名,抛出InvalidToken。
修复方案
修改加解密逻辑,确保每个加密后的Token单独存储(用换行分隔,Fernet Token不含换行符),解密时按完整Token读取:
from cryptography.fernet import Fernet from functools import partial key = Fernet.generate_key() print(key) cypher = Fernet(key) def encryypt(): with open('file.pdf', 'rb') as f, open('file2.pdf', 'wb') as target_f: # 二进制读取的哨兵值改为b'',匹配返回类型 for _bytes in iter(partial(f.read, 10*2048), b''): if not _bytes: break encrypt_data = cypher.encrypt(_bytes) # 每个Token后写入换行符分隔 target_f.write(encrypt_data + b'\n') def decryypt(): with open('file2.pdf', 'rb') as ff, open('file3.pdf', 'wb') as target_ff: # 按行读取每个完整的Token for line in ff: token = line.strip() if not token: continue decrypt_data = cypher.decrypt(token) target_ff.write(decrypt_data) encryypt() decryypt()
关键修改点
- 加密时将哨兵值改为
b'',避免处理无效空字节块。 - 每个加密Token后添加换行符,保证Token的独立性。
- 解密时按行读取,去除换行符后再解密,确保传入
decrypt()的是完整有效的Fernet Token。
内容的提问来源于stack exchange,提问作者Ninja-Flex6969
相关产品推荐
相关产品推荐

