Почему crypt() дает разные результаты?

Crypt генерирует разные хэши с одними и теми же входными данными, а [следующий] ранее функциональный генератор/проверка хэшей больше не работает для аутентификации пользователей:

public static function blowfish($password, $storedpass = false) {
    //if encrypted data is passed, check it against input ($info) 
      if ($storedpass) { 
            if (substr($storedpass, 0, 60) == crypt($password, "$2y$08$".substr($storedpass, 60))) { 
                return true; 
            }  else { 
                return false; 
            } 
      }  else { 
          //make a salt and hash it with input, and add salt to end 
          $salt = ""; 
          for ($i = 0; $i < 22; $i++) { 
            $salt .= substr("./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", mt_rand(0, 63), 1); 
          } 
          //return 82 char string (60 char hash & 22 char salt) 
          return crypt($password, "$2y$08$".$salt).$salt; 
     }
}

Я бьюсь головой о стену и не нашел ответов в различиях между внутренними алгоритмами Zend, PHP и алгоритмами операционной системы; или вариации между PHP 5.3.8 и более ранними...

РЕДАКТИРОВАТЬ: На мой вопрос технически дан ответ, и это моя вина, что я не спросил должным образом. Я реализовал:

$salt = substr(bin2hex(openssl_random_pseudo_bytes(22)), 0, 22);
          //for ($i = 0; $i < 22; $i++) { 
            //$salt .= substr("./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", mt_rand(0, 63), 1); 
          //} 

Мой настоящий вопрос; почему следующие функции возвращаются по-разному?

print(substr($storedpass, 0, 60)."<br />");

возвращает: $2г$08$43f053b1538df81054d4cOJyrO5/j7NtZBCw6LrFof29cLBs7giK6

print(crypt($password, "$2a$08$".substr($storedpass, 60)));

возвращает: $2a$08$43f053b1538df81054d4cOPSGh/LMc0PZx6RC6PlXOSc61BKq/F6.


person KneeSkrap3r    schedule 15.08.2012    source источник
comment
В качестве побочного примечания: используйте криптографический генератор случайных чисел для генерации соли, а не плохо засеянный твистер Мерсенна.   -  person CodesInChaos    schedule 15.08.2012
comment
@CodesInChaos Достаточно честно, какую функцию [PHP] лучше всего использовать для этого? mt_rand()?   -  person KneeSkrap3r    schedule 15.08.2012
comment
Я не разработчик php, но mcrypt_create_iv(size, MCRYPT_DEV_URANDOM) может быть хорошим выбором. Или вы можете напрямую читать из /dev/urandom в Linux stackoverflow.com/a/1551064/445517 или openssl_random_pseudo_bytes   -  person CodesInChaos    schedule 15.08.2012
comment
@CodesInChaos после дальнейших исследований я пришел к тому же выводу: поскольку я чередую среды разработки с разными командами, я не могу использовать /dev/random, поэтому я все равно буду использовать mcrypt_create_iv(size, MCRYPT_DEV_URANDOM). Спасибо!   -  person KneeSkrap3r    schedule 15.08.2012


Ответы (1)


Поскольку вы создаете salt с помощью случайных чисел,

Функция mt_rand() будет создавать случайное число каждый раз, когда вы звоните, опционально с параметрами min, max. Обычно для надежного хеширования криптографических паролей Salt следует генерировать с помощью криптографически безопасного генератора псевдослучайных чисел (CSPRNG).

Тогда перейдем к вашей проблеме, я предполагаю, что между ZEND и php не будет разницы в алгоритме. Потому что zend — это фреймворк, обертывающий ядро ​​php, и используйте его.

Чтобы проверить пароль, как работает проверка crypt

crypt($password, $stored_hash) == $stored_hash;

После того, как вы сохранили хэш при первом хешировании, его будет легко проверить.

Вот что на самом деле происходит здесь, если вы передадите хэш в качестве второго параметра функции blowfish, она вернет проверку в виде логического значения, независимо от соли.

if (substr($storedpass, 0, 60) == crypt($password, "$2y$08$".substr($storedpass, 60))) { 
    return true; 
}  else { 
    return false; 
}

для получения информации о хешировании и безопасности прочитайте это

Надеюсь это поможет

person code-jaff    schedule 15.08.2012
comment
Я предполагаю, что код изначально работал, потому что в более старых версиях php PRNG за mt_rand не заполнялся автоматически. - person CodesInChaos; 15.08.2012
comment
Итак, вы оба говорите, что использование CSPRNG вместо моего mt_rand должно работать? Вместо этого я применил $salt = bin2hex(openssl_random_pseudo_bytes(22)) и столкнулся с той же проблемой... - person KneeSkrap3r; 15.08.2012
comment
Даже псевдоГСЧ обычно содержат настоящие случайные данные. - person Maarten Bodewes; 16.08.2012