Java 9: AES-GCM performance

独自空忆成欢 提交于 2020-02-26 12:11:48

问题


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.


回答1:


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);



回答2:


A couple of updates on this issue.

  1. The Java 10, released in late March, has the same problem, that can be bypassed with the same workaround - for data encryption only.

  2. The workaround basically doesn't work for data decryption - in both Java 9 and Java 10.

I've submitted a bug report to the Java platform. It had been evaluated and published as JDK-8201633.




回答3:


This problem is fixed in Java 13. The fix is 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




回答4:


The Java version, released on July 16, 2019 (Java 11.0.4), fixes this problem.



来源:https://stackoverflow.com/questions/48905291/java-9-aes-gcm-performance

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!