Сравнение паролей с crypt () в PHP

Мне нужно получить основы этой функции. В документации php.net указано, что для алгоритма blowfish:

Blowfish хеширование с солью следующим образом: «$ 2a $», двухзначный параметр стоимости, «$» и 22 базовых 64 цифры из алфавита «./0-9A-Za-z». Использование символов вне этого диапазона в соли приведет к тому, что 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? } 

Спасибо за ваше время

Следующий пример кода может ответить на ваши вопросы.

Чтобы генерировать хешированный пароль с помощью Blowfish, сначала нужно сгенерировать соль, которая начинается с $ 2a $, за которой следует число итераций и 22 символа строки Base64.

 $salt = '$2a$07$usesomadasdsadsadsadasdasdasdsadesillystringfors'; $digest = crypt('rasmuslerdorf', $salt); 

Храните весь $ digest в базе данных, у него есть соль и дайджест.

Сравнивая пароль, просто сделайте это,

  if (crypt($user_input, $digest) == $digest) 

Вы повторно используете дайджест как соль. crypt знает, сколько времени соль из идентификатора алгоритма.

Цитата из руководства

CRYPT_BLOWFISH – хеширование Blowfish с солью следующим образом: «$ 2a $», двухзначный параметр стоимости, «$» и 22 базовые 64 цифры из алфавита

Примечание: 22 базовых 64 цифры

BCrypt использует 128 бит для соли, поэтому 22 байта Base64, причем используются только два бита последнего байта.

Хэш вычисляется с использованием соли и пароля. Когда вы передаете зашифрованный пароль, алгоритм считывает силу, соль (игнорируя все за ее пределами) и пароль, который вы дали, и вычисляет хэш, добавляя его. Если у вас есть PostgreSQL и pg_crypto, SELECT gen_salt ('bf'); покажет вам, что из $ salt читается.

Вот пример кода для генерации соли, из моего тестового вектора .NET-gen.php в .NET:

 $salt = sprintf('$2a$%02d$%s', [strength goes here], strtr(str_replace( '=', '', base64_encode(openssl_random_pseudo_bytes(16)) ), 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/', './ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789')); 

Нет причин использовать одну соль для всех ваших паролей. В любом случае соль является частью выхода, поэтому вы ничего не получаете в удобстве … хотя я предоставляю PHP, что у вас должна быть встроенная функция gen_salt.

Новая соль для каждого пароля

 $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 

Первый вопрос:

Поэтому это, по определению, не должно работать:

echo crypt('rasmuslerdorf', '$2a$07$usesomadasdsadsadsadasdasdasdsadesillystringforsalt$');

Где кажется, что crypt () разрезает соль до длины 22. Может ли кто-нибудь объяснить это?

Нет проблемы с наличием слишком большого количества символов … фраза Использование символов вне этого диапазона в соли вызовет crypt (), чтобы вернуть строку нулевой длины, выходящую за пределы диапазона 64, а не диапазон 22 символов . Попробуйте помещать недопустимый символ в солевую строку, и вы должны обнаружить, что вы получаете пустой вывод (или если вы помещаете <22 символа, что приводит к незаконным пустым байтам).

Второй вопрос:

Вы передаете зашифрованный сохраненный пароль как соль, потому что строка солярия всегда отображается (по дизайну) в зашифрованной строке, и таким образом вы гарантируете, что у вас есть такая же соль для шифрования сохраненного и введенного пользователем пароля.

Этот вопрос касается моего ответа на ответ ZZ Coder. В основном мой вопрос заключается в сохранении результата crypt () в базе данных. Я должен хранить весь вывод в базе данных, чтобы моя база данных выглядела так:

 -------------------------------------------------------------------------------- | ID | Username | Password | -------------------------------------------------------------------------------- | 32 | testuser | $2a$07$usesomadasdsadsadsadaeMTUHlZEItvtV00u0.kb7qhDlC0Kou9e | -------------------------------------------------------------------------------- 

Если да, то разве это не значит, что цель использования соли в первую очередь? Если кто-то получает доступ к db, они могут ясно видеть соль, используемую для шифрования?

Бонусный вопрос: безопасно ли использовать одну соль для каждого пароля?