wolfcrypt-jni/jni/jni_dh.c

409 lines
11 KiB
C

/* jni_dh.c
*
* Copyright (C) 2006-2025 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 2 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/wolfcrypt/dh.h>
#include <com_wolfssl_wolfcrypt_Dh.h>
#include <wolfcrypt_jni_NativeStruct.h>
#include <wolfcrypt_jni_error.h>
/* #define WOLFCRYPT_JNI_DEBUG_ON */
#include <wolfcrypt_jni_debug.h>
#if !defined(WC_NO_RNG) && defined(NO_OLD_RNGNAME)
#define RNG WC_RNG
#endif
JNIEXPORT jlong JNICALL Java_com_wolfssl_wolfcrypt_Dh_mallocNativeStruct_1internal(
JNIEnv* env, jobject this)
{
#ifndef NO_DH
DhKey* dh = NULL;
dh = (DhKey*)XMALLOC(sizeof(DhKey), NULL, DYNAMIC_TYPE_TMP_BUFFER);
if (dh == NULL) {
throwOutOfMemoryException(env, "Failed to allocate Dh object");
}
else {
XMEMSET(dh, 0, sizeof(DhKey));
}
LogStr("new Dh() = %p\n", dh);
return (jlong)(uintptr_t)dh;
#else
throwNotCompiledInException(env);
return (jlong)0;
#endif
}
JNIEXPORT void JNICALL
Java_com_wolfssl_wolfcrypt_Dh_wc_1InitDhKey(
JNIEnv* env, jobject this)
{
#ifndef NO_DH
int ret = 0;
DhKey* key = (DhKey*) getNativeStruct(env, this);
if ((*env)->ExceptionOccurred(env)) {
/* getNativeStruct may throw exception */
return;
}
ret = wc_InitDhKey(key);
if (ret != 0) {
throwWolfCryptExceptionFromError(env, ret);
}
LogStr("wc_InitDhKey(key=%p)\n", key);
#else
throwNotCompiledInException(env);
#endif
}
JNIEXPORT void JNICALL
Java_com_wolfssl_wolfcrypt_Dh_wc_1FreeDhKey(
JNIEnv* env, jobject this)
{
#ifndef NO_DH
int ret = 0;
DhKey* key = (DhKey*) getNativeStruct(env, this);
if ((*env)->ExceptionOccurred(env)) {
/* getNativeStruct may throw exception */
return;
}
ret = wc_FreeDhKey(key);
if (ret != 0) {
throwWolfCryptExceptionFromError(env, ret);
}
LogStr("wc_FreeDhKey(key=%p)\n", key);
#else
throwNotCompiledInException(env);
#endif
}
JNIEXPORT void JNICALL
Java_com_wolfssl_wolfcrypt_Dh_wc_1DhSetKey(
JNIEnv* env, jobject this, jbyteArray p_object, jbyteArray g_object)
{
#ifndef NO_DH
int ret = 0;
DhKey* key = NULL;
byte* p = NULL;
byte* g = NULL;
word32 pSz = 0, gSz = 0;
key = (DhKey*) getNativeStruct(env, this);
if ((*env)->ExceptionOccurred(env)) {
/* getNativeStruct may throw exception, prevent throwing another */
return;
}
p = getByteArray(env, p_object);
pSz = getByteArrayLength(env, p_object);
g = getByteArray(env, g_object);
gSz = getByteArrayLength(env, g_object);
if (key == NULL || p == NULL || g == NULL) {
ret = BAD_FUNC_ARG;
}
else {
ret = wc_DhSetKey(key, p, pSz, g, gSz);
}
if (ret != 0) {
throwWolfCryptExceptionFromError(env, ret);
}
LogStr("wc_DhSetKey(key=%p, p, pSz, g, gSz) = %d\n", key, ret);
LogStr("p[%u]: [%p]\n", (word32)pSz, p);
LogHex((byte*) p, 0, pSz);
LogStr("g[%u]: [%p]\n", (word32)gSz, g);
LogHex((byte*) g, 0, gSz);
releaseByteArray(env, p_object, p, JNI_ABORT);
releaseByteArray(env, g_object, g, JNI_ABORT);
#else
throwNotCompiledInException(env);
#endif
}
JNIEXPORT void JNICALL
Java_com_wolfssl_wolfcrypt_Dh_wc_1DhGenerateKeyPair(
JNIEnv* env, jobject this, jobject rng_object, jint size)
{
#ifndef NO_DH
int ret = 0;
DhKey* key = NULL;
RNG* rng = NULL;
byte* priv = NULL;
byte* pub = NULL;
word32 privSz = size;
word32 pubSz = size;
int lBitPriv = 0, lBitPub = 0;
byte lBit[1] = { 0x00 };
int exceptionThrown = 0;
key = (DhKey*) getNativeStruct(env, this);
if ((*env)->ExceptionOccurred(env)) {
/* getNativeStruct may throw exception, prevent throwing another */
return;
}
rng = (RNG*) getNativeStruct(env, rng_object);
if ((*env)->ExceptionOccurred(env)) {
/* getNativeStruct may throw exception, prevent throwing another */
return;
}
if (key == NULL || rng == NULL || (size < 0)) {
ret = BAD_FUNC_ARG;
}
if (ret == 0) {
priv = XMALLOC(privSz, NULL, DYNAMIC_TYPE_TMP_BUFFER);
if (priv == NULL) {
throwOutOfMemoryException(env,
"Failed to allocate private key buffer");
return;
}
XMEMSET(priv, 0, privSz);
pub = XMALLOC(pubSz, NULL, DYNAMIC_TYPE_TMP_BUFFER);
if (pub == NULL) {
XFREE(priv, NULL, DYNAMIC_TYPE_TMP_BUFFER);
throwOutOfMemoryException(env,
"Failed to allocate public key buffer");
return;
}
XMEMSET(pub, 0, pubSz);
PRIVATE_KEY_UNLOCK();
ret = wc_DhGenerateKeyPair(key, rng, priv, &privSz, pub, &pubSz);
PRIVATE_KEY_LOCK();
}
if (ret == 0) {
/* keys should be positive, if leading bit is set, add zero byte */
if (priv[0] & 0x80) {
lBitPriv = 1;
}
if (pub[0] & 0x80) {
lBitPub = 1;
}
jbyteArray privateKey = (*env)->NewByteArray(env, lBitPriv + privSz);
jbyteArray publicKey = (*env)->NewByteArray(env, lBitPub + pubSz);
if (privateKey) {
if (lBitPriv) {
(*env)->SetByteArrayRegion(env, privateKey, 0, 1,
(const jbyte*)lBit);
(*env)->SetByteArrayRegion(env, privateKey, 1, privSz,
(const jbyte*)priv);
} else {
(*env)->SetByteArrayRegion(env, privateKey, 0, privSz,
(const jbyte*)priv);
}
setByteArrayMember(env, this, "privateKey", privateKey);
if ((*env)->ExceptionOccurred(env)) {
/* if exception raised, skip any additional JNI functions */
exceptionThrown = 1;
}
} else {
throwWolfCryptException(env, "Failed to allocate privateKey");
exceptionThrown = 1;
}
if (publicKey && (exceptionThrown == 0)) {
if (lBitPub) {
(*env)->SetByteArrayRegion(env, publicKey, 0, 1,
(const jbyte*)lBit);
(*env)->SetByteArrayRegion(env, publicKey, 1, pubSz,
(const jbyte*)pub);
} else {
(*env)->SetByteArrayRegion(env, publicKey, 0, pubSz,
(const jbyte*)pub);
}
setByteArrayMember(env, this, "publicKey", publicKey);
} else {
throwWolfCryptException(env, "Failed to allocate publicKey");
}
} else {
throwWolfCryptExceptionFromError(env, ret);
}
LogStr("wc_DhGenerateKeyPair(key, rng, priv, privSz, pub, pubSz) = %d\n",
ret);
LogStr("private[%u]: [%p]\n", privSz, priv);
LogHex(priv, 0, privSz);
LogStr("public[%u]: [%p]\n", pubSz, pub);
LogHex(pub, 0, pubSz);
if (priv != NULL) {
XMEMSET(priv, 0, privSz);
XFREE(priv, NULL, DYNAMIC_TYPE_TMP_BUFFER);
}
if (pub != NULL) {
XMEMSET(pub, 0, pubSz);
XFREE(pub, NULL, DYNAMIC_TYPE_TMP_BUFFER);
}
#else
throwNotCompiledInException(env);
#endif
}
JNIEXPORT void JNICALL
Java_com_wolfssl_wolfcrypt_Dh_wc_1DhCheckPubKey(
JNIEnv* env, jobject this, jbyteArray pub_object)
{
#ifndef NO_DH
int ret = 0;
DhKey* key = NULL;
byte* pub = NULL;
word32 pubSz = 0;
key = (DhKey*) getNativeStruct(env, this);
if ((*env)->ExceptionOccurred(env)) {
/* getNativeStruct may throw exception, prevent throwing another */
return;
}
pub = getByteArray(env, pub_object);
pubSz = getByteArrayLength(env, pub_object);
if (key == NULL || pub == NULL) {
ret = BAD_FUNC_ARG;
}
else {
ret = wc_DhCheckPubKey(key, pub, pubSz);
}
if (ret != 0) {
throwWolfCryptExceptionFromError(env, ret);
}
LogStr("wc_DhCheckPubKey(key=%p, pub, pubSz) = %d\n", key, ret);
LogStr("p[%u]: [%p]\n", (word32)pubSz, pub);
LogHex((byte*) pub, 0, pubSz);
releaseByteArray(env, pub_object, pub, JNI_ABORT);
#else
throwNotCompiledInException(env);
#endif
}
JNIEXPORT jbyteArray JNICALL
Java_com_wolfssl_wolfcrypt_Dh_wc_1DhAgree(
JNIEnv* env, jobject this, jbyteArray priv_object, jbyteArray pub_object)
{
jbyteArray result = NULL;
#ifndef NO_DH
int ret = 0;
DhKey* key = NULL;
byte* priv = NULL;
byte* pub = NULL;
byte* secret = NULL;
word32 privSz = 0, pubSz = 0, secretSz = 0;
key = (DhKey*) getNativeStruct(env, this);
if ((*env)->ExceptionOccurred(env)) {
/* getNativeStruct may throw exception, prevent throwing another */
return NULL;
}
priv = getByteArray(env, priv_object);
privSz = getByteArrayLength(env, priv_object);
pub = getByteArray(env, pub_object);
pubSz = getByteArrayLength(env, pub_object);
secretSz = pubSz;
secret = XMALLOC(pubSz, NULL, DYNAMIC_TYPE_TMP_BUFFER);
if (secret == NULL) {
throwOutOfMemoryException(env, "Failed to allocate private key buffer");
releaseByteArray(env, priv_object, priv, JNI_ABORT);
releaseByteArray(env, pub_object, pub, JNI_ABORT);
return result;
}
XMEMSET(secret, 0, pubSz);
if (key == NULL || priv == NULL || pub == NULL) {
ret = BAD_FUNC_ARG;
}
else {
PRIVATE_KEY_UNLOCK();
ret = wc_DhAgree(key, secret, &secretSz, priv, privSz, pub, pubSz);
PRIVATE_KEY_LOCK();
}
if (ret == 0) {
result = (*env)->NewByteArray(env, secretSz);
if (result) {
(*env)->SetByteArrayRegion(env, result, 0, secretSz,
(const jbyte*)secret);
} else {
throwWolfCryptException(env, "Failed to allocate shared secret");
}
} else {
throwWolfCryptExceptionFromError(env, ret);
}
LogStr("wc_DhAgree(key, secret, secretSz, priv, privSz, pub, pubSz) = %d\n",
ret);
LogStr("secret[%u]: [%p]\n", secretSz, secret);
LogHex(secret, 0, secretSz);
if (secret != NULL) {
XMEMSET(secret, 0, secretSz);
XFREE(secret, NULL, DYNAMIC_TYPE_TMP_BUFFER);
}
releaseByteArray(env, priv_object, priv, JNI_ABORT);
releaseByteArray(env, pub_object, pub, JNI_ABORT);
#else
throwNotCompiledInException(env);
#endif
return result;
}