Шифрование AES, выполненное в OpenSSL, успешно расшифровывается, но происходит сбой при шифровании в Java - PullRequest
2 голосов
/ 25 сентября 2019

Я использовал приведенный ниже код OpenSSL для шифрования AES, которое успешно расшифровывается на веб-сайте Tax

openssl rand 48 > 48byterandomvalue.bin
hexdump /bare 48byterandomvalue.bin > 48byterandomvalue.txt

set /a counter=0
for /f "tokens=* delims= " %%i in (48byterandomvalue.txt) do (
set /a counter=!counter!+1
set var=%%i
if "!counter!"=="1" (set aes1=%%i)
if "!counter!"=="2" (set aes2=%%i)
if "!counter!"=="3" (set iv=%%i)
)

set result1=%aes1:~0,50%
set result1=%result1: =%
set result2=%aes2:~0,50%
set result2=%result2: =%
set aeskey=%result1%%result2%
set initvector=%iv:~0,50%
set initvector=%initvector: =%

openssl aes-256-cbc -e -in PAYLOAD.zip -out PAYLOAD -K %aeskey% -iv %initvector%

openssl rsautl -encrypt -certin -inkey test_public.cer -in 
48byterandomvalue.bin -out 000000.00000.TA.840_Key

Но я хотел сделать то же самое на Java в рамках миграции, поэтому я использовалбиблиотеки javax.crypto и java.security , но при расшифровке происходит сбой при загрузке файла на веб-сайт Tax *

//creating the random AES-256 secret key
SecureRandom srandom = new SecureRandom(); 
KeyGenerator keyGen = KeyGenerator.getInstance("AES");
keyGen.init(256);
SecretKey secretKey = keyGen.generateKey();
byte[] aesKeyb = secretKey.getEncoded();

//creating the initialization vector
byte[] iv = new byte[128/8];
srandom.nextBytes(iv);
IvParameterSpec ivspec = new IvParameterSpec(iv);

byte[] encoded = Files.readAllBytes(Paths.get(filePath));
str = new String(encoded, StandardCharsets.US_ASCII);

//fetching the Public Key from certificate
FileInputStream fin = new FileInputStream("test_public.cer");
CertificateFactory f = CertificateFactory.getInstance("X.509");
X509Certificate certificate = (X509Certificate)f.generateCertificate(fin);
PublicKey pk = certificate.getPublicKey();

//encrypting the AES Key with Public Key
Cipher RSACipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
RSACipher.init(Cipher.ENCRYPT_MODE, pk);
byte[] RSAEncrypted = RSACipher.doFinal(aesKeyb);

FileOutputStream out = new FileOutputStream("000000.00000.TA.840_Key");
out.write(RSAEncrypted);
out.write(iv);
out.close();

Также сгенерирован ключ AESв Java отличается от того, сгенерированного через openssl.Ребята, пожалуйста, помогите.

РЕДАКТИРОВАТЬ 1: Ниже приведен код используемого шифрования AES:

Cipher AESCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
AESCipher.init(Cipher.ENCRYPT_MODE, secretKey, ivspec);
byte[] AESEncrypted = AESCipher.doFinal(str.getBytes("UTF-8"));
String encryptedStr = new String(AESEncrypted);

1 Ответ

2 голосов
/ 26 сентября 2019
  • Данные, которые скрипт и Java-код шифруют с помощью RSA, различаются:

    Скрипт генерирует случайную 48-байтовую последовательность и сохраняет ее в файле 48byterandomvalue.bin.Первые 32 байта используются как ключ AES, последние 16 байтов - как IV.Ключ и IV используются для шифрования файла PAYLOAD.zip с помощью AES-256 в режиме CBC и сохранения его в виде файла PAYLOAD.Файл 48byterandomvalue.bin шифруется с помощью RSA и сохраняется как файл 000000.00000.TA.840_Key.

    . В Java-коде генерируется случайный 32-байтовый ключ AES и случайный 16-байтовый IV.Оба используются для выполнения шифрования с AES-256 в режиме CBC.Ключ AES шифруется RSA, соединяется с незашифрованным IV, и результат сохраняется в файле 000000.00000.TA.840_Key.

    Содержимое файла 000000.00000.TA.840_Key отличается для скрипта и Java-кода.Чтобы Java-код генерировал file 000000.00000.TA.840_Key с помощью логики сценария, ключ незашифрованный AES должен быть соединен с незашифрованным IV, а этот результат должен быть зашифрован с помощью RSA:

    ...
    //byte[] aesKeyb byte-array with random 32-bytes key
    //byte[] iv      byte-array with random 16-bytes iv
    byte[] key_iv = new byte[aesKeyb.length + iv.length];
    System.arraycopy(aesKeyb, 0, key_iv, 0, aesKeyb.length);
    System.arraycopy(iv, 0, key_iv, aesKeyb.length, iv.length);
    ...
    byte[] RSAEncrypted = RSACipher.doFinal(key_iv);
    FileOutputStream out = new FileOutputStream("000000.00000.TA.840_Key");
    out.write(RSAEncrypted);
    out.close();
    ...
    

    Примечание: IV не должен быть секретным и, следовательно, не должен шифроваться.Шифрование необходимо только для генерации результата скрипта в Java-коде.

  • Другая проблема касается преобразования произвольных двоичных данных в строки.Обычно это приводит к повреждению данных, если кодировка не подходит (например, ASCII или UTF8).Поэтому

    ...
    byte[] encoded = Files.readAllBytes(Paths.get(filePath));
    str = new String(encoded, StandardCharsets.US_ASCII);           // Doesn't work: ASCII (7-bit) unsuitable for arbitrary bytes, *        
    ...
    byte[] AESEncrypted = AESCipher.doFinal(str.getBytes("UTF-8")); // Doesn't work: UTF-8 unsuitable for arbitrary bytes and additionally different from * 
    String encryptedStr = new String(AESEncrypted);                 // Doesn't work: UTF-8 unsuitable for arbitrary bytes
    ...
    

    следует заменить на

    ...
    byte[] encoded = Files.readAllBytes(Paths.get(filePath));
    ...
    byte[] AESEncrypted = AESCipher.doFinal(encoded);
    FileOutputStream out = new FileOutputStream("PAYLOAD");
    out.write(AESEncrypted);
    out.close();
    ...
    

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

  • Попробуйте эти изменения.Если возникают другие проблемы, лучше всего протестировать шифрование AES, шифрование RSA и key_iv -генерирование отдельно .Это облегчает выявление ошибок.

...