Проблемы с методом DES3 в библиотеке PHP openssl - PullRequest
1 голос
/ 26 апреля 2020

У меня есть веб-сервис, куда я отправляю зашифрованные данные в формате «TripleDES, режим ECB, размер ключа 192 и заполнение нулями». Провайдер показывает пример необработанного значения и ожидаемого результата:

необработанная строка = IA000001 зашифрованная строка (для отправки в веб-службу) = aVR5J/0Lph0=;

В PHP, openssl_encrypt() функция прекрасно работает для этой строки, но выдает ошибку data not multiple of block length SSL.

Я сделал скрипт, чтобы показать все проблемы (с комментариями):

<?php

$key = '1234567890123456ABCDEFGH';
$expected_result = 'aVR5J/0Lph0=';

function test_results($expected_value, $return_value) {
    echo openssl_error_string() . "\n";
    $compare = var_export($return_value == $expected_value, 1);
    echo "'$return_value' == '$expected_value' => {$compare}\n" ;
}

echo "Function value == Expected Value => same strings?\n";

// This works with $data == 'IA000001'
$data = 'IA000001';
$resultado_function = @openssl_encrypt($data, 'DES3', $key, OPENSSL_ZERO_PADDING);
test_results($expected_result, $resultado_function); // true

// but if I change string value (i.e. $data == 'IA000001T')
// openssl function fail:
//  error:0607F08A:digital envelope routines:EVP_EncryptFinal_ex:data not multiple of block length
$data = 'IA000001T';
$resultado_function = @openssl_encrypt($data, 'DES3', $key, OPENSSL_ZERO_PADDING);

// if change options to OPENSSL_RAW_DATA, errors gone, but strings aren't equals
$data = 'IA000001';
$resultado_function = @openssl_encrypt($data, 'DES3', $key, OPENSSL_RAW_DATA);
test_results($expected_result, $resultado_function); // false

// results are encoded in base64? not equal, but almost equal
$resultado_function = @openssl_encrypt($data, 'DES3', $key, OPENSSL_RAW_DATA);
$decoded_result = base64_encode($resultado_function);
test_results($expected_result, $decoded_result); // false but...

// Compare the firsts 11 chars:
// aVR5J/0Lph0=
// aVR5J/0Lph05HiLWyHnDqg==
//          ^-- Until this char, the strings are equal.

Что такое Я делаю не так? Размер блока? не закодированный ключ или данные?

Примечание. Я не контролирую реализацию веб-службы.

1 Ответ

1 голос
/ 26 апреля 2020

Я не гуру шифрования, но мне пришлось решить аналогичную проблему при недавнем переключении с mcrypt на openssl. Я считаю, что ваши данные должны иметь длину, кратную восьми (т.е. блоки по 8 символов). Эта строка имеет длину девять символов, а не 8 или шестнадцать, поэтому вы получаете эту ошибку.

Вы можете преодолеть это, заполнив ее нулевыми символами, чтобы получить желаемую длину (то есть кратную 8).

Я обернул код шифрования в функцию, чтобы лучше инкапсулировать логи c:

$key = '1234567890123456ABCDEFGH';
$expected_result = 'aVR5J/0Lph0=';

function test_results($expected_value, $return_value) {
    echo openssl_error_string() . "\n";
    $compare = var_export($return_value == $expected_value, 1);
    echo "'$return_value' == '$expected_value' => {$compare}\n" ;
}

function encrypt($text, $key) {
    $block_size = 8;
    if (strlen($text) % $block_size) {
        $text = str_pad($text, strlen($text) + $block_size - strlen($text) % $block_size, "\0");
    }
    return base64_encode(@openssl_encrypt($text, 'DES3', $key, OPENSSL_RAW_DATA | OPENSSL_NO_PADDING));
}

foreach (['IA000001', 'IA000001T'] as $data) {
    $resultado_function = encrypt($data, $key);
    test_results($expected_result, $resultado_function);
}

Вывод:

'aVR5J/0Lph0=' == 'aVR5J/0Lph0=' => true

'aVR5J/0Lph21RT9SWL7RSg==' == 'aVR5J/0Lph0=' => false
...