关于安全:Bcrypt怎么能有内置salts?

How can bcrypt have built-in salts?

Coda Hale的文章"如何安全存储密码"声称:

bcrypt has salts built-in to prevent rainbow table attacks.

他引用了这篇文章,其中说在OpenBSD的bcrypt的实现中:

OpenBSD generates the 128-bit bcrypt salt from an arcfour
(arc4random(3)) key stream, seeded with random data the kernel
collects from device timings.

我不明白这是怎么回事。在我对盐的概念中:

  • 对于每个存储的密码,它需要是不同的,因此必须为每个存储的密码生成一个单独的彩虹表。
  • 它需要存储在某个地方,这样它才是可重复的:当用户试图登录时,我们会尝试使用他们的密码,重复最初存储他们的密码时所做的相同的salt和hash过程,并比较

当我将DEVICE(一个Rails登录管理器)与Bcrypt一起使用时,数据库中没有salt列,所以我很困惑。如果盐是随机的,并且没有存储在任何地方,那么我们如何可靠地重复散列过程呢?

简而言之,Bcrypt怎么能有内置盐呢?


这是BCRIPT:

生成随机盐。预先配置了"成本"系数。收集密码。

使用salt和成本系数从密码派生加密密钥。使用它加密一个众所周知的字符串。存储成本、盐和密码文本。因为这三个元素有一个已知的长度,所以很容易将它们连接起来并存储在一个字段中,但是稍后可以将它们分开。

当有人试图验证时,检索存储的成本和盐。从输入密码、成本和salt派生一个键。加密相同的已知字符串。如果生成的密码文本与存储的密码文本匹配,则密码是匹配的。

BCRYPT的运行方式与基于PBKdf2等算法的更传统的方案非常相似。主要区别在于它使用派生密钥加密已知的纯文本;其他方案(合理地)假定密钥派生函数是不可逆的,并直接存储派生密钥。

存储在数据库中的bcrypt的"hash"可能如下所示:

$2a$10$vI8aWBnW3fID.ZQ4/zo1G.q1lRps.9cGLcZEiGDMVr5yUP1KUOYTa

这实际上是三个字段,由"$"分隔:

  • 2a标识所使用的bcrypt算法版本。
  • 10是成本因素;使用210次关键派生函数迭代(顺便说一下,这还不够)。我建议花费12英镑或更多。)
  • vI8aWBnW3fID.ZQ4/zo1G.q1lRps.9cGLcZEiGDMVr5yUP1KUOYTa是盐和密码文本,在修改的base-64中连接和编码。前22个字符解码为salt的16字节值。其余字符是要进行身份验证比较的密码文本。

这个例子取自CodaHale的Ruby实现文档。


我认为该短语的措辞如下:

bcrypt has salts built into the generated hashes to prevent rainbow table attacks.

bcrypt实用程序本身似乎没有维护盐的列表。相反,随机生成盐并附加到函数的输出,以便以后记住它们(根据EDCOX1(0)的Java实现)。换句话说,bcrypt生成的"hash"不仅仅是hash。相反,它是哈希和盐的连接。


这是来自Spring Security的密码编码器接口文档,

1
2
3
4
5
6
 * @param rawPassword the raw password to encode and match
 * @param encodedPassword the encoded password from storage to compare with
 * @return true if the raw password, after encoding, matches the encoded password from
 * storage
 */
boolean matches(CharSequence rawPassword, String encodedPassword);

这意味着,需要匹配用户下次登录时再次输入的rawpassword,并将其与在上次登录/注册期间存储在数据库中的bcrypt编码密码匹配。