Java:摆脱`Cipher.init()`的开销

4
我需要提高以下方法的性能:

我需要提高以下方法的性能:

private byte[] decrypt(final byte[] encrypted, final Key key) throws ... {
    this.cipher.init(Cipher.DECRYPT_MODE, key);
    return this.cipher.doFinal(encrypted);
}

在构造函数中初始化了“AES/ECB/NoPadding”加密方式的对象,以便可以重复使用。由于encrypted数组始终只包含16个字节的数据(即1个数据块),因此使用ECB模式。使用128位密钥。

这种方法被调用了数百万次来解密16字节的数据块,每次使用不同的密钥。例如,该方法被以下方式调用:

final List<Key> keys = List with millions of keys
final byte[] data = new byte[] { ... 16 bytes of data go here ...}

for (final Key key : keys) {
    final byte[] encrypted = decrypt(data, key);

    // Do something with encrypted
}

Cipher.init()方法在decrypt方法中占据了大部分时间,因为数据非常小。也就是说,在超过1200万次调用中,Cipher.init()的平均耗时为3微秒,而Cipher.doFinal()的平均耗时小于0.5微秒。

  • Cipher.init()方法需要这么长的时间是由于什么原因?
  • 有没有 Java 方式来加速此部分代码?比如说利用每次只解密单个数据块这个事实?
  • 使用 C/C++ 实现并通过 JNI 调用会更快吗?如果是,是否有任何成熟的库可用?

我使用 JDK 1.8.0_73,我的处理器支持 AES-NI。


潜在的密钥总是相同的吗?换句话说,您会在每个16字节块上运行相同的密钥列表吗?还是每个16字节块都有自己的密钥列表? - Pace
密钥设置需要一些时间。我认为仅仅使用Java无法加快速度。 - Artjom B.
@Pace:密钥不经常更改。您是否考虑存储已初始化的“Cipher”对象? - Augustin
@Augustin 是的,那正是我的想法。 - Pace
只需在构造函数中调用Cipher.init()一次即可。 - user924
感谢你关于C/C++的问题,为什么我没想到呢。 - user924
1个回答

7

Cipher.init()为什么需要这么长的时间?

在初始化过程中,用户提供的密钥数据会被扩展成加密和解密例程使用的会话密钥。

有没有办法仅使用Java来加速此代码?例如利用我始终只解密单个数据块的事实?

有,但这需要重写AES算法的基本部分。您可以在JDK源代码中找到它,位于AESCrypt.java

或者,您可以存储一组预初始化的Ciphers而不是Keys。

使用C/C++实现并使用JNI调用是否更快?如果是,是否有任何成熟的库可用?

很可能是的。OpenSSL的一部分libcrypto将有所帮助。这里是一个示例


最终(在我的使用情况下),存储预初始化的“Cipher”对象导致速度提高了约10倍。谢谢。 - Augustin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接