必须先生成并安全保存Fernet密钥,否则加密文件将永久丢失;密钥为bytes类型,须用"rb"模式读取文件,加密结果不可篡改或错误编码,否则解密失败报InvalidToken。

用 Fernet 加密文件前必须先生成密钥
不生成或没保存好 key,加密后的文件等于直接丢弃——Fernet 不提供密钥恢复机制,也没办法“猜”出来。
-
Fernet.generate_key()返回的是 bytes,得存成文件(比如key.key),不能只打印完就扔掉 - 密钥不能硬编码进脚本,尤其别提交到 Git;推荐通过环境变量或独立配置文件加载
- 同一个
key可反复用于加解密,但换一次密钥,旧文件就彻底打不开
示例:生成并保存密钥
from cryptography.fernet import Fernet
key = Fernet.generate_key()
with open("key.key", "wb") as f:
f.write(key)
读文件时别用 open(..., "r") 直接传给 Fernet.encrypt()
Fernet.encrypt() 只接受 bytes,而 open(..., "r") 返回字符串,会直接报 TypeError: data must be bytes。
- 加密二进制文件(如 PDF、图片)必须用
"rb"模式读取 - 加密文本文件也建议统一用
"rb",避免编码歧义;若坚持用文本模式,得手动.encode("utf-8") - 别试图对超大文件一次性
.read()进内存——Fernet不支持流式加解密,得自己分块处理(但注意:分块破坏完整性校验,一般不推荐)
正确做法:
立即学习“Python免费学习笔记(深入)”;
with open("data.txt", "rb") as f:
plaintext = f.read()
f_obj = Fernet(key)
ciphertext = f_obj.encrypt(plaintext)
Fernet 加密后内容自带时间戳和 HMAC,不能当普通 base64 乱改
加密结果是带元数据的 bytes,base64 编码后看起来像随机字符串,但结构固定。任意修改(比如截断、替换字符、重新 base64 编码)都会导致 InvalidToken 错误。
- 存储或传输加密结果时,应保持原始 bytes 或用
base64.urlsafe_b64encode()编码,解密前再urlsafe_b64decode() -
InvalidToken不单表示密钥错,也可能是数据损坏、被截断、或用了错误的 base64 解码方式 - 别用
str(ciphertext)或ciphertext.decode()强转字符串——它含不可见字节,会静默破坏数据
解密失败常见原因:密钥类型错、文件读写模式不匹配、Python 版本差异
Fernet 对输入极其敏感,一个环节出错就 InvalidToken,而不是提示具体哪错了。
- 密钥必须是
bytes类型,如果从文件读出来是字符串,得先.encode();如果用os.environ.get()拿密钥,记得base64.urlsafe_b64decode() - 加密用
"rb",解密后写回也得用"wb";文本场景下若想写回 UTF-8 文件,解密后要显式.decode("utf-8") - Python 3.12+ 对某些 base64 边界行为更严格,老脚本在新版本可能因编码方式不一致而失败
最简验证流程:
# 确保 key 是 bytes,ciphertext 是原始加密结果(非 str)
f_obj = Fernet(key)
try:
plaintext = f_obj.decrypt(ciphertext)
except Exception as e:
print(type(e).__name__) # 看清到底是 InvalidToken 还是其他
加密本身不难,难在密钥生命周期管理和二进制/文本边界处理——这两处一松懈,文件就再也打不开。


















