Расшифровать mcrypt с помощью openssl

Поскольку mcrypt считается устаревшим, моя задача – обновить текущий код для использования openssl. Звучит просто, но … после нескольких дней попытки и неудачи мне кажется, что я схожу с ума.

Мой вопрос к вам: есть ли способ, которым вы можете расшифровать данные openssl, ранее зашифрованные с помощью mcrypt? Я прочитал столько сообщений по этому вопросу, и большинство из них говорит, что предыдущее заполнение данных вручную было / необходимо, прежде чем запускать mcrypt на нем. Проблема заключается в том, что данные mcrypt-ed уже зашифрованы (с автоматическим заполнением нулевого заполнения mcrypt) и находятся в базе данных, поэтому модификация этого невозможна и / или желательна.

Упоминания:

  1. используется алгоритм rijndael-128 cbc с 32-байтным ключом (поэтому я использую aes-256-cbc для openssl).
  2. Я использую оболочку openssl для php (php-crypto).
  3. Мне удалось выполнить обратную операцию (декодировать openssl с помощью mcrypt), просто удалив конечные декодированные символы, если они не альфа-числовые.
  4. Вручную заполняя данные до mcrypt-ing, а затем расшифровывая их с помощью openssl, это работает как шарм, но это не проблема.

Некоторые фрагменты кода:

// Simple mcrypt encrypt, decrypt with php-crypto example // This doesn't work and produces a "Finalizing of cipher failed" error $data = "This is a text"; $strMcryptData=mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $data, MCRYPT_MODE_CBC, $iv); $algorithm = 'aes-256-cbc'; $cipher = new Cipher($algorithm); $sim_text = $cipher->decrypt($strMcryptData, $key, $iv); // Simple mcrypt encrypt with padding, decrypt with php-crypto // Works and produces the correct text on decryption $pad = $blocksize - (strlen($data) % $blocksize); $text = $data; $text .= str_repeat(chr($pad), $pad); $strPaddedData=mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $text, MCRYPT_MODE_CBC, $iv); $sim_text = $cipher->decrypt($strPaddedData, $key, $iv); 

Если вы зашифруете в mcrypt без добавления PKCS7 вручную, mcrypt с радостью добавит ваш пустой текст с NUL байтами.

OpenSSL будет заполнять PKCS7 для вас при использовании aes-X-cbc . К сожалению, это связано с тем, что если у вас есть AES-CBC(NULL_PADDED(plaintext)) и попытайтесь его расшифровать, openssl_decrypt попытается удалить дополнение и сбой.

Сравнить http://3v4l.org/bdQe9 vs http://3v4l.org/jr68f и http://3v4l.org/K6ZEU

Расширение OpenSSL в настоящее время не предлагает вам сказать: «Эта строка не дополняется, пожалуйста, не стягивайте меня для заполнения», а затем удалите байты NUL по своему усмотрению. Вы должны зашифровать с помощью дополнения PKCS7 для успешного завершения дешифрования.

Хотя это ограничение OpenSSL, важно подчеркнуть, что единственная причина, по которой вы работаете в ней, – это то, что mcrypt ужасен .

Немного старый, но вы можете решить это с небольшой работой. Вы можете указать OpenSSL PHP, что зашифрованная строка не заполнена, и сообщите ей, чтобы дать вам исходный вывод (так что вам также не нужно его декодировать base64). Затем вы можете отбросить нули от конца результирующей строки, если длина строки будет отлично делиться на IV (это проверка работоспособности, как если бы итоговая строка не делилась на IV, тогда она не была заполненными вообще).

Помните, что этот код имеет два основных ограничения :

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

  2. Если для заполнения строки понадобился только один нулевой байт, тогда этот код не будет лишать ее.

Вы можете решить их оба, если знаете, что ФАКТ означает, что вы не зашифровали что-либо, заканчивающееся нулевыми байтами, вы можете изменить код, который удаляет нули, чтобы просто выполнить preg_replace; просто убедитесь, что вы привязываете регулярное выражение к концу строки, чтобы оно только отделялось от конца.

http://3v4l.org/kYAXn

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

Не должно быть никаких существенных различий, кроме заполнения. Вы должны иметь возможность вызвать EVP_CIPHER_CTX_set_padding если EVP_CIPHER_CTX_set_padding используете конструкторы OpenSSL (EVP) более высокого уровня. Я полагаю, что аргумент заполнения должен быть равен нулю, хотя он не документирован . Для этого вам нужен предварительно сконфигурированный контекст шифрования / расшифровки.

Впоследствии вы получите свой открытый текст такой же длины, как и зашифрованный текст. От нуля до пятнадцати байтов в конце будет установлено ноль. Вам необходимо удалить эти байты вручную. Если открытый текст заканчивается нулевыми байтами, то они также будут удалены; однако это не так, если открытый текст является печатаемой строкой (которая использует 8-битную кодировку). Вы можете убедиться, что вы не удалите более 15 байт.

Если вы получаете полностью случайный текст, то ваш ключ или зашифрованный текст неверны. Если вы получаете читаемый открытый текст, но для первых 16 байтов, то ваша обработка IV неверна.