Argon2、bcrypt、scrypt 还是 PBKDF2?

本文深入探讨了Argon2, bcrypt, scrypt和PBKDF2四种密码哈希方法,比较了它们在安全性、性能和应用场景方面的差异。文章还提供了基于WASM和JavaScript的实现示例,并分析了每种方法的优缺点,以及在WPA2和TrueCrypt等实际应用中的使用情况,强调了选择合适的哈希方法对于保护密码安全的重要性。

Argon2, bcrypt, scrypt 还是 PBKDF2?

网络安全最基本的原则之一是,哈希方法基本上分为两类:快速的和慢速的。由此,我们有 MD5、SHA-1、SHA-256 等快速哈希方法,以及 Argon2、Bcrypt、scrypt 和 PBKDF2 等慢速哈希方法。下面,我使用 WASM 和 JavaScript 实现了每种方法:

  • 带有 WASM 和 JavaScript 的 Argon2使用 WASM 和 JavaScript 进行哈希。Argon2 在 RFC 9106 中定义,标题为“用于密码哈希和工作量证明应用的内存硬函数”,用于密码哈希、密钥派生和工作量证明。主要变体是 Argon2id,它针对 x86 架构进行了优化。它有两个子变体:Argon2d 和 Argon2i。总的来说,Argon2d 使用数据相关的内存访问方法。这对于加密货币和工作量证明应用很有用,并且对于侧信道定时攻击没有任何威胁。或者,Argon2i 使用数据独立的内存访问,可用于密码哈希和基于密码的密钥派生 (KDF)。
  • 带有 WASM 和 JavaScript 的 Bcrypt带有 WASM 和 JavaScript 的 Bcrypt。bcrypt 由 Niels Provos 和 David Mazières 于 1999 年创建 [1],作为一种密码哈希方法。它基于 Blowfish 密码 [2]。我们使用一定数量的迭代进行哈希,这被定义为哈希处理的成本。输出的前四个字符是“2 b”,这是哈希标识符。 之后是成本参数。 值 8 表示哈希方法的 28 次迭代。 接下来的 22 个字符表示 salt 值的 Base64 表示形式,最后的 31 个字符表示 24 字节哈希的 Base64 表示形式。 一个例子是:“2 b 10$341C.SMLWm5DOk9rjYtNxevOd2EyOWw1EfggQELVfXKSrFM6cseEa”,其中“2b”标识 bcrypt 方法,“10” 表示 \(2^{10}\) 轮哈希,“341C.SMLWm5DOk9rjYtNxe”表示salt值,而“vOd2EyOWw1EfggQELVfXKSrFM6cseEa”表示哈希值。
  • 带有 WASM 和 JavaScript 的 PBKDF带有 WASM 和 JavaScript 的 PBKDF。PBKDF2(基于口令的密钥推导函数 2)在 RFC 2898 中定义,并生成一个加 salt 的哈希。它用于生成 WPA-2 Wi-fi 系统中密码的哈希。通常,这用于从定义的密码创建加密密钥,并且无法从哈希值反转密码。 它用于 TrueCrypt 中,以生成读取加密驱动器的标头信息所需的密钥,该标头信息存储加密密钥。 我们可以使用一系列哈希方法,例如 MD5、SHA1、SHA256 和 SHA3。 主要参数是:迭代次数、哈希方法、哈希长度和 salt 大小。
  • 带有 WASM 和 JavaScript 的 scrypt带有 WASM 和 JavaScript 的 scrypt。基于密码的密钥派生函数 (KDF) 的重点是从秘密中派生秘密。这包括使用 crypt、PBKDF2 和 bcrypt,它们使用许多密码学轮次来减慢操作速度并通常增加成本。不幸的是,随着处理器速度越来越快,迭代次数造成的障碍将会减少。如果我们使用 GPU,情况尤其如此。总的来说,PBKDF2 不会占用太多内存,因此不会给 GPU 带来困难。因此,scrypt 的破解成本远高于 bcrypt 和 PBKDF2。在这种情况下,对于每种方法生成密钥的大致相同的时间,scrypt 的成本总是高得多。对于 10 个字符,我们看到 PBKDF2(5.0 秒)的成本为 1000 万英镑,而 scrypt 的相同成本为 2100 亿美元。即使有六个字符,破解 scrypt 的成本也为 900 美元。

希望总的来说,我们已经过了使用 MD5 或 SHA1 对密码进行哈希处理的阶段,因为这些方法可能很弱。基本上,MD5 和 SHA1 是快速哈希方法,可以在其中快速尝试许多可能的密码。 bcrypt 和 Argon 2 减慢了这一过程,从而大大降低了哈希速率。那么,你应该使用哪一个呢?

bcrypt

MD5 和 SHA-1 生成哈希签名,但可以通过彩虹表对其进行攻击。Bcrypt 是一种更强大的密码哈希生成器,它使用 salt 来创建非重复哈希。它由 Niels Provos 和 David Mazières 设计,基于 Blowfish cipher。它被用作 BSD 和其他系统的默认密码哈希方法。总的来说,它使用 128 位的 salt 值,这需要 22 个 Radix-64 字符。它可以使用多次迭代,这将减慢对哈希值的任何暴力破解。

最近使用 hashcat 的 AWS EC2 服务器基准测试突出了 Bcrypt 的慢速 [ here]:

Hash type: MD5 Speed/sec: 380.02M words
Hash type: SHA1 Speed/sec: 218.86M words
Hash type: SHA256 Speed/sec: 110.37M words
Hash type: bcrypt, Blowfish(OpenBSD) Speed/sec: 25.86k words
Hash type: NTLM. Speed/sec: 370.22M words

因此,我们从每秒 3.8 亿个单词转移到每秒仅 25,860 个单词。

工作因子是 2^轮数,默认情况下通常设置为 11。设置为 11(这与大多数实现中的默认值相匹配,并且目前被认为是良好的安全/风险级别)。映射是:

| Cost  | Iterations               |
    |-------|--------------------------|
    |   8   |    256 iterations        |
    |   9   |    512 iterations        |
    |  10   |  1,024 iterations        |
    |  11   |  2,048 iterations        |
    |  12   |  4,096 iterations        |
    |  13   |  8,192 iterations        |
    |  14   | 16,384 iterations        |
    |  15   | 32,768 iterations        |
    |  16   | 65,536 iterations        |
    |  17   | 131,072 iterations       |
    |  18   | 262,144 iterations       |
    |  19   | 524,288 iterations       |
    |  20   | 1,048,576 iterations     |
    |  21   | 2,097,152 iterations     |
    |  22   | 4,194,304 iterations     |
    |  23   | 8,388,608 iterations     |
    |  24   | 16,777,216 iterations    |
    |  25   | 33,554,432 iterations    |
    |  26   | 67,108,864 iterations    |
    |  27   | 134,217,728 iterations   |
    |  28   | 268,435,456 iterations   |
    |  29   | 536,870,912 iterations   |
    |  30   | 1,073,741,824 iterations |
    |  31   | 2,147,483,648 iterations |

这是使用 WASM 的 bcrypt:

使用带有 JavaScript 的 WASM 的 Bcrypt \ \ bcrypt 由 Niels Provos 和 David Mazières 于 1999 年创建 [1],作为一种密码哈希方法。它基于 Blowfish...\ \ asecuritysite.com

Argon 2

Argon2 在 RFC 9106 中定义,标题为“用于密码哈希和工作量证明应用的内存硬函数”。用于密码哈希、密钥派生和工作量证明。主要变体是 Argon2id,它针对 x86 架构进行了优化。它有两个子变体:Argon2d 和 Argon2i。总的来说,Argon2d 提供数据相关的内存访问方法,适用于加密货币和工作量证明应用。它也没有任何侧信道定时攻击的威胁。或者,Argon2i 使用数据独立的内存访问,可用于密码哈希和基于密码的密钥派生 (KDF)。

Argon 2 中使用的主要参数在图 1 中定义,例如迭代、memcost 和并行性。标准形式为:

$argon2i$v=19$m=4096,t=2,p=4$salt$rZHPyRIa8XEvQ9rVqpvoibllLagNNGUeCNCmxeZfgBA

其中 v=19 标识我们正在使用 Argon 2。然后,这些参数在“m=4096,t=2,p=4”中定义,其中我们的内存成本为 4,096 字节,并行性为 4,迭代次数为 2。在这种情况下,salt 为“salt”,派生的哈希为“rZHPyRIa8XEvQ9rVqpvoibllLagNNGUeCNCmxeZfgBA”。Argon 2 也可以使用定义的字节数(摘要大小)输出。

这是带有 WASM 的 Argon 2:

使用带有 JavaScript 的 WASM 的 Argon2 \ \ Argon2 在 RFC 9106 中定义,标题为“用于密码哈希和工作量证明的内存硬函数…\ \ asecuritysite.com

scrypt

scrypt 基于 Colin Percival [2] 的一篇原始论文:

该论文对成本进行了以下估算:

参考资料 [2]

由此,我们看到 scrypt 的破解成本远高于 bcrypt 和 PBKDF2。在这种情况下,对于每种方法生成密钥的大致相同的时间,scrypt 的成本总是高得多。对于 10 个字符,我们看到 PBKDF2(5.0 秒)的成本为 1000 万英镑,而 scrypt 的相同成本为 2100 亿美元。即使有六个字符,破解 scrypt 的成本也为 900 美元。

它使用密码和 salt 值并计算内存硬计算。 为此,它采用与大多数 KDF 不同的方法,具有多个参数:块大小 (r) 和 CPU/内存成本参数 (N — 2 的幂) 和并行量 (p)。 计算的核心不是哈希函数,而是 Salsa20/8 Core — 它是 Salsa20 Core [1] 的精简变体。

总的来说,可以使用 N、r 和 p 运行系统,这与可用的内存和计算能力以及所需的并行量有关。可以看出 r = 8 且 p = 1 给出良好的结果。

2016 年的一项评估 [ here], 概述了 2^N、r 和 p 的值对计算密钥的时间的影响:

在此,我们看到增加参数会增加所需内存的大小。 如果 GPU 具有一定大小的内存,我们可以确保我们使其溢出。 推荐参数为:

  • N: 16384 (2¹⁴)
  • r: 8
  • p: 1

使用的内存为:

Memory (Bytes) = (128.N.r) + (128.r.p)

如果我们使用上面的参数,我们会得到:

Memory = (128 * 214 \* 8) + (128 * 8 \* 1) = 16,778,240 bytes (16 MB)

带有 WASM 的 scrypt 编码为:

使用带有 JavaScript 的 WASM 的 scrypt \ \ 基于密码的密钥派生函数 (KDF) 的重点是从秘密中派生秘密。 这包括...\ \ asecuritysite.com

PBKDF2

PBKDF2 是一种简单的哈希方法,在 RFC 2898 中定义 [ here]:

但是,它像其他一些方法一样保护你的在线安全。 为什么? 因为每次你连接到 Wifi 网络时,都是 PBKDF2(基于密码的密钥派生函数 2)保护你的 Wifi 密码。 总的来说,它使用多个哈希迭代来确定最终的哈希值,其中这些迭代会减慢哈希过程。 并且,当我们向哈希添加 salt 时,攻击者无法使用彩虹表来破解密码。 通常,攻击者每秒只能尝试不到 1,000 个密码短语,而像 SHA-256 这样的快速哈希方法,可以允许尝试 10 万个。

TrueCrypt

通常,PBKDF2 也用于从已定义的密码创建加密密钥,并且无法从哈希值反转密码。 否则,我们可以使用它来保护敏感资产,例如在 TrueCrypt 中使用它来生成读取加密驱动器的标头信息所需的加密密钥,该标头信息存储加密密钥。 在 TrueCrypt 中,我们使用 PBKDF2 生成密钥(带有 salt),它将解密标头并显示用于加密磁盘的密钥(使用 AES、3DES 或 Twofish):

我们这样使用它:

byte[] result = passwordDerive.GenerateDerivedKey(16,
   ASCIIEncoding.UTF8.GetBytes(message), salt, 1000);

它具有 16 字节(128 位 — dklen)的密钥长度,使用 salt 字节数组,并且哈希迭代 1000 次(Miterations)。 你应该发现生成的哈希值将具有 32 个十六进制字符(16 字节)。

WPA2

PBKDF2 的通用格式为:

DK = PBKDF2(Password, Salt, Miterations, dkLen)

其中 Password 是密码,Salt 是 salt,Miterations 是迭代次数,dklen 是派生哈希的长度。 总的来说,我们可以创建与我们的应用程序匹配的大小的 DK。

但是,它的主要用途是在 WPA-2 中,我们在其中创建了密码的哈希版本。 因此,WPA-2 使用 4,096 次迭代。 它的主要重点是生成密码的哈希版本,并包括一个 salt 以减少彩虹表攻击的机会。 它通常使用超过 1,000 次迭代来减慢哈希的创建速度,以便它可以克服暴力攻击。

定义 Wifi 中使用的 WPA 安全性的 IEEE 802.11i 标准概述了预共享密钥由以下公式定义:

PSK = PBKDF2(PassPhrase, ssid, ssidLength, 4096, 256)

因此,我们看到我们使用了 4,096 次迭代。

WASM 中的编码为:

使用带有 JavaScript 的 WASM 的 PBKDF2 \ \ Bib: @misc{asecuritysite_19466, title = {使用带有 JavaScript 的 WASM 的 PBKDF2}, year={2025}, organization =…\ \ asecuritysite.com

参考资料

[2] Percival, C. (2009). 通过连续内存硬函数实现更强的密钥派生。

  • 原文链接: medium.com/asecuritysite...
  • 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
asecuritysite
asecuritysite
江湖只有他的大名,没有他的介绍。