Я зашифровал файл с помощью OpenSSL aes-256-gcm. Поскольку aes-256-gcm не поддерживается командной строкой, я установил LibreSSL и могу использовать приведенную ниже команду для шифрования данных файла.

Openssl enc -aes-256-gcm -K 61616161616161616161616161616161 -iv 768A5C31A97D5FE9 -e -in file.in -out file.out

Мне нужно расшифровать данные file.out на Java, и я не могу этого сделать.

Образец кода :

    // Get Cipher Instance
    Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");

    String key = "61616161616161616161616161616161";
    byte[] IV = "768A5C31A97D5FE9".getBytes();

    // Create SecretKeySpec
    SecretKeySpec keySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES");

    // Create GCMParameterSpec
    GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(128, IV);

    // Initialize Cipher for DECRYPT_MODE
    cipher.init(Cipher.DECRYPT_MODE, keySpec, gcmParameterSpec);

    // Perform Decryption
    byte[] decryptedText = cipher.doFinal(cipherText); // for the data by reading file.out

Однако я получаю исключение, говорящее javax.crypto.AEADBadTagException: несоответствие тегов!

1
subrat padhi 22 Мар 2020 в 20:29

1 ответ

Это не должно работать. Командная строка openssl enc не поддерживает шифры/режимы AEAD, хотя ранние версии 1.0.1 (ниже патча h, в 2012-2014 гг.) не могли отловить, если вы неправильно указали такой шифр и молча выдали неверный вывод. Если вы на самом деле используете LibreSSL, а не OpenSSL, похоже, он унаследовал эту проблему, а не исправил ее, хотя весь смысл проекта LibreSSL заключался в том, чтобы исправить все ошибки, вызванные некомпетентными людьми OpenSSL.

Если бы это был шифр, который правильно работал в OpenSSL (а также в Java), например, aes-256-ctr, то ваша единственная проблема заключалась бы в том, что openssl enc -K -iv берут свои аргументы в шестнадцатеричном формате (подходит для контекста оболочки), тогда как Java crypto вызывается из кода, который может обрабатывать двоичные данные, и ожидает свои аргументы в этой форме. В результате значения, которые вы предоставляете OpenSSL, на самом деле составляют 16 байтов (128 бит) и 8 байтов (64 бита), а не 256 бит и 128 бит, как они должны быть (для CTR; для GCM IV из 96 бит было бы правильным, но, как уже отмечалось, GCM здесь не работает). openssl enc автоматически дополняет -K -iv (двоичными) нулями, но Java этого не делает. Таким образом, вам нужно что-то более похожее на

 byte[] key = Arrays.copyOf( javax.xml.bind.DatatypeConverter.parseHexBinary("61616161616161616161616161616161"), 32);
 // Arrays.copyOf zero-pads when expanding an array
 // then use SecretKeySpec (key, "AES")
 // and IVParameterSpec (iv) instead of GCMParameterSpec

 // but after Java8 most of javax.xml is removed, so unless you
 // are using a library that contains this (e.g. Apache) 
 // or have already written your own, you need something like

 byte[] fromHex(String h){
   byte[] v = new byte[h.length()/2];
   for( int i = 0; i < h.length(); i += 2 ) v[i] = Integer.parseInt(h.substring(i,i+2),16);
   return v;
 }

Сравните шифрование AES с помощью инструмента командной строки openssl и расшифровывать в Java и Blowfish шифровать в Java/Scala и расшифровать в bash (последнее — в обратном направлении, но необходимость сопоставления такая же)

3
dave_thompson_085 23 Мар 2020 в 00:24
Я использую версию OpenSSL OpenSSL 1.1.1c, и с помощью LibreSSL я могу шифровать и расшифровывать с помощью приведенной ниже команды. openssl enc -aes-256-gcm -nopad -K 61616161616161616161616161616161 -iv 768A5C31A97D5FE9 -e -in file.in -out file13.out openssl enc -d -aes-256-gcm -nopad -K 61616161616161616161616161616161 -iv 768A5C31A97D5FE9 -e -in file13.out -out file113.in И я использую режим CBC, я могу шифровать с помощью команды openssl и расшифровывать на Java. Я думаю, что делаю что-то неправильно для режима GCM.
 – 
subrat padhi
23 Мар 2020 в 10:45
- LibreSSL, похоже, игнорирует тег аутентификации в AES-GCM, здесь, что на самом деле является ошибкой. Поскольку это относится как к шифрованию, так и к дешифрованию, оба они работают внутри LibreSSL. Однако при кросс-платформенном (например, с Java) дешифровании произойдет сбой (даже если ключ и IV переданы правильно, так что они идентичны с обеих сторон), поскольку тег обязателен для аутентификации.
 – 
Topaco
23 Мар 2020 в 13:03
Можем ли мы выполнить расшифровку AES GCM, минуя тег аутентификации на стороне Java?
 – 
subrat padhi
23 Мар 2020 в 15:52