Java 9:AES-GCM性能

时间:2018-02-21 11:55:24

标签: java performance encryption java-9 aes-gcm

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

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

    我的测试代码如下:

    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
    }
    

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

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

4 个答案:

答案 0 :(得分:9)

感谢@Holger指向正确的方向。预先cipher.doFinal多次cipher.update次呼叫将立即触发硬件加速。

根据此参考GCM Analysis,我在每次更新中使用 4KB 块。现在, 1MB 100MB 缓冲区都以 1100 MB /秒速度加密(几十毫秒后)。

解决方案是替换

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

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

答案 1 :(得分:3)

关于这个问题的几个更新。

  1. 3月底发布的 Java 10 存在同样的问题,可以使用相同的解决方法绕过 - 仅限数据加密

  2. 对于数据解密,解决方法基本上不起作用 - 在Java 9和Java 10中。

  3. 我已经向Java平台提交了错误报告。它已被评估并发布为JDK-8201633

答案 2 :(得分:2)

此问题已在Java 13中解决。此修复程序也已反向移植到Java 11和12。

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

答案 3 :(得分:0)

2019年7月16日发布的Java版本(Java 11.0.4)修复了此问题。