bcrypt如何内置盐?

时间:2011-07-26 15:21:34

标签: security hash internals bcrypt

Coda Hale的文章"How To Safely Store a Password"声称:

  

bcrypt内置了盐来防止彩虹表攻击。

他引用了this paper,其中表示在OpenBSD的bcrypt实现中:

  

OpenBSD从arcfour生成128位bcrypt salt   (arc4random(3))密钥流,用随机数据播种内核   从设备时间收集。

我不明白这是如何工作的。在我对盐的概念中:

  • 每个存储的密码需要不同,因此必须为每个
  • 生成单独的彩虹表。
  • 它需要存储在某处,以便它可重复:当用户尝试登录时,我们会尝试密码,重复我们最初存储密码时所做的盐和哈希过程,并进行比较

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

简而言之, bcrypt如何内置盐

5 个答案:

答案 0 :(得分:692)

这是bcrypt:

生成随机盐。已经预先配置了“成本”因素。收集密码。

使用salt和cost因子从密码中导出加密密钥。用它来加密一个众所周知的字符串。 存储费用, salt,和密文。因为这三个元素具有已知的长度,所以很容易将它们连接起来并将它们存储在一个字段中,但以后能够将它们分开。

当有人尝试进行身份验证时,检索存储的成本和盐。从输入密码,成本和盐中获取密钥。加密相同的知名字符串。如果生成的密文与存储的密文匹配,则密码匹配。

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


存储在数据库中的bcrypt“哈希”可能如下所示:

  

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

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

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

此示例取自documentation for Coda Hale's ruby implementation.

答案 1 :(得分:162)

我认为这句话应该措辞如下:

  

bcrypt在生成的哈希 中内置了 盐,以防止彩虹表攻击。

bcrypt实用程序本身似乎没有维护盐列表。相反,盐是随机生成的,并附加到函数的输出中,以便稍后记住它们(根据the Java implementation of bcrypt)。换句话说,bcrypt生成的“哈希”不是 只是 哈希。相反,它是连接盐的哈希

答案 2 :(得分:1)

为了使事情更加清晰

注册/登录方向->

使用从以下各项生成的密钥对密码+盐加密:成本,盐和密码。我们将该加密值称为cipher text。然后将盐附加到该值,并使用base64对其进行编码。附加费用,这是bcrypt产生的字符串:

$2a$COST$BASE64

此值最终存储。

攻击者需要做什么才能找到密码? (其他方向<-)

如果攻击者获得了对数据库的控制权,则攻击者将轻松解码base64值,然后他就能看到盐。盐不是秘密。虽然是随机的 然后,他将需要解密cipher text

更重要的是:在此过程中没有散列,而是CPU昂贵的加密-解密。因此,彩虹表的相关性较低。

答案 3 :(得分:1)

这是一个简单的术语...

Bcrypt 没有存储盐的数据库...

salt 以 base64 格式添加到哈希中....

问题是bcrypt在没有数据库的情况下是如何验证密码的...?

bcrypt 的作用是从密码散列中提取盐...使用提取的盐来加密普通密码并将新散列与旧散列进行比较,看看它们是否相同......

答案 4 :(得分:0)

这来自Spring Security的PasswordEncoder接口文档,

 * @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编码密码进行匹配。