Skip to content

Commit

Permalink
Optimize AES/CBC cipher initialization
Browse files Browse the repository at this point in the history
The EVP cipher initialization cost has been found to be expensive in
the `OpenSSL 3.x` API compared to the `OpenSSL 1.x` API.

This update allows for two different types of initializations to occur.
The first initialization type is a full initialization which sets the key,
iv, and EVP cipher context. The second type of initialization sets just
the key and iv and does NOT recreate and reinitialize the EVP context.
The former of these two is required once per Cipher instance, the later
of these two can be used whenever we are reusing a specific
Java cipher object within methods such as `Cipher.doFinal()`.

Signed-off by: Jason Katonica <katonica@us.ibm.com>
  • Loading branch information
jasonkatonica committed Sep 7, 2023
1 parent a152046 commit ce08f73
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
*/
/*
* ===========================================================================
* (c) Copyright IBM Corp. 2018, 2022 All Rights Reserved
* (c) Copyright IBM Corp. 2018, 2023 All Rights Reserved
* ===========================================================================
*/

Expand Down Expand Up @@ -56,6 +56,7 @@ class NativeCipherBlockChaining extends FeedbackCipher {

private static final NativeCrypto nativeCrypto;
private static final Cleaner contextCleaner;
private int previousKeyLength = -1;

/*
* Initialize the CBC context.
Expand Down Expand Up @@ -184,7 +185,12 @@ void init(boolean decrypting, String algorithm, byte[] key, byte[] iv)

int ret;
synchronized (this) {
ret = nativeCrypto.CBCInit(nativeContext, mode, iv, iv.length, key, key.length);
if (previousKeyLength == key.length) {
ret = nativeCrypto.CBCInit(nativeContext, mode, iv, iv.length, key, key.length, true);
} else {
ret = nativeCrypto.CBCInit(nativeContext, mode, iv, iv.length, key, key.length, false);
previousKeyLength = key.length;
}
}
if (ret == -1) {
throw new ProviderException("Error in Native CipherBlockChaining");
Expand All @@ -201,7 +207,7 @@ void reset() {
System.arraycopy(iv, 0, r, 0, blockSize);
int ret;
synchronized (this) {
ret = nativeCrypto.CBCInit(nativeContext, mode, iv, iv.length, key, key.length);
ret = nativeCrypto.CBCInit(nativeContext, mode, iv, iv.length, key, key.length, true);
}
if (ret == -1) {
throw new ProviderException("Error in Native CipherBlockChaining");
Expand All @@ -225,7 +231,7 @@ void restore() {
System.arraycopy(rSave, 0, r, 0, blockSize);
int ret;
synchronized (this) {
ret = nativeCrypto.CBCInit(nativeContext, mode, r, r.length, key, key.length);
ret = nativeCrypto.CBCInit(nativeContext, mode, r, r.length, key, key.length, true);
}
if (ret == -1) {
throw new ProviderException("Error in Native CipherBlockChaining");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,8 @@ public final native int CBCInit(long context,
byte[] iv,
int ivlen,
byte[] key,
int keylen);
int keylen,
boolean doReset);

public final native int CBCUpdate(long context,
byte[] input,
Expand Down
32 changes: 18 additions & 14 deletions closed/src/java.base/share/native/libjncrypto/NativeCrypto.c
Original file line number Diff line number Diff line change
Expand Up @@ -1092,7 +1092,7 @@ JNIEXPORT jint JNICALL Java_jdk_crypto_jniprovider_NativeCrypto_DestroyContext
*/
JNIEXPORT jint JNICALL Java_jdk_crypto_jniprovider_NativeCrypto_CBCInit
(JNIEnv *env, jclass thisObj, jlong c, jint mode, jbyteArray iv, jint iv_len,
jbyteArray key, jint key_len) {
jbyteArray key, jint key_len, jboolean doReset) {

EVP_CIPHER_CTX *ctx = (EVP_CIPHER_CTX*)(intptr_t) c;
unsigned char* ivNative = NULL;
Expand All @@ -1103,18 +1103,20 @@ JNIEXPORT jint JNICALL Java_jdk_crypto_jniprovider_NativeCrypto_CBCInit
return -1;
}

switch(key_len) {
case 16:
evp_cipher1 = (*OSSL_aes_128_cbc)();
break;
case 24:
evp_cipher1 = (*OSSL_aes_192_cbc)();
break;
case 32:
evp_cipher1 = (*OSSL_aes_256_cbc)();
break;
default:
break;
if (JNI_FALSE == doReset) {
switch (key_len) {
case 16:
evp_cipher1 = (*OSSL_aes_128_cbc)();
break;
case 24:
evp_cipher1 = (*OSSL_aes_192_cbc)();
break;
case 32:
evp_cipher1 = (*OSSL_aes_256_cbc)();
break;
default:
break;
}
}

ivNative = (unsigned char*)((*env)->GetByteArrayElements(env, iv, 0));
Expand All @@ -1135,7 +1137,9 @@ JNIEXPORT jint JNICALL Java_jdk_crypto_jniprovider_NativeCrypto_CBCInit
return -1;
}

(*OSSL_CIPHER_CTX_set_padding)(ctx, 0);
if (JNI_FALSE == doReset) {
(*OSSL_CIPHER_CTX_set_padding)(ctx, 0);
}

(*env)->ReleaseByteArrayElements(env, iv, (jbyte*)ivNative, JNI_ABORT);
(*env)->ReleaseByteArrayElements(env, key, (jbyte*)keyNative, JNI_ABORT);
Expand Down

0 comments on commit ce08f73

Please sign in to comment.