JNIEXPORT jint JNICALL Java_com_amazon_corretto_crypto_provider_AesGcmSpi_oneShotDecrypt()

in csrc/aes_gcm.cpp [352:425]


JNIEXPORT jint JNICALL Java_com_amazon_corretto_crypto_provider_AesGcmSpi_oneShotDecrypt(
    JNIEnv *pEnv,
    jclass,
    jlong ctxPtr,
    jlongArray ctxOut,
    jbyteArray inputArray,
    jint inoffset,
    jint inlen,
    jbyteArray resultArray,
    jint resultOffset,
    jint tagLen,
    jbyteArray keyArray,
    jbyteArray ivArray,
    jbyteArray aadBuffer,
    jint aadSize
) {
    try {
        raii_env env(pEnv);

        java_buffer input = java_buffer::from_array(env, inputArray, inoffset, inlen);
        java_buffer result = java_buffer::from_array(env, resultArray, resultOffset);
        java_buffer iv = java_buffer::from_array(env, ivArray);

        raii_cipher_ctx ctx;
        if (ctxPtr) {
            ctx.borrow(reinterpret_cast<EVP_CIPHER_CTX *>(ctxPtr));

            jni_borrow ivBorrow(env, iv, "iv");
            if (unlikely(!EVP_CipherInit_ex(ctx, NULL, NULL, NULL, ivBorrow.data(), NATIVE_MODE_DECRYPT))) {
                throw java_ex::from_openssl(EX_RUNTIME_CRYPTO, "Failed to set IV");
            }
        } else {
            ctx.init();
            EVP_CIPHER_CTX_init(ctx);
            java_buffer key = java_buffer::from_array(env, keyArray);
            initContext(env, ctx, NATIVE_MODE_DECRYPT, key, iv);
        }

        // Decrypt mode: Set the tag before we decrypt
        if (unlikely(tagLen > 16 || tagLen < 0)) {
            throw java_ex(EX_ILLEGAL_ARGUMENT, "Bad tag length");
        }

        if (unlikely(inlen < tagLen)) {
            throw java_ex(EX_BADTAG, "Input too short - need tag");
        }

        SecureBuffer<uint8_t, 16> tag;
        input.get_bytes(env, tag.buf, input.len() - tagLen, tagLen);

        if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, tagLen, tag.buf)) {
            throw java_ex::from_openssl(EX_RUNTIME_CRYPTO, "Failed to set GCM tag");
        }
        input = input.subrange(0, input.len() - tagLen);

        if (aadSize != 0) {
            updateAAD_loop(env, ctx, java_buffer::from_array(env, aadBuffer, 0, aadSize));
        }

        int outoffset = updateLoop(env, result, input, ctx);
        outoffset += cryptFinish(env, NATIVE_MODE_DECRYPT, result.subrange(outoffset), tagLen, ctx);

        if (!ctxPtr && ctxOut) {
            // Context is new, but caller does want it back
            jlong tmpPtr = reinterpret_cast<jlong>(ctx.take());
            env->SetLongArrayRegion(ctxOut, 0, 1, &tmpPtr);
        }

        return outoffset;
    } catch (java_ex &ex) {
        ex.throw_to_java(pEnv);
        return -1;
    }
}