Я шифрую текст с помощью 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 дает проблемы.
@James Вот почему у меня есть флаг -a в команде openssl выше. Я что-то пропустил? Спасибо за ответ
Ах да, я забыл об этом флаге.
Я не вижу, как это будет отличаться для 16 и 64 байтов, но заполнение PKCS5 не совсем хорошо определено для AES. Может быть, попробовать PKCS7 на случай, если Java делает с ним что-то странное?




Я не воспроизводил вашу проблему, но подозреваю, что это вызывает у вас проблемы: функция 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), но у меня все еще возникает та же проблема.
Это очень плохо. Сможете ли вы опубликовать фактические примеры значений для требуемых переменных, чтобы упростить воспроизведение и анализ проблемы?
Кстати, вы сказали "изменено" на флаг -A. Однако вам следует его добавить. Ты сделал это?
Еще немного поигравшись с функциональностью openssl base64, кажется, что отсечка составляет 64 байта, а не 80. Имеет ли это какое-то значение? (Я соответственно обновил пример кода.)
Я нахожусь вдали от своего рабочего ноутбука, я не смогу привести вам примерные значения до понедельника. Под изменением я имею в виду: я заменил -a на -A
Хорошо, приятных выходных ... Вам нужно будет использовать и -a, и -A бок о бок. В документации для -A сказано: «Если опция -a установлена, то base64 обрабатывает данные в одной строке». Или используйте -base64 -A вместо -a -A, который такой же, но выглядит лучше.
Для 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: Я пробовал printf "MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4OTA = " | openssl enc -d -a (68 символов), и он не работает без -A. (Версия 1.0.2n). Выходные данные кодировки base64 также составляют 64 байта.
@ReinierTorenbeek: добавить терминатор строки (либо Unix \ n, либо Windows \ r \ n). Ввод для простого -d -a должен быть линии, не превышающим лимит, и даже более короткое значение, такое как 32 символа без терминатора, не сработает. Точно так же при кодировании без -A на выходе всегда есть хотя бы один терминатор. (Что может быть более запутанным, так это если у вас есть входной файл с несколькими строками, а последний не завершен, но другие, конечно же, потому что необходимо иметь несколько строк, тогда вы получите декодирование с часть ваших данных.)
@ dave_thompson_085: вау, это сбивает с толку, спасибо за исправление. Другие эксперименты также показывают различное поведение между разными версиями 1.0.2 (например, при сравнении 1.0.2d и 1.0.2n).
@ReinierTorenbeek: Я никогда не видел отличий, кроме той, что на 1.1.0+, и был бы заинтересован в ваших доказательствах, но боюсь, если мы будем продолжать в том же духе, мы можем рассердить богов комментариев.
@ dave_thompson_085: упомянутые мной различия могут больше не иметь значения, учитывая, что Примечания к выпуску серии OpenSSL 1.0.2 упоминает «Переписать EVP_DecodeUpdate (декодирование base64) для исправления нескольких ошибок» для выпуска 1.0.2e. Однако я думаю, что полное описание точных тонкостей / различий различных механизмов base64 (процедуры кодирования EVP, приложение openssl enc, base64 BIO) было бы весьма полезно.
@ReinierTorenbeek: добавление -a и -A устранило проблему. Огромное спасибо!
Рад это слышать. Я немного поясню ответ об одновременном использовании обоих вариантов.
Это определенно не может работать, пока вы не декодируете зашифрованный текст с помощью base64, прежде чем расшифровать его с помощью openssl.