Skip to content

Commit

Permalink
Merge pull request #690 from KostasTsiounis/gcm_perf
Browse files Browse the repository at this point in the history
Optimize AES/GCM cipher and IV initialization and improve array cleanup code
  • Loading branch information
keithc-ca authored Sep 13, 2023
2 parents 71d4a40 + 26e6fd1 commit cba526a
Show file tree
Hide file tree
Showing 5 changed files with 272 additions and 314 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ class NativeCipherBlockChaining extends FeedbackCipher {
contexts = new long[numContexts];

for (int i = 0; i < numContexts; i++) {
long context = nativeCrypto.CBCCreateContext();
long context = nativeCrypto.CreateContext();
if (context == -1) {
throw new ProviderException("Error in Native CipherBlockChaining");
}
Expand All @@ -90,7 +90,7 @@ public void run() {
*/
synchronized (NativeCipherBlockChaining.class) {
if (ctxIndx == -1) {
long ret = nativeCrypto.CBCDestroyContext(nativeContext);
long ret = nativeCrypto.DestroyContext(nativeContext);
if (ret == -1) {
throw new ProviderException("Error in Native CipherBlockChaining");
}
Expand All @@ -108,7 +108,7 @@ synchronized static long getContext(NativeCipherBlockChaining cipher) {

if (avStack.isEmpty()) {
cipher.ctxIndx = -1;
long context = nativeCrypto.CBCCreateContext();
long context = nativeCrypto.CreateContext();
if (context == -1) {
throw new ProviderException("Error in Native CipherBlockChaining");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,20 +25,27 @@

/*
* ===========================================================================
* (c) Copyright IBM Corp. 2018, 2021 All Rights Reserved
* (c) Copyright IBM Corp. 2018, 2023 All Rights Reserved
* ===========================================================================
*/

package com.sun.crypto.provider;

import java.util.Arrays;
import java.io.*;
import java.security.*;
import javax.crypto.*;
import com.sun.crypto.provider.*;
import com.sun.crypto.provider.AESCrypt;
import static com.sun.crypto.provider.AESConstants.AES_BLOCK_SIZE;

import java.io.ByteArrayOutputStream;
import java.security.InvalidKeyException;
import java.security.ProviderException;

import javax.crypto.AEADBadTagException;
import javax.crypto.ShortBufferException;
import javax.crypto.IllegalBlockSizeException;

import jdk.crypto.jniprovider.NativeCrypto;

import sun.misc.Cleaner;

/**
* This class represents ciphers in GaloisCounter (GCM) mode.
*
Expand All @@ -54,9 +61,11 @@
*/
final class NativeGaloisCounterMode extends FeedbackCipher {

private static final byte[] EMPTY_BUF = new byte[0];

private byte[] key;
private boolean decrypting;
private static final byte[] emptyAAD = new byte[0];
private final long context;

static int DEFAULT_TAG_LEN = AES_BLOCK_SIZE;
static int DEFAULT_IV_LEN = 12; // in bytes
Expand Down Expand Up @@ -98,10 +107,33 @@ final class NativeGaloisCounterMode extends FeedbackCipher {
private byte[] ibufferSave_enc = null;
private int processedSave = 0;

private static NativeCrypto nativeCrypto;
private byte[] lastKey = EMPTY_BUF;
private byte[] lastIv = EMPTY_BUF;

private boolean newIVLen;
private boolean newKeyLen;

private static final NativeCrypto nativeCrypto = NativeCrypto.getNativeCrypto();

private static final class GCMCleanerRunnable implements Runnable {
private final long nativeContext;

public GCMCleanerRunnable(long nativeContext) {
this.nativeContext = nativeContext;
}

static {
nativeCrypto = NativeCrypto.getNativeCrypto();
@Override
public void run() {
/*
* Release the GCM context.
*/
synchronized (NativeGaloisCounterMode.class) {
long ret = nativeCrypto.DestroyContext(nativeContext);
if (ret == -1) {
throw new ProviderException("Error in destroying context in NativeGaloisCounterMode.");
}
}
}
}

// value must be 16-byte long; used by GCTR and GHASH as well
Expand Down Expand Up @@ -203,6 +235,12 @@ private static void checkDataLength(int processed, int len) {
NativeGaloisCounterMode(SymmetricCipher embeddedCipher) {
super(embeddedCipher);
aadBuffer = new ByteArrayOutputStream();

context = nativeCrypto.CreateContext();
if (context == -1) {
throw new ProviderException("Error in creating context for NativeGaloisCounterMode.");
}
Cleaner.create(this, new GCMCleanerRunnable(context));
}

/**
Expand Down Expand Up @@ -355,6 +393,22 @@ void init(boolean decrypting, String algorithm, byte[] keyValue,
} else {
ibuffer_enc = new ByteArrayOutputStream();
}

/*
* Check whether cipher and IV need to be set,
* whether because something changed here or
* a call to set them in context hasn't been
* made yet.
*/
if (lastIv.length != this.iv.length) {
newIVLen = true;
}
if (lastKey.length != this.key.length) {
newKeyLen = true;
}

lastKey = keyValue;
lastIv = iv;
}
}

Expand Down Expand Up @@ -465,18 +519,26 @@ int encryptFinal(byte[] in, int inOfs, int len, byte[] out, int outOfs)
throw new ShortBufferException("Output buffer too small");
}

byte[] aad = (((aadBuffer == null) || (aadBuffer.size() == 0)) ? emptyAAD : aadBuffer.toByteArray());
byte[] aad = (((aadBuffer == null) || (aadBuffer.size() == 0)) ? EMPTY_BUF : aadBuffer.toByteArray());

ret = nativeCrypto.GCMEncrypt(key, key.length,
ret = nativeCrypto.GCMEncrypt(context,
key, key.length,
iv, iv.length,
in, inOfs, len,
out, outOfs,
aad, aad.length, localTagLenBytes);
aad, aad.length,
localTagLenBytes,
newIVLen,
newKeyLen);
}
if (ret == -1) {
throw new ProviderException("Error in Native GaloisCounterMode");
}

/* Cipher and IV length were set, since call to GCMEncrypt succeeded. */
newKeyLen = false;
newIVLen = false;

return (len + localTagLenBytes);
}

Expand Down Expand Up @@ -552,7 +614,7 @@ int decryptFinal(byte[] in, int inOfs, int len,
}

byte[] aad = (((aadBuffer == null) || (aadBuffer.size() == 0)) ?
emptyAAD : aadBuffer.toByteArray());
EMPTY_BUF : aadBuffer.toByteArray());

aadBuffer = null;

Expand All @@ -566,11 +628,15 @@ int decryptFinal(byte[] in, int inOfs, int len,
len = in.length;
ibuffer.reset();

ret = nativeCrypto.GCMDecrypt(key, key.length,
ret = nativeCrypto.GCMDecrypt(context,
key, key.length,
iv, iv.length,
in, inOfs, len,
out, outOfs,
aad, aad.length, tagLenBytes);
aad, aad.length,
tagLenBytes,
newIVLen,
newKeyLen);
}

if (ret == -2) {
Expand All @@ -579,6 +645,9 @@ int decryptFinal(byte[] in, int inOfs, int len,
throw new ProviderException("Error in Native GaloisCounterMode");
}

/* Cipher and IV length were set, since call to GCMDecrypt succeeded. */
newKeyLen = false;
newIVLen = false;

return ret;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -232,11 +232,11 @@ public final native int DigestComputeAndReset(long context,

public final native int DigestReset(long context);

/* Native CBC interfaces */
/* Native interfaces shared by CBC and GCM. */

public final native long CBCCreateContext();
public final native long CreateContext();

public final native int CBCDestroyContext(long context);
public final native int DestroyContext(long context);

public final native int CBCInit(long context,
int mode,
Expand All @@ -262,7 +262,8 @@ public final native int CBCFinalEncrypt(long context,

/* Native GCM interfaces */

public final native int GCMEncrypt(byte[] key,
public final native int GCMEncrypt(long context,
byte[] key,
int keylen,
byte[] iv,
int ivlen,
Expand All @@ -273,9 +274,12 @@ public final native int GCMEncrypt(byte[] key,
int outOffset,
byte[] aad,
int aadLen,
int tagLen);
int tagLen,
boolean newIVLen,
boolean newKeyLen);

public final native int GCMDecrypt(byte[] key,
public final native int GCMDecrypt(long context,
byte[] key,
int keylen,
byte[] iv,
int ivlen,
Expand All @@ -286,7 +290,9 @@ public final native int GCMDecrypt(byte[] key,
int outOffset,
byte[] aad,
int aadLen,
int tagLen);
int tagLen,
boolean newIVLen,
boolean newKeyLen);

/* Native RSA interfaces */
public final native long createRSAPublicKey(byte[] n,
Expand Down
Loading

0 comments on commit cba526a

Please sign in to comment.