【发布时间】:2021-05-13 23:39:04
【问题描述】:
问题
我正在尝试为 Android 制作文件加密器(加密算法为 AES)。一切正常,直到我尝试加密/解密一个大文件。例如,当我尝试加密一个 771 MB 的文件时,它给了我这个错误:
E/AndroidRuntime: FATAL EXCEPTION: Thread-6
Process: com.suslanium.encryptor, PID: 27638
java.lang.OutOfMemoryError: Failed to allocate a 536869904 byte allocation with 25165824 free bytes and 254MB until OOM, target footprint 295637424, growth limit 536870912
at com.android.org.conscrypt.OpenSSLCipher$EVP_AEAD.expand(OpenSSLCipher.java:1219)
at com.android.org.conscrypt.OpenSSLCipher$EVP_AEAD.updateInternal(OpenSSLCipher.java:1336)
at com.android.org.conscrypt.OpenSSLCipher.engineUpdate(OpenSSLCipher.java:323)
at javax.crypto.Cipher.update(Cipher.java:1722)
at javax.crypto.CipherOutputStream.write(CipherOutputStream.java:158)
at com.suslanium.encryptor.MainActivity.encryptFileAES_GCM(MainActivity.java:912)
at com.suslanium.encryptor.MainActivity$18.run(MainActivity.java:794)
at java.lang.Thread.run(Thread.java:919)
我的代码片段
public void encryptFileAES_GCM(File file , File fileToSave) throws Exception {
File keyEncrypted = new File(pathToStorage + "EncryptedKey.enc");
File IVEncrypted = new File(pathToStorage + "EncryptedKIV.enc");
if (keyEncrypted.exists() && IVEncrypted.exists()) {
FileInputStream fis = new FileInputStream(file);
FileOutputStream fos = new FileOutputStream(fileToSave);
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
SecretKeySpec keySpec = new SecretKeySpec(globalKey, "AES");
GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(GCM_TAG_LENGTH * 8, globalIV);
cipher.init(Cipher.ENCRYPT_MODE, keySpec, gcmParameterSpec);
CipherOutputStream cos = new CipherOutputStream(fos, cipher);
int b;
byte[] d = new byte[512];
while ((b = fis.read(d)) != -1) {
cos.write(d, 0, b); //Line 912
}
cos.flush();
cos.close();
fis.close();
} else {
throw new Exception("Key or IV does not exist, encryption can't be done. Please create a key first.");
}
}
我已经尝试寻找一些解决方案,但没有成功。我不知道这段代码有什么问题。缓冲区大小不是太大,但即使减小它 - 也没有任何反应。谁能帮帮我?
更新
问题解决了。在加密大文件时,我决定使用以下算法:将文件分成 X 大小的块,加密这些块并将它们放入 zip 存档中。解密大文件时,需要从存档中提取之前加密的chunk,解密后将解密后的chunk合并到一个文件中。
【问题讨论】:
-
确实很奇怪。让你的缓冲区更大。至少 8192 并在 while 循环中尝试使用 flush()。
-
是第一个 write() 调用导致了这种情况吗?还是过了一段时间?
-
1.你知道
CipherOutputStream使用内部缓冲区吗? 2.我认为用同一个实例加密16 x N字节是安全的。 -
您是否在链接的stackoverflow.com/a/57384337/8166854 中查看@President James K. Polk 的示例?他给出了一个完整的例子来避免“Conscrypt”中的错误,并建议使用 Bouncy Castle
标签: java android android-studio encryption out-of-memory