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

如何用Argon2生成可用于Fernet加密的32字节密钥?

问题:用明文密码生成Fernet兼容的32字节密钥失败

我的目标

将明文密码生成可用于Fernet加密的32字节令牌。

已尝试操作

>>> from cryptography.fernet import Fernet
>>> import argon2
>>> import base64
>>> hash = argon2.hash_password('abc'.encode(), hash_len=32)
>>> hash
b'$argon2i$v=19$m=65536,t=3,p=4$ee2ZpEZ5Q58HwIT91xQxgw$QrzxXCLBOnuzLgVPoccIPcaeF4mS4uvmrRBFzNXZbxw'
>>> Fernet(hash)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python3/dist-packages/cryptography/fernet.py", line 34, in __init__
    raise ValueError(
ValueError: Fernet key must be 32 url-safe base64-encoded bytes.

后续尝试

>>> b64_hash = base64.urlsafe_b64decode(hash)
>>> b64_hash
b'j\xb8(\x9fh\xaf\xd7\xd9'
>>> Fernet(b64_hash)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python3/dist-packages/cryptography/fernet.py", line 32, in __init__
    key = base64.urlsafe_b64decode(key)
  File "/usr/lib/python3.10/base64.py", line 133, in urlsafe_b64decode
    return b64decode(s)
  File "/usr/lib/python3.10/base64.py", line 87, in b64decode
    return binascii.a2b_base64(s)
binascii.Error: Incorrect padding

错误根源与解决方法

核心问题

  1. 第一次错误:传入Fernet的是argon2生成的完整格式化哈希字符串——这个字符串包含算法标识、参数、盐和哈希值,完全不符合Fernet要求的「32字节原始数据的url-safe base64编码」格式。
  2. 第二次错误:对整个argon2哈希做base64解码逻辑完全颠倒:Fernet需要的是把32字节原始密钥编码成base64,而非解码;而且argon2哈希里只有最后一段是哈希值的base64编码,整个字符串无法直接解码。

正确实现步骤

要从明文密码生成Fernet可用的密钥,需分两步:从密码导出32字节原始密钥,再将其编码为url-safe base64格式。

代码示例:

from cryptography.fernet import Fernet
import argon2
import base64

# 1. 生成盐(若需要固定密钥可复用同一盐,否则每次生成新盐)
salt = argon2.generate_salt()

# 2. 从明文密码导出32字节原始密钥(用argon2低级API获取原始哈希值)
raw_key = argon2.low_level.hash_secret_raw(
    secret='abc'.encode(),
    salt=salt,
    time_cost=3,
    memory_cost=65536,
    parallelism=4,
    hash_len=32,
    type=argon2.Type.I
)

# 3. 将原始密钥编码为Fernet要求的url-safe base64格式
fernet_key = base64.urlsafe_b64encode(raw_key)

# 4. 初始化Fernet并测试
f = Fernet(fernet_key)
encrypted = f.encrypt(b"测试消息")
print("加密结果:", encrypted)
decrypted = f.decrypt(encrypted)
print("解密结果:", decrypted.decode())

关键提示

  • argon2.hash_password返回的是用于密码验证的格式化哈希字符串,不适合直接作为加密密钥;要获取原始32字节密钥,必须使用argon2.low_level.hash_secret_raw。
  • Fernet的密钥格式是「32字节二进制数据 → url-safe base64编码字符串」,切勿搞反编码/解码顺序。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 10:23:10