admin管理员组文章数量:1639831
1.背景
之前为某同事写了一个很小的工具,用于:批量将指定目录下的文件进行AES加密和解密。
同事用了一段时间。
今天同事说:报错了。
2.报错信息
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:956)
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:845)
at com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.java:446)
at javax.crypto.Cipher.doFinal(Cipher.java:2165)
...
3.错误分析
4.1.日志分析
从日志很容易分析出报错原因:内存溢出。
找到错误代码之处:
/**
* 对byte[]进行AES加密解密
* @param strKey 密钥
* @param encryptType 加密还是解密:Cipher.ENCRYPT_MODE Cipher.DECRYPT_MODE
* @param oriBytes 原始文件的byte[]数组
* @return 加密或解密后的文件byte[]数组
*/
private static byte[] AESEncodeAndDecode(String strKey,int encryptType, byte[] oriBytes){
byte[] result = null;
try {
//指定为AES加密,不区分大小写
KeyGenerator keygen = KeyGenerator.getInstance(AES);
//根据传入的key,生成随机流
keygen.init(128,new SecureRandom(strKey.getBytes()));
//产生原始对称key
SecretKey originKey = keygen.generateKey();
//获取原始对称key的字节数组
byte[] keyBytes = originKey.getEncoded();
//生成AES密钥
SecretKey key = new SecretKeySpec(keyBytes,AES);
//生成密码器
Cipher cipher = Cipher.getInstance(AES);
//初始化为加密器
cipher.init(encryptType,key);
//加密
result = cipher.doFinal(oriBytes);
} catch (Exception e) {
//...
} finally{
//...
}
return result;
}
具体报错代码:
//加密
result = cipher.doFinal(oriBytes);
3.2.当前加密策略分析
当前的加密策略:
- 将文件转换成byte[]。
- 对byte[]数组进行AES加密或解密。
- 将加密或解密完成的byte[]转换成文件。
3.3.分析结论
结合报错信息与加密策略,分析得出:
- 报错原因:内存溢出
- 具体原因:在使用Cipher进行加密解密时,处理的byte[]数组超出了内存限制。
验证:
让同事使用较小的文件进行加解密,并未报错。
4.错误解决
由上面的结论可知,原来的加密策略并不可用。因为,只要文件超过一定大小,都会内存溢出。
因此,尝试采用流的方式进行加密,即:CipherOutputStream与CipherInputStream。
对加密进行测试,代码如下:
/**
* 通过AES 以流的形式 对文件进行加密
* @param strKey
* @param oFileName 源文件路径
* @param rFileName 目标文件路径
* @return
*/
public static boolean AESEncodeFileByStream(String strKey, String oFileName, String rFileName) throws Exception {
//指定为AES加密,不区分大小写
KeyGenerator keygen = KeyGenerator.getInstance(AES);
//根据传入的key,生成随机流
keygen.init(128,new SecureRandom(strKey.getBytes()));
//产生原始对称key
SecretKey originKey = keygen.generateKey();
//获取原始对称key的字节数组
byte[] keyBytes = originKey.getEncoded();
//生成AES密钥
SecretKey key = new SecretKeySpec(keyBytes,AES);
//生成密码器
Cipher cipher = Cipher.getInstance(AES);
//初始化为加密器
cipher.init(Cipher.ENCRYPT_MODE,key);
//定义缓存区,用于存储字节流
byte[] buffer = new byte[1024];
//定义输入流
InputStream in = new FileInputStream(oFileName);
//定义输出流
OutputStream out = new FileOutputStream(rFileName);
//定义加密输出流
CipherOutputStream cipherOut = new CipherOutputStream(out,cipher);
//定义游标
int index;
//读写
while ((index = in.read(buffer)) != -1){
cipherOut.write(buffer,0,index);
}
//关闭IO流
cipherOut.close();
in.close();
return true;
}
经测试,分别对大小为900MB和2.38GB的文件进行加密,均成功。
5.总结
从这个问题,看文件和文件流:
- 直接处理文件:需要把整个文件加载到内存中,当文件很大时,这种方式十分不可行。
- 用文件流处理文件:能够分阶段将相应的数据写入缓冲区,不仅能够解决内存溢出的问题,而且极大地提高了相应的操作效率。
本文标签: 内存加密解密AESOutOfMemoryErrorSpace
版权声明:本文标题:AES加密解密内存溢出:OutOfMemoryError: Java heap space 解决 内容由热心网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:https://www.elefans.com/xitong/1729295684a1194689.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论