【问题标题】:How do the salt argument and return value for PHP's crypt() function work?PHP 的 crypt() 函数的 salt 参数和返回值如何工作?
【发布时间】:2011-11-02 08:56:31
【问题描述】:

通常如果我有密码,我会使用这个伪代码:

$password = "this is the user's password";
/***/
$salt = GenerateSalt();
$hash = Hash($password);
$hash = Hash($hash . $salt);

但是,据我了解,PHP 有一个crypt() 函数,它接受盐以及特定算法的迭代次数。显然你是......应该将返回的crypt 散列传递回 crypt 作为盐。我不明白这个。

谁能解释一下crypt是如何工作的?我还需要添加自己的盐并重新哈希吗?在那种情况下,我是否只使用固定盐进行 crypt,然后为每个用户生成一个单独的 crypt?或者 crypt 的 $salt 参数会为我解决这个问题吗?

【问题讨论】:

  • 请注意您应该PHP 的crypt 不适合在5.3 之前的版本中使用。您总是想使用 $2a$$5$$6$ 前缀分别获取 Blowfish、SHA-256 或 SHA-512,并且不保证在早期版本中可用。请阅读手册页了解更多详情。
  • 还要注意 crypt 在 PHP 5.3.7 for MD5 中被破坏。他们刚刚发布了错误修复 5.3.8

标签: php hash cryptography


【解决方案1】:

crypt 是单向散列,类似于 MD5

按照手册中的说明使用它

<?php
$password = crypt('mypassword'); // let the salt be automatically generated

/* You should pass the entire results of crypt() as the salt for comparing a
   password, to avoid problems when different hashing algorithms are used. (As
   it says above, standard DES-based password hashing uses a 2-character salt,
   but MD5-based hashing uses 12.) */
if (crypt($user_input, $password) == $password) {
   echo "Password verified!";
}
?>

【讨论】:

  • 这正是我的问题。 if (crypt($user_input, $password) == $password) 对我来说真的没有意义。你为什么要传递$password,它是哈希值,作为盐?
  • crypt('mypassword') 创建盐,而不是密码。
【解决方案2】:

crypt 的输出包括:

  • (可选算法标识符 + 负载因子)
  • 所用算法的盐
  • 真正的哈希

当您将此输出作为“salt”传递回crypt 时,它将提取正确的算法和盐,并将它们用于操作。如果只提到一种算法,它会使用这个算法并生成随机盐。否则它将选择默认算法并生成随机盐。传递的 salt 参数中的hash 部分将被忽略。

因此,您可以简单地将您的 stored_hash 与 crypt(password, stored_hash) 进行比较 - 如果相等,则很可能是正确的密码。

这是一个伪代码解释(使用类似 PHP 的语法)crypt 的工作原理:

function crypt($password, $salt)
{
  if (substr($salt,0 1) == "_") {
     $count = substr($salt, 1, 4);
     $real_salt = substr($salt, 5, 4);
     return "_" . $count . $real_salt . crypt_ext_des($password, $count, $salt);
  }
  if(substr($salt, 0, 3) == "$1$") {
     list($ignored, $real_salt, $ignored) = explode("$", $salt);
     return "$1$" . $real_salt . "$" . crypt_md5($password, $real_salt);
  }
  if(substr($salt, 0, 4) == "$2a$") {
      $cost = substr($salt, 4, 2);
      $real_salt = substr($salt, 7, 22);
      return "$2a$" . $cost . "$" . $real_salt . crypt_brypt($password, $real_salt, $cost);
  }
  // ... SHA256 and SHA512 analogons

  // no match => STD_DES
  $real_salt = substr($salt, 0, 2);
  return $real_salt . crypt_std_des($password, $real_salt);
}

然后各个 crypt_xxx 函数会根据算法进行实际工作。 (其实这个描述中少了随机盐的生成,如果$real_salt为空就会做。)

【讨论】:

  • 所以返回的“哈希”实际上既是盐又是哈希,通常在 MySQL 数据库中我只会将其存储为一个值?
  • 所有算法标识符、盐和哈希。是的,您可以将整个返回值作为一个 varchar 值存储在数据库中。
猜你喜欢
  • 2014-10-06
  • 1970-01-01
  • 2018-09-05
  • 2018-01-21
  • 1970-01-01
  • 2018-11-09
  • 2010-10-14
  • 2012-03-28
  • 2013-05-20
相关资源
最近更新 更多