Не удалось обновить mcrypt для расшифровки openssl в PHP - PullRequest
0 голосов
/ 05 октября 2018

Я обновляю устаревшее приложение с PHP 7.0 до 7.2, и моя функция расшифровки не работает, когда я отключаю mcrypt для openssl.

Я пробовал существующие ответы, такие как mcrypt устарела,что является альтернативой? , и Gists как https://gist.github.com/odan/c1dc2798ef9cedb9fedd09cdfe6e8e76,, но я все еще не могу заставить код работать.

Может кто-нибудь пролить свет на то, что я делаю неправильно?

Старый код

function decrypt($value, $key) {
    $ivLength = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
    $iv = substr($value, 0, $ivLength);
    return rtrim(
        mcrypt_decrypt(
            MCRYPT_RIJNDAEL_128,
            hash('sha256', $key, true),
            substr($value, $ivLength),
            MCRYPT_MODE_CBC,
            $iv
        ),
        "\0"
    );
}

Новый код (не работает с существующими входами)

function decrypt($value, $key) {
    $ivLength = openssl_cipher_iv_length('AES-128-CBC');
    $iv = substr($value, 0, $ivLength);
    // Note: $key is hashed because it was hashed in the old encrypt function below
    return openssl_decrypt(substr($value, $ivLength), 'AES-128-CBC', hash('sha256', $key, true), OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $iv);
}

Для контекста, воткак старый код шифровал значения:

function encrypt($value, $key) {
    $iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC), MCRYPT_DEV_URANDOM);
    return $iv . mcrypt_encrypt(
            MCRYPT_RIJNDAEL_128,
            hash('sha256', $key, true),
            $value,
            MCRYPT_MODE_CBC,
            $iv
        );
}

Кроме того, необработанное значение в $value вдвое длиннее при выводе в журнал ошибок в новом коде, чем старый код, и выглядит аналогично, но с большим количествомсимволы.

1 Ответ

0 голосов
/ 05 октября 2018

Основной проблемой здесь является размер ключа.Вы создаете ключ с SHA256, который возвращает 256-битный хеш, поэтому вы используете AES / Rijndael с 256-битным ключом.

Число в Rijndael-128 определяет размер блока, размер ключа определяется длиной ключа, который мы используем.Число в AES-128 определяет размер ключа (размер блока постоянен, 128 бит), и если фактическая длина ключа отличается от этого числа, то ключ укорачивается или расширяется (с нулевыми байтами), чтобы соответствовать выбранному ключуsize.

Это означает, что ваш код mcrypt использует Rijndael-128 (AES) с 256-битным ключом в режиме CBC.Эквивалентом openssl является AES-256-CBC, и если мы используем этот алгоритм, то mcrypt и openssl должны давать совместимые результаты.

function decrypt_mcrypt_with_openssl($value, $key) {
    $iv = substr($value, 0, 16);
    $ciphertext = substr($value, 16);
    $key = hash('sha256', $key, true);
    $plaintext = openssl_decrypt(
        $ciphertext, 'AES-256-CBC', $key, 
        OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, 
        $iv
    );
    return rtrim($plaintext, "\0");
}

SHA256 не подходит в качестве функции вывода ключа.Если вы извлекаете ключ из пароля, вы можете использовать hash_pbkdf2 со случайной солью и достаточно большим числом итераций.Или вы можете создать криптографически защищенный псевдослучайный ключ с openssl_random_pseudo_bytes.

Я думаю, что лучше полностью прекратить использование mcrypt и использовать только openssl.Mcrypt не поддерживает заполнение PKCS7, не предоставляет алгоритмы аутентифицированного шифрования , и он больше не поддерживается.

...