【问题标题】:Determining the salt from a password_hash()从 password_hash() 确定盐
【发布时间】:2014-01-22 10:32:12
【问题描述】:

我正在使用 bcrypt 对我的密码进行哈希处理(实际上是使用 password_compat,因为我运行的是 php 5.3.10)
我想将函数的结果字符串分成两部分:使用的盐和哈希本身。 (我知道使用 password_verify() 来验证密码。但我需要哈希值才能将其用作密钥,以便在更广泛的安全系统中加密私钥。)

对于给定的密码 (abcdef),结果如下:

 $2y$10$ult68Ti4/zEWX4VQ       ....           YCOWjL6

我稍微修改了the function,以输出 concat、salt、hash 和 hash_format。

 ... from the password_compat ...
 $salt = substr($salt, 0, $required_salt_len);
 $hash = $hash_format . $salt;
 $ret = crypt($password, $hash);
 if (!is_string($ret) || strlen($ret) <= 13) {
        return false;
 }

 return array( 'concat'=>$ret, 
               'salt'=>$salt, 
               'format'=>$hash_format,
               'hash_format'=>$hash);

我认为结果哈希是$hash_format$salthash 的连接...但最后一个字符不同...

                                               _
[concat] =>        $2y$10$oWfFYcNqlcUeGwJM0AFUguSJ5t  .....  SvWG
[salt] =>                 oWfFYcNqlcUeGwJM0AFUgw
[hash_format] =>   $2y$10$oWfFYcNqlcUeGwJM0AFUgw
[format] =>        $2y$10$
                                               ^

如您所见,盐中的最后一个字符在 crypt 函数之前和函数之后是不同的。

这怎么可能?

【问题讨论】:

  • 你为什么要滥用密码哈希库?
  • 也许更适合的库是github.com/ircmaxell/RandomLib
  • 好吧,我没有滥用它...但是在更广泛的密码派生加密方案中使用它:security.stackexchange.com/a/48085/36643
  • @stUrb:那为什么不使用像 PBKDF2 这样的密钥派生函数 (KDF) 呢?一种专门为从密码生成加密密钥而设计的算法... BCrypt 专为密码存储而设计。 PBKDF2+SHA256|512 将是一个很好的选择...

标签: php hash bcrypt crypt


【解决方案1】:

传递给crypt() 的盐可能与生成的哈希值中返回的盐不同的原因是,BCrypt 内部仅使用 126 位盐,但传递给函数的盐始终包含 128 位。由于 crypt 函数需要 base64 编码的 salt 类型,因此不能直接传递 126 位。

您可以在这里找到更详细的答案:Why does crypt/blowfish generate the same hash with two different salts?

我了解您想使用真正的哈希作为密钥来加密另一个密钥,您可以从生成的哈希值中提取它。这个字符串总是有一定的格式,用$分隔部分,用BCrypt真正的哈希是最后31个字符

$2y$10$nOUIs5kJ7naTuTFkBy1veuK0kSxUFXfuaOKdOKf9xYT0KKIGSJwFa
 |  |  |                     |
 |  |  |                     hash-value = K0kSxUFXfuaOKdOKf9xYT0KKIGSJwFa
 |  |  |
 |  |  salt = nOUIs5kJ7naTuTFkBy1veu (22 characters)
 |  |
 |  cost-factor = 10 = 2^10 iterations
 |
 hash-algorithm = 2y = BCrypt

另一种可能性是计算整个字符串(所有 60 个字符)的哈希值。您可以选择返回所需长度的算法,例如sha256 获取 MCRYPT_TWOFISH 的 256 位密钥。

【讨论】:

  • 感谢您的回答!所以这就是为什么盐有 126 位而不是 128 位的原因。顺便说一句,我不能使用整个字符串来生成密钥,因为我必须存储 bcrypt 字符串(以及生成的密钥)来验证服务器上的登录;这就是我要避免的。
  • @stUrb - 您只需要存储 bcrypt 字符串的 sha256,我不明白为什么这比使用 bcrypt 字符串中的哈希部分更难。请记住,bcrypt 字符串是加盐的,因此您不能仅使用原始密码重新创建散列部分(不存储加盐)。
  • 啊我误解了你的第一条评论,你是对的。但是如果我必须验证哈希,那么我需要将盐存储在某个地方。并且由于它是自动创建的,因此无论如何我都必须拆分字符串。这是我正在实施的系统... security.stackexchange.com/a/48085/36643
  • @stUrb -确实这是一个非常有趣的问题,我一定会研究它。现在,祝你好运!
  • 一般来说,你是对的。然而,一个次要(或不是)点:BCrypt 使用 128 位盐。 salt 的第 22 个字符仅提供 2 位 salt(和 4 位哈希)。所以你不能把它干净地分成“盐”和“哈希”。几乎就像你在这里一样,它会起作用,但请注意你正在混合......
猜你喜欢
  • 1970-01-01
  • 2017-12-28
  • 1970-01-01
  • 1970-01-01
  • 2015-04-17
  • 2014-01-15
  • 2014-12-03
  • 2016-11-12
  • 2018-11-09
相关资源
最近更新 更多