【发布时间】:2020-07-15 19:25:55
【问题描述】:
我正在尝试通过 Java 和以下代码解密文件。但是在解密大文件时会出现OutOfMemory 异常。我尝试更改为cipher.update,但程序将冻结而没有任何响应。
如何将其从 doFinal 更改为 update?
public File decryptDataFile(File inputFile, File outputFile, File keyFile, String correlationId) {
try {
Security.addProvider(new BouncyCastleProvider());
String key = new String(Files.readAllBytes(keyFile.toPath())).trim();
byte[] byteInput = this.getFileInBytes(inputFile);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding", "BC");
byte[] salt = new byte[8];
System.arraycopy(byteInput, 8, salt, 0, 8);
SecretKeyFactory fact = SecretKeyFactory.getInstance("PBEWITHMD5AND256BITAES-CBC-OPENSSL", "BC");
cipher.init(Cipher.DECRYPT_MODE, fact.generateSecret(new PBEKeySpec(key.toCharArray(), salt, 100)));
byte[] data = cipher.doFinal(byteInput, 16, byteInput.length-16);
OutputStream os = new FileOutputStream(outputFile);
os.write(data);
os.close();
if(outputFile.exists()) {
return outputFile;
} else {
return null;
}
} catch (IOException | NoSuchAlgorithmException | NoSuchProviderException | NoSuchPaddingException | InvalidKeyException | InvalidKeySpecException | IllegalBlockSizeException | BadPaddingException e) {
logger.WriteLog(appConfig.getPlatform(), "INFO", alsConfig.getProjectCode(), correlationId, alsConfig.getFunctionId(), "SCAN_DECRYPT", e.getClass().getCanonicalName() + " - " + e.getMessage() );
return null;
}
}
我的非工作版本:
Security.addProvider(new BouncyCastleProvider());
String key = new String(Files.readAllBytes(keyFile.toPath())).trim();
byte[] byteInput = this.getFileInBytes(inputFile);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding", "BC");
byte[] salt = new byte[8];
System.arraycopy(byteInput, 8, salt, 0, 8);
SecretKeyFactory fact = SecretKeyFactory.getInstance("PBEWITHMD5AND256BITAES-CBC-OPENSSL", "BC");
cipher.init(Cipher.DECRYPT_MODE, fact.generateSecret(new PBEKeySpec(key.toCharArray(), salt, 100)));
FileInputStream fis = new FileInputStream(inputFile);
FileOutputStream fos = new FileOutputStream(outputFile);
CipherInputStream cis = new CipherInputStream(fis, cipher);
int b;
byte[] d = new byte[8];
while((b = cis.read(d)) != -1) {
fos.write(d, 0, b);
}
fos.flush();
fos.close();
cis.close();
if(outputFile.exists()) {
return outputFile;
} else {
return null;
}
【问题讨论】:
-
你读取了内存中的整个文件。你应该使用
CipherOutputStream/CipherInputStream -
在 Baeldung 中找到了一个示例,但我无法弄清楚如何在我的代码中实现。如何使用
CipherOutputStream/CipherInputStream? -
请提供 encryptDataFile-method 以及我不知道 byteInput 的前 8 字节数据(您正在读取从 pos 8 到 16 = 8 字节的盐)中的内容并使用其余的作为 cipher.Update 的输入)
-
@MichaelFehr 感谢您的回复。加密实际上是由这个 shell 脚本完成的。
openssl enc -aes-256-cbc -e -salt -in ${tarFile} -out ${encTarFile} -pass file:./${KEY_RANDOM} -
请不要将更长的代码作为评论发布,而是编辑您的问题并在此处添加代码。您是否将 OpenSSL 前缀 (
Salted__) 和盐与FileInputStream分开?此外,您的缓冲区太小了。
标签: java encryption