用 PHP 中的 crypt() 比较密码
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3135524/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Comparing passwords with crypt() in PHP
提问by soren.qvist
I need to get the basics of this function. The php.net documentation states, for the blowfish algorithm, that:
我需要了解此功能的基础知识。对于河豚算法,php.net 文档指出:
Blowfish hashing with a salt as follows: "$2a$", a two digit cost parameter, "$", and 22 base 64 digits from the alphabet "./0-9A-Za-z". Using characters outside of this range in the salt will cause crypt() to return a zero-length string
Blowfish 使用盐进行散列如下:“$2a$”,一个两位数的成本参数,“$”,以及来自字母表“./0-9A-Za-z”的 22 个基数 64 位数字。在 salt 中使用此范围之外的字符将导致 crypt() 返回零长度字符串
So this, by definition, should not work:
因此,根据定义,这不应该起作用:
echo crypt('rasmuslerdorf', 'a$usesomadasdsadsadsadasdasdasdsadesillystringforsalt$');
However, it spits out:
然而,它吐出:
a$usesomadasdsadsadsadaeMTUHlZEItvtV00u0.kb7qhDlC0Kou9e
Where it seems that crypt() has cut the salt itself to a length of 22. Could somebody please explain this?
似乎 crypt() 已将盐本身的长度减少到 22。有人可以解释一下吗?
Another aspect of this function I can't get my head around is when they use crypt() to compare passwords. http://php.net/manual/en/function.crypt.php(look at ex. #1). Does this mean that if I use the same salt for all encrypting all my passwords, I have to crypt it first? ie:
这个函数的另一个我无法理解的方面是当他们使用 crypt() 来比较密码时。http://php.net/manual/en/function.crypt.php(看例子#1)。这是否意味着如果我使用相同的盐来加密所有密码,我必须先对其进行加密?IE:
$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?
}
Thanks for your time
谢谢你的时间
回答by ZZ Coder
Following code example may answer your questions.
以下代码示例可能会回答您的问题。
To generate hashed password using Blowfish, you first need to generate a salt, which starts with $2a$ followed by iteration count and 22 characters of Base64 string.
要使用 Blowfish 生成散列密码,您首先需要生成一个盐,它以 $2a$ 开头,然后是迭代计数和 22 个 Base64 字符串字符。
$salt = 'a$usesomadasdsadsadsadasdasdasdsadesillystringfors';
$digest = crypt('rasmuslerdorf', $salt);
Store the whole $digest in database, it has both the salt and digest.
将整个 $digest 存储在数据库中,它同时包含盐和摘要。
When comparing password, just do this,
比较密码时,只需这样做,
if (crypt($user_input, $digest) == $digest)
You are reusing the digest as salt. crypt knows how long is the salt from the algorithm identifier.
您正在将消化重新用作盐。crypt 从算法标识符中知道盐的长度。
回答by Brock Hensley
New salt for every password
每个密码的新盐
$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";
Authentication
验证
if (crypt($passwordFromPost, $hashedPasswordInDb) == $hashedPasswordInDb) {
// Authenticated
回答by Zer
BCrypt uses 128 bits for salt, so 22 bytes Base64, with only two bits of the last byte being used.
BCrypt 使用 128 位的盐,所以 22 字节的 Base64,最后一个字节只使用了两位。
The hash is computed using the salt and the password. When you pass the crypted password, the algorithm reads the strength, the salt (ignoring everything beyond it), and the password you gave, and computes the hash, appending it. If you have PostgreSQL and pg_crypto handy, SELECT gen_salt('bf'); will show you what of $salt is being read.
散列是使用盐和密码计算的。当您传递加密密码时,算法会读取强度、盐度(忽略除此之外的所有内容)和您提供的密码,然后计算散列值并附加它。如果你手边有 PostgreSQL 和 pg_crypto,SELECT gen_salt('bf'); 将向您显示正在读取的 $salt 内容。
Here's a code sample for salt generation, from my .NET implementation's test-vector-gen.php, alternatively:
这是盐生成的代码示例,来自我的.NET 实现的 test-vector-gen.php,或者:
$salt = sprintf('a$%02d$%s', [strength goes here],
strtr(str_replace(
'=', '', base64_encode(openssl_random_pseudo_bytes(16))
),
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/',
'./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'));
There is no reason to use the same salt for all of your passwords. The salt is part of the output anyway so you gain nothing in convenience... though I grant PHP ought to have a built-in gen_salt function.
没有理由对所有密码使用相同的盐。无论如何,盐是输出的一部分,因此您不会在方便时获得任何好处……尽管我认为 PHP 应该具有内置的 gen_salt 函数。
回答by Mark Baker
Quoting from the manual
从手册中引用
CRYPT_BLOWFISH - Blowfish hashing with a salt as follows: "$2a$", a two digit cost parameter, "$", and 22 base 64 digits from the alphabet
CRYPT_BLOWFISH - Blowfish 使用 salt 散列如下:“$2a$”,一个两位数的成本参数,“$”,以及来自字母表的 22 个基数 64 位
Note: 22base 64 digits
注:22基 64 位
回答by G__
First question:
第一个问题:
So this, by definition, should not work:
echo crypt('rasmuslerdorf', '$2a$07$usesomadasdsadsadsadasdasdasdsadesillystringforsalt$');Where it seems that crypt() has cut the salt itself to a length of 22. Could somebody please explain this?
因此,根据定义,这不应该起作用:
echo crypt('rasmuslerdorf', '$2a$07$usesomadasdsadsadsadasdasdasdsadesillystringforsalt$');似乎 crypt() 已将盐本身的长度减少到 22。有人可以解释一下吗?
There isn't a problem with having too many characters... the phrase Using characters outside of this range in the salt will cause crypt() to return a zero-length stringreferse to outside the range of base 64not the range of 22 characters. Try putting an illegal character in the salt string, and you should find that you get an empty output (or if you put < 22 characters in, resulting in illegal empty bytes).
有太多字符没有问题......短语在盐中使用此范围之外的字符将导致 crypt() 返回一个零长度字符串引用到base 64的范围之外而不是22的范围字符。尝试在 salt 字符串中放入一个非法字符,你会发现你得到一个空输出(或者如果你放入了 < 22 个字符,导致非法空字节)。
Second question:
第二个问题:
You pass in the encrypted stored password as salt because the salt string always appears (by design) in the encrypted string, and this way you ensure that you have the same salt for both encryption of stored and user-entered password.
您将加密存储的密码作为 salt 传入,因为 salt 字符串始终(按设计)出现在加密字符串中,这样您就可以确保对存储的密码和用户输入的密码进行加密时使用相同的 salt。
回答by soren.qvist
This question is in relation to my response to ZZ Coder's answer. Basically my question is regarding storing the crypt() result in the database. Am I supposed to store the entire output in the database, so that my database looks like this:
这个问题与我对 ZZ Coder 的回答有关。基本上我的问题是关于将 crypt() 结果存储在数据库中。我是否应该将整个输出存储在数据库中,以便我的数据库如下所示:
--------------------------------------------------------------------------------
| ID | Username | Password |
--------------------------------------------------------------------------------
| 32 | testuser | a$usesomadasdsadsadsadaeMTUHlZEItvtV00u0.kb7qhDlC0Kou9e |
--------------------------------------------------------------------------------
If yes, then doesn't this kind of defy the purpose of using a salt in the first place? If someone gains access to the db, they can clearly see the salt used for the encryption?
如果是,那么这是否违背了使用盐的初衷?如果有人访问数据库,他们可以清楚地看到用于加密的盐吗?
Bonus question: Is it secure to use the same salt for every password?
额外问题:对每个密码使用相同的盐是否安全?

