【问题标题】:Java: Get rid of `Cipher.init()` overheadJava:摆脱 `Cipher.init()` 开销
【发布时间】:2016-03-03 17:11:41
【问题描述】:

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

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

cipher 对象(“AES/ECB/NoPadding”)在构造函数中被初始化,以便可以重用。使用 ECB 是因为 encrypted 数组将始终只包含 16 个字节的数据(即 1 个数据块)。使用 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 方法的大部分时间,因为数据非常小。 IE。在超过 1200 万次调用中,Cipher.init() 平均需要 3 微秒,而Cipher.doFinal() 平均需要

  • Cipher.init() 需要这么长时间?
  • 是否有任何方法可以仅使用 Java 来加速此代码?例如,利用我将始终只解密单个数据块这一事实?
  • 使用 C/C++ 实现并使用 JNI 调用会更快吗?如果是这样,是否有任何完善的图书馆?

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

【问题讨论】:

  • 潜在键总是相同的吗?换句话说,你会在每个 16 字节块上运行相同的键列表吗?还是每个 16 字节的块都有自己的键列表?
  • 密钥设置需要一段时间。我不认为,您可以仅使用 Java 使其更快。
  • @Pace:键会改变,但不会那么频繁。您是否正在考虑存储已初始化的 Cipher 对象?
  • @Augustin 是的,这是我的想法。
  • 只调用一次Cipher.init()(在构造函数中)

标签: java performance encryption aes


【解决方案1】:

在 Cipher.init() 中什么需要这么长时间?

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

有没有什么方法可以只使用 Java 来加速这段代码?例如,利用我将始终只解密一个数据块这一事实?

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

或者,您可以存储预初始化密码列表而不是密钥。

使用 C/C++ 实现并使用 JNI 调用它会更快吗?如果是这样,是否有任何完善的图书馆?

很可能,是的。 libcrypto 是 OpenSSL 的一部分,它会有所帮助。 Here is an example.

【讨论】:

  • 最后(在我的用例中),存储预初始化的 Cipher 对象可以提高大约 10 倍的速度。谢谢。
猜你喜欢
  • 2013-10-13
  • 2013-05-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-03
  • 2012-08-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多