Coda Hale的文章"How To Safely Store a Password"声称:
bcrypt内置了盐来防止彩虹表攻击。
他引用了this paper,它说在OpenBSD的bcrypt
实现中:
OpenBSD从arcfour(arc4random(3))密钥流生成128位bcrypt salt,并使用内核从设备计时收集的随机数据进行种子处理。
我不明白这是如何工作的。在我的盐概念中:
当我使用带有bcrypt的Devise(一个Rails登录管理器)时,数据库中没有salt列,所以我很困惑。如果盐是随机的并且没有存储在任何地方,我们如何可靠地重复散列过程?
简而言之,bcrypt如何内置盐?
这是bcrypt:
生成随机盐。已经预先配置了“成本”因素。收集密码。
使用salt和cost因子从密码派生加密密钥。用它来加密一个众所周知的字符串。存储成本,盐和密文。因为这三个元素具有已知的长度,所以很容易将它们连接起来并将它们存储在单个字段中,但是稍后可以将它们分开。
当有人尝试进行身份验证时,检索存储的成本和盐。从输入密码,成本和盐中获取密钥。加密相同的知名字符串。如果生成的密文与存储的密文匹配,则密码匹配。
Bcrypt以与基于诸如PBKDF2的算法的更传统方案非常类似的方式操作。主要区别在于使用派生密钥加密已知的纯文本;其他方案(合理地)假设密钥派生函数是不可逆的,并直接存储派生密钥。
存储在数据库中,bcrypt
“hash”可能看起来像这样:
$ 2A $ 10 $ vI8aWBnW3fID.ZQ4 / zo1G.q1lRps.9cGLcZEiGDMVr5yUP1KUOYTa
这实际上是三个字段,由“$”分隔:
2a
识别使用的bcrypt
算法版本。10
是成本因素;使用密钥派生函数的210次迭代(顺便说一下这是不够的。我建议成本为12或更多。)vI8aWBnW3fID.ZQ4/zo1G.q1lRps.9cGLcZEiGDMVr5yUP1KUOYTa
是盐和密文,在改进的Base-64中连接和编码。前22个字符解码为盐的16字节值。其余字符是要进行身份验证的密文。我认为这句话应该措辞如下:
bcrypt在生成的哈希中内置了盐,以防止彩虹表攻击。
bcrypt
实用程序本身似乎没有维护盐列表。相反,盐是随机生成的,并附加到函数的输出中,以便稍后记住它们(根据the Java implementation of bcrypt
)。换句话说,bcrypt
生成的“哈希”不仅仅是哈希。相反,它是哈希和盐连接。
这是来自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编码密码进行匹配。