Java 9:AES-GCM性能

gid*_*don 12 java encryption performance aes-gcm java-11

我已经运行了一个简单的测试,通过加密循环中的字节缓冲区来测量Java 9中AES-GCM性能.结果有点令人困惑.原生(硬件)加速似乎有效 - 但并非总是如此.进一步来说,

  1. 在循环中加密1MB缓冲区时,前50秒的速度约为60 MB /秒.然后它跳到1100 MB /秒,并保持在那里.JVM是否决定在50秒后激活硬件加速(或3GB数据)?可以配置吗?我在哪里可以阅读有关新的AES-GCM实现(除了这里).
  2. 加密100MB缓冲区时,硬件加速根本没有启动.速度是平坦的60 MB /秒.

为什么?

我的测试代码如下所示:

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
}
Run Code Online (Sandbox Code Playgroud)

2019年2月更新: HotSpot已被修改以解决此问题.该修复程序在Java 13中应用,并且还向后移植到Java 11和12.

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

gid*_*don 9

感谢@Holger指向正确的方向.预先cipher.doFinal进行多次cipher.update调用将几乎立即触发硬件加速.

基于此参考,GCM分析,我在每次更新中使用4KB块.现在,1MB100MB缓冲区都以1100 MB /秒的速度加密(几十毫秒后).

解决方案是更换

byte[] cipherText = cipher.doFinal(input);
Run Code Online (Sandbox Code Playgroud)

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);
Run Code Online (Sandbox Code Playgroud)