Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java: Get rid of `Cipher.init()` overhead

I need to increase performance of the following method:

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

The cipher object ("AES/ECB/NoPadding") is initialized in the constructor, so that it can be reused. ECB is used since the encrypted array will contain always only 16 bytes of data (i.e. 1 block of data). 128 bit key is used.

This method is called millions of times to decrypt 16 byte chunk, each time with a different key. E.g. the method is called like this:

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
}

The Cipher.init() takes most of the time of the decrypt method, since the data is so small. I.e. with over 12 million invocations, Cipher.init() takes 3 microseconds on average while Cipher.doFinal() takes < 0.5 microseconds on average.

  • What takes so long in Cipher.init()?
  • Is there any way to speed up this code using Java only? For instance by taking advantage of the fact I will be decrypting always only a single block of data?
  • Would it be faster to use a C/C++ implementation and call it using JNI? If so, is there any well-established library for that?

I use JDK 1.8.0_73 and my processor supports AES-NI.

like image 887
Augustin Avatar asked Mar 13 '23 01:03

Augustin


1 Answers

What takes so long in Cipher.init()?

During initialization a user-supplied key data is expanded into session keys used by encryption and decryption routines.

Is there any way to speed up this code using Java only? For instance by taking advantage of the fact I will be decrypting always only a single block of data?

Yes, but this would require rewriting the essential part of AES algorithm. You may find it in JDK sources in AESCrypt.java.

Alternatively, you may store a list of preinitialized Ciphers instead of Keys.

Would it be faster to use a C/C++ implementation and call it using JNI? If so, is there any well-established library for that?

Most likely, yes. libcrypto which is a part of OpenSSL will help. Here is an example.

like image 98
apangin Avatar answered Mar 24 '23 17:03

apangin