PHP Bcrypt Salt 自 7.0 起

问题描述

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

解决方法

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

哪里:

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

这个字符串包含一切,bcrypt impl需要检查给定密码是否正确。因此,所有非白痴的 bcrypt 库实现只有两种方法,没有其他方法:

pass

编辑:注意:一个真正设计良好的加密库调用这些方法 // 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); processNewPassword 以避免导致您问这个问题的那种混淆,但不幸的是,那里似乎没有人有足够的时间思考他们的名字所暗示的 5 秒钟。不幸的。安全很难。

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

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

因此,您永远不应该生成盐,也不应该从这样的字符串中提取盐。让 bcrypt 库来做。标准 bcrypt 库生成的那些“哈希”(validate 字符串)是可以互换的;你的 PHP 库可以生成 em,你的 java 库可以检查 em,反之亦然。

如果您必须提取盐(但不要):

  • $2y$ 部分之后取这 22 个字符。
  • 在此后附加“aa”。
  • base64decode 结果。
  • 这会让你得到 18 个字节。丢弃最后 2 个字节,其中包含垃圾。
  • 剩下的 16 个字节是盐。

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