最近在一个项目中用到CipherInputStream / CipherOutputStream对用户通过http上传的文件进行加密存储,上传之后加密没有任何问题,但是在解密之后下载时发现即使是本地测试也要等好长时间才能下载完成,下载代码肯定出现了问题。
文本使用CipherInputStream加密,加密使用AES算法,使用CBC模式填充,代码如下:
</pre><pre name="code" class="java"> Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");
c.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(new byte[16]));
使用填充保证不会丢失最后(文件大小模16)的字节数。
但在解密时设置http协议实体头部ContentLength时,设为
response.setContentLength((int)file.length());
file表示加密过之后的文件,所以file的大小不一定为源文件的大小(当源文件的大小能被16整除时才相等)。
由于response ContentLength 的长度和实体的长度不一致,导致下载完解密之后的文件后,浏览器仍保持链接去等待下载剩余的字节直到http协议超时。这就是下载加密文件时间比较长的原因。
暂时想到的解决办法有两个:
1. 先把解密后的文件保存为临时文件,然后下载这个临时文件。
2. 上传时保存文件的大小,下载时 把ContentLength设置为这个大小。
根据需求,本项目已保存了每次上传的文件大小,顾采用第二种方式。