mcrypt_encrypt на openssl_encrypt и проблемы OPENSSL_ZERO_PADDING

У меня есть этот вызов mcrypt_encrypt для заданных $key, $message и $iv:

$string = mcrypt_encrypt(MCRYPT_3DES, $key, $message, MCRYPT_MODE_CBC, $iv);

Я хотел бы изменить вызов mcrypt_encrypt на вызов openssl_encrypt, чтобы обеспечить это в будущем.

Имея $mode = 'des-ede3-cbc' или $mode = '3DES'; и $options = true, я получаю более похожий ответ, но не идентичный. Есть ли другой способ назвать это, чтобы получить идеальное совпадение?

Я получаю это (base64_encoded) для комбинаций lorem-ipsum $message+$key, поэтому я начинаю верить, что одна функция или другая дополняют сообщение перед шифрованием...

для mcrypt

"Y+JgMBdfI7ZYY3M9lJXCtb5Vgu+rWvLBfjug2GLX7uo="

для для openssl

"Y+JgMBdfI7ZYY3M9lJXCtb5Vgu+rWvLBvte4swdttHY="

Попытка использовать $options для передачи OPENSSL_ZERO_PADDING, но передача чего-либо, кроме 1 (OPENSSL_RAW_DATA или true), приводит к ошибке пустой строки...

Ни OPENSSL_ZERO_PADDING, ни OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING не работают... :( Я использую "OpenSSL 1.0.2g 1 марта 2016".

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


person yivi    schedule 16.12.2016    source источник
comment
Вы никогда не должны получать идеальное совпадение, НИКОГДА. Вот для чего нужен вектор инициализации. Каждый раз, когда вы шифруете одну и ту же полезную нагрузку с помощью одного и того же алгоритма и одного и того же ключа, вы должны получать совершенно разные результаты, если хотите быть в безопасности. Если вы получаете один и тот же вывод для одного и того же ввода, ваше шифрование слабое. В этом смысл IV в шифровании. После шифрования вы доставляете зашифрованную полезную нагрузку с IV на другую сторону.   -  person Mjh    schedule 16.12.2016
comment
Если я использую ту же полезную нагрузку, тот же алгоритм, тот же IV; Я думаю, что я должен получить тот же результат. Неважно, что я должен использовать разные IV для каждого вызова: используя один и тот же IV для обоих вызовов (mcrypt и openssl), я думаю, что должен получить один и тот же результат, верно? Я начинаю полагать, что это связано с заполнением сообщений, так как попрошайничество вывода такое же.   -  person yivi    schedule 16.12.2016
comment
Если все то же самое, вы должны получить тот же результат, правильно. 4-й параметр для openssl_encrypt управляет заполнением. Вы можете зашифровать с помощью $encrypted = openssl_encrypt($data, $alg, $key, OPENSSL_ZERO_PADDING, $iv); и проверить, получите ли вы тот же результат. На www.php.net/openssl_encrypt вы можете прочитать комментарии, чтобы увидеть, как использовать 4-й параметр.   -  person Mjh    schedule 16.12.2016
comment
OPENSSL_ZERO_PADDING не работает, по крайней мере, для меня ... но да, заполнение - вот почему вы не можете получить тот же результат. Тем не менее, в вашей схеме шифрования так много ошибок, что вы можете просто заменить ее новой - пожалуйста, используйте для этого библиотеку, а не сворачивайте свою собственную.   -  person Narf    schedule 16.12.2016
comment
Прямо сейчас собираюсь понять, как сделать этот вызов и получить те же результаты, что и с mcrypt. Спасибо за ваши комментарии по шифрованию. Это не полное решение, и у меня нет полномочий изменять все, что я хочу, в этой кодовой базе.   -  person yivi    schedule 16.12.2016
comment
Что ж, в этом проблема - правильное дополнение данных самостоятельно является ключом к получению тех же результатов, и если вы это сделаете, вы измените схему шифрования. Я знаю, вы пытаетесь избежать перерывов в BC, но здесь это невозможно, поэтому вы должны сделать себе одолжение и сделать все правильно.   -  person Narf    schedule 16.12.2016
comment
Я думаю, тогда это не решаемо. Мне нужно создать это сообщение для сравнения с проверочным сообщением, предоставленным третьей стороной (для которого у меня есть $key и $iv, предоставленные отдельно). У меня нет контроля над этими сторонними методами шифрования, я могу только проверить предоставленное ими зашифрованное сообщение, которое, по-видимому, соответствует ответу mcrypt, но не openssl. Если бы OPENSSL_ZERO_PADDING работал, все было бы прекрасно.   -  person yivi    schedule 16.12.2016
comment
Пожалуйста, прочитайте эти вопросы и ответы, некоторые вещи изменились относительно заполнения в IV, и вы в любом случае должны использовать mcrypt_create_iv().   -  person Daniel W.    schedule 16.01.2017
comment
Лучше не использовать mcrypt, он уже почти десять лет является заброшенным. Поэтому он объявлен устаревшим и будет удален из ядра и включен в PECL в PHP 7.2. Он не поддерживает стандартное заполнение PKCS#7 (урожденное PKCS#5), а только нестандартное нулевое заполнение, которое нельзя использовать даже с двоичными данными. mcrypt содержит множество нерешенных ошибок, начиная с 2003 года. Вместо этого рассмотрите возможность использования defuse или RNCryptor, они обеспечивают полное решение, поддерживаются и являются правильными.   -  person zaph    schedule 16.01.2017
comment
Этот вопрос касается отказа от использования mcrypt.   -  person yivi    schedule 16.01.2017


Ответы (2)


mcrypt_encrypt дополняет входные данные нулями, если они не кратны размеру блока. Это приводит к неоднозначным результатам, если сами данные имеют конечные нули. По-видимому, OpenSSL не позволяет использовать нулевое заполнение в этом случае, что объясняет ложное возвращаемое значение.

Вы можете обойти это, добавив отступы вручную.

$message = "Lorem ipsum";
$key = "123456789012345678901234";
$iv = "12345678";

$message_padded = $message;
if (strlen($message_padded) % 8) {
    $message_padded = str_pad($message_padded,
        strlen($message_padded) + 8 - strlen($message_padded) % 8, "\0");
}
$encrypted_mcrypt = mcrypt_encrypt(MCRYPT_3DES, $key,
    $message, MCRYPT_MODE_CBC, $iv);
$encrypted_openssl = openssl_encrypt($message_padded, "DES-EDE3-CBC", 
    $key, OPENSSL_RAW_DATA | OPENSSL_NO_PADDING, $iv);

printf("%s => %s\n", bin2hex($message), bin2hex($encrypted_mcrypt));
printf("%s => %s\n", bin2hex($message_padded), bin2hex($encrypted_openssl));

Это печатает оба как равные.

4c6f72656d20697073756d => c6fed0af15d494e485af3597ad628cec
4c6f72656d20697073756d0000000000 => c6fed0af15d494e485af3597ad628cec
person Joe    schedule 16.01.2017

mcrypt_encrypt использует нули для заполнения сообщения до размера блока. Таким образом, вы можете добавить нули к хвосту ваших необработанных данных, а затем зашифровать блок.

Использование OPENSSL_RAW_DATA|OPENSSL_ZERO_PADDING должно работать. Если это не так, вы можете самостоятельно удалить заполнение из расшифрованных данных.

person Nickolay Olshevsky    schedule 16.01.2017
comment
Почему я должен тратить на это время? - person Nickolay Olshevsky; 16.01.2017
comment
OPENSSL_RAW_DATA|OPENSSL_ZERO_PADDING не работают. Вероятно, ошибка в реализации phps openssl или что-то в этом роде? Удаление лишних символов из незашифрованных данных у меня не работает. Эта строка используется в качестве проверочной подписи: мне предоставлены один и несколько данных, создайте эти зашифрованные данные, чтобы они соответствовали полученной подписи. Я не контролирую систему на другой стороне. Изменение вызова mcrypt_ так, чтобы он соответствовал openssl_, мне не помогает, мне нужно, чтобы openssl_ соответствовал mcrypt_ :) - person yivi; 16.01.2017
comment
Вы можете самостоятельно добавить нулевое заполнение, а затем вызвать openssl_encrypt. Это также добавит заполнение openssl. Затем удалите это дополнение (последние 8 байтов). Тогда вывод должен соответствовать mcrypt_encrypt - person Nickolay Olshevsky; 16.01.2017
comment
Я не уверен, что следую. Можете ли вы опубликовать это как часть своего ответа с примером кода, показывающим, что вы имеете в виду? Спасибо. - person yivi; 16.01.2017