ZipInputStream 和 RSA 算法的纠葛( 二 )


RSA解密流程压缩文件中的加密文件是通过RSA算法生成的 , 解密代码如下:private byte[] decryptDescriptor(InputStream inputstream) { ByteArrayOutputStream bos = new ByteArrayOutputStream(); X509EncodedKeySpec keySpec; try {keySpec = new X509EncodedKeySpec(new BASE64Decoder().decodeBuffer(Encription.KEY_PUBLIC));PublicKey key = KeyFactory.getInstance("RSA").generatePublic(keySpec);Cipher cipher = Cipher.getInstance("RSA");cipher.init(Cipher.DECRYPT_MODE, key);byte[] data = http://kandian.youth.cn/index/new byte[cipher.getOutputSize(inputstream.available())];int len = 0;//直接循环读取密文输入流 , doFinal解密写入字节输出流中while ((len = bufferedInputStream.read(data))> 0) {bos.write(cipher.doFinal(data, 0, len));}return bos.toByteArray(); } catch (IOException | InvalidKeySpecException | NoSuchAlgorithmException | NoSuchPaddingException| InvalidKeyException | IllegalBlockSizeException | BadPaddingException e) {logger.error("解密升级描述文件异常.",e); }finally{try {inputstream.close();} catch (IOException e) {logger.error("关闭升级描述文件流异常.",e);} }return null;}上述解密代码 , 直接使用InputStream的read(data)方法 , 现将文件读入字节数组中 , 然后调用doFinal进行解密 。 那么对于WinRAR压缩包莫名多出一次的读取操作而言 , 就有问题 。
RSA解密算法会根据待解密数据的长度 , 得到一个固定长度 , 然后每次doFinal时只解密指定长度的数据 。
byte[] data = http://kandian.youth.cn/index/new byte[cipher.getOutputSize(inputstream.available())];这行代码定义的data长度 , 是128 , 根据真正的文件长度768得到的 。 那么InputStream在执行read操作过程中会读768/128=6次 , 每次读取128字节的数据 。 360压缩文件是符合这逻辑的 。 但是WinRAR压缩文件因为莫名多读了一次 , 导致第6次读取的长度是125 , 最后3字节还需再读一次 。 而doFinal在第6次执行时期待128字节 , 结果只有正常的125字节的数据 , 所以就直接报异常了 。
ZipInputStream 和 RSA 算法的纠葛文章插图
解决办法:通过缓冲区输入流 , 让不同的压缩文件都read相同的次数 , 保证doFinal操作能得到正确的数据 。 修改上述代码如下:
private byte[] decryptDescriptor(InputStream inputstream) {//使用缓冲字节流BufferedInputStream bufferedInputStream = new BufferedInputStream(inputstream);……try {……byte[] data = http://kandian.youth.cn/index/new byte[cipher.getOutputSize(bufferedInputStream .available())];int len = 0;//缓冲读取密文 , doFinal解密写入字节输出流中while ((len = bufferedInputStream .read(data))> 0) {bos.write(cipher.doFinal(data, 0, len));}return bos.toByteArray(); } catch (){ …… }return null;}启示录处理文件的时候 , 尽量使用 BufferedInputstream , 速度高效 , 减少不必要的IO次数 。 万一遇到本文这样的问题 , 就一并解决了 。
"人是有惰性的动物 , 如果过多地沉湎于温柔乡里 , 就会削弱重新投入风暴的勇气和力量 。 ”
【ZipInputStream 和 RSA 算法的纠葛】摘自路遥先生的《早晨从中午开始》 , 欠下的债总是要还的 , 也是对自己的警醒 。


推荐阅读