我需要了解这个功能的基础知识。对于blowfish算法,php.net文档指出:
Blowfish用盐进行散列如下:“$ 2a $”,两位数的成本参数“$”,以及字母“./0-9A-Za-z”中的22位64位数字。在salt 中使用此范围之外的字符将导致crypt()返回零长度字符串
因此,根据定义,这不应该起作用:
echo crypt('rasmuslerdorf', '$2a$07$usesomadasdsadsadsadasdasdasdsadesillystringforsalt$');
然而,它吐了出来:
$2a$07$usesomadasdsadsadsadaeMTUHlZEItvtV00u0.kb7qhDlC0Kou9e
看来crypt()已将盐本身切成22的长度。有人可以解释一下吗?
我无法理解这个功能的另一个方面是当他们使用crypt()比较密码时。 http://php.net/manual/en/function.crypt.php(见前#1)。这是否意味着如果我使用相同的盐来加密所有密码,我必须首先加密它?即:
$salt = "usesomadasdsadsadsadae";
$salt_crypt = crypt($salt);
if (crypt($user_input, $salt) == $password) {
// FAIL WONT WORK
}
if (crypt($user_input, $salt_crypt) == $password) {
// I HAVE TO DO THIS?
}
感谢您的时间
答案 0 :(得分:21)
以下代码示例可能会回答您的问题。
要使用Blowfish生成散列密码,首先需要生成一个salt,它以$ 2a $开头,后跟迭代计数和22个字符的Base64字符串。
$salt = '$2a$07$usesomadasdsadsadsadasdasdasdsadesillystringfors';
$digest = crypt('rasmuslerdorf', $salt);
将整个$ digest存储在数据库中,它同时包含salt和digest。
比较密码时,只需执行此操作,
if (crypt($user_input, $digest) == $digest)
您正在重复使用摘要作为盐。 crypt知道算法标识符中的盐有多长。
答案 1 :(得分:3)
每个密码的新盐
$password = 'p@ssw0rd';
$salt = uniqid('', true);
$algo = '6'; // CRYPT_SHA512
$rounds = '5042';
$cryptSalt = '$'.$algo.'$rounds='.$rounds.'$'.$salt;
$hashedPassword = crypt($password, $cryptSalt);
// Store complete $hashedPassword in DB
echo "<hr>$password<hr>$algo<hr>$rounds<hr>$cryptSalt<hr>$hashedPassword";
<强>验证强>
if (crypt($passwordFromPost, $hashedPasswordInDb) == $hashedPasswordInDb) {
// Authenticated
答案 2 :(得分:2)
从手册中引用
CRYPT_BLOWFISH - 与河豚一起散列 盐如下:“$ 2a $”,两位数 成本参数,“$”和22基数64 字母表中的数字
注意: 22 基本64位
答案 3 :(得分:2)
BCrypt对盐使用128位,因此使用22字节Base64,只使用最后一个字节的两位。
使用salt和密码计算哈希值。当您传递加密密码时,算法将读取强度,盐(忽略除此之外的所有内容)和您提供的密码,并计算哈希值,并附加它。如果你有方便的PostgreSQL和pg_crypto,SELECT gen_salt('bf');会告诉你正在读什么盐。
这是一个用于生成盐的代码示例,来自我的.NET implementation的test-vector-gen.php,或者:
$salt = sprintf('$2a$%02d$%s', [strength goes here],
strtr(str_replace(
'=', '', base64_encode(openssl_random_pseudo_bytes(16))
),
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/',
'./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'));
没有理由对所有密码使用相同的盐。无论如何,盐是输出的一部分,所以你在方便中没有获得任何东西......虽然我认为PHP应该有一个内置的gen_salt函数。
答案 4 :(得分:0)
第一个问题:
因此,根据定义,这不应该起作用:
echo crypt('rasmuslerdorf', '$2a$07$usesomadasdsadsadsadasdasdasdsadesillystringforsalt$');
crypt()似乎已经削减了 盐本身长度为22。 有人可以解释一下吗?
有太多字符没有问题......短语在salt中使用此范围之外的字符将导致crypt()返回零长度字符串指向外部 base 64 的范围不是 22个字符的范围。尝试在salt字符串中放入一个非法字符,你会发现你得到一个空输出(或者你输入了<22个字符,导致非法的空字节)。
第二个问题:
您将加密的存储密码作为salt传递,因为salt字符串始终(通过设计)出现在加密字符串中,这样您就可以确保对存储密码和用户输入密码的加密具有相同的盐。 / p>
答案 5 :(得分:0)
这个问题与我对ZZ Coder答案的回应有关。基本上我的问题是关于将crypt()结果存储在数据库中。我应该将整个输出存储在数据库中,以便我的数据库看起来像这样:
--------------------------------------------------------------------------------
| ID | Username | Password |
--------------------------------------------------------------------------------
| 32 | testuser | $2a$07$usesomadasdsadsadsadaeMTUHlZEItvtV00u0.kb7qhDlC0Kou9e |
--------------------------------------------------------------------------------
如果是,那么这首先是否违背了使用盐的目的?如果有人获得了对数据库的访问权限,他们可以清楚地看到用于加密的盐吗?
奖金问题:为每个密码使用相同的盐是否安全?