PHP mcrypt для openssl BF-CBC: как получить то же зашифрованное значение - PullRequest
0 голосов
/ 16 мая 2019

Необходимо заменить существующие функции шифрования и дешифрования, которые используют режим mcrypt blowfish cbc, на эквивалент openssl.

Необходимо иметь возможность обрабатывать старые значения, чтобы методы оставались совместимыми.

Пусть дешифрование работает, и шифрование "почти" нормально, но не совсем там.

У меня есть код:

$value = "myTextValue";
$key = 'c40f5b7ad3b7c787d400e923e461064b141fa878ce61cb0d1782593a5a2d842832c80fc2';

$enc = @encrypt_openssl($value, $key);
//$enc = @encrypt_mcrypt($value, $key);
$original_openssl = @decrypt_openssl($enc, $key);
$original_mcrypt = @decrypt_mcrypt($enc, $key);

echo $original_mcrypt."\n";
echo $original_openssl."\n";

function encrypt_openssl($string, $key) {
    $iv_size = openssl_cipher_iv_length("BF-CBC");
    $iv = openssl_random_pseudo_bytes($iv_size);
    $enc = openssl_encrypt($string, "BF-CBC", pack('H*',$key), OPENSSL_RAW_DATA, $iv);
    return base64_encode($iv.$enc);
}

function encrypt_mcrypt($string, $key) {
    $iv_size = mcrypt_get_iv_size(MCRYPT_BLOWFISH, MCRYPT_MODE_CBC);
    $iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
    $enc = mcrypt_encrypt(MCRYPT_BLOWFISH, pack('H*', $key), $string, MCRYPT_MODE_CBC, $iv);
    return base64_encode($iv.$enc);
}

function decrypt_openssl($enc, $key) {
    $iv_size = openssl_cipher_iv_length("BF-CBC");
    $dec = base64_decode($enc);
    $iv = substr($dec, 0, $iv_size);
    $string = openssl_decrypt(substr($dec, $iv_size), "BF-CBC", pack('H*',$key), OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING | OPENSSL_DONT_ZERO_PAD_KEY, $iv);
    return rtrim($string, "\x00");
}

function decrypt_mcrypt($enc, $key) {
    $iv_size = mcrypt_get_iv_size(MCRYPT_BLOWFISH, MCRYPT_MODE_CBC);
    $dec = base64_decode($enc);
    $iv = substr($dec, 0, $iv_size);
    $string = mcrypt_decrypt(MCRYPT_BLOWFISH, pack('H*', $key), substr($dec, $iv_size), MCRYPT_MODE_CBC, $iv);
    return rtrim($string, "\x00");
}

При шифровании с помощью openssl добавляются дополнительные двоичные данные.

Не гуру шифрования и получаю только половину, это было так, как я получил с помощью других сообщений stackoverflow и всемогущего Google


РЕДАКТИРОВАТЬ

Следуя совету Топако, я пришел к следующему коду, который теперь работает:

function encrypt_openssl($string, $key) {
    $string_padded = $string;
    if (strlen($string_padded) % 8) {
        $string_padded = str_pad($string_padded,
            strlen($string_padded) + 8 - strlen($string_padded) % 8, "\0");
    }
    $iv_size = openssl_cipher_iv_length("BF-CBC");
    $iv = openssl_random_pseudo_bytes($iv_size);
    $enc = openssl_encrypt($string_padded, "BF-CBC", pack('H*',$key), OPENSSL_RAW_DATA | OPENSSL_NO_PADDING, $iv);
    return base64_encode($iv.$enc);
}

1 Ответ

1 голос
/ 17 мая 2019

openssl_encrypt/decrypt использует PKCS7-заполнение по умолчанию, mcrypt_encrypt/decrypt использует Zero-Byte-padding .

Наблюдаемые дополнительные данные после дешифрования являются байтами заполнения заполнения PKCS7: текущий код использует заполнение PKCS7 для вызова openssl_encrypt (флаг OPENSSL_ZERO_PADDING не установлен). Поскольку для openssl_decrypt -call (набор флагов OPENSSL_ZERO_PADDING) заполнение не используется, заполнение все еще присутствует после расшифровки. Обратите внимание, что флаг OPENSSL_ZERO_PADDING отключает заполнение, он не означает заполнение нулями.

Хотя PKCS7-заполнение, как правило, является лучшим выбором по сравнению с заполнением нулями (поскольку последнее ненадежно), в этом случае имеет больше смысла использовать заполнение старых данных, т.е. заполнение нулями-байтами, Что касается совместимости старых данных. В противном случае были бы данные с другим заполнением, которые, как правило, не могут быть получены из данных, например, последний заполненный блок 41 42 43 44 45 46 02 02 может быть создан с помощью PKCS7-padding или Zero-Byte-padding:

before padding             after padding
41 42 43 44 45 46 __ __ -> 41 42 43 44 45 46 02 02  PKCS7-Padding
41 42 43 44 45 46 02 02 -> 41 42 43 44 45 46 02 02  Zero-Byte-Padding (variant of mcrypt_encrypt)  

Это сделает разложение более сложным. Использование Zero-Byte-padding позволяет избежать этой проблемы.

Поскольку openssl_encrypt/decrypt не поддерживает заполнение нулями, оно должно быть явно реализовано. Имеет смысл использовать вариант с нулевым байтом для mcrypt_encrypt: если открытый текст уже делится на размер блока (8 байт для Blowfish), дополнительный блок из нулевых байтов не добавляется. В противном случае заполнение выполняется нулевыми байтами до тех пор, пока длина открытого текста не будет соответствовать целому кратному размеру блока.

Заполнение нулевым байтом должно было произойти до openssl_encrypt -коллока. Кроме того, дополнение в самом вызове openssl_encrypt должно быть отключено (установите флаг OPENSSL_ZERO_PADDING, аналогично вызову openssl_decrypt).

...