Openssl, Java: невозможно расшифровать длинные сообщения

Я шифрую текст с помощью java и пытаюсь расшифровать его с помощью Openssl в Linux. Я использую AES-128 с CBC.

Я получаю сообщение об ошибке «плохая расшифровка» от Openssl, когда использую Openssl для расшифровки 64-символьной зашифрованной строки, созданной Java. Но если строка состоит из 16 символов, Openssl сможет ее правильно расшифровать.

Я запускаю это в Linux:

echo ${encryptedText} | ./openssl aes-128-cbc -d -a -K $( echo -n ${KEY} | hexdump -v -e '/1 "%02X"') -iv $(echo -n ${IV} | hexdump -v -e '/1 "%02X"')

Примечание. $ EncryptedText, $ KEY, $ IV передаются как строки, а не шестнадцатеричные. Эта команда превращает его в шестнадцатеричный: $ (echo -n $ {KEY} | hexdump -v -e '/ 1 "% 02X"')

и получив эту ошибку:

358048944:error:0606506D:digital envelope routines:EVP_DecryptFinal_ex:wrong final block length:evp_enc.c:460:

Мой код шифрования из Java в основном:

import javax.crypto.*;

Cipher cipher;
SecretKey key;
String IV;
IvParameterSpec params;

cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
String randomString = GENERATE_RANDOM_TYPEABLE_ASCII(16_LENGTH);

key = new SecretKeySpec(randomString.getBytes("UTF-8"), "AES");
IV = GENERATE_RANDOM_TYPEABLE_ASCII(16_LENGTH);
params = new IvParameterSpec(IV.getBytes("UTF-8"));

cipher.init(Cipher.ENCRYPT_MODE, key, params);
byte[] encryptedTextBytes = cipher.doFinal((decryptedString).getBytes("UTF-8")); // decryptedString is passed as a parameter

String encryptedText = new Base64().encodeAsString(encryptedTextBytes);
return encryptedText;

Я не понимаю, почему криптография работает для 16-символьных строк, но не работает для 64-символьных строк.

Еще одна важная вещь, на которую следует обратить внимание, это то, что если я расшифрую текст с помощью онлайн-инструментов, таких как http://aes.online-domain-tools.com/, строка расшифровывается отлично. Поэтому я думаю, что мое шифрование работает нормально, но по какой-то причине OpenSSL дает проблемы.

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

President James K. Polk 24.08.2018 19:19

@James Вот почему у меня есть флаг -a в команде openssl выше. Я что-то пропустил? Спасибо за ответ

Saim Siddiqui 24.08.2018 20:59

Ах да, я забыл об этом флаге.

President James K. Polk 24.08.2018 21:19

Я не вижу, как это будет отличаться для 16 и 64 байтов, но заполнение PKCS5 не совсем хорошо определено для AES. Может быть, попробовать PKCS7 на случай, если Java делает с ним что-то странное?

lockcmpxchg8b 27.08.2018 01:03
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
4
282
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Я не воспроизводил вашу проблему, но подозреваю, что это вызывает у вас проблемы: функция Base64.encodeAsString(), когда вы ее используете, возвращает длинную строку, а не блок шириной в 16 символов:

import org.apache.commons.codec.binary.Base64;

public class B64Test {

    public static void main(String[] args) {
        byte[] plaintext = new byte[100];
        String b64text = new Base64().encodeAsString(plaintext);
        System.out.println(b64text);
    }
}

дает результат

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==

Если вы хотите передать это в openssl для декодирования, вам необходимо предоставить дополнительную опцию -A, чтобы openssl base64 обрабатывал данные в одной строке. Обратите внимание, что -A необходимо использовать вместе с -a или с -base64, что то же самое, но более читаемое. Это объясняется в документации для openssl enc.

В качестве альтернативы вы можете указать конструктору Base64() вставлять разрывы строк, например, после 64 символов, например:

String b64text = new Base64(64).encodeAsString(plaintext);

Я изменил флаг на -A, но у меня такая же проблема. Я также пробовал разрыв строки из 80 символов (с флагом -a), но у меня все еще возникает та же проблема.

Saim Siddiqui 25.08.2018 00:41

Это очень плохо. Сможете ли вы опубликовать фактические примеры значений для требуемых переменных, чтобы упростить воспроизведение и анализ проблемы?

Reinier Torenbeek 25.08.2018 01:10

Кстати, вы сказали "изменено" на флаг -A. Однако вам следует его добавить. Ты сделал это?

Reinier Torenbeek 25.08.2018 01:14

Еще немного поигравшись с функциональностью openssl base64, кажется, что отсечка составляет 64 байта, а не 80. Имеет ли это какое-то значение? (Я соответственно обновил пример кода.)

Reinier Torenbeek 25.08.2018 01:18

Я нахожусь вдали от своего рабочего ноутбука, я не смогу привести вам примерные значения до понедельника. Под изменением я имею в виду: я заменил -a на -A

Saim Siddiqui 25.08.2018 02:18

Хорошо, приятных выходных ... Вам нужно будет использовать и -a, и -A бок о бок. В документации для -A сказано: «Если опция -a установлена, то base64 обрабатывает данные в одной строке». Или используйте -base64 -A вместо -a -A, который такой же, но выглядит лучше.

Reinier Torenbeek 25.08.2018 02:41

Для OpenSSL через 1.0.2 -a/base64 -d без -A отсечка составляет 76 (НЕ 80 или 64) символа base64 на строку, что соответствует 59 байтам. Для OpenSSL 1.1.0 это 1024 символа или 768 байтов. Даже -A обрезается в более высокой точке, AFAICT 4000 байт.

dave_thompson_085 25.08.2018 03:53

@ dave_thompson_085: Я пробовал printf "MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ‌​1Njc4OTA = " | openssl enc -d -a (68 символов), и он не работает без -A. (Версия 1.0.2n). Выходные данные кодировки base64 также составляют 64 байта.

Reinier Torenbeek 25.08.2018 04:02

@ReinierTorenbeek: добавить терминатор строки (либо Unix \ n, либо Windows \ r \ n). Ввод для простого -d -a должен быть линии, не превышающим лимит, и даже более короткое значение, такое как 32 символа без терминатора, не сработает. Точно так же при кодировании без -A на выходе всегда есть хотя бы один терминатор. (Что может быть более запутанным, так это если у вас есть входной файл с несколькими строками, а последний не завершен, но другие, конечно же, потому что необходимо иметь несколько строк, тогда вы получите декодирование с часть ваших данных.)

dave_thompson_085 25.08.2018 09:01

@ dave_thompson_085: вау, это сбивает с толку, спасибо за исправление. Другие эксперименты также показывают различное поведение между разными версиями 1.0.2 (например, при сравнении 1.0.2d и 1.0.2n).

Reinier Torenbeek 25.08.2018 10:02

@ReinierTorenbeek: Я никогда не видел отличий, кроме той, что на 1.1.0+, и был бы заинтересован в ваших доказательствах, но боюсь, если мы будем продолжать в том же духе, мы можем рассердить богов комментариев.

dave_thompson_085 26.08.2018 08:04

@ dave_thompson_085: упомянутые мной различия могут больше не иметь значения, учитывая, что Примечания к выпуску серии OpenSSL 1.0.2 упоминает «Переписать EVP_DecodeUpdate (декодирование base64) для исправления нескольких ошибок» для выпуска 1.0.2e. Однако я думаю, что полное описание точных тонкостей / различий различных механизмов base64 (процедуры кодирования EVP, приложение openssl enc, base64 BIO) было бы весьма полезно.

Reinier Torenbeek 26.08.2018 22:28

@ReinierTorenbeek: добавление -a и -A устранило проблему. Огромное спасибо!

Saim Siddiqui 27.08.2018 16:24

Рад это слышать. Я немного поясню ответ об одновременном использовании обоих вариантов.

Reinier Torenbeek 27.08.2018 16:26

Другие вопросы по теме