简体   繁体   English

bcrypt 怎么会有内置盐?

[英]How can bcrypt have built-in salts?

Coda Hale's article "How To Safely Store a Password" claims that: Coda Hale 的文章“如何安全地存储密码”声称:

bcrypt has salts built-in to prevent rainbow table attacks. bcrypt 内置盐以防止彩虹表攻击。

He cites this paper , which says that in OpenBSD's implementation of bcrypt :他引用了这篇论文,其中说在 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. OpenBSD 从 arcfour (arc4random(3)) 密钥 stream 生成 128 位 bcrypt salt,并使用 kernel 从设备计时收集的随机数据作为种子。

I don't understand how this can work.我不明白这是怎么回事。 In my conception of a salt:在我的盐概念中:

  • It needs to be different for each stored password, so that a separate rainbow table would have to be generated for each每个存储的密码都需要不同,因此必须为每个密码生成一个单独的彩虹表
  • It needs to be stored somewhere so that it's repeatable: when a user tries to log in, we take their password attempt, repeat the same salt-and-hash procedure we did when we originally stored their password, and compare它需要存储在某个地方以便它是可重复的:当用户尝试登录时,我们获取他们的密码尝试,重复我们最初存储他们的密码时所做的相同的加盐和哈希过程,然后比较

When I'm using Devise (a Rails login manager) with bcrypt, there is no salt column in the database, so I'm confused.当我将 Devise(Rails 登录管理器)与 bcrypt 一起使用时,数据库中没有 salt 列,所以我很困惑。 If the salt is random and not stored anywhere, how can we reliably repeat the hashing process?如果盐是随机的并且没有存储在任何地方,我们如何才能可靠地重复哈希过程?

In short, how can bcrypt have built-in salts ?简而言之, bcrypt 怎么会有内置盐

This is bcrypt:这是 bcrypt:

Generate a random salt.生成随机盐。 A "cost" factor has been pre-configured. “成本”因素已预先配置。 Collect a password.收集密码。

Derive an encryption key from the password using the salt and cost factor.使用盐和成本因素从密码中导出加密密钥。 Use it to encrypt a well-known string.用它来加密一个众所周知的字符串。 Store the cost, salt, and cipher text.存储成本、和密文。 Because these three elements have a known length, it's easy to concatenate them and store them in a single field, yet be able to split them apart later.因为这三个元素的长度已知,所以很容易将它们连接起来并将它们存储在一个字段中,但稍后可以将它们分开。

When someone tries to authenticate, retrieve the stored cost and salt.当有人尝试进行身份验证时,检索存储的成本和盐。 Derive a key from the input password, cost and salt.从输入的密码、成本和盐中派生出一个密钥。 Encrypt the same well-known string.加密同一个众所周知的字符串。 If the generated cipher text matches the stored cipher text, the password is a match.如果生成的密文与存储的密文匹配,则密码匹配。

Bcrypt operates in a very similar manner to more traditional schemes based on algorithms like PBKDF2. Bcrypt 的运行方式与基于 PBKDF2 等算法的更传统方案非常相似。 The main difference is its use of a derived key to encrypt known plain text;主要区别在于它使用派生密钥来加密已知的纯文本; other schemes (reasonably) assume the key derivation function is irreversible, and store the derived key directly.其他方案(合理地)假设密钥派生函数是不可逆的,并直接存储派生的密钥。


Stored in the database, a bcrypt "hash" might look something like this:存储在数据库中的bcrypt “hash” 可能如下所示:

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

This is actually three fields, delimited by "$":这实际上是三个字段,以“$”分隔:

  • 2a identifies the bcrypt algorithm version that was used. 2a标识了使用的bcrypt算法版本。
  • 10 is the cost factor; 10是成本因素; 2 10 iterations of the key derivation function are used (which is not enough, by the way. I'd recommend a cost of 12 or more.) 2 使用了密钥派生函数的10次迭代(顺便说一下,这还不够。我建议成本为 12 次或更多。)
  • vI8aWBnW3fID.ZQ4/zo1G.q1lRps.9cGLcZEiGDMVr5yUP1KUOYTa is the salt and the cipher text, concatenated and encoded in a modified Base-64. vI8aWBnW3fID.ZQ4/zo1G.q1lRps.9cGLcZEiGDMVr5yUP1KUOYTa是盐和密文,以修改后的 Base-64 连接和编码。 The first 22 characters decode to a 16-byte value for the salt.前 22 个字符解码为盐的 16 字节值。 The remaining characters are cipher text to be compared for authentication.其余字符为密文,用于进行认证比较。

This example is taken from the documentation for Coda Hale's ruby implementation.此示例取自Coda Hale 的 ruby​​ 实现文档。

I believe that phrase should have been worded as follows:我认为这句话的措辞应该如下:

bcrypt has salts built into the generated hashes to prevent rainbow table attacks. bcrypt在生成的哈希中内置了盐,以防止彩虹表攻击。

The bcrypt utility itself does not appear to maintain a list of salts. bcrypt实用程序本身似乎不维护盐列表。 Rather, salts are generated randomly and appended to the output of the function so that they are remembered later on (according to the Java implementation of bcrypt ).相反,盐是随机生成的,并附加到函数的输出中,以便稍后记住它们(根据bcrypt的 Java 实现)。 Put another way, the "hash" generated by bcrypt is not just the hash.换句话说, bcrypt生成的“散列”不仅仅是散列。 Rather, it is the hash and the salt concatenated.相反,它是连接的散列盐。

To make things even more clearer,为了让事情更清楚,

Registeration/Login direction ->注册/登录方向 ->

The password + salt is encrypted with a key generated from the: cost, salt and the password.密码 + salt 使用从成本、salt 和密码生成的密钥进行加密。 we call that encrypted value the cipher text .我们称该加密值为cipher text then we attach the salt to this value and encoding it using base64.然后我们将盐附加到该值并使用 base64 对其进行编码。 attaching the cost to it and this is the produced string from bcrypt :将成本附加到它上面,这是从bcrypt生成的字符串:

$2a$COST$BASE64

This value is stored eventually.该值最终被存储。

What the attacker would need to do in order to find the password ?攻击者需要做什么才能找到密码? (other direction <- ) (其他方向 <- )

In case the attacker got control over the DB, the attacker will decode easily the base64 value, and then he will be able to see the salt.如果攻击者控制了数据库,攻击者将轻松解码 base64 值,然后他将能够看到盐。 the salt is not secret.盐不是秘密。 though it is random.虽然是随机的。 Then he will need to decrypt the cipher text .然后他将需要解密cipher text

What is more important : There is no hashing in this process, rather CPU expensive encryption - decryption.更重要的是:在这个过程中没有散列,而是 CPU 昂贵的加密 - 解密。 thus rainbow tables are less relevant here.因此彩虹表在这里不太相关。

This is a simple terms...这是一个简单的术语...

Bcrypt does not have a database it stores the salt... Bcrypt 没有存储盐的数据库......

The salt is added to the hash in base64 format....盐以 base64 格式添加到哈希中....

The question is how does bcrypt verifies the password when it has no database...?问题是bcrypt在没有数据库的情况下如何验证密码...?

What bcrypt does is that it extract the salt from the password hash... Use the salt extracted to encrypt the plain password and compares the new hash with the old hash to see if they are the same... bcrypt 所做的是它从密码哈希中提取盐......使用提取的盐来加密普通密码并将新的哈希与旧的哈希进行比较,看看它们是否相同......

Lets imagine a table that has 1 hashed password.让我们想象一个有 1 个散列密码的表。 If hacker gets access he would know the salt but he will have to calculate a big list for all the common passwords and compare after each calculation.如果黑客获得访问权限,他会知道盐,但他必须为所有常用密码计算一个大列表,并在每次计算后进行比较。 This will take time and he would have only cracked 1 password.这需要时间,而且他只会破解 1 个密码。

Imagine a second hashed password in the same table.想象在同一个表中的第二个散列密码。 The salt is visible but the same above calculation needs to happen again to crack this one too because the salts are different.盐是可见的,但由于盐不同,需要再次进行上述相同的计算才能破解此盐。

If no random salts were used, it would have been much easier, why?如果不使用随机盐,事情会容易得多,为什么? If we use simple hashing we can just generate hashes for common passwords 1 single time (rainbow table) and just do a simple table search, or simple file search between the db table hashes and our pre-calculated hashes to find the plain passwords.如果我们使用简单的散列,我们可以只生成一次常见密码的散列(彩虹表),然后进行简单的表搜索,或者在 db 表散列和我们预先计算的散列之间进行简单的文件搜索,以找到普通密码。

This is from PasswordEncoder interface documentation from Spring Security,这是来自 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);

Which means, one will need to match rawPassword that user will enter again upon next login and matches it with Bcrypt encoded password that's stores in database during previous login/registration.这意味着,需要匹配用户在下次登录时再次输入的 rawPassword,并将其与上次登录/注册期间存储在数据库中的 Bcrypt 编码密码匹配。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM