Argon2
Argon2 是一种现代、安全且抗 ASIC、抗 GPU 的密钥派生函数。在 CPU 和 RAM 用量配置参数相近的情况下,正确配置的 Argon2 比 PBKDF2、Bcrypt 和 Scrypt 更能抵抗密码破解。
Argon2 的变体
Argon2 函数有多个变体:
- Argon2d——具有很强的 GPU 抗性,但可能受到侧信道攻击(只在非常特殊的情况下可能发生)。
- Argon2i——GPU 抗性较弱,但不存在侧信道攻击。
- Argon2id——推荐使用(结合了 Argon2d 和 Argon2i)。
Argon2 的配置参数
Argon2 具有以下配置参数,与 Scrypt 非常相似:
- password
P:要进行哈希的密码(或消息) - salt
S:随机生成的盐(密码哈希建议使用 16 字节) - iterations
t:要执行的迭代次数 - memorySizeKB
m:要使用的内存量(以 KB 为单位) - parallelism
p:并行度(即线程数) - outputKeyLength
T:期望返回的字节数
Argon2——示例
可以在这里在线试用 Argon2 基于密码的密钥派生函数:http://antelle.net/argon2-browser。

在 Python 中计算 Argon2——示例
现在编写一些 Python 代码,使用 Argon2 算法从密码派生密钥。
首先,使用以下命令安装 Python 包 argon2_cffi:
pip install argon2_cffi
现在编写用于计算 Argon2 的 Python 代码:
import argon2, binascii
hash = argon2.hash_password_raw(
time_cost=16, memory_cost=2**15, parallelism=2, hash_len=32,
password=b'password', salt=b'some salt', type=argon2.low_level.Type.ID)
print("Argon2 raw hash:", binascii.hexlify(hash))
argon2Hasher = argon2.PasswordHasher(
time_cost=16, memory_cost=2**15, parallelism=2, hash_len=32, salt_len=16)
hash = argon2Hasher.hash("password")
print("Argon2 hash (random salt):", hash)
verifyValid = argon2Hasher.verify(hash, "password")
print("Argon2 verify (correct password):", verifyValid)
try:
argon2Hasher.verify(hash, "wrong123")
except:
print("Argon2 verify (incorrect password):", False)
运行上面的代码示例:https://repl.it/@nakov/Argon2-in-Python。
上述代码首先派生一个“原始哈希”(256 位密钥),这是基于 argon2 的密钥派生,与 scrypt 类似。它还会派生一个“argon2 哈希”,其中包含算法参数、随机盐和派生密钥。后者用于密码存储和验证。最后,使用正确密码和错误密码测试计算出的哈希。
Argon2 计算接受多个输入配置项:time_cost(迭代次数)、memory_cost(以 KB 计的内存用量)、parallelism(要使用的并行线程数)、hash_len(派生密钥大小)、salt_len(随机生成的盐大小,通常为 128 位/16 字节)。
上述代码执行的输出示例:
Argon2 raw hash: b'157f21dd3fdf7bafb76d2923ccaffa0b7be7cbae394709474d2bc66ee7b09d3e'
Argon2 hash (random salt): $argon2id$v=19$m=32768,t=16,p=2$Rfy6J41W9idBU+n/8sZc6Q$i3QYYPtoogIAw78I2qqlUQ8vjzUXGG1V6QsBOq2NIp4
Argon2 verify (correct password): True
Argon2 verify (incorrect password): False
请注意,上述输出中的 argon2 哈希采用标准化格式,其中包含 Argon2 算法配置参数 + 派生密钥 + 随机盐。按照设计,每次执行代码时,盐和派生密钥都应不同。
尝试多次执行上述代码,确认派生密钥保持相同(因为盐固定),而派生出的 argon2 哈希每次执行都不同(因为算法内部会生成随机盐)。
尝试修改 time_cost 或 memory_cost 设置,观察它们如何影响密钥派生的执行时间。
将算法设置 + 盐 + 哈希一同存储
在许多应用、框架和工具中,Argon2 密码哈希会与算法设置和盐一同存储在一个具有特定格式(如上所示)的字符串中。该字符串由多个部分组成,以 $ 字符分隔。例如,密码 p@ss~123 可以按如下 Argon2 标准格式存储(这里给出多个示例,以便看清其模式):
$argon2d$v=19$m=1024,t=16,p=4$c2FsdDEyM3NhbHQxMjM$2dVtFVPCezhvjtyu2PaeXOeBR+RUZ6SqhtD/+QF4F1o
$argon2d$v=19$m=1024,t=16,p=4$YW5vdGhlcnNhbHRhbm90aGVyc2FsdA$KB7Nj7kK21YdGeEBQy7R3vKkYCz1cdR/I3QcArMhl/Q
$argon2i$v=19$m=8192,t=32,p=1$c21hbGxzYWx0$lmO1aPPy3x0CcvrKpFLi1TL/uSVJ/eO5hPHiWZFaWvY
上述所有哈希都对应同一个密码,但算法设置和盐各不相同。
何时使用 Argon2?
正确配置时,Argon2 被认为是一种高度安全的 KDF 函数,也是业界可用的最佳选择之一。因此,可以把它用作通用的基于密码的密钥派生算法,例如用于加密钱包、文档、文件或应用密码。一般情况下,推荐使用 Argon2,而非 Scrypt、Bcrypt 或 PBKDF2。