PHP Bcrypt Salt 自 7.0 起

PHP Bcrypt Salt as of 7.0

我正在开发一个应用程序,我必须在其中比较数据库中的 2 个散列密码,一个密码在 PHP 和 $Password = password_hash($RawPassword, PASSWORD_BCRYPT); 中生成 而发送到数据库以与 PHP 散列密码进行比较的另一个密码是在 Java 中生成的 String hashedPassword = BCrypt.hashpw(password); 从 PHP 7.0 开始,加盐是自动生成的,我怎么知道 PHP 中应用了什么加盐,以便我可以将其应用到我的 java 代码中?或者有没有办法仍然指定不再在 PHP 散列的文档中的盐?

绝大多数 bcrypt impls 背后的标准思想是数据库中的内容看起来像 y$AB,其中 A 是 22 个字符,B 是 31 个字符,总共 60 个字符。A 是:left(base64(salt + 00 + 00), 22) 和 B 是:left(base64(bcryptraw(salt + pass)), 31)。 (2y 指的是哈希算法/编辑:2y 和 2a 或多或少是可以互换的;大多数 bcrypt impls 将它们视为相同,并且不太可能重要。10 指的是应用的 bcrypt 轮数。10 是常见的,通常是你想要的)。

其中:

  • base64(X) = 应用 base64 转换,使用 .和 / 作为第 63 和 64 个字符。
  • + 是串联的,即 salt(一个 16 字节的字节数组)添加了 2 个零字节。
  • left(chars, size) 表示:取前 size 个字符并丢弃其余字符。
  • salt 是以字节为单位的盐,pass 是密码,通过 UTF_8 转换为字节。 (如果不是通过 UTF-8 转换,它通常是 $2a$,你应该升级,密码中有非 ascii 字符的人在旧的 $2a$ 模式下会得到非常糟糕的哈希值!

这个字符串包含 bcrypt impl 需要检查给定密码是否正确的所有内容。因此,所有非愚蠢的 bcrypt 库 impls 只有两种方法,没有其他方法:

// This is for when the user creates an account or edits their password.
// send the password to this method, then take the string it returns,
// and store this in your database.
hash = crypto.hashPass(password);

// This is for when the user tries to log in. For 'hash', send the thing
// that the hashPass method made for you.
boolean passwordIsCorrect = crypto.checkPass(password, hash);

编辑:注意:一个真正设计良好的加密库调用这些方法 processNewPasswordcheckExistingPassword 以避免导致你问这个问题的那种混淆,但不幸的是,似乎没有人有足够的资金思考 5 秒钟他们的名字所暗示的意思。不幸的。安全很难。

如果您的 BCrypt API 不能像这样工作,摆脱它,并找到像这样工作的标准实现。

听起来你使用了错误的方法。要检查密码,请不要使用 hashPass。使用 checkPass,或者在你的 impl 中用于 checkPass 的任何东西(它可能被称为 checkPwverifyPwvalidate,等等。它需要 2 个字符串)。

因此,你不应该生成盐,也不应该从这样的字符串中提取盐。让 bcrypt 库来做。标准 bcrypt 库生成的那些 'hashes'(y$ 字符串)是可以互换的;您的 PHP 图书馆可以生成 em,您的 java 图书馆可以检查 em,反之亦然。

如果您必须提取盐(但没有提取):

  • 取那 22 个字符,在 $protocol$rounds$ 部分之后。
  • 将 'aa' 添加到此。
  • base64解码结果
  • 这会得到 18 个字节。扔掉最后2个字节,其中包含垃圾。
  • 剩下的16个字节是盐。

你绝对不应该这样写 - 你的 bcrypt 库会这样做。