Предисловие: Я не смог расшифровать вашим исходным методом файл, который был зашифрован с помощью вашей openssl-команды
openssl enc -aes-256-cbc -e -salt -in ${tarFile} -out ${encTarFile} -pass file:./${KEY_RANDOM}
, но следующий метод должен декодировать даже большие файлы, аналогичные вашему исходному методу - я тестировал файлы размером до 1 ГБ.
Изменить: Что касается оператора OpenSSL, стоит упомянуть, что, начиная с версии 1.1.0, дайджест по умолчанию изменился с MD5 на SHA256, поэтому для более высоких В версиях для совместимости с кодом Java необходимо явно указать параметр -md MD5. (спасибо @Topaco).
Пожалуйста, имейте в виду, что меня не интересуют правильные пути к файлам для
new FileInputStream(inputFile.toPath().toString())
and
new FileOutputStream(outputFile.toPath().toString())
так как я работаю локально и со своей папкой, возможно, вам придется изменить код, чтобы «найти» ваши файлы. Кроме того, в этом примере нет обработки исключений.
Строка кода
byte[] ibuf = new byte[8096];
определяет используемый буфер - больший буфер ускоряет дешифрование, но потребляет больше памяти (8096 означает 8096 байт по сравнению с 1 ГБ при чтении полного файла в память и возникновении ошибки нехватки памяти).
public static File decryptDataFileBuffered(File inputFile, File outputFile, File keyFile, String correlationId) throws IOException, NoSuchPaddingException, NoSuchAlgorithmException, NoSuchProviderException, InvalidKeySpecException, BadPaddingException, IllegalBlockSizeException, InvalidKeyException {
Security.addProvider(new BouncyCastleProvider());
String key = new String(Files.readAllBytes(keyFile.toPath())).trim();
byte[] salt = new byte[8];
byte[] salted = new byte[8]; // text SALTED__
try (FileInputStream in = new FileInputStream(inputFile.toPath().toString()); // i don't care about the path as all is lokal
FileOutputStream out = new FileOutputStream(outputFile.toPath().toString())) // i don't care about the path as all is lokal
{
byte[] ibuf = new byte[8096]; // thats the buffer used - larger is faster
int len;
in.read(salted);
in.read(salt);
SecretKeyFactory fact = SecretKeyFactory.getInstance("PBEWITHMD5AND256BITAES-CBC-OPENSSL", "BC");
SecretKey secretKey = fact.generateSecret(new PBEKeySpec(key.toCharArray(), salt, 100));
System.out.println("secretKey length: " + secretKey.getEncoded().length + " data: " + bytesToHex(secretKey.getEncoded()));
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, secretKey);
while ((len = in.read(ibuf)) != -1) {
byte[] obuf = cipher.update(ibuf, 0, len);
if (obuf != null)
out.write(obuf);
}
byte[] obuf = cipher.doFinal();
if (obuf != null)
out.write(obuf);
} catch (IOException | BadPaddingException | IllegalBlockSizeException e) {
e.printStackTrace();
}
if (outputFile.exists()) {
return outputFile;
} else {
return null;
}
}
Edit2: Как прокомментировал @Topaco использование CipherInput / OutputStream сокращает код и делает его более читабельным, поэтому вот код:
public static File decryptDataFileBufferedCipherInputStream (File inputFile, File outputFile, File keyFile, String correlationId) throws
IOException, NoSuchPaddingException, NoSuchAlgorithmException, NoSuchProviderException, InvalidKeySpecException, InvalidKeyException
{
Security.addProvider(new BouncyCastleProvider());
String key = new String(Files.readAllBytes(keyFile.toPath())).trim();
byte[] salt = new byte[8];
byte[] salted = new byte[8]; // text SALTED__
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
try (FileInputStream in = new FileInputStream(inputFile.toPath().toString()); // i don't care about the path as all is lokal
CipherInputStream cipherInputStream = new CipherInputStream(in, cipher);
FileOutputStream out = new FileOutputStream(outputFile.toPath().toString())) // i don't care about the path as all is lokal
{
byte[] buffer = new byte[8192];
in.read(salted);
in.read(salt);
SecretKeyFactory fact = SecretKeyFactory.getInstance("PBEWITHMD5AND256BITAES-CBC-OPENSSL", "BC");
SecretKey secretKey = fact.generateSecret(new PBEKeySpec(key.toCharArray(), salt, 100));
System.out.println("secretKey length: " + secretKey.getEncoded().length + " data: " + bytesToHex(secretKey.getEncoded()));
cipher.init(Cipher.DECRYPT_MODE, secretKey);
int nread;
while ((nread = cipherInputStream.read(buffer)) > 0) {
out.write(buffer, 0, nread);
}
out.flush();
}
if (outputFile.exists()) {
return outputFile;
} else {
return null;
}
}