Как хэш пароля PHP генерирует соль?


Здравствуйте, как вы, возможно, знаете, недавно появился PHP password_hash встроенный в последних версиях. В документации говорится:

Если этот параметр опущен, то будет создана произвольная соль и будет использована стоимость по умолчанию.

Вопрос в том, какой метод он использует для добавления соли?

Мне интересно, потому что я хотел бы знать, создается Ли Соль случайным образом, Чтобы при хранении моих хэшированных паролей они были всегда уникальными.

1 3

1 ответ:

Соль создается случайным образом. Они должны быть статистически уникальными.

Чтобы узнать, как это сделать, проверьте исходный код C.

В Windows он попытается использовать php_win32_get_random_bytes() для генерации соли:

BYTE *iv_b = (BYTE *) buffer;
if (php_win32_get_random_bytes(iv_b, raw_length) == SUCCESS) {
    buffer_valid = 1;
}

В Linux он попытается прочитать /dev/urandom, чтобы сгенерировать соль:

int fd, n;
size_t read_bytes = 0;
fd = open("/dev/urandom", O_RDONLY);
if (fd >= 0) {
    while (read_bytes < raw_length) {
        n = read(fd, buffer + read_bytes, raw_length - read_bytes);
        if (n < 0) {
            break;
        }
        read_bytes += (size_t) n;
    }
    close(fd);
}
if (read_bytes >= raw_length) {
    buffer_valid = 1;
}

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

if (!buffer_valid) {
    for (i = 0; i < raw_length; i++) {
        buffer[i] ^= (char) (255.0 * php_rand(TSRMLS_C) / RAND_MAX);
    }
}

Теперь, если C - это не ваша чашка чая, та же логика и алгоритмы реализованы в PHP в моей библиотеке compat :

$buffer = '';
$raw_length = (int) ($required_salt_len * 3 / 4 + 1);
$buffer_valid = false;
if (function_exists('mcrypt_create_iv')) {
    $buffer = mcrypt_create_iv($raw_length, MCRYPT_DEV_URANDOM);
    if ($buffer) {
        $buffer_valid = true;
    }
}
if (!$buffer_valid && function_exists('openssl_random_pseudo_bytes')) {
    $buffer = openssl_random_pseudo_bytes($raw_length);
    if ($buffer) {
        $buffer_valid = true;
    }
}
if (!$buffer_valid && is_readable('/dev/urandom')) {
    $f = fopen('/dev/urandom', 'r');
    $read = strlen($buffer);
    while ($read < $raw_length) {
        $buffer .= fread($f, $raw_length - $read);
        $read = strlen($buffer);
    }
    fclose($f);
    if ($read >= $raw_length) {
        $buffer_valid = true;
    }
}
if (!$buffer_valid || strlen($buffer) < $raw_length) {
    $bl = strlen($buffer);
    for ($i = 0; $i < $raw_length; $i++) {
        if ($i < $bl) {
            $buffer[$i] = $buffer[$i] ^ chr(mt_rand(0, 255));
        } else {
            $buffer .= chr(mt_rand(0, 255));
        }
    }
}
Единственная разница заключается в том, что версия PHP будет использовать mcrypt или openssl, если установлен любой из них...