指定hash_len=32后Argon2哈希仍超32字节?AES加密报错求助
问题原因与解决方案
核心问题:Base64编码导致长度膨胀
你指定的hash_len=32是二进制哈希值的长度,但PasswordHasher.hash()返回的是符合Argon2标准格式的字符串,其中的哈希部分是经过Base64编码后的结果。
Base64编码规则是每3个二进制字节转换为4个ASCII字符,32字节的二进制数据编码后会变成43个字符(计算方式:ceil(32 / 3) * 4 = 43),这就是你看到哈希长度为43的原因。直接用这个编码后的字符串作为AES密钥,自然会因为长度不符合要求报错。
解决步骤
方法1:从哈希字符串中提取并解码哈希部分
Argon2的哈希字符串格式为:$argon2id$v=19$m=xxx,t=xxx,p=xxx$<Base64编码的盐>$<Base64编码的哈希>
你可以按$分割字符串,提取最后一段(哈希的Base64编码),再解码为原始二进制字节:
import base64 from argon2 import PasswordHasher ph = PasswordHasher(hash_len=32, salt_len=16) hash_str = ph.hash(key) # 分割哈希字符串,提取Base64编码的哈希部分 parts = hash_str.split('$') b64_hash = parts[-1] # 解码为32字节的二进制密钥 aes_key = base64.b64decode(b64_hash) # 现在可以正常使用AES from Crypto.Cipher import AES cipher = AES.new(aes_key, AES.MODE_EAX) nonce = cipher.nonce ciphertext, tag = cipher.encrypt_and_digest(data)
方法2:使用Argon2低级API直接生成原始哈希
如果不需要用于密码验证,只是生成密钥,可以跳过PasswordHasher的格式化输出,直接用低级API生成二进制哈希:
from argon2.low_level import hash_secret_raw, Type import os # 生成16字节随机盐 salt = os.urandom(16) # 生成32字节的二进制哈希 aes_key = hash_secret_raw( secret=key.encode('utf-8'), salt=salt, time_cost=3, memory_cost=65536, parallelism=4, hash_len=32, type=Type.ID )
额外提醒
PasswordHasher的设计初衷是密码验证,它生成的带格式字符串包含了验证所需的所有参数(算法、迭代次数、内存占用等),所以如果之后需要验证密码,要保留完整的hash_str,不要只存解码后的密钥。- AES密钥必须是二进制字节,不能是字符串,所以一定要确保你传递给
AES.new()的是解码后的字节数据,不是编码后的字符串。
内容的提问来源于stack exchange,提问作者Varun Pius Rodrigues
相关产品推荐
相关产品推荐

