Кодирование строки bcrypt с помощью mcrypt

Используя PHP, я создал следующий набор функций, которые в конечном итоге получают строку (пароль) и применяют к ней шифрование bcrypt. Кроме того, он генерирует ключ для использования с mcrypt, затем применяет его к строке bcrypt (вместе с base64 для упрощения строки), чтобы затем вставить в базу данных для хранения.
Из этого при декодировании я расшифровываю шифрование mcrypt, примененное к хешу, а затем использую password_verify() чтобы затем подтвердить это.

Тем не менее, я не могу получить password_verify() чтобы проверить хеш, если он был запущен через процесс mcrypt, даже если после того, как он был декодирован, две строки (одна из функции кодирования и одна из декодирования) являются IDENTICAL.

Функция кодирования выглядит так:

function passwordEncode($string) {
$hash = password_hash($string, PASSWORD_BCRYPT, ['cost' => 12]);

$key = generateKey();

$encrypt = base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key."******", $hash, MCRYPT_MODE_ECB));

return [$encrypt, $key, $hash];
}

Это вернуло бы:

[0] ENCRYPT: lTzVGcAY1jkuawebFG/9ZI4O5f/+4hjZHRewstOBAAJwQlYydLJ+B+2QHg9A16qjCUe7FHfTacPzmvH+xnT4rQ==
[1] KEY: 122593420654793b0ee4efc932
[2] HASH: $2y$10$k/4gM1jMIMxnmfBMgrML6enMgqIvnZp2EzPU.G64P3Bb3MDrwJj8e

Индекс HASH предназначен только для целей отладки, чтобы обеспечить выходной хэш, который не был запущен в процессе mcrypt

Функция декодирования выглядит так:

function passwordDecode($string, $key) {
$decrypt = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key."******", base64_decode($string), MCRYPT_MODE_ECB);

return $decrypt;
}

Это вернуло бы:

DECRYPT: $2y$10$k/4gM1jMIMxnmfBMgrML6enMgqIvnZp2EzPU.G64P3Bb3MDrwJj8e

Использование необработанного хэша, который не был выполнен через mcrypt, возвращает Verified

$encode = passwordEncode("password");
if(password_verify("password", $encode[2])) {
echo 'Verified';
} else {
echo 'Not verified';
}

Однако при использовании хэша выполняется шифрование mcrypt и возвращается дешифрование Not verified

$encode = passwordEncode("password");
if(password_verify("password", passwordDecode($encode[0], $encode[1]))) {
echo 'Verified';
} else {
echo 'Not verified';
}

Потратив часы на то, чтобы поцарапать лоб против терки для сыра, я так и не смог выяснить, что mcrypt делает со струной, чтобы ее не проверить. Я предпринял попытку поиска невидимых символов (попытка ключевого слова), но кроме этого у меня нет идей относительно причины.


Изменить: также, этот возврат не проверен

$encode = passwordEncode("password");
if($encode[2]==passwordDecode($encode[0], $encode[1])) {
echo 'Verified';
} else {
echo 'Not verified';
}

Итак, что-то делается со строкой … Я просто не знаю, что

-1

Решение

По какой-то глупой причине PHP включает \0 Значимые символы, которые используются в качестве дополнения нулями mcrypt в расшифрованном открытом тексте. Еще более глупо, кажется, что они включены в декодирование base64, выполняемое password_verify а также, что делает его неудачным без явной причины. Такая глупость делает PHP одной из худших сред для использования в функциях, связанных с безопасностью.

Таким образом, без лишних слов, переписанные функции, которые выполняют rtrimв куске кода, который Можно быть запущенным сам по себе. Требуется либо PHP 5.5, либо password_compat :

<?php

# uncomment for PHP 5.3/5.4
# require "lib/password.php";

function generateKey() {
$fp = @fopen('/dev/urandom','rb');
if ($fp !== FALSE) {
$key = @fread($fp, 16);
@fclose($fp);
return $key;
}
return null;
}

function hashPassword($password) {
$hash = password_hash($password, PASSWORD_BCRYPT, array('cost' => 12));
return $hash;
}

function encryptHash($key, $hash) {
# encrypt using unsafe ECB mode and without AES
$encrypted = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $hash, MCRYPT_MODE_ECB);
$encoded = base64_encode($encrypted);
return $encoded;
}

function decryptHash($key, $ciphertext) {
$decoded = base64_decode($ciphertext);
$decryptedHash = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, $decoded, MCRYPT_MODE_ECB);
# remove stupid zero padding
$decryptedHash = rtrim($decryptedHash, "\0");
return $decryptedHash;
}

$hash = hashPassword("password");

if(password_verify("password", $hash)) {
echo 'Verified' . PHP_EOL;
} else {
echo 'Not verified' . PHP_EOL;
}

$key = generateKey();
$encrypted = encryptHash($key, $hash);
$decrypted = decryptHash($key, $encrypted);

if(password_verify('password', $decrypted)) {
echo 'Verified' . PHP_EOL;
} else {
echo 'Not verified' . PHP_EOL;
}
?>
0

Другие решения

Других решений пока нет …