Skip to content

Commit 0065372

Browse files
committed
Optimize AES/CBC cipher initialization
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 <[email protected]>
1 parent 31de43f commit 0065372

File tree

3 files changed

+30
-19
lines changed

3 files changed

+30
-19
lines changed

closed/src/java.base/share/classes/com/sun/crypto/provider/NativeCipherBlockChaining.java

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
*/
2525
/*
2626
* ===========================================================================
27-
* (c) Copyright IBM Corp. 2018, 2022 All Rights Reserved
27+
* (c) Copyright IBM Corp. 2018, 2023 All Rights Reserved
2828
* ===========================================================================
2929
*/
3030

@@ -56,6 +56,7 @@ class NativeCipherBlockChaining extends FeedbackCipher {
5656

5757
private static final NativeCrypto nativeCrypto;
5858
private static final Cleaner contextCleaner;
59+
private int previousKeyLength = -1;
5960

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

185186
int ret;
186187
synchronized (this) {
187-
ret = nativeCrypto.CBCInit(nativeContext, mode, iv, iv.length, key, key.length);
188+
if (previousKeyLength == key.length) {
189+
ret = nativeCrypto.CBCInit(nativeContext, mode, iv, iv.length, key, key.length, true);
190+
} else {
191+
ret = nativeCrypto.CBCInit(nativeContext, mode, iv, iv.length, key, key.length, false);
192+
previousKeyLength = key.length;
193+
}
188194
}
189195
if (ret == -1) {
190196
throw new ProviderException("Error in Native CipherBlockChaining");
@@ -201,7 +207,7 @@ void reset() {
201207
System.arraycopy(iv, 0, r, 0, blockSize);
202208
int ret;
203209
synchronized (this) {
204-
ret = nativeCrypto.CBCInit(nativeContext, mode, iv, iv.length, key, key.length);
210+
ret = nativeCrypto.CBCInit(nativeContext, mode, iv, iv.length, key, key.length, true);
205211
}
206212
if (ret == -1) {
207213
throw new ProviderException("Error in Native CipherBlockChaining");
@@ -225,7 +231,7 @@ void restore() {
225231
System.arraycopy(rSave, 0, r, 0, blockSize);
226232
int ret;
227233
synchronized (this) {
228-
ret = nativeCrypto.CBCInit(nativeContext, mode, r, r.length, key, key.length);
234+
ret = nativeCrypto.CBCInit(nativeContext, mode, r, r.length, key, key.length, true);
229235
}
230236
if (ret == -1) {
231237
throw new ProviderException("Error in Native CipherBlockChaining");

closed/src/java.base/share/classes/jdk/crypto/jniprovider/NativeCrypto.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,8 @@ public final native int CBCInit(long context,
233233
byte[] iv,
234234
int ivlen,
235235
byte[] key,
236-
int keylen);
236+
int keylen,
237+
boolean doReset);
237238

238239
public final native int CBCUpdate(long context,
239240
byte[] input,

closed/src/java.base/share/native/libjncrypto/NativeCrypto.c

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1097,7 +1097,7 @@ JNIEXPORT jint JNICALL Java_jdk_crypto_jniprovider_NativeCrypto_DestroyContext
10971097
*/
10981098
JNIEXPORT jint JNICALL Java_jdk_crypto_jniprovider_NativeCrypto_CBCInit
10991099
(JNIEnv *env, jclass thisObj, jlong c, jint mode, jbyteArray iv, jint iv_len,
1100-
jbyteArray key, jint key_len)
1100+
jbyteArray key, jint key_len, jboolean doReset)
11011101
{
11021102
EVP_CIPHER_CTX *ctx = (EVP_CIPHER_CTX*)(intptr_t) c;
11031103
unsigned char* ivNative = NULL;
@@ -1108,18 +1108,20 @@ JNIEXPORT jint JNICALL Java_jdk_crypto_jniprovider_NativeCrypto_CBCInit
11081108
return -1;
11091109
}
11101110

1111-
switch(key_len) {
1112-
case 16:
1113-
evp_cipher1 = (*OSSL_aes_128_cbc)();
1114-
break;
1115-
case 24:
1116-
evp_cipher1 = (*OSSL_aes_192_cbc)();
1117-
break;
1118-
case 32:
1119-
evp_cipher1 = (*OSSL_aes_256_cbc)();
1120-
break;
1121-
default:
1122-
break;
1111+
if (JNI_FALSE == doReset) {
1112+
switch (key_len) {
1113+
case 16:
1114+
evp_cipher1 = (*OSSL_aes_128_cbc)();
1115+
break;
1116+
case 24:
1117+
evp_cipher1 = (*OSSL_aes_192_cbc)();
1118+
break;
1119+
case 32:
1120+
evp_cipher1 = (*OSSL_aes_256_cbc)();
1121+
break;
1122+
default:
1123+
break;
1124+
}
11231125
}
11241126

11251127
ivNative = (unsigned char*)((*env)->GetByteArrayElements(env, iv, 0));
@@ -1140,7 +1142,9 @@ JNIEXPORT jint JNICALL Java_jdk_crypto_jniprovider_NativeCrypto_CBCInit
11401142
return -1;
11411143
}
11421144

1143-
(*OSSL_CIPHER_CTX_set_padding)(ctx, 0);
1145+
if (JNI_FALSE == doReset) {
1146+
(*OSSL_CIPHER_CTX_set_padding)(ctx, 0);
1147+
}
11441148

11451149
(*env)->ReleaseByteArrayElements(env, iv, (jbyte*)ivNative, JNI_ABORT);
11461150
(*env)->ReleaseByteArrayElements(env, key, (jbyte*)keyNative, JNI_ABORT);

0 commit comments

Comments
 (0)