bcrypt如何能够内build盐?

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

bcrypt有防止彩虹表攻击的内置盐。

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

OpenBSD从arcfour(arc4random(3))密钥stream中生成128位bcrypt salt,内核从设备时序收集随机数据。

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

  • 每个存储的密码需要不同,所以每个都需要生成一个单独的彩虹表
  • 它需要存储在某个地方,以便它是可重复的:当用户尝试login时,我们会尝试密码,重复我们原来存储密码时所做的相同的salt-and-hash程序,然后比较

当我使用bcrypt使用Devise(Railsloginpipe理器)时,数据库中没有salt列,所以我很困惑。 如果盐是随机的,没有存储在任何地方,我们如何可靠地重复哈希过程呢?

简而言之, bcrypt如何能够embedded盐

这是bcrypt:

生成一个随机的盐。 “成本”因素已经预先configuration。 收集密码。

使用盐和成本因子从密码导出encryption密钥。 用它来encryption一个众所周知的string。 存储成本, 和密文。 因为这三个元素具有已知的长度,所以很容易将它们连接起来并将它们存储在一个单独的字段中,但是可以稍后拆分它们。

当有人试图authentication,检索存储的成本和盐。 从input密码中导出密钥。 encryption相同的众所周知的string。 如果生成的密文与存储的密文匹配,则密码匹配。

Bcrypt的运作方式与基于PBKDF2等algorithm的更传统的scheme非常类似。 使用派生密钥encryption已知纯文本的主要区别在于: 其他scheme(合理地)假设密钥导出函数是不可逆的,并直接存储派生密钥。


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

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

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

  • 2a标识所使用的bcryptalgorithm版本。
  • 10是成本因素; 使用密钥派生函数的2 10次迭代(这是不够的,顺便说一句,我推荐12或更多的代价)。
  • vI8aWBnW3fID.ZQ4/zo1G.q1lRps.9cGLcZEiGDMVr5yUP1KUOYTa是盐和密文,连接并编码在一个修改后的Base-64中。 前22个字符解码为盐的16字节值。 其余字符是密码文本进行比较authentication。

这个例子取自Coda Hale的ruby实现的文档。

我相信这句话应该是这样写的:

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

bcrypt实用程序本身似乎不会维护一个盐的列表。 相反,salt是随机生成的,并附加到函数的输出中,以便稍后记住它们(根据bcrypt的Java实现 )。 换句话说,由bcrypt生成的“散列” 不仅仅是散列。 相反,它是哈希盐级联。