Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

8269827: JMH tests for AES/GCM byte[] and bytebuffers #4672

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
84 changes: 54 additions & 30 deletions test/micro/org/openjdk/bench/javax/crypto/full/AESGCMBench.java
Expand Up @@ -26,41 +26,38 @@
import org.openjdk.jmh.annotations.Param;
import org.openjdk.jmh.annotations.Setup;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidParameterSpecException;

/**
* This performance tests runs AES/GCM encryption and decryption using byte[]
* as input and output buffers for single and multi-part testing.
*
* This test rotates the IV and creates a new GCMParameterSpec for each encrypt
* benchmark operation
*/

public class AESGCMBench extends CryptoBase {

@Param({"AES/GCM/NoPadding"})
private String algorithm;

@Param({"128"})
private int keyLength;

@Param({""+16*1024})
@Param({"1024", "1500", "4096", "16384"})
private int dataSize;

byte[] data;
byte[] encryptedData;
byte[] in, out;
private Cipher encryptCipher;
private Cipher decryptCipher;
SecretKeySpec ks;
GCMParameterSpec gcm_spec;
byte[] aad;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not an expert on this, but why no more AAD?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For a performance test there isn't any value in adding an AAD. It's data sitting in a buffer that an be easily replicated with a multipart operation

byte[] iv;

public static final int IV_BUFFER_SIZE = 32;
public static final int IV_MODULO = IV_BUFFER_SIZE - 16;
private static final int IV_BUFFER_SIZE = 32;
private static final int IV_MODULO = IV_BUFFER_SIZE - 16;
int iv_index = 0;
int updateLen = 0;

private int next_iv_index() {
int r = iv_index;
Expand All @@ -69,36 +66,63 @@ private int next_iv_index() {
}

@Setup
public void setup() throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, InvalidAlgorithmParameterException, InvalidParameterSpecException {
public void setup() throws Exception {
setupProvider();
assert algorithm.split("/")[1].compareToIgnoreCase("GCM") == 0;

// Setup key material
byte[] keystring = fillSecureRandom(new byte[keyLength / 8]);
ks = new SecretKeySpec(keystring, "AES");
iv = fillSecureRandom(new byte[IV_BUFFER_SIZE]);
gcm_spec = new GCMParameterSpec(96, iv, next_iv_index(), 16);
aad = fillSecureRandom(new byte[5]);
encryptCipher = makeCipher(prov, algorithm);

// Setup Cipher classes
encryptCipher = makeCipher(prov, "AES/GCM/NoPadding");
encryptCipher.init(Cipher.ENCRYPT_MODE, ks, gcm_spec);
encryptCipher.updateAAD(aad);
decryptCipher = makeCipher(prov, algorithm);
data = fillRandom(new byte[dataSize]);
encryptedData = encryptCipher.doFinal(data);
decryptCipher = makeCipher(prov, "AES/GCM/NoPadding");
decryptCipher.init(Cipher.DECRYPT_MODE, ks,
encryptCipher.getParameters().
getParameterSpec(GCMParameterSpec.class));

// Setup input/output buffers
in = fillRandom(new byte[dataSize]);
encryptedData = new byte[encryptCipher.getOutputSize(in.length)];
out = new byte[encryptedData.length];
encryptCipher.doFinal(in, 0, in.length, encryptedData, 0);
updateLen = in.length / 2;

}

@Benchmark
public byte[] encrypt() throws BadPaddingException, IllegalBlockSizeException, InvalidAlgorithmParameterException, InvalidKeyException {
public void encrypt() throws Exception {
gcm_spec = new GCMParameterSpec(96, iv, next_iv_index(), 16);
encryptCipher.init(Cipher.ENCRYPT_MODE, ks, gcm_spec);
encryptCipher.updateAAD(aad);
return encryptCipher.doFinal(data);
encryptCipher.doFinal(in, 0, in.length, out, 0);
}

@Benchmark
public byte[] decrypt() throws BadPaddingException, IllegalBlockSizeException, InvalidParameterSpecException, InvalidAlgorithmParameterException, InvalidKeyException {
decryptCipher.init(Cipher.DECRYPT_MODE, ks, encryptCipher.getParameters().getParameterSpec(GCMParameterSpec.class));
decryptCipher.updateAAD(aad);
return decryptCipher.doFinal(encryptedData);
public void encryptMultiPart() throws Exception {
gcm_spec = new GCMParameterSpec(96, iv, next_iv_index(), 16);
encryptCipher.init(Cipher.ENCRYPT_MODE, ks, gcm_spec);
int outOfs = encryptCipher.update(in, 0, updateLen, out, 0);
encryptCipher.doFinal(in, updateLen, in.length - updateLen,
out, outOfs);
}

@Benchmark
public void decrypt() throws Exception {
decryptCipher.init(Cipher.DECRYPT_MODE, ks,
encryptCipher.getParameters().
getParameterSpec(GCMParameterSpec.class));
decryptCipher.doFinal(encryptedData, 0, encryptedData.length, out, 0);
}

@Benchmark
public void decryptMultiPart() throws Exception {
decryptCipher.init(Cipher.DECRYPT_MODE, ks,
encryptCipher.getParameters().
getParameterSpec(GCMParameterSpec.class));
decryptCipher.update(encryptedData, 0, updateLen, out, 0);
decryptCipher.doFinal(encryptedData, updateLen,
encryptedData.length - updateLen, out, 0);
}
}
163 changes: 163 additions & 0 deletions test/micro/org/openjdk/bench/javax/crypto/full/AESGCMByteBuffer.java
@@ -0,0 +1,163 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package org.openjdk.bench.javax.crypto.full;

import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.Param;
import org.openjdk.jmh.annotations.Setup;

import javax.crypto.Cipher;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.ByteBuffer;

/**
* This performance tests runs AES/GCM encryption and decryption using heap and
* direct ByteBuffers as input and output buffers for single and multi-part
* operations.
*
* This test rotates the IV and creates a new GCMParameterSpec for each encrypt
* benchmark operation
*/

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you want to create a "small" version?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I debated it.. I'm still not sure, but I guess I could.

public class AESGCMByteBuffer extends CryptoBase {

@Param({"128"})
private int keyLength;

@Param({"1024", "1500", "4096", "16384"})
private int dataSize;

@Param({"direct", "heap"})
private String dataMethod;

byte[] data;
ByteBuffer encryptedData;
ByteBuffer in, out;
private Cipher encryptCipher;
private Cipher decryptCipher;
SecretKeySpec ks;
GCMParameterSpec gcm_spec;
byte[] iv;

private static final int IV_BUFFER_SIZE = 32;
private static final int IV_MODULO = IV_BUFFER_SIZE - 16;
int iv_index = 0;
int updateLen = 0;

private int next_iv_index() {
int r = iv_index;
iv_index = (iv_index + 1) % IV_MODULO;
return r;
}

@Setup
public void setup() throws Exception {
setupProvider();

// Setup key material
byte[] keystring = fillSecureRandom(new byte[keyLength / 8]);
ks = new SecretKeySpec(keystring, "AES");
iv = fillSecureRandom(new byte[IV_BUFFER_SIZE]);
gcm_spec = new GCMParameterSpec(96, iv, next_iv_index(), 16);

// Setup Cipher classes
encryptCipher = makeCipher(prov, "AES/GCM/NoPadding");
encryptCipher.init(Cipher.ENCRYPT_MODE, ks, gcm_spec);
decryptCipher = makeCipher(prov, "AES/GCM/NoPadding");
decryptCipher.init(Cipher.DECRYPT_MODE, ks,
encryptCipher.getParameters().
getParameterSpec(GCMParameterSpec.class));

// Setup input/output buffers
data = fillRandom(new byte[dataSize]);
if (dataMethod.equalsIgnoreCase("direct")) {
in = ByteBuffer.allocateDirect(data.length);
in.put(data);
in.flip();
encryptedData = ByteBuffer.allocateDirect(
encryptCipher.getOutputSize(data.length));
out = ByteBuffer.allocateDirect(encryptedData.capacity());
} else if (dataMethod.equalsIgnoreCase("heap")) {
in = ByteBuffer.wrap(data);
encryptedData = ByteBuffer.allocate(
encryptCipher.getOutputSize(data.length));
out = ByteBuffer.allocate(encryptedData.capacity());
}

encryptCipher.doFinal(in, encryptedData);
encryptedData.flip();
in.flip();
updateLen = in.remaining() / 2;
}

@Benchmark
public void encrypt() throws Exception {
gcm_spec = new GCMParameterSpec(96, iv, next_iv_index(), 16);
encryptCipher.init(Cipher.ENCRYPT_MODE, ks, gcm_spec);
encryptCipher.doFinal(in, out);
out.flip();
in.flip();
}

@Benchmark
public void encryptMultiPart() throws Exception {
gcm_spec = new GCMParameterSpec(96, iv, next_iv_index(), 16);
encryptCipher.init(Cipher.ENCRYPT_MODE, ks, gcm_spec);
in.limit(updateLen);
encryptCipher.update(in, out);
in.limit(in.capacity());
encryptCipher.doFinal(in, out);
out.flip();
in.flip();
}

@Benchmark
public void decrypt() throws Exception {
decryptCipher.init(Cipher.DECRYPT_MODE, ks,
encryptCipher.getParameters().
getParameterSpec(GCMParameterSpec.class));
decryptCipher.doFinal(encryptedData, out);
encryptedData.flip();
out.flip();
}

@Benchmark
public void decryptMultiPart() throws Exception {
decryptCipher.init(Cipher.DECRYPT_MODE, ks,
encryptCipher.getParameters().
getParameterSpec(GCMParameterSpec.class));

int len = encryptedData.remaining();
encryptedData.limit(updateLen);
decryptCipher.update(encryptedData, out);
encryptedData.limit(len);

decryptCipher.doFinal(encryptedData, out);
encryptedData.flip();
out.flip();
}

}
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
Expand All @@ -24,11 +24,8 @@

import org.openjdk.jmh.annotations.Param;

public class AESGCMBench extends org.openjdk.bench.javax.crypto.full.AESGCMBench {


@Param({"AES/GCM/NoPadding"})
private String algorithm;
public class AESGCMBench extends
org.openjdk.bench.javax.crypto.full.AESGCMBench {

@Param({"128"})
private int keyLength;
Expand Down
@@ -0,0 +1,36 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package org.openjdk.bench.javax.crypto.small;

import org.openjdk.jmh.annotations.Param;

public class AESGCMByteBuffer extends
org.openjdk.bench.javax.crypto.full.AESGCMByteBuffer {

@Param({"128"})
private int keyLength;

@Param({"1024"})
private int dataSize;

}