diff --git a/closed/src/java.base/share/classes/com/sun/crypto/provider/NativeGaloisCounterMode.java b/closed/src/java.base/share/classes/com/sun/crypto/provider/NativeGaloisCounterMode.java index a4826ddc16..4d568995bf 100644 --- a/closed/src/java.base/share/classes/com/sun/crypto/provider/NativeGaloisCounterMode.java +++ b/closed/src/java.base/share/classes/com/sun/crypto/provider/NativeGaloisCounterMode.java @@ -24,20 +24,26 @@ */ /* * =========================================================================== - * (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 static com.sun.crypto.provider.AESConstants.AES_BLOCK_SIZE; import com.sun.crypto.provider.AESCrypt; +import static com.sun.crypto.provider.AESConstants.AES_BLOCK_SIZE; + +import java.io.ByteArrayOutputStream; +import java.lang.ref.Cleaner; +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 jdk.internal.ref.CleanerFactory; /** * This class represents ciphers in GaloisCounter (GCM) mode. @@ -54,9 +60,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 @@ -92,10 +100,34 @@ final class NativeGaloisCounterMode extends FeedbackCipher { private byte[] ibufferSave = null; private byte[] ibufferSave_enc = null; - 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 Cleaner contextCleaner = CleanerFactory.cleaner(); + + 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."); + } + } + } } private static void checkDataLength(int processed, int len) { @@ -111,6 +143,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."); + } + contextCleaner.register(this, new GCMCleanerRunnable(context)); } /** @@ -244,6 +282,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; } } @@ -354,18 +408,26 @@ int encryptFinal(byte[] in, int inOfs, int len, byte[] out, int outOfs) len = in.length; ibuffer_enc.reset(); - 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); } @@ -442,7 +504,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; @@ -456,11 +518,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, localTagLenBytes); + aad, aad.length, + localTagLenBytes, + newIVLen, + newKeyLen); } if (ret == -2) { throw new AEADBadTagException("Tag mismatch!"); @@ -468,6 +534,10 @@ 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; } diff --git a/closed/src/java.base/share/classes/jdk/crypto/jniprovider/NativeCrypto.java b/closed/src/java.base/share/classes/jdk/crypto/jniprovider/NativeCrypto.java index 176c5e6289..02e681f93c 100644 --- a/closed/src/java.base/share/classes/jdk/crypto/jniprovider/NativeCrypto.java +++ b/closed/src/java.base/share/classes/jdk/crypto/jniprovider/NativeCrypto.java @@ -220,7 +220,7 @@ public final native int DigestComputeAndReset(long context, public final native int DigestReset(long context); - /* Native interfaces shared by CBC and ChaCha20 */ + /* Native interfaces shared by CBC, ChaCha20 and GCM. */ public final native long CreateContext(); @@ -252,7 +252,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, @@ -263,9 +264,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, @@ -276,7 +280,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 */ diff --git a/closed/src/java.base/share/native/libjncrypto/NativeCrypto.c b/closed/src/java.base/share/native/libjncrypto/NativeCrypto.c index 470143feec..6bca26cab6 100644 --- a/closed/src/java.base/share/native/libjncrypto/NativeCrypto.c +++ b/closed/src/java.base/share/native/libjncrypto/NativeCrypto.c @@ -50,6 +50,11 @@ #define OPENSSL_VERSION_3_0_0 OPENSSL_VERSION_CODE(3, 0, 0, 0) #define OPENSSL_VERSION_4_0_0 OPENSSL_VERSION_CODE(4, 0, 0, 0) +/* OpenSSL operation modes. */ +#define OPENSSL_ENCRYPTION_MODE 1 +#define OPENSSL_DECRYPTION_MODE 0 +#define OPENSSL_SAME_MODE (-1) + /* needed for OpenSSL 1.0.2 Thread handling routines */ # define CRYPTO_LOCK 1 @@ -1307,61 +1312,33 @@ int first_time_gcm = 0; * * Class: jdk_crypto_jniprovider_NativeCrypto * Method: GCMEncrypt - * Signature: ([BI[BI[BII[BI[BII)I + * Signature: (J[BI[BI[BII[BI[BIIZZ)I */ JNIEXPORT jint JNICALL Java_jdk_crypto_jniprovider_NativeCrypto_GCMEncrypt - (JNIEnv * env, jclass obj, jbyteArray key, jint keyLen, jbyteArray iv, jint ivLen, + (JNIEnv * env, jclass obj, jlong context, jbyteArray key, jint keyLen, jbyteArray iv, jint ivLen, jbyteArray input, jint inOffset, jint inLen, jbyteArray output, jint outOffset, - jbyteArray aad, jint aadLen, jint tagLen) { - - unsigned char* inputNative = NULL; - int len = 0, len_cipher = 0; - unsigned char* keyNative = NULL; - unsigned char* ivNative = NULL; - unsigned char* outputNative = NULL; - unsigned char* aadNative = NULL; - - EVP_CIPHER_CTX* ctx = NULL; - const EVP_CIPHER* evp_gcm_cipher = NULL; - - keyNative = (unsigned char*)((*env)->GetPrimitiveArrayCritical(env, key, 0)); - if (NULL == keyNative) { - return -1; - } - - ivNative = (unsigned char*)((*env)->GetPrimitiveArrayCritical(env, iv, 0)); - if (NULL == ivNative) { - (*env)->ReleasePrimitiveArrayCritical(env, key, keyNative, JNI_ABORT); - return -1; - } + jbyteArray aad, jint aadLen, jint tagLen, jboolean newIVLen, jboolean newKeyLen) +{ + jint ret = -1; - aadNative = (unsigned char*)((*env)->GetPrimitiveArrayCritical(env, aad, 0)); - if (NULL == aadNative) { - (*env)->ReleasePrimitiveArrayCritical(env, key, keyNative, JNI_ABORT); - (*env)->ReleasePrimitiveArrayCritical(env, iv, ivNative, JNI_ABORT); - return -1; - } + int len = 0; + int len_cipher = 0; + unsigned char *keyNative = NULL; + unsigned char *ivNative = NULL; + unsigned char *inputNative = NULL; + unsigned char *outputNative = NULL; + unsigned char *aadNative = NULL; - outputNative = (unsigned char*)((*env)->GetPrimitiveArrayCritical(env, output, 0)); - if (NULL == outputNative) { - (*env)->ReleasePrimitiveArrayCritical(env, key, keyNative, JNI_ABORT); - (*env)->ReleasePrimitiveArrayCritical(env, iv, ivNative, JNI_ABORT); - (*env)->ReleasePrimitiveArrayCritical(env, aad, aadNative, JNI_ABORT); - return -1; - } + EVP_CIPHER_CTX *ctx = (EVP_CIPHER_CTX *)(intptr_t) context; + const EVP_CIPHER *evp_gcm_cipher = NULL; - if (inLen > 0) { - inputNative = (unsigned char*)((*env)->GetPrimitiveArrayCritical(env, input, 0)); - if (NULL == inputNative) { - (*env)->ReleasePrimitiveArrayCritical(env, key, keyNative, JNI_ABORT); - (*env)->ReleasePrimitiveArrayCritical(env, iv, ivNative, JNI_ABORT); - (*env)->ReleasePrimitiveArrayCritical(env, aad, aadNative, JNI_ABORT); - (*env)->ReleasePrimitiveArrayCritical(env, output, outputNative, JNI_ABORT); - return -1; - } + if (NULL == ctx) { + printErrors(); + goto cleanup; } - switch(keyLen) { + if (newKeyLen) { + switch (keyLen) { case 16: evp_gcm_cipher = (*OSSL_aes_128_gcm)(); break; @@ -1373,196 +1350,133 @@ JNIEXPORT jint JNICALL Java_jdk_crypto_jniprovider_NativeCrypto_GCMEncrypt break; default: break; - } + } - ctx = (*OSSL_CIPHER_CTX_new)(); - if (NULL == ctx) { - printErrors(); - (*env)->ReleasePrimitiveArrayCritical(env, key, keyNative, JNI_ABORT); - (*env)->ReleasePrimitiveArrayCritical(env, iv, ivNative, JNI_ABORT); - (*env)->ReleasePrimitiveArrayCritical(env, aad, aadNative, JNI_ABORT); - (*env)->ReleasePrimitiveArrayCritical(env, output, outputNative, JNI_ABORT); - if (inLen > 0) { - (*env)->ReleasePrimitiveArrayCritical(env, input, inputNative, JNI_ABORT); + if (1 != (*OSSL_CipherInit_ex)(ctx, evp_gcm_cipher, NULL, NULL, NULL, OPENSSL_SAME_MODE)) { + printErrors(); + goto cleanup; } - return -1; } - if (1 != (*OSSL_CipherInit_ex)(ctx, evp_gcm_cipher, NULL, NULL, NULL, 1 )) { /* 1 - Encrypt mode 0 Decrypt Mode*/ - printErrors(); - (*OSSL_CIPHER_CTX_free)(ctx); - (*env)->ReleasePrimitiveArrayCritical(env, key, keyNative, JNI_ABORT); - (*env)->ReleasePrimitiveArrayCritical(env, iv, ivNative, JNI_ABORT); - (*env)->ReleasePrimitiveArrayCritical(env, aad, aadNative, JNI_ABORT); - (*env)->ReleasePrimitiveArrayCritical(env, output, outputNative, JNI_ABORT); - if (inLen > 0) { - (*env)->ReleasePrimitiveArrayCritical(env, input, inputNative, JNI_ABORT); + if (newIVLen) { + if (1 != (*OSSL_CIPHER_CTX_ctrl)(ctx, EVP_CTRL_GCM_SET_IVLEN, ivLen, NULL)) { + printErrors(); + goto cleanup; } - return -1; } - if (1 != (*OSSL_CIPHER_CTX_ctrl)(ctx, EVP_CTRL_GCM_SET_IVLEN, ivLen, NULL)) { - printErrors(); - (*OSSL_CIPHER_CTX_free)(ctx); - (*env)->ReleasePrimitiveArrayCritical(env, key, keyNative, JNI_ABORT); - (*env)->ReleasePrimitiveArrayCritical(env, iv, ivNative, JNI_ABORT); - (*env)->ReleasePrimitiveArrayCritical(env, aad, aadNative, JNI_ABORT); - (*env)->ReleasePrimitiveArrayCritical(env, output, outputNative, JNI_ABORT); - if (inLen > 0) { - (*env)->ReleasePrimitiveArrayCritical(env, input, inputNative, JNI_ABORT); - } - return -1; + /* Initialize context with key and IV. */ + keyNative = (unsigned char *)((*env)->GetPrimitiveArrayCritical(env, key, 0)); + if (NULL == keyNative) { + goto cleanup; } - if (1 != (*OSSL_CipherInit_ex)(ctx, NULL, NULL, keyNative, ivNative, -1)) { + ivNative = (unsigned char *)((*env)->GetPrimitiveArrayCritical(env, iv, 0)); + if (NULL == ivNative) { + goto cleanup; + } + + if (1 != (*OSSL_CipherInit_ex)(ctx, NULL, NULL, keyNative, ivNative, OPENSSL_ENCRYPTION_MODE)) { printErrors(); - (*OSSL_CIPHER_CTX_free)(ctx); - (*env)->ReleasePrimitiveArrayCritical(env, key, keyNative, JNI_ABORT); - (*env)->ReleasePrimitiveArrayCritical(env, iv, ivNative, JNI_ABORT); - (*env)->ReleasePrimitiveArrayCritical(env, aad, aadNative, JNI_ABORT); - (*env)->ReleasePrimitiveArrayCritical(env, output, outputNative, JNI_ABORT); - if (inLen > 0) { - (*env)->ReleasePrimitiveArrayCritical(env, input, inputNative, JNI_ABORT); - } - return -1; + goto cleanup; + } + + /* Provide AAD. */ + aadNative = (unsigned char *)((*env)->GetPrimitiveArrayCritical(env, aad, 0)); + if (NULL == aadNative) { + goto cleanup; } - /* provide AAD */ if (1 != (*OSSL_CipherUpdate)(ctx, NULL, &len, aadNative, aadLen)) { printErrors(); - (*OSSL_CIPHER_CTX_free)(ctx); - (*env)->ReleasePrimitiveArrayCritical(env, key, keyNative, JNI_ABORT); - (*env)->ReleasePrimitiveArrayCritical(env, iv, ivNative, JNI_ABORT); - (*env)->ReleasePrimitiveArrayCritical(env, aad, aadNative, JNI_ABORT); - (*env)->ReleasePrimitiveArrayCritical(env, output, outputNative, JNI_ABORT); - if (inLen > 0) { - (*env)->ReleasePrimitiveArrayCritical(env, input, inputNative, JNI_ABORT); - } - return -1; + goto cleanup; } - /* encrypt plaintext and obtain ciphertext */ + outputNative = (unsigned char *)((*env)->GetPrimitiveArrayCritical(env, output, 0)); + if (NULL == outputNative) { + goto cleanup; + } + + /* Encrypt plaintext, if available and obtain ciphertext. */ if (inLen > 0) { + inputNative = (unsigned char *)((*env)->GetPrimitiveArrayCritical(env, input, 0)); + if (NULL == inputNative) { + goto cleanup; + } + if (1 != (*OSSL_CipherUpdate)(ctx, outputNative + outOffset, &len, inputNative + inOffset, inLen)) { printErrors(); - (*OSSL_CIPHER_CTX_free)(ctx); - (*env)->ReleasePrimitiveArrayCritical(env, key, keyNative, JNI_ABORT); - (*env)->ReleasePrimitiveArrayCritical(env, iv, ivNative, JNI_ABORT); - (*env)->ReleasePrimitiveArrayCritical(env, aad, aadNative, JNI_ABORT); - (*env)->ReleasePrimitiveArrayCritical(env, output, outputNative, JNI_ABORT); - if (inLen > 0) { - (*env)->ReleasePrimitiveArrayCritical(env, input, inputNative, JNI_ABORT); - } - return -1; + goto cleanup; } len_cipher = len; } - /* finalize the encryption */ + /* Finalize the encryption. */ if (1 != (*OSSL_CipherFinal_ex)(ctx, outputNative + outOffset + len_cipher, &len)) { printErrors(); - (*OSSL_CIPHER_CTX_free)(ctx); - (*env)->ReleasePrimitiveArrayCritical(env, key, keyNative, JNI_ABORT); - (*env)->ReleasePrimitiveArrayCritical(env, iv, ivNative, JNI_ABORT); - (*env)->ReleasePrimitiveArrayCritical(env, aad, aadNative, JNI_ABORT); - (*env)->ReleasePrimitiveArrayCritical(env, output, outputNative, JNI_ABORT); - if (inLen > 0) { - (*env)->ReleasePrimitiveArrayCritical(env, input, inputNative, JNI_ABORT); - } - return -1; + goto cleanup; } + len_cipher += len; - /* Get the tag, place it at the end of the cipherText buffer */ - if (1 != (*OSSL_CIPHER_CTX_ctrl)(ctx, EVP_CTRL_GCM_GET_TAG, tagLen, outputNative + outOffset + len + len_cipher)) { + /* Get the tag, place it at the end of the cipherText buffer. */ + if (1 != (*OSSL_CIPHER_CTX_ctrl)(ctx, EVP_CTRL_GCM_GET_TAG, tagLen, outputNative + outOffset + len_cipher)) { printErrors(); - (*OSSL_CIPHER_CTX_free)(ctx); - (*env)->ReleasePrimitiveArrayCritical(env, key, keyNative, JNI_ABORT); - (*env)->ReleasePrimitiveArrayCritical(env, iv, ivNative, JNI_ABORT); - (*env)->ReleasePrimitiveArrayCritical(env, aad, aadNative, JNI_ABORT); - (*env)->ReleasePrimitiveArrayCritical(env, output, outputNative, JNI_ABORT); - if (inLen > 0) { - (*env)->ReleasePrimitiveArrayCritical(env, input, inputNative, JNI_ABORT); - } - return -1; + goto cleanup; } - (*OSSL_CIPHER_CTX_free)(ctx); + ret = (jint)len_cipher; - (*env)->ReleasePrimitiveArrayCritical(env, key, keyNative, JNI_ABORT); - (*env)->ReleasePrimitiveArrayCritical(env, iv, ivNative, JNI_ABORT); - (*env)->ReleasePrimitiveArrayCritical(env, output, outputNative, 0); - - if (inLen > 0) { +cleanup: + if (NULL != inputNative) { (*env)->ReleasePrimitiveArrayCritical(env, input, inputNative, JNI_ABORT); } + if (NULL != outputNative) { + (*env)->ReleasePrimitiveArrayCritical(env, output, outputNative, 0); + } + if (NULL != aadNative) { + (*env)->ReleasePrimitiveArrayCritical(env, aad, aadNative, JNI_ABORT); + } + if (NULL != ivNative) { + (*env)->ReleasePrimitiveArrayCritical(env, iv, ivNative, JNI_ABORT); + } + if (NULL != keyNative) { + (*env)->ReleasePrimitiveArrayCritical(env, key, keyNative, JNI_ABORT); + } - (*env)->ReleasePrimitiveArrayCritical(env, aad, aadNative, JNI_ABORT); - - return (jint)len_cipher; + return ret; } /* GCM Decryption * * Class: jdk_crypto_jniprovider_NativeCrypto * Method: GCMDecrypt - * Signature: ([BI[BI[BII[BI[BII)I + * Signature: (J[BI[BI[BII[BI[BIIZZ)I */ JNIEXPORT jint JNICALL Java_jdk_crypto_jniprovider_NativeCrypto_GCMDecrypt - (JNIEnv * env, jclass obj, jbyteArray key, jint keyLen, jbyteArray iv, jint ivLen, + (JNIEnv * env, jclass obj, jlong context, jbyteArray key, jint keyLen, jbyteArray iv, jint ivLen, jbyteArray input, jint inOffset, jint inLen, jbyteArray output, jint outOffset, - jbyteArray aad, jint aadLen, jint tagLen) { - - unsigned char* inputNative = NULL; - unsigned char* aadNative = NULL; - int ret = 0, len = 0, plaintext_len = 0; - unsigned char* keyNative = NULL; - unsigned char* ivNative = NULL; - unsigned char* outputNative = NULL; - EVP_CIPHER_CTX* ctx = NULL; - const EVP_CIPHER* evp_gcm_cipher = NULL; - - keyNative = (unsigned char*)((*env)->GetPrimitiveArrayCritical(env, key, 0)); - if (NULL == keyNative) { - return -1; - } - - ivNative = (unsigned char*)((*env)->GetPrimitiveArrayCritical(env, iv, 0)); - if (NULL == ivNative) { - (*env)->ReleasePrimitiveArrayCritical(env, key, keyNative, JNI_ABORT); - return -1; - } + jbyteArray aad, jint aadLen, jint tagLen, jboolean newIVLen, jboolean newKeyLen) +{ + jint ret = -1; - outputNative = (unsigned char*)((*env)->GetPrimitiveArrayCritical(env, output, 0)); - if (NULL == outputNative) { - (*env)->ReleasePrimitiveArrayCritical(env, key, keyNative, JNI_ABORT); - (*env)->ReleasePrimitiveArrayCritical(env, iv, ivNative, JNI_ABORT); - return -1; - } + int len = 0; + int plaintext_len = 0; + unsigned char *keyNative = NULL; + unsigned char *ivNative = NULL; + unsigned char *aadNative = NULL; + unsigned char *inputNative = NULL; + unsigned char *outputNative = NULL; - if (inLen > 0) { - inputNative = (unsigned char*)((*env)->GetPrimitiveArrayCritical(env, input, 0)); - if (NULL == inputNative) { - (*env)->ReleasePrimitiveArrayCritical(env, key, keyNative, JNI_ABORT); - (*env)->ReleasePrimitiveArrayCritical(env, iv, ivNative, JNI_ABORT); - (*env)->ReleasePrimitiveArrayCritical(env, output, outputNative, JNI_ABORT); - return -1; - } - } + EVP_CIPHER_CTX *ctx = (EVP_CIPHER_CTX *)(intptr_t) context; + const EVP_CIPHER *evp_gcm_cipher = NULL; - if (aadLen > 0) { - aadNative = (unsigned char*)((*env)->GetPrimitiveArrayCritical(env, aad, 0)); - if (NULL == aadNative) { - (*env)->ReleasePrimitiveArrayCritical(env, key, keyNative, JNI_ABORT); - (*env)->ReleasePrimitiveArrayCritical(env, iv, ivNative, JNI_ABORT); - (*env)->ReleasePrimitiveArrayCritical(env, output, outputNative, JNI_ABORT); - if (inLen > 0) { - (*env)->ReleasePrimitiveArrayCritical(env, input, inputNative, JNI_ABORT); - } - return -1; - } + if (NULL == ctx) { + printErrors(); + goto cleanup; } - switch(keyLen) { + if (newKeyLen) { + switch (keyLen) { case 16: evp_gcm_cipher = (*OSSL_aes_128_gcm)(); break; @@ -1574,131 +1488,102 @@ JNIEXPORT jint JNICALL Java_jdk_crypto_jniprovider_NativeCrypto_GCMDecrypt break; default: break; - } - - ctx = (*OSSL_CIPHER_CTX_new)(); - - if (1 != (*OSSL_CipherInit_ex)(ctx, evp_gcm_cipher, NULL, NULL, NULL, 0 )) { /* 1 - Encrypt mode 0 Decrypt Mode*/ - printErrors(); - (*OSSL_CIPHER_CTX_free)(ctx); - (*env)->ReleasePrimitiveArrayCritical(env, key, keyNative, JNI_ABORT); - (*env)->ReleasePrimitiveArrayCritical(env, iv, ivNative, JNI_ABORT); - (*env)->ReleasePrimitiveArrayCritical(env, output, outputNative, JNI_ABORT); - if (inLen > 0) { - (*env)->ReleasePrimitiveArrayCritical(env, input, inputNative, JNI_ABORT); } - if (aadLen > 0) { - (*env)->ReleasePrimitiveArrayCritical(env, aad, aadNative, JNI_ABORT); + + if (1 != (*OSSL_CipherInit_ex)(ctx, evp_gcm_cipher, NULL, NULL, NULL, OPENSSL_DECRYPTION_MODE)) { + printErrors(); + goto cleanup; } - return -1; } - if (1 != (*OSSL_CIPHER_CTX_ctrl)(ctx, EVP_CTRL_GCM_SET_IVLEN, ivLen, NULL)) { - printErrors(); - (*OSSL_CIPHER_CTX_free)(ctx); - (*env)->ReleasePrimitiveArrayCritical(env, key, keyNative, JNI_ABORT); - (*env)->ReleasePrimitiveArrayCritical(env, iv, ivNative, JNI_ABORT); - (*env)->ReleasePrimitiveArrayCritical(env, output, outputNative, JNI_ABORT); - if (inLen > 0) { - (*env)->ReleasePrimitiveArrayCritical(env, input, inputNative, JNI_ABORT); - } - if (aadLen > 0) { - (*env)->ReleasePrimitiveArrayCritical(env, aad, aadNative, JNI_ABORT); + if (newIVLen) { + if (1 != (*OSSL_CIPHER_CTX_ctrl)(ctx, EVP_CTRL_GCM_SET_IVLEN, ivLen, NULL)) { + printErrors(); + goto cleanup; } - return -1; } - /* Initialise key and IV */ + /* Initialise context with key and IV. */ + keyNative = (unsigned char *)((*env)->GetPrimitiveArrayCritical(env, key, 0)); + if (NULL == keyNative) { + goto cleanup; + } + + ivNative = (unsigned char *)((*env)->GetPrimitiveArrayCritical(env, iv, 0)); + if (NULL == ivNative) { + goto cleanup; + } + if (0 == (*OSSL_DecryptInit_ex)(ctx, NULL, NULL, keyNative, ivNative)) { printErrors(); - (*OSSL_CIPHER_CTX_free)(ctx); - (*env)->ReleasePrimitiveArrayCritical(env, key, keyNative, JNI_ABORT); - (*env)->ReleasePrimitiveArrayCritical(env, iv, ivNative, JNI_ABORT); - (*env)->ReleasePrimitiveArrayCritical(env, output, outputNative, JNI_ABORT); - if (inLen > 0) { - (*env)->ReleasePrimitiveArrayCritical(env, input, inputNative, JNI_ABORT); - } - if (aadLen > 0) { - (*env)->ReleasePrimitiveArrayCritical(env, aad, aadNative, JNI_ABORT); - } - return -1; + goto cleanup; } - /* Provide any AAD data */ + /* Provide any AAD data. */ if (aadLen > 0) { + aadNative = (unsigned char *)((*env)->GetPrimitiveArrayCritical(env, aad, 0)); + if (NULL == aadNative) { + goto cleanup; + } + if (0 == (*OSSL_DecryptUpdate)(ctx, NULL, &len, aadNative, aadLen)) { printErrors(); - (*OSSL_CIPHER_CTX_free)(ctx); - (*env)->ReleasePrimitiveArrayCritical(env, key, keyNative, JNI_ABORT); - (*env)->ReleasePrimitiveArrayCritical(env, iv, ivNative, JNI_ABORT); - (*env)->ReleasePrimitiveArrayCritical(env, output, outputNative, JNI_ABORT); - if (inLen > 0) { - (*env)->ReleasePrimitiveArrayCritical(env, input, inputNative, JNI_ABORT); - } - if (aadLen > 0) { - (*env)->ReleasePrimitiveArrayCritical(env, aad, aadNative, JNI_ABORT); - } - return -1; + goto cleanup; + } + } + + outputNative = (unsigned char *)((*env)->GetPrimitiveArrayCritical(env, output, 0)); + if (NULL == outputNative) { + goto cleanup; + } + + if (inLen > 0) { + inputNative = (unsigned char *)((*env)->GetPrimitiveArrayCritical(env, input, 0)); + if (NULL == inputNative) { + goto cleanup; } } if (inLen - tagLen > 0) { if(0 == (*OSSL_DecryptUpdate)(ctx, outputNative + outOffset, &len, inputNative + inOffset, inLen - tagLen)) { printErrors(); - (*OSSL_CIPHER_CTX_free)(ctx); - (*env)->ReleasePrimitiveArrayCritical(env, key, keyNative, JNI_ABORT); - (*env)->ReleasePrimitiveArrayCritical(env, iv, ivNative, JNI_ABORT); - (*env)->ReleasePrimitiveArrayCritical(env, output, outputNative, JNI_ABORT); - if (inLen > 0) { - (*env)->ReleasePrimitiveArrayCritical(env, input, inputNative, JNI_ABORT); - } - if (aadLen > 0) { - (*env)->ReleasePrimitiveArrayCritical(env, aad, aadNative, JNI_ABORT); - } - return -1; + goto cleanup; } plaintext_len = len; } if (0 == (*OSSL_CIPHER_CTX_ctrl)(ctx, EVP_CTRL_GCM_SET_TAG, tagLen, inputNative + inOffset + inLen - tagLen)) { printErrors(); - (*OSSL_CIPHER_CTX_free)(ctx); - (*env)->ReleasePrimitiveArrayCritical(env, key, keyNative, JNI_ABORT); - (*env)->ReleasePrimitiveArrayCritical(env, iv, ivNative, JNI_ABORT); - (*env)->ReleasePrimitiveArrayCritical(env, output, outputNative, JNI_ABORT); - if (inLen > 0) { - (*env)->ReleasePrimitiveArrayCritical(env, input, inputNative, JNI_ABORT); - } - if (aadLen > 0) { - (*env)->ReleasePrimitiveArrayCritical(env, aad, aadNative, JNI_ABORT); - } - return -1; + goto cleanup; } - ret = (*OSSL_DecryptFinal)(ctx, outputNative + outOffset + len, &len); - - (*OSSL_CIPHER_CTX_free)(ctx); - - (*env)->ReleasePrimitiveArrayCritical(env, key, keyNative, JNI_ABORT); - (*env)->ReleasePrimitiveArrayCritical(env, iv, ivNative, JNI_ABORT); - (*env)->ReleasePrimitiveArrayCritical(env, output, outputNative, 0); + if (0 < (*OSSL_DecryptFinal)(ctx, outputNative + outOffset + len, &len)) { + /* Decryption was successful. */ + plaintext_len += len; + ret = (jint)plaintext_len; + } else { + /* There was a tag mismatch. */ + ret = -2; + } - if (inLen > 0) { +cleanup: + if (NULL != inputNative) { (*env)->ReleasePrimitiveArrayCritical(env, input, inputNative, JNI_ABORT); } - - if (aadLen > 0) { + if (NULL != outputNative) { + (*env)->ReleasePrimitiveArrayCritical(env, output, outputNative, 0); + } + if (NULL != aadNative) { (*env)->ReleasePrimitiveArrayCritical(env, aad, aadNative, JNI_ABORT); } - - if (ret > 0) { - /* Successful Decryption */ - plaintext_len += len; - return (jint)plaintext_len; - } else { - /* Tag Mismatch */ - return -2; + if (NULL != ivNative) { + (*env)->ReleasePrimitiveArrayCritical(env, iv, ivNative, JNI_ABORT); } + if (NULL != keyNative) { + (*env)->ReleasePrimitiveArrayCritical(env, key, keyNative, JNI_ABORT); + } + + return ret; } BIGNUM* convertJavaBItoBN(unsigned char* in, int len); @@ -2214,13 +2099,13 @@ JNIEXPORT jint JNICALL Java_jdk_crypto_jniprovider_NativeCrypto_ChaCha20Init unsigned char *ivNative = NULL; unsigned char *keyNative = NULL; const EVP_CIPHER *evp_cipher1 = NULL; - int encrypt = -1; + int encrypt = OPENSSL_SAME_MODE; if (NULL == ctx) { return -1; } - if ((0 == mode) || (1 == mode)) { + if ((OPENSSL_DECRYPTION_MODE == mode) || (OPENSSL_ENCRYPTION_MODE == mode)) { /* Use the existing evp_cipher? */ if (JNI_FALSE == doReset) { evp_cipher1 = (*OSSL_chacha20_poly1305)(); @@ -2232,7 +2117,7 @@ JNIEXPORT jint JNICALL Java_jdk_crypto_jniprovider_NativeCrypto_ChaCha20Init evp_cipher1 = (*OSSL_chacha20)(); } /* encrypt or decrypt does not matter */ - encrypt = 1; + encrypt = OPENSSL_ENCRYPTION_MODE; } else { return -1; }