wolfcrypt-jni/jni/jni_mldsa.c

2069 lines
57 KiB
C

/* jni_mldsa.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>
#ifdef HAVE_FIPS
#include <wolfssl/wolfcrypt/fips.h>
#endif
#include <wolfssl/wolfcrypt/types.h>
#if defined(HAVE_DILITHIUM) || defined(WOLFSSL_HAVE_MLDSA)
/* Newer wolfSSL declares the wc_MlDsaKey API in wc_mldsa.h and keeps
* dilithium.h only as a temporary compatibility shim slated for removal.
* Prefer wc_mldsa.h when the compiler can confirm it exists, otherwise
* fall back to dilithium.h (wolfSSL <= 5.9.1 releases). */
#if defined(__has_include)
#if __has_include(<wolfssl/wolfcrypt/wc_mldsa.h>)
#define WC_JNI_HAVE_WC_MLDSA_H
#endif
#endif
#ifdef WC_JNI_HAVE_WC_MLDSA_H
#include <wolfssl/wolfcrypt/wc_mldsa.h>
#else
#include <wolfssl/wolfcrypt/dilithium.h>
#endif
#endif
#include <wolfssl/wolfcrypt/error-crypt.h>
#include <wolfssl/wolfcrypt/memory.h>
#include <com_wolfssl_wolfcrypt_MlDsa.h>
#include <wolfcrypt_jni_NativeStruct.h>
#include <wolfcrypt_jni_error.h>
/* #define WOLFCRYPT_JNI_DEBUG_ON */
#include <wolfcrypt_jni_debug.h>
/* Compatibility mappings for wolfSSL releases that predate the ML-DSA rename
* (<= 5.9.1, no WOLFSSL_HAVE_MLDSA). Releases since 5.7.4 already provide most
* wc_MlDsaKey_* names as macros in dilithium.h, fill in the type and the names
* missing from older releases in terms of the legacy API. */
#if defined(HAVE_DILITHIUM) && !defined(WOLFSSL_HAVE_MLDSA)
typedef dilithium_key wc_MlDsaKey;
#ifndef wc_MlDsaKey_SignCtx
#define wc_MlDsaKey_SignCtx(key, ctx, ctxLen, sig, sigLen, msg, \
msgLen, rng) \
wc_dilithium_sign_ctx_msg((ctx), (ctxLen), (msg), (msgLen), \
(sig), (sigLen), (key), (rng))
#endif
#ifndef wc_MlDsaKey_VerifyCtx
#define wc_MlDsaKey_VerifyCtx(key, sig, sigLen, ctx, ctxLen, msg, \
msgLen, res) \
wc_dilithium_verify_ctx_msg((sig), (sigLen), (ctx), (ctxLen), \
(msg), (msgLen), (res), (key))
#endif
#ifndef wc_MlDsaKey_KeyToDer
#define wc_MlDsaKey_KeyToDer(key, output, len) \
wc_Dilithium_KeyToDer((key), (output), (len))
#endif
#ifndef wc_MlDsaKey_PublicKeyToDer
#define wc_MlDsaKey_PublicKeyToDer(key, output, len, withAlg) \
wc_Dilithium_PublicKeyToDer((key), (output), (len), (withAlg))
#endif
#ifndef wc_MlDsaKey_PrivateKeyDecode
#define wc_MlDsaKey_PrivateKeyDecode(key, input, sz, idx) \
wc_Dilithium_PrivateKeyDecode((input), (idx), (key), (sz))
#endif
#ifndef wc_MlDsaKey_PublicKeyDecode
#define wc_MlDsaKey_PublicKeyDecode(key, input, sz, idx) \
wc_Dilithium_PublicKeyDecode((input), (idx), (key), (sz))
#endif
#ifndef wc_MlDsaKey_MakeKeyFromSeed
#define wc_MlDsaKey_MakeKeyFromSeed(key, seed) \
wc_dilithium_make_key_from_seed((key), (seed))
#endif
#ifndef wc_MlDsaKey_SignCtxHash
#define wc_MlDsaKey_SignCtxHash(key, ctx, ctxLen, sig, sigLen, hash, \
hashLen, hashAlg, rng) \
wc_dilithium_sign_ctx_hash((ctx), (ctxLen), (hashAlg), (hash), \
(hashLen), (sig), (sigLen), (key), (rng))
#endif
#ifndef wc_MlDsaKey_SignCtxWithSeed
#define wc_MlDsaKey_SignCtxWithSeed(key, ctx, ctxLen, sig, sigLen, msg, \
msgLen, seed) \
wc_dilithium_sign_ctx_msg_with_seed((ctx), (ctxLen), (msg), \
(msgLen), (sig), (sigLen), (key), (seed))
#endif
#ifndef wc_MlDsaKey_SignCtxHashWithSeed
#define wc_MlDsaKey_SignCtxHashWithSeed(key, ctx, ctxLen, sig, sigLen, \
hash, hashLen, hashAlg, seed) \
wc_dilithium_sign_ctx_hash_with_seed((ctx), (ctxLen), (hashAlg), \
(hash), (hashLen), (sig), (sigLen), (key), (seed))
#endif
#ifndef wc_MlDsaKey_VerifyCtxHash
#define wc_MlDsaKey_VerifyCtxHash(key, sig, sigLen, ctx, ctxLen, hash, \
hashLen, hashAlg, res) \
wc_dilithium_verify_ctx_hash((sig), (sigLen), (ctx), (ctxLen), \
(hashAlg), (hash), (hashLen), (res), (key))
#endif
#ifndef wc_MlDsaKey_ImportKey
#define wc_MlDsaKey_ImportKey(key, priv, privSz, pub, pubSz) \
wc_dilithium_import_key((priv), (privSz), (pub), (pubSz), (key))
#endif
#ifndef wc_MlDsaKey_CheckKey
#define wc_MlDsaKey_CheckKey(key) \
wc_dilithium_check_key(key)
#endif
#ifndef wc_MlDsaKey_PrivateKeyToDer
#define wc_MlDsaKey_PrivateKeyToDer(key, output, len) \
wc_Dilithium_PrivateKeyToDer((key), (output), (len))
#endif
#endif /* HAVE_DILITHIUM && !WOLFSSL_HAVE_MLDSA */
/* Sub-feature gates, normalized across the legacy (DILITHIUM) and MLDSA
* spellings. Each JNI function below compiles its real body only when the
* native wolfSSL build declares the functions it calls, otherwise it compiles
* a NOT_COMPILED_IN stub. */
#if defined(HAVE_DILITHIUM) || defined(WOLFSSL_HAVE_MLDSA)
#if !defined(WOLFSSL_MLDSA_VERIFY_ONLY) && \
!defined(WOLFSSL_DILITHIUM_VERIFY_ONLY) && \
!defined(WOLFSSL_MLDSA_NO_MAKE_KEY) && \
!defined(WOLFSSL_DILITHIUM_NO_MAKE_KEY)
#define WC_JNI_MLDSA_HAVE_MAKE_KEY
#endif
#if !defined(WOLFSSL_MLDSA_VERIFY_ONLY) && \
!defined(WOLFSSL_DILITHIUM_VERIFY_ONLY) && \
!defined(WOLFSSL_MLDSA_NO_SIGN) && \
!defined(WOLFSSL_DILITHIUM_NO_SIGN)
#define WC_JNI_MLDSA_HAVE_SIGN
#endif
#if !defined(WOLFSSL_MLDSA_NO_VERIFY) && \
!defined(WOLFSSL_DILITHIUM_NO_VERIFY)
#define WC_JNI_MLDSA_HAVE_VERIFY
#endif
#if defined(WOLFSSL_MLDSA_PUBLIC_KEY) || \
defined(WOLFSSL_DILITHIUM_PUBLIC_KEY)
#define WC_JNI_MLDSA_HAVE_PUB_KEY
#endif
#if defined(WOLFSSL_MLDSA_PRIVATE_KEY) || \
defined(WOLFSSL_DILITHIUM_PRIVATE_KEY)
#define WC_JNI_MLDSA_HAVE_PRIV_KEY
#endif
#if !defined(WOLFSSL_MLDSA_NO_ASN1) && \
!defined(WOLFSSL_DILITHIUM_NO_ASN1)
#define WC_JNI_MLDSA_HAVE_ASN1
#endif
#if defined(WOLFSSL_MLDSA_CHECK_KEY) || \
defined(WOLFSSL_DILITHIUM_CHECK_KEY)
#define WC_JNI_MLDSA_HAVE_CHECK_KEY
#endif
#endif /* HAVE_DILITHIUM) || WOLFSSL_HAVE_MLDSA */
/* Force-zero a buffer before XFREE */
#if (LIBWOLFSSL_VERSION_HEX >= 0x05008004) && !defined(WOLFSSL_NO_FORCE_ZERO)
#define MLDSA_FORCE_ZERO(p, len) wc_ForceZero((p), (len))
#else
#define MLDSA_FORCE_ZERO(p, len) XMEMSET((p), 0, (len))
#endif
JNIEXPORT jlong JNICALL Java_com_wolfssl_wolfcrypt_MlDsa_mallocNativeStruct
(JNIEnv* env, jobject this)
{
#if defined(HAVE_DILITHIUM) || defined(WOLFSSL_HAVE_MLDSA)
wc_MlDsaKey* key = NULL;
key = (wc_MlDsaKey*)XMALLOC(sizeof(wc_MlDsaKey), NULL,
DYNAMIC_TYPE_TMP_BUFFER);
if (key == NULL) {
throwOutOfMemoryException(env, "Failed to allocate MlDsa object");
}
else {
XMEMSET(key, 0, sizeof(wc_MlDsaKey));
}
LogStr("new MlDsa() = %p\n", key);
return (jlong)(uintptr_t)key;
#else
(void)env;
(void)this;
throwNotCompiledInException(env);
return (jlong)0;
#endif
}
JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_MlDsa_wc_1dilithium_1init
(JNIEnv* env, jobject this)
{
#if defined(HAVE_DILITHIUM) || defined(WOLFSSL_HAVE_MLDSA)
int ret = 0;
wc_MlDsaKey* key = NULL;
key = (wc_MlDsaKey*) getNativeStruct(env, this);
if ((*env)->ExceptionOccurred(env)) {
return;
}
if (key == NULL) {
ret = BAD_FUNC_ARG;
}
else {
ret = wc_MlDsaKey_Init(key, NULL, INVALID_DEVID);
}
if (ret != 0) {
throwWolfCryptExceptionFromError(env, ret);
}
LogStr("wc_MlDsaKey_Init(key=%p) = %d\n", key, ret);
#else
(void)env;
(void)this;
throwNotCompiledInException(env);
#endif
}
JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_MlDsa_wc_1dilithium_1free
(JNIEnv* env, jobject this)
{
#if defined(HAVE_DILITHIUM) || defined(WOLFSSL_HAVE_MLDSA)
wc_MlDsaKey* key = NULL;
key = (wc_MlDsaKey*) getNativeStruct(env, this);
if ((*env)->ExceptionOccurred(env)) {
return;
}
if (key != NULL) {
wc_MlDsaKey_Free(key);
}
LogStr("wc_MlDsaKey_Free(key=%p)\n", key);
#else
(void)env;
(void)this;
throwNotCompiledInException(env);
#endif
}
JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_MlDsa_wc_1dilithium_1set_1level
(JNIEnv* env, jobject this, jint level)
{
#if defined(HAVE_DILITHIUM) || defined(WOLFSSL_HAVE_MLDSA)
int ret = 0;
wc_MlDsaKey* key = NULL;
key = (wc_MlDsaKey*) getNativeStruct(env, this);
if ((*env)->ExceptionOccurred(env)) {
return;
}
if (key == NULL) {
ret = BAD_FUNC_ARG;
}
else {
ret = wc_MlDsaKey_SetParams(key, (byte)level);
}
if (ret != 0) {
throwWolfCryptExceptionFromError(env, ret);
}
LogStr("wc_MlDsaKey_SetParams(key=%p, level=%d) = %d\n",
key, (int)level, ret);
#else
(void)env;
(void)this;
(void)level;
throwNotCompiledInException(env);
#endif
}
JNIEXPORT jint JNICALL Java_com_wolfssl_wolfcrypt_MlDsa_wc_1dilithium_1get_1level
(JNIEnv* env, jobject this)
{
#if defined(HAVE_DILITHIUM) || defined(WOLFSSL_HAVE_MLDSA)
int ret = 0;
byte level = 0;
wc_MlDsaKey* key = NULL;
key = (wc_MlDsaKey*) getNativeStruct(env, this);
if ((*env)->ExceptionOccurred(env)) {
return 0;
}
if (key == NULL) {
ret = BAD_FUNC_ARG;
}
else {
ret = wc_MlDsaKey_GetParams(key, &level);
}
if (ret != 0) {
throwWolfCryptExceptionFromError(env, ret);
return 0;
}
LogStr("wc_MlDsaKey_GetParams(key=%p) = %d\n", key, (int)level);
return (jint)level;
#else
(void)env;
(void)this;
throwNotCompiledInException(env);
return 0;
#endif
}
JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_MlDsa_wc_1dilithium_1make_1key
(JNIEnv* env, jobject this, jobject rng_object)
{
#if (defined(HAVE_DILITHIUM) || defined(WOLFSSL_HAVE_MLDSA)) && \
defined(WC_JNI_MLDSA_HAVE_MAKE_KEY)
int ret = 0;
wc_MlDsaKey* key = NULL;
WC_RNG* rng = NULL;
key = (wc_MlDsaKey*) getNativeStruct(env, this);
if ((*env)->ExceptionOccurred(env)) {
return;
}
rng = (WC_RNG*) getNativeStruct(env, rng_object);
if ((*env)->ExceptionOccurred(env)) {
return;
}
if (key == NULL || rng == NULL) {
ret = BAD_FUNC_ARG;
}
else {
ret = wc_MlDsaKey_MakeKey(key, rng);
}
if (ret != 0) {
throwWolfCryptExceptionFromError(env, ret);
}
LogStr("wc_MlDsaKey_MakeKey(key=%p) = %d\n", key, ret);
#else
(void)env;
(void)this;
(void)rng_object;
throwNotCompiledInException(env);
#endif
}
JNIEXPORT jbyteArray JNICALL Java_com_wolfssl_wolfcrypt_MlDsa_wc_1dilithium_1sign_1ctx_1msg
(JNIEnv* env, jobject this, jbyteArray ctx_object, jbyteArray msg_object, jobject rng_object)
{
jbyteArray result = NULL;
#if (defined(HAVE_DILITHIUM) || defined(WOLFSSL_HAVE_MLDSA)) && \
defined(WC_JNI_MLDSA_HAVE_SIGN)
int ret = 0;
int sigSz = 0;
wc_MlDsaKey* key = NULL;
WC_RNG* rng = NULL;
byte* ctx = NULL;
byte* msg = NULL;
byte* sig = NULL;
word32 ctxLen = 0;
word32 msgLen = 0;
word32 sigLen = 0;
key = (wc_MlDsaKey*) getNativeStruct(env, this);
if ((*env)->ExceptionOccurred(env)) {
return NULL;
}
rng = (WC_RNG*) getNativeStruct(env, rng_object);
if ((*env)->ExceptionOccurred(env)) {
return NULL;
}
if (key == NULL || rng == NULL) {
throwWolfCryptExceptionFromError(env, BAD_FUNC_ARG);
return NULL;
}
/* ctx_object may be null for an empty context. */
if (ctx_object != NULL) {
ctx = getByteArray(env, ctx_object);
ctxLen = getByteArrayLength(env, ctx_object);
}
if (msg_object != NULL) {
msg = getByteArray(env, msg_object);
msgLen = getByteArrayLength(env, msg_object);
}
/* getByteArray() returns NULL with OutOfMemoryError pending when
* GetByteArrayElements fails. Release what was acquired and return
* without further JNI calls. */
if ((ctx_object != NULL && ctx == NULL) ||
(msg_object != NULL && msg == NULL)) {
if (ctx != NULL) {
releaseByteArray(env, ctx_object, ctx, JNI_ABORT);
}
if (msg != NULL) {
releaseByteArray(env, msg_object, msg, JNI_ABORT);
}
return NULL;
}
/* FIPS 204 caps context length at 255 bytes (also enforced in Java). */
if (ctxLen > com_wolfssl_wolfcrypt_MlDsa_ML_DSA_MAX_CTX_LEN) {
ret = BAD_FUNC_ARG;
}
if (ret == 0) {
ret = wc_MlDsaKey_GetSigLen(key, &sigSz);
if (ret == 0) {
sigLen = (word32)sigSz;
}
}
if (ret == 0) {
sig = (byte*)XMALLOC(sigLen, NULL, DYNAMIC_TYPE_TMP_BUFFER);
if (sig == NULL) {
ret = MEMORY_E;
}
else {
XMEMSET(sig, 0, sigLen);
}
}
if (ret == 0) {
ret = wc_MlDsaKey_SignCtx(key, ctx, (byte)ctxLen, sig, &sigLen,
msg, msgLen, rng);
}
if (ret == 0) {
result = (*env)->NewByteArray(env, sigLen);
if (result != NULL) {
(*env)->SetByteArrayRegion(env, result, 0, sigLen,
(const jbyte*)sig);
}
else {
throwWolfCryptException(env, "Failed to allocate sig");
}
}
else {
throwWolfCryptExceptionFromError(env, ret);
}
LogStr("wc_MlDsaKey_SignCtx(key=%p) = %d\n", key, ret);
if (sig != NULL) {
XFREE(sig, NULL, DYNAMIC_TYPE_TMP_BUFFER);
}
if (ctx_object != NULL) {
releaseByteArray(env, ctx_object, ctx, JNI_ABORT);
}
if (msg_object != NULL) {
releaseByteArray(env, msg_object, msg, JNI_ABORT);
}
#else
(void)env;
(void)this;
(void)ctx_object;
(void)msg_object;
(void)rng_object;
throwNotCompiledInException(env);
#endif
return result;
}
JNIEXPORT jboolean JNICALL Java_com_wolfssl_wolfcrypt_MlDsa_wc_1dilithium_1verify_1ctx_1msg
(JNIEnv* env, jobject this, jbyteArray sig_object, jbyteArray ctx_object, jbyteArray msg_object)
{
jboolean result = JNI_FALSE;
#if (defined(HAVE_DILITHIUM) || defined(WOLFSSL_HAVE_MLDSA)) && \
defined(WC_JNI_MLDSA_HAVE_VERIFY)
int ret = 0;
int verifyRes = 0;
wc_MlDsaKey* key = NULL;
byte* sig = NULL;
byte* ctx = NULL;
byte* msg = NULL;
word32 sigLen = 0;
word32 ctxLen = 0;
word32 msgLen = 0;
key = (wc_MlDsaKey*) getNativeStruct(env, this);
if ((*env)->ExceptionOccurred(env)) {
return JNI_FALSE;
}
if (key == NULL) {
throwWolfCryptExceptionFromError(env, BAD_FUNC_ARG);
return JNI_FALSE;
}
if (sig_object != NULL) {
sig = getByteArray(env, sig_object);
sigLen = getByteArrayLength(env, sig_object);
}
if (ctx_object != NULL) {
ctx = getByteArray(env, ctx_object);
ctxLen = getByteArrayLength(env, ctx_object);
}
if (msg_object != NULL) {
msg = getByteArray(env, msg_object);
msgLen = getByteArrayLength(env, msg_object);
}
/* getByteArray() returns NULL with OutOfMemoryError pending when
* GetByteArrayElements fails. Release what was acquired and return
* without further JNI calls. */
if ((sig_object != NULL && sig == NULL) ||
(ctx_object != NULL && ctx == NULL) ||
(msg_object != NULL && msg == NULL)) {
if (sig != NULL) {
releaseByteArray(env, sig_object, sig, JNI_ABORT);
}
if (ctx != NULL) {
releaseByteArray(env, ctx_object, ctx, JNI_ABORT);
}
if (msg != NULL) {
releaseByteArray(env, msg_object, msg, JNI_ABORT);
}
return JNI_FALSE;
}
/* FIPS 204 caps context length at 255 bytes (also enforced in Java). */
if (ctxLen > com_wolfssl_wolfcrypt_MlDsa_ML_DSA_MAX_CTX_LEN) {
ret = BAD_FUNC_ARG;
}
if (ret == 0) {
ret = wc_MlDsaKey_VerifyCtx(key, sig, sigLen, ctx, (byte)ctxLen,
msg, msgLen, &verifyRes);
}
if (ret == 0 && verifyRes == 1) {
result = JNI_TRUE;
}
else if (ret != 0 && ret != SIG_VERIFY_E) {
throwWolfCryptExceptionFromError(env, ret);
}
LogStr("wc_MlDsaKey_VerifyCtx(key=%p) = %d (res=%d)\n",
key, ret, verifyRes);
if (sig_object != NULL) {
releaseByteArray(env, sig_object, sig, JNI_ABORT);
}
if (ctx_object != NULL) {
releaseByteArray(env, ctx_object, ctx, JNI_ABORT);
}
if (msg_object != NULL) {
releaseByteArray(env, msg_object, msg, JNI_ABORT);
}
#else
(void)env;
(void)this;
(void)sig_object;
(void)ctx_object;
(void)msg_object;
throwNotCompiledInException(env);
#endif
return result;
}
JNIEXPORT jbyteArray JNICALL Java_com_wolfssl_wolfcrypt_MlDsa_wc_1dilithium_1export_1public
(JNIEnv* env, jobject this)
{
jbyteArray result = NULL;
#if (defined(HAVE_DILITHIUM) || defined(WOLFSSL_HAVE_MLDSA)) && \
defined(WC_JNI_MLDSA_HAVE_PUB_KEY)
int ret = 0;
int pubSz = 0;
wc_MlDsaKey* key = NULL;
byte* output = NULL;
word32 outputSz = 0;
key = (wc_MlDsaKey*) getNativeStruct(env, this);
if ((*env)->ExceptionOccurred(env)) {
return NULL;
}
if (key == NULL) {
throwWolfCryptExceptionFromError(env, BAD_FUNC_ARG);
return NULL;
}
ret = wc_MlDsaKey_GetPubLen(key, &pubSz);
if (ret != 0) {
throwWolfCryptExceptionFromError(env, ret);
return NULL;
}
outputSz = (word32)pubSz;
output = (byte*)XMALLOC(outputSz, NULL, DYNAMIC_TYPE_TMP_BUFFER);
if (output == NULL) {
throwOutOfMemoryException(env, "Failed to allocate public key buffer");
return NULL;
}
XMEMSET(output, 0, outputSz);
ret = wc_MlDsaKey_ExportPubRaw(key, output, &outputSz);
if (ret == 0) {
result = (*env)->NewByteArray(env, outputSz);
if (result != NULL) {
(*env)->SetByteArrayRegion(env, result, 0, outputSz,
(const jbyte*)output);
}
else {
throwWolfCryptException(env, "Failed to allocate public key");
}
}
else {
throwWolfCryptExceptionFromError(env, ret);
}
LogStr("wc_MlDsaKey_ExportPubRaw(key=%p) = %d\n", key, ret);
XFREE(output, NULL, DYNAMIC_TYPE_TMP_BUFFER);
#else
(void)env;
(void)this;
throwNotCompiledInException(env);
#endif
return result;
}
JNIEXPORT jbyteArray JNICALL Java_com_wolfssl_wolfcrypt_MlDsa_wc_1dilithium_1export_1private
(JNIEnv* env, jobject this)
{
jbyteArray result = NULL;
#if (defined(HAVE_DILITHIUM) || defined(WOLFSSL_HAVE_MLDSA)) && \
defined(WC_JNI_MLDSA_HAVE_PRIV_KEY)
int ret = 0;
int privSz = 0;
wc_MlDsaKey* key = NULL;
byte* output = NULL;
word32 outputSz = 0;
word32 outputBufSz = 0;
key = (wc_MlDsaKey*) getNativeStruct(env, this);
if ((*env)->ExceptionOccurred(env)) {
return NULL;
}
if (key == NULL) {
throwWolfCryptExceptionFromError(env, BAD_FUNC_ARG);
return NULL;
}
ret = wc_MlDsaKey_GetPrivLen(key, &privSz);
if (ret != 0) {
throwWolfCryptExceptionFromError(env, ret);
return NULL;
}
outputSz = (word32)privSz;
outputBufSz = outputSz;
output = (byte*)XMALLOC(outputSz, NULL, DYNAMIC_TYPE_TMP_BUFFER);
if (output == NULL) {
throwOutOfMemoryException(env, "Failed to allocate private key buffer");
return NULL;
}
XMEMSET(output, 0, outputSz);
PRIVATE_KEY_UNLOCK();
ret = wc_MlDsaKey_ExportPrivRaw(key, output, &outputSz);
PRIVATE_KEY_LOCK();
if (ret == 0) {
result = (*env)->NewByteArray(env, outputSz);
if (result != NULL) {
(*env)->SetByteArrayRegion(env, result, 0, outputSz,
(const jbyte*)output);
}
else {
throwWolfCryptException(env, "Failed to allocate private key");
}
}
else {
throwWolfCryptExceptionFromError(env, ret);
}
LogStr("wc_MlDsaKey_ExportPrivRaw(key=%p) = %d\n", key, ret);
MLDSA_FORCE_ZERO(output, outputBufSz);
XFREE(output, NULL, DYNAMIC_TYPE_TMP_BUFFER);
#else
(void)env;
(void)this;
throwNotCompiledInException(env);
#endif
return result;
}
JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_MlDsa_wc_1dilithium_1import_1public
(JNIEnv* env, jobject this, jbyteArray in_object)
{
#if (defined(HAVE_DILITHIUM) || defined(WOLFSSL_HAVE_MLDSA)) && \
defined(WC_JNI_MLDSA_HAVE_PUB_KEY)
int ret = 0;
wc_MlDsaKey* key = NULL;
byte* in = NULL;
word32 inLen = 0;
key = (wc_MlDsaKey*) getNativeStruct(env, this);
if ((*env)->ExceptionOccurred(env)) {
return;
}
in = getByteArray(env, in_object);
inLen = getByteArrayLength(env, in_object);
if (key == NULL || in == NULL) {
ret = BAD_FUNC_ARG;
}
else {
ret = wc_MlDsaKey_ImportPubRaw(key, in, inLen);
}
if (ret != 0) {
throwWolfCryptExceptionFromError(env, ret);
}
LogStr("wc_MlDsaKey_ImportPubRaw(key=%p) = %d\n", key, ret);
releaseByteArray(env, in_object, in, JNI_ABORT);
#else
(void)env;
(void)this;
(void)in_object;
throwNotCompiledInException(env);
#endif
}
JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_MlDsa_wc_1dilithium_1import_1private
(JNIEnv* env, jobject this, jbyteArray in_object)
{
#if (defined(HAVE_DILITHIUM) || defined(WOLFSSL_HAVE_MLDSA)) && \
defined(WC_JNI_MLDSA_HAVE_PRIV_KEY)
int ret = 0;
wc_MlDsaKey* key = NULL;
byte* in = NULL;
word32 inLen = 0;
jboolean inIsCopy = JNI_FALSE;
key = (wc_MlDsaKey*) getNativeStruct(env, this);
if ((*env)->ExceptionOccurred(env)) {
return;
}
if (in_object != NULL) {
in = (byte*)(*env)->GetByteArrayElements(env, in_object, &inIsCopy);
}
inLen = getByteArrayLength(env, in_object);
if (key == NULL || in == NULL) {
ret = BAD_FUNC_ARG;
}
else {
ret = wc_MlDsaKey_ImportPrivRaw(key, in, inLen);
}
if (ret != 0) {
throwWolfCryptExceptionFromError(env, ret);
}
LogStr("wc_MlDsaKey_ImportPrivRaw(key=%p) = %d\n", key, ret);
if (in != NULL && inIsCopy == JNI_TRUE) {
MLDSA_FORCE_ZERO(in, inLen);
}
releaseByteArray(env, in_object, in, JNI_ABORT);
#else
(void)env;
(void)this;
(void)in_object;
throwNotCompiledInException(env);
#endif
}
JNIEXPORT jbyteArray JNICALL Java_com_wolfssl_wolfcrypt_MlDsa_wc_1Dilithium_1PublicKeyToDer
(JNIEnv* env, jobject this, jboolean withAlg)
{
jbyteArray result = NULL;
#if (defined(HAVE_DILITHIUM) || defined(WOLFSSL_HAVE_MLDSA)) && \
defined(WC_JNI_MLDSA_HAVE_PUB_KEY) && \
defined(WC_JNI_MLDSA_HAVE_ASN1) && defined(WC_ENABLE_ASYM_KEY_EXPORT)
int ret = 0;
wc_MlDsaKey* key = NULL;
byte* output = NULL;
word32 outputSz = 0;
key = (wc_MlDsaKey*) getNativeStruct(env, this);
if ((*env)->ExceptionOccurred(env)) {
return NULL;
}
if (key == NULL) {
throwWolfCryptExceptionFromError(env, BAD_FUNC_ARG);
return NULL;
}
/* Two-pass: first call with NULL output to get required size. */
ret = wc_MlDsaKey_PublicKeyToDer(key, NULL, 0, (int)withAlg);
if (ret <= 0) {
throwWolfCryptExceptionFromError(env, ret);
return NULL;
}
outputSz = (word32)ret;
output = (byte*)XMALLOC(outputSz, NULL, DYNAMIC_TYPE_TMP_BUFFER);
if (output == NULL) {
throwOutOfMemoryException(env, "Failed to allocate public DER buffer");
return NULL;
}
XMEMSET(output, 0, outputSz);
ret = wc_MlDsaKey_PublicKeyToDer(key, output, outputSz, (int)withAlg);
if (ret > 0) {
result = (*env)->NewByteArray(env, ret);
if (result != NULL) {
(*env)->SetByteArrayRegion(env, result, 0, ret,
(const jbyte*)output);
}
else {
throwWolfCryptException(env, "Failed to allocate public DER");
}
}
else {
throwWolfCryptExceptionFromError(env, ret);
}
LogStr("wc_MlDsaKey_PublicKeyToDer(key=%p) = %d\n", key, ret);
XFREE(output, NULL, DYNAMIC_TYPE_TMP_BUFFER);
#else
(void)env;
(void)this;
(void)withAlg;
throwNotCompiledInException(env);
#endif
return result;
}
JNIEXPORT jbyteArray JNICALL Java_com_wolfssl_wolfcrypt_MlDsa_wc_1Dilithium_1KeyToDer
(JNIEnv* env, jobject this)
{
jbyteArray result = NULL;
#if (defined(HAVE_DILITHIUM) || defined(WOLFSSL_HAVE_MLDSA)) && \
defined(WC_JNI_MLDSA_HAVE_PRIV_KEY) && defined(WC_JNI_MLDSA_HAVE_ASN1)
int ret = 0;
wc_MlDsaKey* key = NULL;
byte* output = NULL;
word32 outputSz = 0;
word32 outputBufSz = 0;
key = (wc_MlDsaKey*) getNativeStruct(env, this);
if ((*env)->ExceptionOccurred(env)) {
return NULL;
}
if (key == NULL) {
throwWolfCryptExceptionFromError(env, BAD_FUNC_ARG);
return NULL;
}
/* Two-pass: first call with NULL output to get required size. */
PRIVATE_KEY_UNLOCK();
ret = wc_MlDsaKey_KeyToDer(key, NULL, 0);
PRIVATE_KEY_LOCK();
if (ret <= 0) {
throwWolfCryptExceptionFromError(env, ret);
return NULL;
}
outputSz = (word32)ret;
outputBufSz = outputSz;
output = (byte*)XMALLOC(outputSz, NULL, DYNAMIC_TYPE_TMP_BUFFER);
if (output == NULL) {
throwOutOfMemoryException(env, "Failed to allocate PKCS#8 buffer");
return NULL;
}
XMEMSET(output, 0, outputSz);
PRIVATE_KEY_UNLOCK();
ret = wc_MlDsaKey_KeyToDer(key, output, outputSz);
PRIVATE_KEY_LOCK();
if (ret > 0) {
result = (*env)->NewByteArray(env, ret);
if (result != NULL) {
(*env)->SetByteArrayRegion(env, result, 0, ret,
(const jbyte*)output);
}
else {
throwWolfCryptException(env, "Failed to allocate PKCS#8 DER");
}
}
else {
throwWolfCryptExceptionFromError(env, ret);
}
LogStr("wc_MlDsaKey_KeyToDer(key=%p) = %d\n", key, ret);
MLDSA_FORCE_ZERO(output, outputBufSz);
XFREE(output, NULL, DYNAMIC_TYPE_TMP_BUFFER);
#else
(void)env;
(void)this;
throwNotCompiledInException(env);
#endif
return result;
}
JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_MlDsa_wc_1Dilithium_1PublicKeyDecode
(JNIEnv* env, jobject this, jbyteArray der_object)
{
#if (defined(HAVE_DILITHIUM) || defined(WOLFSSL_HAVE_MLDSA)) && \
defined(WC_JNI_MLDSA_HAVE_PUB_KEY) && defined(WC_JNI_MLDSA_HAVE_ASN1)
int ret = 0;
wc_MlDsaKey* key = NULL;
byte* der = NULL;
word32 derLen = 0;
word32 idx = 0;
key = (wc_MlDsaKey*) getNativeStruct(env, this);
if ((*env)->ExceptionOccurred(env)) {
return;
}
der = getByteArray(env, der_object);
derLen = getByteArrayLength(env, der_object);
if (key == NULL || der == NULL) {
ret = BAD_FUNC_ARG;
}
else {
ret = wc_MlDsaKey_PublicKeyDecode(key, der, derLen, &idx);
}
if (ret != 0) {
throwWolfCryptExceptionFromError(env, ret);
}
LogStr("wc_MlDsaKey_PublicKeyDecode(key=%p) = %d\n", key, ret);
releaseByteArray(env, der_object, der, JNI_ABORT);
#else
(void)env;
(void)this;
(void)der_object;
throwNotCompiledInException(env);
#endif
}
JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_MlDsa_wc_1Dilithium_1PrivateKeyDecode
(JNIEnv* env, jobject this, jbyteArray der_object)
{
#if (defined(HAVE_DILITHIUM) || defined(WOLFSSL_HAVE_MLDSA)) && \
defined(WC_JNI_MLDSA_HAVE_PRIV_KEY) && defined(WC_JNI_MLDSA_HAVE_ASN1)
int ret = 0;
wc_MlDsaKey* key = NULL;
byte* der = NULL;
byte* derCopy = NULL;
word32 derLen = 0;
word32 idx = 0;
key = (wc_MlDsaKey*) getNativeStruct(env, this);
if ((*env)->ExceptionOccurred(env)) {
return;
}
der = getByteArray(env, der_object);
derLen = getByteArrayLength(env, der_object);
if (key == NULL || der == NULL || derLen == 0) {
ret = BAD_FUNC_ARG;
}
if (ret == 0) {
/* Copy because PrivateKeyDecode may modify input buffer. */
derCopy = (byte*)XMALLOC(derLen, NULL, DYNAMIC_TYPE_TMP_BUFFER);
if (derCopy == NULL) {
ret = MEMORY_E;
}
else {
XMEMCPY(derCopy, der, derLen);
}
}
if (ret == 0) {
ret = wc_MlDsaKey_PrivateKeyDecode(key, derCopy, derLen, &idx);
}
if (ret != 0) {
throwWolfCryptExceptionFromError(env, ret);
}
LogStr("wc_MlDsaKey_PrivateKeyDecode(key=%p) = %d\n", key, ret);
if (derCopy != NULL) {
MLDSA_FORCE_ZERO(derCopy, derLen);
XFREE(derCopy, NULL, DYNAMIC_TYPE_TMP_BUFFER);
}
releaseByteArray(env, der_object, der, JNI_ABORT);
#else
(void)env;
(void)this;
(void)der_object;
throwNotCompiledInException(env);
#endif
}
JNIEXPORT jint JNICALL Java_com_wolfssl_wolfcrypt_MlDsa_wc_1dilithium_1pub_1size
(JNIEnv* env, jobject this)
{
#if defined(HAVE_DILITHIUM) || defined(WOLFSSL_HAVE_MLDSA)
int ret = 0;
int pubSz = 0;
wc_MlDsaKey* key = (wc_MlDsaKey*) getNativeStruct(env, this);
if ((*env)->ExceptionOccurred(env)) {
return 0;
}
if (key == NULL) {
ret = BAD_FUNC_ARG;
}
else {
ret = wc_MlDsaKey_GetPubLen(key, &pubSz);
}
if (ret != 0) {
throwWolfCryptExceptionFromError(env, ret);
return 0;
}
return (jint)pubSz;
#else
(void)env;
(void)this;
throwNotCompiledInException(env);
return 0;
#endif
}
JNIEXPORT jint JNICALL Java_com_wolfssl_wolfcrypt_MlDsa_wc_1dilithium_1priv_1size
(JNIEnv* env, jobject this)
{
#if defined(HAVE_DILITHIUM) || defined(WOLFSSL_HAVE_MLDSA)
int ret = 0;
int privSz = 0;
wc_MlDsaKey* key = (wc_MlDsaKey*) getNativeStruct(env, this);
if ((*env)->ExceptionOccurred(env)) {
return 0;
}
if (key == NULL) {
ret = BAD_FUNC_ARG;
}
else {
ret = wc_MlDsaKey_GetPrivLen(key, &privSz);
}
if (ret != 0) {
throwWolfCryptExceptionFromError(env, ret);
return 0;
}
return (jint)privSz;
#else
(void)env;
(void)this;
throwNotCompiledInException(env);
return 0;
#endif
}
JNIEXPORT jint JNICALL Java_com_wolfssl_wolfcrypt_MlDsa_wc_1dilithium_1sig_1size
(JNIEnv* env, jobject this)
{
#if defined(HAVE_DILITHIUM) || defined(WOLFSSL_HAVE_MLDSA)
int ret = 0;
int sigSz = 0;
wc_MlDsaKey* key = (wc_MlDsaKey*) getNativeStruct(env, this);
if ((*env)->ExceptionOccurred(env)) {
return 0;
}
if (key == NULL) {
ret = BAD_FUNC_ARG;
}
else {
ret = wc_MlDsaKey_GetSigLen(key, &sigSz);
}
if (ret != 0) {
throwWolfCryptExceptionFromError(env, ret);
return 0;
}
return (jint)sigSz;
#else
(void)env;
(void)this;
throwNotCompiledInException(env);
return 0;
#endif
}
JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_MlDsa_wc_1dilithium_1make_1key_1from_1seed
(JNIEnv* env, jobject this, jbyteArray seed_object)
{
#if (defined(HAVE_DILITHIUM) || defined(WOLFSSL_HAVE_MLDSA)) && \
defined(WC_JNI_MLDSA_HAVE_MAKE_KEY)
int ret = 0;
wc_MlDsaKey* key = NULL;
byte* seed = NULL;
word32 seedLen = 0;
jboolean seedIsCopy = JNI_FALSE;
key = (wc_MlDsaKey*) getNativeStruct(env, this);
if ((*env)->ExceptionOccurred(env)) {
return;
}
if (seed_object != NULL) {
seed = (byte*)(*env)->GetByteArrayElements(env, seed_object,
&seedIsCopy);
}
seedLen = getByteArrayLength(env, seed_object);
/* Native API takes no seed length, seed must be exactly 32 bytes */
if (key == NULL || seed == NULL ||
seedLen != com_wolfssl_wolfcrypt_MlDsa_ML_DSA_SEED_LEN) {
ret = BAD_FUNC_ARG;
}
else {
PRIVATE_KEY_UNLOCK();
ret = wc_MlDsaKey_MakeKeyFromSeed(key, seed);
PRIVATE_KEY_LOCK();
}
if (ret != 0) {
throwWolfCryptExceptionFromError(env, ret);
}
LogStr("wc_MlDsaKey_MakeKeyFromSeed(key=%p) = %d\n", key, ret);
if (seed != NULL && seedIsCopy == JNI_TRUE) {
MLDSA_FORCE_ZERO(seed, seedLen);
}
releaseByteArray(env, seed_object, seed, JNI_ABORT);
#else
(void)env;
(void)this;
(void)seed_object;
throwNotCompiledInException(env);
#endif
}
JNIEXPORT jbyteArray JNICALL Java_com_wolfssl_wolfcrypt_MlDsa_wc_1dilithium_1sign_1ctx_1hash
(JNIEnv* env, jobject this, jbyteArray ctx_object, jint hashAlg, jbyteArray hash_object, jobject rng_object)
{
jbyteArray result = NULL;
#if (defined(HAVE_DILITHIUM) || defined(WOLFSSL_HAVE_MLDSA)) && \
defined(WC_JNI_MLDSA_HAVE_SIGN)
int ret = 0;
int sigSz = 0;
wc_MlDsaKey* key = NULL;
WC_RNG* rng = NULL;
byte* ctx = NULL;
byte* hash = NULL;
byte* sig = NULL;
word32 ctxLen = 0;
word32 hashLen = 0;
word32 sigLen = 0;
key = (wc_MlDsaKey*) getNativeStruct(env, this);
if ((*env)->ExceptionOccurred(env)) {
return NULL;
}
rng = (WC_RNG*) getNativeStruct(env, rng_object);
if ((*env)->ExceptionOccurred(env)) {
return NULL;
}
if (key == NULL || rng == NULL) {
throwWolfCryptExceptionFromError(env, BAD_FUNC_ARG);
return NULL;
}
/* ctx_object may be null for an empty context. */
if (ctx_object != NULL) {
ctx = getByteArray(env, ctx_object);
ctxLen = getByteArrayLength(env, ctx_object);
}
if (hash_object != NULL) {
hash = getByteArray(env, hash_object);
hashLen = getByteArrayLength(env, hash_object);
}
/* getByteArray() returns NULL with OutOfMemoryError pending when
* GetByteArrayElements fails. Release what was acquired and return
* without further JNI calls. */
if ((ctx_object != NULL && ctx == NULL) ||
(hash_object != NULL && hash == NULL)) {
if (ctx != NULL) {
releaseByteArray(env, ctx_object, ctx, JNI_ABORT);
}
if (hash != NULL) {
releaseByteArray(env, hash_object, hash, JNI_ABORT);
}
return NULL;
}
/* FIPS 204 caps context length at 255 bytes. */
if (ctxLen > com_wolfssl_wolfcrypt_MlDsa_ML_DSA_MAX_CTX_LEN) {
ret = BAD_FUNC_ARG;
}
if (ret == 0) {
ret = wc_MlDsaKey_GetSigLen(key, &sigSz);
if (ret == 0) {
sigLen = (word32)sigSz;
}
}
if (ret == 0) {
sig = (byte*)XMALLOC(sigLen, NULL, DYNAMIC_TYPE_TMP_BUFFER);
if (sig == NULL) {
ret = MEMORY_E;
}
else {
XMEMSET(sig, 0, sigLen);
}
}
if (ret == 0) {
ret = wc_MlDsaKey_SignCtxHash(key, ctx, (byte)ctxLen, sig, &sigLen,
hash, hashLen, (int)hashAlg, rng);
}
if (ret == 0) {
result = (*env)->NewByteArray(env, sigLen);
if (result != NULL) {
(*env)->SetByteArrayRegion(env, result, 0, sigLen,
(const jbyte*)sig);
}
else {
throwWolfCryptException(env, "Failed to allocate sig");
}
}
else {
throwWolfCryptExceptionFromError(env, ret);
}
LogStr("wc_MlDsaKey_SignCtxHash(key=%p) = %d\n", key, ret);
if (sig != NULL) {
XFREE(sig, NULL, DYNAMIC_TYPE_TMP_BUFFER);
}
if (ctx_object != NULL) {
releaseByteArray(env, ctx_object, ctx, JNI_ABORT);
}
if (hash_object != NULL) {
releaseByteArray(env, hash_object, hash, JNI_ABORT);
}
#else
(void)env;
(void)this;
(void)ctx_object;
(void)hashAlg;
(void)hash_object;
(void)rng_object;
throwNotCompiledInException(env);
#endif
return result;
}
JNIEXPORT jbyteArray JNICALL Java_com_wolfssl_wolfcrypt_MlDsa_wc_1dilithium_1sign_1ctx_1msg_1with_1seed
(JNIEnv* env, jobject this, jbyteArray ctx_object, jbyteArray msg_object, jbyteArray seed_object)
{
jbyteArray result = NULL;
#if (defined(HAVE_DILITHIUM) || defined(WOLFSSL_HAVE_MLDSA)) && \
defined(WC_JNI_MLDSA_HAVE_SIGN)
int ret = 0;
int sigSz = 0;
wc_MlDsaKey* key = NULL;
byte* ctx = NULL;
byte* msg = NULL;
byte* seed = NULL;
byte* sig = NULL;
word32 ctxLen = 0;
word32 msgLen = 0;
word32 seedLen = 0;
word32 sigLen = 0;
jboolean seedIsCopy = JNI_FALSE;
key = (wc_MlDsaKey*) getNativeStruct(env, this);
if ((*env)->ExceptionOccurred(env)) {
return NULL;
}
if (key == NULL) {
throwWolfCryptExceptionFromError(env, BAD_FUNC_ARG);
return NULL;
}
/* ctx_object may be null for an empty context. */
if (ctx_object != NULL) {
ctx = getByteArray(env, ctx_object);
ctxLen = getByteArrayLength(env, ctx_object);
}
if (msg_object != NULL) {
msg = getByteArray(env, msg_object);
msgLen = getByteArrayLength(env, msg_object);
}
if (seed_object != NULL) {
seed = (byte*)(*env)->GetByteArrayElements(env, seed_object,
&seedIsCopy);
seedLen = getByteArrayLength(env, seed_object);
}
/* getByteArray() returns NULL with OutOfMemoryError pending when
* GetByteArrayElements fails. Release what was acquired and return
* without further JNI calls. */
if ((ctx_object != NULL && ctx == NULL) ||
(msg_object != NULL && msg == NULL) ||
(seed_object != NULL && seed == NULL)) {
if (ctx != NULL) {
releaseByteArray(env, ctx_object, ctx, JNI_ABORT);
}
if (msg != NULL) {
releaseByteArray(env, msg_object, msg, JNI_ABORT);
}
if (seed != NULL) {
if (seedIsCopy == JNI_TRUE) {
MLDSA_FORCE_ZERO(seed, seedLen);
}
releaseByteArray(env, seed_object, seed, JNI_ABORT);
}
return NULL;
}
/* FIPS 204 caps context length at 255 bytes */
if (ctxLen > com_wolfssl_wolfcrypt_MlDsa_ML_DSA_MAX_CTX_LEN) {
ret = BAD_FUNC_ARG;
}
/* Native API takes no seed length, seed must be exactly 32 bytes */
if (ret == 0 && (seed == NULL ||
seedLen != com_wolfssl_wolfcrypt_MlDsa_ML_DSA_RND_LEN)) {
ret = BAD_FUNC_ARG;
}
if (ret == 0) {
ret = wc_MlDsaKey_GetSigLen(key, &sigSz);
if (ret == 0) {
sigLen = (word32)sigSz;
}
}
if (ret == 0) {
sig = (byte*)XMALLOC(sigLen, NULL, DYNAMIC_TYPE_TMP_BUFFER);
if (sig == NULL) {
ret = MEMORY_E;
}
else {
XMEMSET(sig, 0, sigLen);
}
}
if (ret == 0) {
ret = wc_MlDsaKey_SignCtxWithSeed(key, ctx, (byte)ctxLen, sig,
&sigLen, msg, msgLen, seed);
}
if (ret == 0) {
result = (*env)->NewByteArray(env, sigLen);
if (result != NULL) {
(*env)->SetByteArrayRegion(env, result, 0, sigLen,
(const jbyte*)sig);
}
else {
throwWolfCryptException(env, "Failed to allocate sig");
}
}
else {
throwWolfCryptExceptionFromError(env, ret);
}
LogStr("wc_MlDsaKey_SignCtxWithSeed(key=%p) = %d\n", key, ret);
if (sig != NULL) {
XFREE(sig, NULL, DYNAMIC_TYPE_TMP_BUFFER);
}
if (ctx_object != NULL) {
releaseByteArray(env, ctx_object, ctx, JNI_ABORT);
}
if (msg_object != NULL) {
releaseByteArray(env, msg_object, msg, JNI_ABORT);
}
if (seed_object != NULL) {
if (seed != NULL && seedIsCopy == JNI_TRUE) {
MLDSA_FORCE_ZERO(seed, seedLen);
}
releaseByteArray(env, seed_object, seed, JNI_ABORT);
}
#else
(void)env;
(void)this;
(void)ctx_object;
(void)msg_object;
(void)seed_object;
throwNotCompiledInException(env);
#endif
return result;
}
JNIEXPORT jbyteArray JNICALL Java_com_wolfssl_wolfcrypt_MlDsa_wc_1dilithium_1sign_1ctx_1hash_1with_1seed
(JNIEnv* env, jobject this, jbyteArray ctx_object, jint hashAlg, jbyteArray hash_object, jbyteArray seed_object)
{
jbyteArray result = NULL;
#if (defined(HAVE_DILITHIUM) || defined(WOLFSSL_HAVE_MLDSA)) && \
defined(WC_JNI_MLDSA_HAVE_SIGN)
int ret = 0;
int sigSz = 0;
wc_MlDsaKey* key = NULL;
byte* ctx = NULL;
byte* hash = NULL;
byte* seed = NULL;
byte* sig = NULL;
word32 ctxLen = 0;
word32 hashLen = 0;
word32 seedLen = 0;
word32 sigLen = 0;
jboolean seedIsCopy = JNI_FALSE;
key = (wc_MlDsaKey*) getNativeStruct(env, this);
if ((*env)->ExceptionOccurred(env)) {
return NULL;
}
if (key == NULL) {
throwWolfCryptExceptionFromError(env, BAD_FUNC_ARG);
return NULL;
}
/* ctx_object may be null for an empty context. */
if (ctx_object != NULL) {
ctx = getByteArray(env, ctx_object);
ctxLen = getByteArrayLength(env, ctx_object);
}
if (hash_object != NULL) {
hash = getByteArray(env, hash_object);
hashLen = getByteArrayLength(env, hash_object);
}
if (seed_object != NULL) {
seed = (byte*)(*env)->GetByteArrayElements(env, seed_object,
&seedIsCopy);
seedLen = getByteArrayLength(env, seed_object);
}
/* getByteArray() returns NULL with OutOfMemoryError pending when
* GetByteArrayElements fails. Release what was acquired and return
* without further JNI calls. */
if ((ctx_object != NULL && ctx == NULL) ||
(hash_object != NULL && hash == NULL) ||
(seed_object != NULL && seed == NULL)) {
if (ctx != NULL) {
releaseByteArray(env, ctx_object, ctx, JNI_ABORT);
}
if (hash != NULL) {
releaseByteArray(env, hash_object, hash, JNI_ABORT);
}
if (seed != NULL) {
if (seedIsCopy == JNI_TRUE) {
MLDSA_FORCE_ZERO(seed, seedLen);
}
releaseByteArray(env, seed_object, seed, JNI_ABORT);
}
return NULL;
}
/* FIPS 204 caps context length at 255 bytes */
if (ctxLen > com_wolfssl_wolfcrypt_MlDsa_ML_DSA_MAX_CTX_LEN) {
ret = BAD_FUNC_ARG;
}
/* Native API takes no seed length, seed must be exactly 32 bytes */
if (ret == 0 && (seed == NULL ||
seedLen != com_wolfssl_wolfcrypt_MlDsa_ML_DSA_RND_LEN)) {
ret = BAD_FUNC_ARG;
}
if (ret == 0) {
ret = wc_MlDsaKey_GetSigLen(key, &sigSz);
if (ret == 0) {
sigLen = (word32)sigSz;
}
}
if (ret == 0) {
sig = (byte*)XMALLOC(sigLen, NULL, DYNAMIC_TYPE_TMP_BUFFER);
if (sig == NULL) {
ret = MEMORY_E;
}
else {
XMEMSET(sig, 0, sigLen);
}
}
if (ret == 0) {
ret = wc_MlDsaKey_SignCtxHashWithSeed(key, ctx, (byte)ctxLen, sig,
&sigLen, hash, hashLen, (int)hashAlg, seed);
}
if (ret == 0) {
result = (*env)->NewByteArray(env, sigLen);
if (result != NULL) {
(*env)->SetByteArrayRegion(env, result, 0, sigLen,
(const jbyte*)sig);
}
else {
throwWolfCryptException(env, "Failed to allocate sig");
}
}
else {
throwWolfCryptExceptionFromError(env, ret);
}
LogStr("wc_MlDsaKey_SignCtxHashWithSeed(key=%p) = %d\n", key, ret);
if (sig != NULL) {
XFREE(sig, NULL, DYNAMIC_TYPE_TMP_BUFFER);
}
if (ctx_object != NULL) {
releaseByteArray(env, ctx_object, ctx, JNI_ABORT);
}
if (hash_object != NULL) {
releaseByteArray(env, hash_object, hash, JNI_ABORT);
}
if (seed_object != NULL) {
if (seed != NULL && seedIsCopy == JNI_TRUE) {
MLDSA_FORCE_ZERO(seed, seedLen);
}
releaseByteArray(env, seed_object, seed, JNI_ABORT);
}
#else
(void)env;
(void)this;
(void)ctx_object;
(void)hashAlg;
(void)hash_object;
(void)seed_object;
throwNotCompiledInException(env);
#endif
return result;
}
JNIEXPORT jboolean JNICALL Java_com_wolfssl_wolfcrypt_MlDsa_wc_1dilithium_1verify_1ctx_1hash
(JNIEnv* env, jobject this, jbyteArray sig_object, jbyteArray ctx_object, jint hashAlg, jbyteArray hash_object)
{
jboolean result = JNI_FALSE;
#if (defined(HAVE_DILITHIUM) || defined(WOLFSSL_HAVE_MLDSA)) && \
defined(WC_JNI_MLDSA_HAVE_VERIFY)
int ret = 0;
int verifyRes = 0;
wc_MlDsaKey* key = NULL;
byte* sig = NULL;
byte* ctx = NULL;
byte* hash = NULL;
word32 sigLen = 0;
word32 ctxLen = 0;
word32 hashLen = 0;
key = (wc_MlDsaKey*) getNativeStruct(env, this);
if ((*env)->ExceptionOccurred(env)) {
return JNI_FALSE;
}
if (key == NULL) {
throwWolfCryptExceptionFromError(env, BAD_FUNC_ARG);
return JNI_FALSE;
}
if (sig_object != NULL) {
sig = getByteArray(env, sig_object);
sigLen = getByteArrayLength(env, sig_object);
}
if (ctx_object != NULL) {
ctx = getByteArray(env, ctx_object);
ctxLen = getByteArrayLength(env, ctx_object);
}
if (hash_object != NULL) {
hash = getByteArray(env, hash_object);
hashLen = getByteArrayLength(env, hash_object);
}
/* getByteArray() returns NULL with OutOfMemoryError pending when
* GetByteArrayElements fails. Release what was acquired and return
* without further JNI calls. */
if ((sig_object != NULL && sig == NULL) ||
(ctx_object != NULL && ctx == NULL) ||
(hash_object != NULL && hash == NULL)) {
if (sig != NULL) {
releaseByteArray(env, sig_object, sig, JNI_ABORT);
}
if (ctx != NULL) {
releaseByteArray(env, ctx_object, ctx, JNI_ABORT);
}
if (hash != NULL) {
releaseByteArray(env, hash_object, hash, JNI_ABORT);
}
return JNI_FALSE;
}
/* FIPS 204 caps context length at 255 bytes */
if (ctxLen > com_wolfssl_wolfcrypt_MlDsa_ML_DSA_MAX_CTX_LEN) {
ret = BAD_FUNC_ARG;
}
if (ret == 0) {
ret = wc_MlDsaKey_VerifyCtxHash(key, sig, sigLen, ctx, (byte)ctxLen,
hash, hashLen, (int)hashAlg, &verifyRes);
}
if (ret == 0 && verifyRes == 1) {
result = JNI_TRUE;
}
else if (ret != 0 && ret != SIG_VERIFY_E) {
throwWolfCryptExceptionFromError(env, ret);
}
LogStr("wc_MlDsaKey_VerifyCtxHash(key=%p) = %d (res=%d)\n",
key, ret, verifyRes);
if (sig_object != NULL) {
releaseByteArray(env, sig_object, sig, JNI_ABORT);
}
if (ctx_object != NULL) {
releaseByteArray(env, ctx_object, ctx, JNI_ABORT);
}
if (hash_object != NULL) {
releaseByteArray(env, hash_object, hash, JNI_ABORT);
}
#else
(void)env;
(void)this;
(void)sig_object;
(void)ctx_object;
(void)hashAlg;
(void)hash_object;
throwNotCompiledInException(env);
#endif
return result;
}
JNIEXPORT jbyteArray JNICALL Java_com_wolfssl_wolfcrypt_MlDsa_wc_1MlDsaKey_1SignMuWithSeed
(JNIEnv* env, jobject this, jbyteArray mu_object, jbyteArray seed_object)
{
jbyteArray result = NULL;
/* External mu sign/verify has no legacy dilithium.h equivalent, only
* available with the wc_MlDsaKey API in newer wolfSSL (wc_mldsa.h). */
#if defined(WOLFSSL_HAVE_MLDSA) && defined(WC_JNI_MLDSA_HAVE_SIGN)
int ret = 0;
int sigSz = 0;
wc_MlDsaKey* key = NULL;
byte* mu = NULL;
byte* seed = NULL;
byte* sig = NULL;
word32 muLen = 0;
word32 seedLen = 0;
word32 sigLen = 0;
jboolean seedIsCopy = JNI_FALSE;
key = (wc_MlDsaKey*) getNativeStruct(env, this);
if ((*env)->ExceptionOccurred(env)) {
return NULL;
}
if (key == NULL) {
throwWolfCryptExceptionFromError(env, BAD_FUNC_ARG);
return NULL;
}
if (mu_object != NULL) {
mu = getByteArray(env, mu_object);
muLen = getByteArrayLength(env, mu_object);
}
if (seed_object != NULL) {
seed = (byte*)(*env)->GetByteArrayElements(env, seed_object,
&seedIsCopy);
seedLen = getByteArrayLength(env, seed_object);
}
/* getByteArray() returns NULL with OutOfMemoryError pending when
* GetByteArrayElements fails. Release what was acquired and return
* without further JNI calls. */
if ((mu_object != NULL && mu == NULL) ||
(seed_object != NULL && seed == NULL)) {
if (mu != NULL) {
releaseByteArray(env, mu_object, mu, JNI_ABORT);
}
if (seed != NULL) {
if (seedIsCopy == JNI_TRUE) {
MLDSA_FORCE_ZERO(seed, seedLen);
}
releaseByteArray(env, seed_object, seed, JNI_ABORT);
}
return NULL;
}
/* Native API takes no seed length, seed must be exactly 32 bytes */
if (seed == NULL || mu == NULL ||
seedLen != com_wolfssl_wolfcrypt_MlDsa_ML_DSA_RND_LEN) {
ret = BAD_FUNC_ARG;
}
if (ret == 0) {
ret = wc_MlDsaKey_GetSigLen(key, &sigSz);
if (ret == 0) {
sigLen = (word32)sigSz;
}
}
if (ret == 0) {
sig = (byte*)XMALLOC(sigLen, NULL, DYNAMIC_TYPE_TMP_BUFFER);
if (sig == NULL) {
ret = MEMORY_E;
}
else {
XMEMSET(sig, 0, sigLen);
}
}
if (ret == 0) {
ret = wc_MlDsaKey_SignMuWithSeed(key, sig, &sigLen, mu, muLen, seed);
}
if (ret == 0) {
result = (*env)->NewByteArray(env, sigLen);
if (result != NULL) {
(*env)->SetByteArrayRegion(env, result, 0, sigLen,
(const jbyte*)sig);
}
else {
throwWolfCryptException(env, "Failed to allocate sig");
}
}
else {
throwWolfCryptExceptionFromError(env, ret);
}
LogStr("wc_MlDsaKey_SignMuWithSeed(key=%p) = %d\n", key, ret);
if (sig != NULL) {
XFREE(sig, NULL, DYNAMIC_TYPE_TMP_BUFFER);
}
if (mu_object != NULL) {
releaseByteArray(env, mu_object, mu, JNI_ABORT);
}
if (seed_object != NULL) {
if (seed != NULL && seedIsCopy == JNI_TRUE) {
MLDSA_FORCE_ZERO(seed, seedLen);
}
releaseByteArray(env, seed_object, seed, JNI_ABORT);
}
#else
(void)env;
(void)this;
(void)mu_object;
(void)seed_object;
throwNotCompiledInException(env);
#endif
return result;
}
JNIEXPORT jboolean JNICALL Java_com_wolfssl_wolfcrypt_MlDsa_wc_1MlDsaKey_1VerifyMu
(JNIEnv* env, jobject this, jbyteArray sig_object, jbyteArray mu_object)
{
jboolean result = JNI_FALSE;
/* External mu sign/verify has no legacy dilithium.h equivalent, only
* available with the wc_MlDsaKey API in newer wolfSSL (wc_mldsa.h). */
#if defined(WOLFSSL_HAVE_MLDSA) && defined(WC_JNI_MLDSA_HAVE_VERIFY)
int ret = 0;
int verifyRes = 0;
wc_MlDsaKey* key = NULL;
byte* sig = NULL;
byte* mu = NULL;
word32 sigLen = 0;
word32 muLen = 0;
key = (wc_MlDsaKey*) getNativeStruct(env, this);
if ((*env)->ExceptionOccurred(env)) {
return JNI_FALSE;
}
if (key == NULL) {
throwWolfCryptExceptionFromError(env, BAD_FUNC_ARG);
return JNI_FALSE;
}
if (sig_object != NULL) {
sig = getByteArray(env, sig_object);
sigLen = getByteArrayLength(env, sig_object);
}
if (mu_object != NULL) {
mu = getByteArray(env, mu_object);
muLen = getByteArrayLength(env, mu_object);
}
/* getByteArray() returns NULL with OutOfMemoryError pending when
* GetByteArrayElements fails. Release what was acquired and return
* without further JNI calls. */
if ((sig_object != NULL && sig == NULL) ||
(mu_object != NULL && mu == NULL)) {
if (sig != NULL) {
releaseByteArray(env, sig_object, sig, JNI_ABORT);
}
if (mu != NULL) {
releaseByteArray(env, mu_object, mu, JNI_ABORT);
}
return JNI_FALSE;
}
/* Native validates muLen itself (must be 64). */
ret = wc_MlDsaKey_VerifyMu(key, sig, sigLen, mu, muLen, &verifyRes);
if (ret == 0 && verifyRes == 1) {
result = JNI_TRUE;
}
else if (ret != 0 && ret != SIG_VERIFY_E) {
throwWolfCryptExceptionFromError(env, ret);
}
LogStr("wc_MlDsaKey_VerifyMu(key=%p) = %d (res=%d)\n",
key, ret, verifyRes);
if (sig_object != NULL) {
releaseByteArray(env, sig_object, sig, JNI_ABORT);
}
if (mu_object != NULL) {
releaseByteArray(env, mu_object, mu, JNI_ABORT);
}
#else
(void)env;
(void)this;
(void)sig_object;
(void)mu_object;
throwNotCompiledInException(env);
#endif
return result;
}
JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_MlDsa_wc_1dilithium_1import_1key
(JNIEnv* env, jobject this, jbyteArray priv_object, jbyteArray pub_object)
{
#if (defined(HAVE_DILITHIUM) || defined(WOLFSSL_HAVE_MLDSA)) && \
defined(WC_JNI_MLDSA_HAVE_PRIV_KEY)
int ret = 0;
wc_MlDsaKey* key = NULL;
byte* priv = NULL;
byte* pub = NULL;
word32 privLen = 0;
word32 pubLen = 0;
jboolean privIsCopy = JNI_FALSE;
key = (wc_MlDsaKey*) getNativeStruct(env, this);
if ((*env)->ExceptionOccurred(env)) {
return;
}
if (priv_object != NULL) {
priv = (byte*)(*env)->GetByteArrayElements(env, priv_object,
&privIsCopy);
}
privLen = getByteArrayLength(env, priv_object);
pub = getByteArray(env, pub_object);
pubLen = getByteArrayLength(env, pub_object);
if (key == NULL || priv == NULL || pub == NULL) {
ret = BAD_FUNC_ARG;
}
else {
ret = wc_MlDsaKey_ImportKey(key, priv, privLen, pub, pubLen);
}
if (ret != 0) {
throwWolfCryptExceptionFromError(env, ret);
}
LogStr("wc_MlDsaKey_ImportKey(key=%p) = %d\n", key, ret);
if (priv != NULL && privIsCopy == JNI_TRUE) {
MLDSA_FORCE_ZERO(priv, privLen);
}
releaseByteArray(env, priv_object, priv, JNI_ABORT);
releaseByteArray(env, pub_object, pub, JNI_ABORT);
#else
(void)env;
(void)this;
(void)priv_object;
(void)pub_object;
throwNotCompiledInException(env);
#endif
}
JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_MlDsa_wc_1dilithium_1check_1key
(JNIEnv* env, jobject this)
{
#if (defined(HAVE_DILITHIUM) || defined(WOLFSSL_HAVE_MLDSA)) && \
defined(WC_JNI_MLDSA_HAVE_CHECK_KEY)
int ret = 0;
wc_MlDsaKey* key = NULL;
key = (wc_MlDsaKey*) getNativeStruct(env, this);
if ((*env)->ExceptionOccurred(env)) {
return;
}
if (key == NULL) {
ret = BAD_FUNC_ARG;
}
else {
ret = wc_MlDsaKey_CheckKey(key);
}
if (ret != 0) {
throwWolfCryptExceptionFromError(env, ret);
}
LogStr("wc_MlDsaKey_CheckKey(key=%p) = %d\n", key, ret);
#else
(void)env;
(void)this;
throwNotCompiledInException(env);
#endif
}
JNIEXPORT jbyteArray JNICALL Java_com_wolfssl_wolfcrypt_MlDsa_wc_1Dilithium_1PrivateKeyToDer
(JNIEnv* env, jobject this)
{
jbyteArray result = NULL;
#if (defined(HAVE_DILITHIUM) || defined(WOLFSSL_HAVE_MLDSA)) && \
defined(WC_JNI_MLDSA_HAVE_PRIV_KEY) && defined(WC_JNI_MLDSA_HAVE_ASN1)
int ret = 0;
wc_MlDsaKey* key = NULL;
byte* output = NULL;
word32 outputSz = 0;
word32 outputBufSz = 0;
key = (wc_MlDsaKey*) getNativeStruct(env, this);
if ((*env)->ExceptionOccurred(env)) {
return NULL;
}
if (key == NULL) {
throwWolfCryptExceptionFromError(env, BAD_FUNC_ARG);
return NULL;
}
/* Two-pass: first call with NULL output to get required size. */
PRIVATE_KEY_UNLOCK();
ret = wc_MlDsaKey_PrivateKeyToDer(key, NULL, 0);
PRIVATE_KEY_LOCK();
if (ret <= 0) {
throwWolfCryptExceptionFromError(env, ret);
return NULL;
}
outputSz = (word32)ret;
outputBufSz = outputSz;
output = (byte*)XMALLOC(outputSz, NULL, DYNAMIC_TYPE_TMP_BUFFER);
if (output == NULL) {
throwOutOfMemoryException(env, "Failed to allocate PKCS#8 buffer");
return NULL;
}
XMEMSET(output, 0, outputSz);
PRIVATE_KEY_UNLOCK();
ret = wc_MlDsaKey_PrivateKeyToDer(key, output, outputSz);
PRIVATE_KEY_LOCK();
if (ret > 0) {
result = (*env)->NewByteArray(env, ret);
if (result != NULL) {
(*env)->SetByteArrayRegion(env, result, 0, ret,
(const jbyte*)output);
}
else {
throwWolfCryptException(env, "Failed to allocate PKCS#8 DER");
}
}
else {
throwWolfCryptExceptionFromError(env, ret);
}
LogStr("wc_MlDsaKey_PrivateKeyToDer(key=%p) = %d\n", key, ret);
MLDSA_FORCE_ZERO(output, outputBufSz);
XFREE(output, NULL, DYNAMIC_TYPE_TMP_BUFFER);
#else
(void)env;
(void)this;
throwNotCompiledInException(env);
#endif
return result;
}
JNIEXPORT jboolean JNICALL Java_com_wolfssl_wolfcrypt_FeatureDetect_MlDsaLevelEnabled
(JNIEnv* env, jclass jcl, jint level)
{
(void)env;
(void)jcl;
#if defined(HAVE_DILITHIUM) || defined(WOLFSSL_HAVE_MLDSA)
jboolean enabled = JNI_FALSE;
wc_MlDsaKey* key = NULL;
key = (wc_MlDsaKey*)XMALLOC(sizeof(wc_MlDsaKey), NULL,
DYNAMIC_TYPE_TMP_BUFFER);
if (key != NULL) {
if (wc_MlDsaKey_Init(key, NULL, INVALID_DEVID) == 0) {
if (wc_MlDsaKey_SetParams(key, (byte)level) == 0) {
enabled = JNI_TRUE;
}
wc_MlDsaKey_Free(key);
}
XFREE(key, NULL, DYNAMIC_TYPE_TMP_BUFFER);
}
return enabled;
#else
(void)level;
return JNI_FALSE;
#endif
}