我正在应用程序中实现AES256加密,这是通过自定义FilterOutputStream完成的,在该代码中,我用加密的流包装了提供的输出流。目标加密为AES/CTR/NoPadding

首先,我开始使用标准Java的javax.crypto.CipherOutputStream,因此代码如下所示:

...
Cipher cipher = Cipher.getInstance("AES/CTR/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, sessionKey, new IvParameterSpec(ivBytes));
this.out = new CipherOutputStream(out, cipher);


但是我注意到使用这种方法加密100 MB文件大约需要10分钟(是的,几分钟!),这显然是不合适的吞吐量。

因此,我开始四处摸索,我的第一个猜测是将Bouncy Castle用作Cipher提供程序(因为在SO上的某处建议使用它)。因此,代码变为:

...
Cipher cipher = Cipher.getInstance("AES/CTR/NoPadding", BouncyCastleProvider.PROVIDER_NAME);
cipher.init(Cipher.ENCRYPT_MODE, sessionKey, new IvParameterSpec(ivBytes));
this.out = new CipherOutputStream(out, cipher);


通过这种更改,加密时间减少到了约45秒,比原来提高了10倍以上,但仍然不合适。

因此,我接下来要做的是用Apache Commons Crypto提供的CipherOutputStream替换标准的CryptoOutputStream,因此代码看起来像这样:

...
this.out = new CryptoOutputStream("AES/CTR/NoPadding", new Properties(), out, sessionKey, new IvParameterSpec(ivBytes));


而且-瞧-同一文件的加密现在只需要2秒钟左右的时间,因此它的速度比BC快15倍,比原始方法快150倍!

所以,我的问题是...背后的原因是什么?仅仅是Java中默认的CipherOutputStream太糟糕而Apache的CryptoOutputStream太好了吗?但是,Bouncy Castle如何提高标准CipherOutputStream?我在这里想念什么?

UPD:我相信这不是Java I/O classes and performance的重复,因为该问题明确地涉及纯数据流的性能,但是该问题与加密流的性能有关,答案并不那么明显。

最佳答案

您需要将流包装在BufferedOutputStream中,这可以提高IO的效率,因为使用了一个较大的写入来代替许多小的写入。

根据实际用途,缓冲CipherOutputStream可能比out更好。有时可能有助于将两者包装在一起。 YMMV,我建议您测试最有效的方法。

08-25 12:13