Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java 9: AES-GCM performance

I have run a simple test to measure the AES-GCM performance in Java 9, by encrypting byte buffers in a loop. The results were somewhat confusing. The native (hardware) acceleration seems to work - but not always. More specifically,

  1. When encrypting 1MB buffers in a loop, the speed is ~60 MB/sec for the first ~50 seconds. Then it jumps to 1100 MB/sec, and stays there. Does JVM decide to activate the hardware acceleration after 50 seconds (or 3GB of data)? can it be configured? Where can I read about the new AES-GCM implementation (besides here).
  2. When encrypting 100MB buffers, the hardware acceleration doesn't kick in at all. The speed is a flat 60 MB/sec.

My test code looks like this:

int plen = 1024*1024;
byte[] input = new byte[plen];
for (int i=0; i < input.length; i++) { input[i] = (byte)i;}
byte[] nonce = new byte[12];
...
// Uses SunJCE provider
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
byte[] key_code = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
SecretKey key = new SecretKeySpec(key_code, "AES");
SecureRandom random = new SecureRandom();

long total = 0;
while (true) {
  random.nextBytes(nonce);
  GCMParameterSpec spec = new GCMParameterSpec(GCM_TAG_LENGTH * 8, nonce);
  cipher.init(Cipher.ENCRYPT_MODE, key, spec);
  byte[] cipherText = cipher.doFinal(input);
  total += plen;
  // print delta_total/delta_time, once in a while
}

Feb 2019 update: HotSpot had been modified to address this issue. The fix is applied in Java 13, and also backported to Java 11 and 12.

https://bugs.java.com/bugdatabase/view_bug.do?bug_id=JDK-8201633, https://hg.openjdk.java.net/jdk/jdk/rev/f35a8aaabcb9

July 16, 2019 update: The newly released Java version (Java 11.0.4) fixes this problem.

like image 211
gidon Avatar asked Feb 21 '18 11:02

gidon


People also ask

Does AES GCM need IV?

As GCM uses AES for encryption, the IV or the counter is 16 bytes. Therefore, we use the first 12 bytes as the IV and the last 4 bytes nonce as a counter. Here also, we need a unique IV, else one can decipher the plaintext.

What is nonce in AES GCM?

GCM. Nonce. A value used once during a cryptographic operation and then discarded.

Does AES GCM require padding?

Yesno. The plaintext is not padded because it uses counter mode encryption (CTR), and CTR mode doesn't require any padding. However, GMAC - which produces the authentication tag within the algorithm - only works on blocks of 128 bits.

What is GCM tag length?

The AES-GCM specification recommends that it should be 96, 104, 112, 120 or 128, although 32 or 64 bits may be acceptable in some applications: Appendix C of the specification provides additional guidance here. tagLength is optional and defaults to 128 if it is not specified.


1 Answers

Thanks @Holger for pointing in the right direction. Prepending cipher.doFinal with multiple cipher.update calls will trigger the hardware acceleration almost immediately.

Based on this reference, GCM Analysis , I'm using 4KB chunks in each update. Now both 1MB and 100MB buffers are encrypted at 1100 MB/sec speed (after a few dozen milliseconds) .

The solution is to replace

byte[] cipherText = cipher.doFinal(input);

with

int clen = plen + GCM_TAG_LENGTH;
byte[] cipherText = new byte[clen];

int chunkLen = 4 * 1024;
int left = plen;
int inputOffset = 0;
int outputOffset = 0;

while (left > chunkLen) {
  int written = cipher.update(input, inputOffset, chunkLen, cipherText, outputOffset);
  inputOffset += chunkLen;
  outputOffset += written;
  left -= chunkLen;
}

cipher.doFinal(input, inputOffset, left, cipherText, outputOffset);
like image 182
gidon Avatar answered Oct 13 '22 01:10

gidon