Openssl_encrypt возвращает false

Я пытаюсь зашифровать строку с помощью openssl_encrypt в PHP, но он продолжает возвращать FALSE.

$encrypted = openssl_encrypt('1234', 'AES-256-CBC', 'kGJeGF2hEQ', OPENSSL_ZERO_PADDING, '1234123412341234');

Что я делаю неправильно?

Ответ 1

В верхней части ответов, которые являются отличными, код, который вы используете, учитывая ваши входные параметры, будет следующим:

$plaintext = '1234';
$cipher = 'AES-256-CBC';
$key = 'this is a bad key';
$iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length($cipher));

$encrypted = openssl_encrypt($plaintext, $cipher, $key, 0, $iv);

if(false === $encrypted)
{
    echo openssl_error_string();
    die;
}

$decrypted = openssl_decrypt($encrypted, $cipher, $key, 0, $iv);

$result = $decrypted === $plaintext;

print $result ? 'Everything is fine' : 'Well, we did not decrypt good, did we?';

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

Я предлагаю использовать defuse/php-encryption

Ответ 2

php > var_dump (openssl_encrypt('1234', 'AES-256-CBC', 'kGJeGF2hEQ', OPENSSL_ZERO_PADDING, '1234123412341234'));
php shell code:1:
bool(false)
php > var_dump (openssl_error_string ());
php shell code:1:
string(94) "error:0607F08A:digital envelope routines:EVP_EncryptFinal_ex:data not multiple of block length"

Кажется, что используемый шифр требует, чтобы данные, которые вы шифровали, имели длину, которая была кратной длине блока. При некоторых экспериментах я обнаружил, что 1234123412341234 успешно зашифрован.

Я не знаю, является ли это универсальной особенностью всех схем шифрования openssl или является ли это чем-то конкретным для определенных схем. В первом случае вам нужно вставить ввод в несколько из размера блока. Если последнее верно, то вы можете либо наложить, либо переключиться на другую схему шифрования, которая не накладывает те же ограничения на вход.

Для заполнения вам нужно узнать, что такое размер блока вашего выбранного cypher (я не знаю, есть ли функция openssl или константа для этого), а затем выясните, сколько символов вам нужно заполнить вашей входной строкой,

Обратите внимание, что в следующем примере предполагается, что a) существует какой-то способ программного программирования блока (если нет, тогда вам придется жестко запрограммировать это) и b) вы работаете с байт-ориентированным символьным форматом ( unicode может вызвать проблемы!)

$plaintext = "Hello, I'm some plaintext!";
$blocksize = function_that_gets_a_blocksize_for_a_given_cypher ($cypher);
$strlen = strlen ($plaintext);
$pad = $blocksize - ($strlen % $blocksize);

// If the string length is already a multiple of the blocksize then we don't need to do anything
if ($pad === $blocksize) {
    $pad = 0;
}

$plaintext = str_pad ($plaintext, $strlen + $pad);

Что касается вашего кода, это предполагает, что вам нужно внедрить в него некоторое обнаружение ошибок (но будьте осторожны, что вы на самом деле регистрируете/эхо из части обнаружения ошибок!).

$encrypted = openssl_encrypt('1234', 'AES-256-CBC', 'kGJeGF2hEQ', OPENSSL_ZERO_PADDING, '1234123412341234');
if (false === $encrypted) {
    error_log ("Encryption failed! " . openssl_error_string ());
}

Ответ 3

  • Так как блочные шифры, такие как AES, требуют, чтобы входные данные были точными кратными размеру блока (16-байтовый для AES). Обычный метод - это просто указать PKCS # 7 (née PKCS # 5), передав его как опцию, и дополнение будет автоматически добавляться при шифровании и удаляться при расшифровке. Нулевое заполнение (OPENSSL_ZERO_PADDING) является плохим решением, поскольку оно не будет работать для двоичных данных.

  • IV должен быть размером блока, 8 байтов для AES. Не полагайтесь на реализацию для заполнения.

  • Ключ должен быть указан в указанном размере, допустимые размеры блоков AES - 128, 192 или 256 бит (16, 24 или 32 байта). Не полагайтесь на реализацию для заполнения.