444 lines
13 KiB
C
444 lines
13 KiB
C
/* jni_aescmac.c
|
|
*
|
|
* Copyright (C) 2006-2026 wolfSSL Inc.
|
|
*
|
|
* This file is part of wolfSSL.
|
|
*
|
|
* wolfSSL is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* wolfSSL is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
|
|
*/
|
|
|
|
#include <stdint.h>
|
|
|
|
#ifdef WOLFSSL_USER_SETTINGS
|
|
#include <wolfssl/wolfcrypt/settings.h>
|
|
#elif !defined(__ANDROID__)
|
|
#include <wolfssl/options.h>
|
|
#endif
|
|
#include <wolfssl/version.h>
|
|
#include <wolfssl/wolfcrypt/cmac.h>
|
|
#include <wolfssl/wolfcrypt/memory.h>
|
|
|
|
#include <com_wolfssl_wolfcrypt_AesCmac.h>
|
|
#include <wolfcrypt_jni_NativeStruct.h>
|
|
#include <wolfcrypt_jni_error.h>
|
|
|
|
/* #define WOLFCRYPT_JNI_DEBUG_ON */
|
|
#include <wolfcrypt_jni_debug.h>
|
|
|
|
#if (LIBWOLFSSL_VERSION_HEX >= 0x05006006) && (!defined(HAVE_FIPS) || \
|
|
(defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION >= 6)))
|
|
#define WC_JNI_CMAC_HAVE_FREE
|
|
#endif
|
|
|
|
JNIEXPORT jlong JNICALL Java_com_wolfssl_wolfcrypt_AesCmac_mallocNativeStruct_1internal(
|
|
JNIEnv* env, jobject this)
|
|
{
|
|
#ifdef WOLFSSL_CMAC
|
|
Cmac* cmac = NULL;
|
|
|
|
cmac = (Cmac*)XMALLOC(sizeof(Cmac), NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
if (cmac == NULL) {
|
|
throwOutOfMemoryException(env, "Failed to allocate Cmac object");
|
|
return (jlong)0;
|
|
}
|
|
|
|
/* Initialize the CMAC structure to a known clean state */
|
|
XMEMSET(cmac, 0, sizeof(Cmac));
|
|
|
|
LogStr("new Cmac() = %p\n", cmac);
|
|
|
|
return (jlong)(uintptr_t)cmac;
|
|
#else
|
|
throwNotCompiledInException(env);
|
|
return (jlong)0;
|
|
#endif
|
|
}
|
|
|
|
JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_AesCmac_native_1init(
|
|
JNIEnv* env, jobject this)
|
|
{
|
|
#ifdef WOLFSSL_CMAC
|
|
Cmac* cmac = (Cmac*) getNativeStruct(env, this);
|
|
if ((*env)->ExceptionOccurred(env)) {
|
|
/* getNativeStruct may throw exception, prevent throwing another */
|
|
return;
|
|
}
|
|
|
|
/* CMAC struct is already zero-initialized in mallocNativeStruct_internal */
|
|
/* Actual initialization happens in wc_CmacSetKey when we have the key */
|
|
|
|
LogStr("native_init(cmac=%p)\n", cmac);
|
|
(void)cmac; /* suppress unused variable warning */
|
|
#else
|
|
throwNotCompiledInException(env);
|
|
#endif
|
|
}
|
|
|
|
JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_AesCmac_native_1free(
|
|
JNIEnv* env, jobject this)
|
|
{
|
|
#ifdef WOLFSSL_CMAC
|
|
Cmac* cmac = (Cmac*) getNativeStruct(env, this);
|
|
if ((*env)->ExceptionOccurred(env)) {
|
|
/* getNativeStruct may throw exception, prevent throwing another */
|
|
return;
|
|
}
|
|
|
|
LogStr("free Cmac %p\n", cmac);
|
|
|
|
if (cmac) {
|
|
/* Release and zeroize CMAC context contents, not freeing the
|
|
* memory since base class NativeStruct.xfree() will handle that
|
|
* deallocation. */
|
|
#ifdef WC_JNI_CMAC_HAVE_FREE
|
|
if (cmac->type == WC_CMAC_AES) {
|
|
wc_CmacFree(cmac);
|
|
}
|
|
else {
|
|
XMEMSET(cmac, 0, sizeof(Cmac));
|
|
}
|
|
#else
|
|
XMEMSET(cmac, 0, sizeof(Cmac));
|
|
#endif
|
|
}
|
|
#else
|
|
throwNotCompiledInException(env);
|
|
#endif
|
|
}
|
|
|
|
JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_AesCmac_wc_1CmacSetKey(
|
|
JNIEnv* env, jobject this, jbyteArray key_object)
|
|
{
|
|
#ifdef WOLFSSL_CMAC
|
|
int ret = 0;
|
|
Cmac* cmac = NULL;
|
|
byte* key = NULL;
|
|
word32 keySz = 0;
|
|
jboolean keyIsCopy = JNI_FALSE;
|
|
|
|
cmac = (Cmac*) getNativeStruct(env, this);
|
|
if ((*env)->ExceptionOccurred(env)) {
|
|
/* getNativeStruct may throw exception, prevent throwing another */
|
|
return;
|
|
}
|
|
|
|
key = getByteArrayIsCopy(env, key_object, &keyIsCopy);
|
|
keySz = getByteArrayLength(env, key_object);
|
|
|
|
if (!cmac || !key) {
|
|
ret = BAD_FUNC_ARG;
|
|
} else {
|
|
#ifdef WC_JNI_CMAC_HAVE_FREE
|
|
/* Free any active context first, reset() and repeated setKey() calls
|
|
* reinitialize the same struct */
|
|
if (cmac->type == WC_CMAC_AES) {
|
|
wc_CmacFree(cmac);
|
|
}
|
|
#endif
|
|
/* Initialize CMAC with the provided key */
|
|
ret = wc_InitCmac(cmac, key, keySz, WC_CMAC_AES, NULL);
|
|
}
|
|
|
|
if (ret != 0)
|
|
throwWolfCryptExceptionFromError(env, ret);
|
|
|
|
LogStr("wc_InitCmac(cmac=%p, key, %d) = %d\n", cmac, keySz, ret);
|
|
|
|
zeroizeByteArrayCopy(key, keySz, keyIsCopy);
|
|
releaseByteArray(env, key_object, key, JNI_ABORT);
|
|
#else
|
|
throwNotCompiledInException(env);
|
|
#endif
|
|
}
|
|
|
|
JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_AesCmac_wc_1CmacUpdate__B(
|
|
JNIEnv* env, jobject this, jbyte data)
|
|
{
|
|
#ifdef WOLFSSL_CMAC
|
|
int ret = 0;
|
|
Cmac* cmac = (Cmac*) getNativeStruct(env, this);
|
|
if ((*env)->ExceptionOccurred(env)) {
|
|
/* getNativeStruct may throw exception, prevent throwing another */
|
|
return;
|
|
}
|
|
|
|
ret = (!cmac)
|
|
? BAD_FUNC_ARG
|
|
: wc_CmacUpdate(cmac, (const byte*)&data, 1);
|
|
|
|
if (ret != 0)
|
|
throwWolfCryptExceptionFromError(env, ret);
|
|
|
|
LogStr("wc_CmacUpdate(cmac=%p, data, 1) = %d\n", cmac, ret);
|
|
LogStr("data: %02x\n", data);
|
|
#else
|
|
throwNotCompiledInException(env);
|
|
#endif
|
|
}
|
|
|
|
JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_AesCmac_wc_1CmacUpdate___3BII(
|
|
JNIEnv* env, jobject this, jbyteArray data_object, jint offset, jint length)
|
|
{
|
|
#ifdef WOLFSSL_CMAC
|
|
int ret = 0;
|
|
Cmac* cmac = NULL;
|
|
byte* data = NULL;
|
|
word32 dataSz = 0;
|
|
|
|
cmac = (Cmac*) getNativeStruct(env, this);
|
|
if ((*env)->ExceptionOccurred(env)) {
|
|
/* getNativeStruct may throw exception, prevent throwing another */
|
|
return;
|
|
}
|
|
|
|
data = getByteArray(env, data_object);
|
|
dataSz = getByteArrayLength(env, data_object);
|
|
|
|
/* Validate bounds to prevent buffer overflow */
|
|
if (!cmac || !data || offset < 0 || length < 0 ||
|
|
((jlong)offset + (jlong)length) > dataSz) {
|
|
ret = BAD_FUNC_ARG;
|
|
} else {
|
|
ret = wc_CmacUpdate(cmac, data + offset, length);
|
|
}
|
|
|
|
if (ret != 0)
|
|
throwWolfCryptExceptionFromError(env, ret);
|
|
|
|
LogStr("wc_CmacUpdate(cmac=%p, data, length) = %d\n", cmac, ret);
|
|
LogStr("data[%u]: [%p]\n", (word32)length, data + offset);
|
|
LogHex((byte*) data, offset, length);
|
|
|
|
releaseByteArray(env, data_object, data, JNI_ABORT);
|
|
#else
|
|
throwNotCompiledInException(env);
|
|
#endif
|
|
}
|
|
|
|
JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_AesCmac_wc_1CmacUpdate__Ljava_nio_ByteBuffer_2II(
|
|
JNIEnv* env, jobject this, jobject data_object, jint offset, jint length)
|
|
{
|
|
#ifdef WOLFSSL_CMAC
|
|
int ret = 0;
|
|
Cmac* cmac = NULL;
|
|
byte* data = NULL;
|
|
word32 bufferLimit = 0;
|
|
|
|
cmac = (Cmac*) getNativeStruct(env, this);
|
|
if ((*env)->ExceptionOccurred(env)) {
|
|
/* getNativeStruct may throw exception, prevent throwing another */
|
|
return;
|
|
}
|
|
|
|
data = getDirectBufferAddress(env, data_object);
|
|
bufferLimit = getDirectBufferLimit(env, data_object);
|
|
|
|
/* Validate bounds to prevent buffer overflow */
|
|
if (!cmac || !data || offset < 0 || length < 0 ||
|
|
((jlong)offset + (jlong)length) > bufferLimit) {
|
|
ret = BAD_FUNC_ARG;
|
|
} else {
|
|
ret = wc_CmacUpdate(cmac, data + offset, length);
|
|
}
|
|
|
|
if (ret != 0)
|
|
throwWolfCryptExceptionFromError(env, ret);
|
|
|
|
LogStr("wc_CmacUpdate(cmac=%p, data, length) = %d\n", cmac, ret);
|
|
LogStr("data[%u]: [%p]\n", (word32)length, data + offset);
|
|
LogHex((byte*) data, offset, length);
|
|
#else
|
|
throwNotCompiledInException(env);
|
|
#endif
|
|
}
|
|
|
|
JNIEXPORT jbyteArray JNICALL Java_com_wolfssl_wolfcrypt_AesCmac_wc_1CmacFinal(
|
|
JNIEnv* env, jobject this)
|
|
{
|
|
jbyteArray result = NULL;
|
|
#ifdef WOLFSSL_CMAC
|
|
int ret = 0;
|
|
word32 macSz = AES_BLOCK_SIZE;
|
|
Cmac* cmac = NULL;
|
|
byte tmp[AES_BLOCK_SIZE];
|
|
|
|
cmac = (Cmac*) getNativeStruct(env, this);
|
|
if ((*env)->ExceptionOccurred(env)) {
|
|
/* getNativeStruct may throw exception, prevent throwing another */
|
|
return NULL;
|
|
}
|
|
|
|
ret = (!cmac)
|
|
? BAD_FUNC_ARG
|
|
: wc_CmacFinal(cmac, tmp, &macSz);
|
|
|
|
if (ret == 0) {
|
|
result = (*env)->NewByteArray(env, macSz);
|
|
|
|
if (result) {
|
|
(*env)->SetByteArrayRegion(env, result, 0, macSz,
|
|
(const jbyte*) tmp);
|
|
} else {
|
|
throwWolfCryptException(env, "Failed to allocate cmac");
|
|
}
|
|
} else {
|
|
throwWolfCryptExceptionFromError(env, ret);
|
|
}
|
|
|
|
LogStr("wc_CmacFinal(cmac=%p, result) = %d\n", cmac, ret);
|
|
LogStr("result[%u]: [%p]\n", (word32)macSz, tmp);
|
|
LogHex(tmp, 0, macSz);
|
|
#if (LIBWOLFSSL_VERSION_HEX >= 0x05008004) && \
|
|
!defined(WOLFSSL_NO_FORCE_ZERO)
|
|
wc_ForceZero(tmp, sizeof(tmp));
|
|
#else
|
|
XMEMSET(tmp, 0, sizeof(tmp));
|
|
#endif
|
|
#else
|
|
throwNotCompiledInException(env);
|
|
#endif
|
|
|
|
return result;
|
|
}
|
|
|
|
JNIEXPORT jint JNICALL Java_com_wolfssl_wolfcrypt_AesCmac_wc_1AesCmacGenerate(
|
|
JNIEnv* env, jobject this, jbyteArray data_object, jint dataSz,
|
|
jbyteArray key_object, jint keySz, jbyteArray mac_object, jint macSz)
|
|
{
|
|
#ifdef WOLFSSL_CMAC
|
|
int ret = 0;
|
|
byte* data = NULL;
|
|
byte* key = NULL;
|
|
byte* mac = NULL;
|
|
word32 actualDataSz, actualKeySz, actualMacArraySz;
|
|
jboolean keyIsCopy = JNI_FALSE;
|
|
|
|
data = getByteArray(env, data_object);
|
|
key = getByteArrayIsCopy(env, key_object, &keyIsCopy);
|
|
actualKeySz = getByteArrayLength(env, key_object);
|
|
mac = getByteArray(env, mac_object);
|
|
|
|
if (data == NULL || key == NULL || mac == NULL) {
|
|
ret = BAD_FUNC_ARG;
|
|
}
|
|
|
|
if (ret == 0) {
|
|
/* Validate size parameters against actual array sizes */
|
|
actualDataSz = getByteArrayLength(env, data_object);
|
|
actualMacArraySz = getByteArrayLength(env, mac_object);
|
|
|
|
if (dataSz < 0 || keySz < 0 || macSz < 0 ||
|
|
(word32)dataSz > actualDataSz ||
|
|
(word32)keySz > actualKeySz ||
|
|
(word32)macSz > actualMacArraySz) {
|
|
ret = BAD_FUNC_ARG;
|
|
}
|
|
}
|
|
|
|
if (ret == 0 ) {
|
|
/* Use a local buffer for the MAC result to avoid corrupting
|
|
* Java memory */
|
|
byte tmp[AES_BLOCK_SIZE];
|
|
word32 tmpSz = AES_BLOCK_SIZE;
|
|
|
|
ret = wc_AesCmacGenerate(tmp, &tmpSz, data, dataSz, key, keySz);
|
|
|
|
if (ret == 0) {
|
|
/* Copy result back to Java byte array, ensuring we don't exceed
|
|
* the original buffer size */
|
|
word32 copySize =
|
|
(tmpSz <= (word32)macSz) ? tmpSz : (word32)macSz;
|
|
(*env)->SetByteArrayRegion(env, mac_object, 0, copySize,
|
|
(const jbyte*) tmp);
|
|
}
|
|
|
|
#if (LIBWOLFSSL_VERSION_HEX >= 0x05008004) && \
|
|
!defined(WOLFSSL_NO_FORCE_ZERO)
|
|
wc_ForceZero(tmp, sizeof(tmp));
|
|
#else
|
|
XMEMSET(tmp, 0, sizeof(tmp));
|
|
#endif
|
|
}
|
|
|
|
LogStr("wc_AesCmacGenerate(data=%p, dataSz=%d, key=%p, keySz=%d) = %d\n",
|
|
data, dataSz, key, keySz, ret);
|
|
|
|
releaseByteArray(env, data_object, data, JNI_ABORT);
|
|
zeroizeByteArrayCopy(key, actualKeySz, keyIsCopy);
|
|
releaseByteArray(env, key_object, key, JNI_ABORT);
|
|
releaseByteArray(env, mac_object, mac, JNI_ABORT);
|
|
|
|
return ret;
|
|
#else
|
|
throwNotCompiledInException(env);
|
|
return NOT_COMPILED_IN;
|
|
#endif
|
|
}
|
|
|
|
JNIEXPORT jint JNICALL Java_com_wolfssl_wolfcrypt_AesCmac_wc_1AesCmacVerify(
|
|
JNIEnv* env, jobject this, jbyteArray mac_object, jint macSz,
|
|
jbyteArray data_object, jint dataSz, jbyteArray key_object, jint keySz)
|
|
{
|
|
#ifdef WOLFSSL_CMAC
|
|
int ret = 0;
|
|
byte* mac = NULL;
|
|
byte* data = NULL;
|
|
byte* key = NULL;
|
|
word32 actualMacSz, actualDataSz, actualKeySz;
|
|
jboolean keyIsCopy = JNI_FALSE;
|
|
|
|
mac = getByteArray(env, mac_object);
|
|
data = getByteArray(env, data_object);
|
|
key = getByteArrayIsCopy(env, key_object, &keyIsCopy);
|
|
actualKeySz = getByteArrayLength(env, key_object);
|
|
|
|
if (mac == NULL || data == NULL || key == NULL) {
|
|
ret = BAD_FUNC_ARG;
|
|
}
|
|
|
|
if (ret == 0) {
|
|
/* Validate size parameters against actual array sizes */
|
|
actualMacSz = getByteArrayLength(env, mac_object);
|
|
actualDataSz = getByteArrayLength(env, data_object);
|
|
|
|
if (macSz < 0 || dataSz < 0 || keySz < 0 ||
|
|
(word32)macSz > actualMacSz ||
|
|
(word32)dataSz > actualDataSz ||
|
|
(word32)keySz > actualKeySz) {
|
|
ret = BAD_FUNC_ARG;
|
|
}
|
|
}
|
|
|
|
if (ret == 0) {
|
|
ret = wc_AesCmacVerify(mac, macSz, data, dataSz, key, keySz);
|
|
}
|
|
|
|
LogStr("wc_AesCmacVerify(mac=%p, macSz=%d, data=%p, dataSz=%d, "
|
|
"key=%p, keySz=%d) = %d\n", mac, macSz, data, dataSz, key, keySz, ret);
|
|
LogHex(mac, 0, macSz);
|
|
|
|
releaseByteArray(env, mac_object, mac, JNI_ABORT);
|
|
releaseByteArray(env, data_object, data, JNI_ABORT);
|
|
zeroizeByteArrayCopy(key, actualKeySz, keyIsCopy);
|
|
releaseByteArray(env, key_object, key, JNI_ABORT);
|
|
|
|
return ret;
|
|
#else
|
|
throwNotCompiledInException(env);
|
|
return NOT_COMPILED_IN;
|
|
#endif
|
|
}
|
|
|