Python Fernet报密钥需为32位url安全base64编码字节错误修复
Fernet密钥格式报错修复
错误触发场景
程序执行解密逻辑
raw_pass = Fernet(key_de).decrypt(data["password"])
时抛出异常:Fernet key must be 32 url-safe base64-encoded bytes,已尝试对key_de做utf-8编码、base64编码处理仍无法解决。
根本原因
- 核心错误出在密钥输出环节:
Fernet.generate_key()返回值是bytes类型,注册流程中直接用str(key_en)将密钥转为字符串打印时,输出结果会自带b'前缀和末尾的'包裹符。例如真实密钥为b'XyZ123...abc=',str转换后打印给用户的内容是字面量b'XyZ123...abc=',用户复制该内容作为解密密钥输入时,会把多余的b'、'字符一并带入,最终编码后的字节长度、格式均不符合Fernet的32位url-safe base64要求。 - 存在隐藏空值bug:查询存储的密码时,如果输入的rapass不存在,
find_one()会返回None,直接访问data["_id"]会触发空对象访问错误。 - 冗余校验逻辑:按
_id=rapass查询到的返回结果,_id字段必然等于输入的rapass,额外做相等判断无意义,还会放大空值报错概率。
修复步骤
1. 修正注册环节的密钥输出逻辑
将原代码中直接str转换打印密钥的逻辑,改为对bytes类型密钥做utf-8解码后输出,保证打印给用户的密钥是纯base64字符串,无多余字符:
# 原错误代码 # print('SecurePass : ' + str(key_en)) # 修正后 print('SecurePass : ' + key_en.decode('utf-8'))
2. 重构查看密码环节的逻辑
增加空值判断、输入前后空格过滤、解密异常捕获,去掉冗余校验:
elif startMenu == 2: clear() print("Enter rapass:") rapass = input().strip() data = pass_collection.find_one({"_id" : rapass}) if not data: print("Invalid credentials.") input() clear() continue print("Enter SecurePass") key_de = input().strip() try: key_de_bytes = key_de.encode('utf-8') cipher = Fernet(key_de_bytes) raw_pass = cipher.decrypt(data["password"]).decode('utf-8') print("Stored password: ", raw_pass) except: print("SecurePass incorrect or invalid format. Please try again.") input() clear()
验证方式
重新走新建密码流程,此时打印的SecurePass不会带有b'前缀,复制该密钥后走查看密码流程,输入对应rapass和复制的SecurePass即可正常解密,不会再触发密钥格式错误。
内容的提问来源于stack exchange,提问作者ANewProgramer
相关产品推荐
相关产品推荐

