1172 lines
30 KiB
C
1172 lines
30 KiB
C
/* jni_ecc.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/ecc.h>
|
|
#include <wolfssl/wolfcrypt/asn.h>
|
|
|
|
#include <com_wolfssl_wolfcrypt_Ecc.h>
|
|
#include <wolfcrypt_jni_NativeStruct.h>
|
|
#include <wolfcrypt_jni_error.h>
|
|
|
|
/* #define WOLFCRYPT_JNI_DEBUG_ON */
|
|
#include <wolfcrypt_jni_debug.h>
|
|
|
|
#define MAX_ECC_PRIVATE_DER_SZ 128
|
|
|
|
#if !defined(WC_NO_RNG) && defined(NO_OLD_RNGNAME)
|
|
#define RNG WC_RNG
|
|
#endif
|
|
|
|
JNIEXPORT jlong JNICALL
|
|
Java_com_wolfssl_wolfcrypt_Ecc_mallocNativeStruct(
|
|
JNIEnv* env, jobject this)
|
|
{
|
|
#ifdef HAVE_ECC
|
|
ecc_key* ecc = NULL;
|
|
|
|
ecc = (ecc_key*)XMALLOC(sizeof(ecc_key), NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
if (ecc == NULL) {
|
|
throwOutOfMemoryException(env, "Failed to allocate Ecc object");
|
|
}
|
|
else {
|
|
XMEMSET(ecc, 0, sizeof(ecc_key));
|
|
}
|
|
|
|
LogStr("new Ecc() = %p\n", ecc);
|
|
|
|
return (jlong)(uintptr_t)ecc;
|
|
#else
|
|
throwNotCompiledInException(env);
|
|
|
|
return (jlong)0;
|
|
#endif
|
|
}
|
|
|
|
JNIEXPORT void JNICALL
|
|
Java_com_wolfssl_wolfcrypt_Ecc_wc_1ecc_1init(
|
|
JNIEnv* env, jobject this)
|
|
{
|
|
#ifdef HAVE_ECC
|
|
int ret = 0;
|
|
ecc_key* ecc = (ecc_key*) getNativeStruct(env, this);
|
|
if ((*env)->ExceptionOccurred(env)) {
|
|
/* getNativeStruct may throw exception, prevent throwing another */
|
|
return;
|
|
}
|
|
|
|
/* Checks ecc for NULL internally */
|
|
ret = wc_ecc_init(ecc);
|
|
if (ret != 0) {
|
|
throwWolfCryptExceptionFromError(env, ret);
|
|
}
|
|
|
|
LogStr("ecc_init(ecc=%p) = %d\n", ecc, ret);
|
|
#else
|
|
throwNotCompiledInException(env);
|
|
#endif
|
|
}
|
|
|
|
JNIEXPORT void JNICALL
|
|
Java_com_wolfssl_wolfcrypt_Ecc_wc_1ecc_1free(
|
|
JNIEnv* env, jobject this)
|
|
{
|
|
#ifdef HAVE_ECC
|
|
ecc_key* ecc = (ecc_key*) getNativeStruct(env, this);
|
|
if ((*env)->ExceptionOccurred(env)) {
|
|
/* getNativeStruct may throw exception */
|
|
return;
|
|
}
|
|
|
|
/* Checks ecc for NULL internally */
|
|
wc_ecc_free(ecc);
|
|
|
|
LogStr("ecc_free(ecc=%p)\n", ecc);
|
|
#else
|
|
throwNotCompiledInException(env);
|
|
#endif
|
|
}
|
|
|
|
JNIEXPORT void JNICALL
|
|
Java_com_wolfssl_wolfcrypt_Ecc_wc_1ecc_1make_1key(
|
|
JNIEnv* env, jobject this, jobject rng_object, jint size)
|
|
{
|
|
#ifdef HAVE_ECC
|
|
int ret = 0;
|
|
ecc_key* ecc = NULL;
|
|
RNG* rng = NULL;
|
|
|
|
ecc = (ecc_key*) 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 (ecc == NULL || rng == NULL) {
|
|
ret = BAD_FUNC_ARG;
|
|
}
|
|
else {
|
|
ret = wc_ecc_make_key(rng, size, ecc);
|
|
}
|
|
|
|
if (ret != 0) {
|
|
throwWolfCryptExceptionFromError(env, ret);
|
|
}
|
|
|
|
LogStr("ecc_make_key(rng, size, ecc=%p) = %d\n", ecc, ret);
|
|
#else
|
|
throwNotCompiledInException(env);
|
|
#endif
|
|
}
|
|
|
|
JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_Ecc_wc_1ecc_1make_1key_1ex
|
|
(JNIEnv* env, jobject this, jobject rng_object, jint size,
|
|
jstring curveName)
|
|
{
|
|
#ifdef HAVE_ECC
|
|
int ret = 0;
|
|
ecc_key* ecc = NULL;
|
|
RNG* rng = NULL;
|
|
const char* name = (*env)->GetStringUTFChars(env, curveName, 0);
|
|
|
|
ecc = (ecc_key*) getNativeStruct(env, this);
|
|
if ((*env)->ExceptionOccurred(env)) {
|
|
/* getNativeStruct may throw exception, prevent throwing another */
|
|
(*env)->ReleaseStringUTFChars(env, curveName, name);
|
|
return;
|
|
}
|
|
|
|
rng = (RNG*) getNativeStruct(env, rng_object);
|
|
if ((*env)->ExceptionOccurred(env)) {
|
|
/* getNativeStruct may throw exception, prevent throwing another */
|
|
(*env)->ReleaseStringUTFChars(env, curveName, name);
|
|
return;
|
|
}
|
|
|
|
if (ecc == NULL || rng == NULL || curveName == NULL || name == NULL) {
|
|
ret = BAD_FUNC_ARG;
|
|
}
|
|
|
|
if (ret == 0) {
|
|
ret = wc_ecc_get_curve_id_from_name(name);
|
|
}
|
|
|
|
if (name != NULL) {
|
|
(*env)->ReleaseStringUTFChars(env, curveName, name);
|
|
}
|
|
|
|
if (ret < 0) {
|
|
throwWolfCryptException(env, "ECC curve unsupported or not enabled");
|
|
|
|
} else {
|
|
ret = wc_ecc_make_key_ex(rng, size, ecc, ret);
|
|
|
|
if (ret < 0) {
|
|
throwWolfCryptExceptionFromError(env, ret);
|
|
}
|
|
}
|
|
|
|
LogStr("ecc_make_key_ex(rng, size, ecc=%p) = %d\n", ecc, ret);
|
|
#else
|
|
throwNotCompiledInException(env);
|
|
#endif
|
|
}
|
|
|
|
JNIEXPORT void JNICALL
|
|
Java_com_wolfssl_wolfcrypt_Ecc_wc_1ecc_1check_1key(
|
|
JNIEnv* env, jobject this)
|
|
{
|
|
#ifdef HAVE_ECC
|
|
int ret = 0;
|
|
ecc_key* ecc = NULL;
|
|
|
|
ecc = (ecc_key*) getNativeStruct(env, this);
|
|
if ((*env)->ExceptionOccurred(env)) {
|
|
/* getNativeStruct may throw exception, prevent throwing another */
|
|
return;
|
|
}
|
|
|
|
if (ecc == NULL) {
|
|
ret = BAD_FUNC_ARG;
|
|
}
|
|
else {
|
|
ret = wc_ecc_check_key(ecc);
|
|
}
|
|
|
|
if (ret != 0) {
|
|
throwWolfCryptExceptionFromError(env, ret);
|
|
}
|
|
|
|
LogStr("wc_ecc_check_key(ecc=%p) = %d\n", ecc, ret);
|
|
#else
|
|
throwNotCompiledInException(env);
|
|
#endif
|
|
}
|
|
|
|
JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_Ecc_wc_1ecc_1import_1private
|
|
(JNIEnv* env, jobject this, jbyteArray priv_object,
|
|
jbyteArray pub_object, jstring curveName)
|
|
{
|
|
#if defined(HAVE_ECC) && defined(HAVE_ECC_KEY_IMPORT)
|
|
int ret = 0;
|
|
word32 idx = 0;
|
|
ecc_key* ecc = NULL;
|
|
byte* priv = NULL;
|
|
byte* pub = NULL;
|
|
word32 privSz = 0, pubSz = 0;
|
|
const char* name = NULL;
|
|
|
|
ecc = (ecc_key*) getNativeStruct(env, this);
|
|
if ((*env)->ExceptionOccurred(env)) {
|
|
/* getNativeStruct may throw exception, prevent throwing another */
|
|
return;
|
|
}
|
|
|
|
priv = getByteArray(env, priv_object);
|
|
privSz = getByteArrayLength(env, priv_object);
|
|
pub = getByteArray(env, pub_object);
|
|
pubSz = getByteArrayLength(env, pub_object);
|
|
|
|
/* pub may be null if only importing private key */
|
|
if (ecc == NULL || priv == NULL) {
|
|
ret = BAD_FUNC_ARG;
|
|
}
|
|
|
|
if (ret == 0) {
|
|
/* detect, and later skip, leading zero byte */
|
|
if (priv[0] == 0) {
|
|
idx = 1;
|
|
}
|
|
|
|
if (curveName != NULL) {
|
|
name = (*env)->GetStringUTFChars(env, curveName, 0);
|
|
ret = wc_ecc_get_curve_id_from_name(name);
|
|
(*env)->ReleaseStringUTFChars(env, curveName, name);
|
|
|
|
if (ret > 0) {
|
|
/* import with curve id, ret stores curve id */
|
|
ret = wc_ecc_import_private_key_ex(priv + idx, privSz - idx,
|
|
pub, pubSz, ecc, ret);
|
|
} else {
|
|
/* unsupported curve name */
|
|
ret = BAD_FUNC_ARG;
|
|
}
|
|
|
|
} else {
|
|
ret = wc_ecc_import_private_key(priv + idx, privSz - idx, pub,
|
|
pubSz, ecc);
|
|
}
|
|
}
|
|
|
|
if (ret != 0) {
|
|
throwWolfCryptExceptionFromError(env, ret);
|
|
}
|
|
|
|
LogStr("wc_ecc_import_private_key(ecc=%p) = %d\n", ecc, ret);
|
|
|
|
releaseByteArray(env, priv_object, priv, JNI_ABORT);
|
|
releaseByteArray(env, pub_object, pub, JNI_ABORT);
|
|
#else
|
|
throwNotCompiledInException(env);
|
|
#endif
|
|
}
|
|
|
|
JNIEXPORT jbyteArray JNICALL
|
|
Java_com_wolfssl_wolfcrypt_Ecc_wc_1ecc_1export_1private(
|
|
JNIEnv* env, jobject this)
|
|
{
|
|
jbyteArray result = NULL;
|
|
|
|
#ifdef HAVE_ECC_KEY_EXPORT
|
|
int ret = 0;
|
|
ecc_key* ecc = NULL;
|
|
byte* output = NULL;
|
|
word32 outputSz = 0;
|
|
word32 outputBufSz = 0;
|
|
|
|
ecc = (ecc_key*) getNativeStruct(env, this);
|
|
if ((*env)->ExceptionOccurred(env)) {
|
|
/* getNativeStruct may throw exception, prevent throwing another */
|
|
return NULL;
|
|
}
|
|
|
|
if (ecc == NULL) {
|
|
ret = BAD_FUNC_ARG;
|
|
}
|
|
|
|
if (ret == 0) {
|
|
outputSz = wc_ecc_size(ecc);
|
|
outputBufSz = outputSz;
|
|
|
|
output = (byte*)XMALLOC(outputSz, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
if (output == NULL) {
|
|
ret = MEMORY_E;
|
|
}
|
|
else {
|
|
XMEMSET(output, 0, sizeof(outputSz));
|
|
}
|
|
}
|
|
|
|
if (ret == 0) {
|
|
PRIVATE_KEY_UNLOCK();
|
|
ret = wc_ecc_export_private_only(ecc, output, &outputSz);
|
|
PRIVATE_KEY_LOCK();
|
|
}
|
|
|
|
if (ret == 0) {
|
|
result = (*env)->NewByteArray(env, outputSz);
|
|
|
|
if (result) {
|
|
(*env)->SetByteArrayRegion(env, result, 0, outputSz,
|
|
(const jbyte*) output);
|
|
} else {
|
|
throwWolfCryptException(env, "Failed to allocate ECC key");
|
|
}
|
|
} else {
|
|
throwWolfCryptExceptionFromError(env, ret);
|
|
}
|
|
|
|
LogStr("wc_ecc_export_private_only(ecc=%p, output=%p, outputSz) = %d\n",
|
|
ecc, output, ret);
|
|
LogStr("output[%u]: [%p]\n", (word32)outputSz, output);
|
|
LogHex((byte*) output, 0, outputSz);
|
|
|
|
if (output != NULL) {
|
|
XMEMSET(output, 0, outputBufSz);
|
|
XFREE(output, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
}
|
|
#else
|
|
throwNotCompiledInException(env);
|
|
#endif
|
|
|
|
return result;
|
|
}
|
|
|
|
JNIEXPORT void JNICALL
|
|
Java_com_wolfssl_wolfcrypt_Ecc_wc_1ecc_1import_1x963(
|
|
JNIEnv* env, jobject this, jbyteArray key_object)
|
|
{
|
|
#ifdef HAVE_ECC_KEY_IMPORT
|
|
int ret = 0;
|
|
ecc_key* ecc = NULL;
|
|
byte* key = NULL;
|
|
word32 keySz = 0;
|
|
|
|
ecc = (ecc_key*) getNativeStruct(env, this);
|
|
if ((*env)->ExceptionOccurred(env)) {
|
|
/* getNativeStruct may throw exception, prevent throwing another */
|
|
return;
|
|
}
|
|
|
|
key = getByteArray(env, key_object);
|
|
keySz = getByteArrayLength(env, key_object);
|
|
|
|
if (ecc == NULL || key == NULL) {
|
|
ret = BAD_FUNC_ARG;
|
|
}
|
|
|
|
if (ret == 0) {
|
|
ret = wc_ecc_import_x963(key, keySz, ecc);
|
|
}
|
|
|
|
if (ret != 0) {
|
|
throwWolfCryptExceptionFromError(env, ret);
|
|
}
|
|
|
|
LogStr("wc_ecc_import_x963(key=%p, keySz=%d, ecc=%p) = %d\n",
|
|
key, (int)keySz, ecc, ret);
|
|
|
|
releaseByteArray(env, key_object, key, JNI_ABORT);
|
|
#else
|
|
throwNotCompiledInException(env);
|
|
#endif
|
|
}
|
|
|
|
JNIEXPORT jbyteArray JNICALL
|
|
Java_com_wolfssl_wolfcrypt_Ecc_wc_1ecc_1export_1x963(
|
|
JNIEnv* env, jobject this)
|
|
{
|
|
jbyteArray result = NULL;
|
|
|
|
#ifdef HAVE_ECC_KEY_EXPORT
|
|
int ret = 0;
|
|
ecc_key* ecc = NULL;
|
|
byte* output = NULL;
|
|
word32 outputSz = 0;
|
|
|
|
ecc = (ecc_key*) getNativeStruct(env, this);
|
|
if ((*env)->ExceptionOccurred(env)) {
|
|
/* getNativeStruct may throw exception, prevent throwing another */
|
|
return NULL;
|
|
}
|
|
|
|
if (ecc == NULL) {
|
|
ret = BAD_FUNC_ARG;
|
|
}
|
|
|
|
/* get size */
|
|
if (ret == 0) {
|
|
PRIVATE_KEY_UNLOCK();
|
|
ret = wc_ecc_export_x963(ecc, NULL, &outputSz);
|
|
PRIVATE_KEY_LOCK();
|
|
if (ret == LENGTH_ONLY_E) {
|
|
ret = 0;
|
|
}
|
|
}
|
|
|
|
if (ret == 0) {
|
|
output = (byte*)XMALLOC(outputSz, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
if (output == NULL) {
|
|
ret = MEMORY_E;
|
|
}
|
|
else {
|
|
XMEMSET(output, 0, outputSz);
|
|
}
|
|
}
|
|
|
|
if (ret == 0) {
|
|
PRIVATE_KEY_UNLOCK();
|
|
ret = wc_ecc_export_x963(ecc, output, &outputSz);
|
|
PRIVATE_KEY_LOCK();
|
|
}
|
|
|
|
if (ret == 0) {
|
|
result = (*env)->NewByteArray(env, outputSz);
|
|
|
|
if (result) {
|
|
(*env)->SetByteArrayRegion(env, result, 0, outputSz,
|
|
(const jbyte*) output);
|
|
} else {
|
|
throwWolfCryptException(env, "Failed to create new ECC key array");
|
|
}
|
|
} else {
|
|
throwWolfCryptExceptionFromError(env, ret);
|
|
}
|
|
|
|
LogStr("wc_ecc_export_x963(ecc=%p, output=%p, outputSz) = %d\n",
|
|
ecc, output, ret);
|
|
LogStr("output[%u]: [%p]\n", (word32)outputSz, output);
|
|
LogHex((byte*) output, 0, outputSz);
|
|
|
|
if (output != NULL) {
|
|
XFREE(output, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
}
|
|
#else
|
|
throwNotCompiledInException(env);
|
|
#endif
|
|
|
|
return result;
|
|
}
|
|
|
|
JNIEXPORT void JNICALL
|
|
Java_com_wolfssl_wolfcrypt_Ecc_wc_1EccPrivateKeyDecode(
|
|
JNIEnv* env, jobject this, jbyteArray key_object)
|
|
{
|
|
#if defined(HAVE_ECC) && !defined(NO_ASN)
|
|
int ret = 0;
|
|
word32 idx = 0;
|
|
ecc_key* ecc = NULL;
|
|
byte* key = NULL;
|
|
word32 keySz = 0;
|
|
|
|
ecc = (ecc_key*) getNativeStruct(env, this);
|
|
if ((*env)->ExceptionOccurred(env)) {
|
|
/* getNativeStruct may throw exception, prevent throwing another */
|
|
return;
|
|
}
|
|
|
|
key = getByteArray(env, key_object);
|
|
keySz = getByteArrayLength(env, key_object);
|
|
|
|
if (ecc == NULL || key == NULL) {
|
|
ret = BAD_FUNC_ARG;
|
|
}
|
|
else {
|
|
ret = wc_EccPrivateKeyDecode(key, &idx, ecc, keySz);
|
|
}
|
|
|
|
if (ret != 0) {
|
|
throwWolfCryptExceptionFromError(env, ret);
|
|
}
|
|
|
|
LogStr("wc_EccPrivateKeyDecode(key=%p, keySz=%d, ecc=%p) = %d\n",
|
|
key, (int)keySz, ecc, ret);
|
|
|
|
releaseByteArray(env, key_object, key, JNI_ABORT);
|
|
#else
|
|
throwNotCompiledInException(env);
|
|
#endif
|
|
}
|
|
|
|
JNIEXPORT jbyteArray JNICALL
|
|
Java_com_wolfssl_wolfcrypt_Ecc_wc_1EccKeyToDer(
|
|
JNIEnv* env, jobject this)
|
|
{
|
|
jbyteArray result = NULL;
|
|
|
|
#if defined(HAVE_ECC) && !defined(NO_ASN) && defined(WOLFSSL_KEY_GEN)
|
|
int ret = 0;
|
|
ecc_key* ecc = NULL;
|
|
byte* output = NULL;
|
|
word32 outputSz = 256;
|
|
word32 outputBufSz = 0;
|
|
|
|
ecc = (ecc_key*) getNativeStruct(env, this);
|
|
if ((*env)->ExceptionOccurred(env)) {
|
|
/* getNativeStruct may throw exception, prevent throwing another */
|
|
ret = BAD_FUNC_ARG;
|
|
}
|
|
|
|
if (ret == 0 && ecc == NULL) {
|
|
ret = BAD_FUNC_ARG;
|
|
}
|
|
|
|
if (ret == 0) {
|
|
output = (byte*)XMALLOC(outputSz, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
if (output == NULL) {
|
|
ret = MEMORY_E;
|
|
}
|
|
else {
|
|
XMEMSET(output, 0, outputSz);
|
|
}
|
|
}
|
|
|
|
if (ret == 0) {
|
|
outputBufSz = outputSz;
|
|
|
|
ret = wc_EccKeyToDer(ecc, output, outputSz);
|
|
if (ret >= 0) {
|
|
outputSz = ret;
|
|
ret = 0;
|
|
}
|
|
}
|
|
|
|
if (ret == 0) {
|
|
result = (*env)->NewByteArray(env, outputSz);
|
|
|
|
if (result) {
|
|
(*env)->SetByteArrayRegion(env, result, 0, outputSz,
|
|
(const jbyte*) output);
|
|
} else {
|
|
throwWolfCryptException(env, "Failed to allocate ECC key");
|
|
}
|
|
} else {
|
|
throwWolfCryptExceptionFromError(env, ret);
|
|
}
|
|
|
|
LogStr("wc_EccKeyToDer(ecc = %p, output=%p, outputSz) = %d\n",
|
|
ecc, output, ret);
|
|
LogStr("output[%u]: [%p]\n", outputSz, output);
|
|
LogHex((byte*) output, 0, outputSz);
|
|
|
|
if (output != NULL) {
|
|
XMEMSET(output, 0, outputBufSz);
|
|
XFREE(output, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
}
|
|
#else
|
|
throwNotCompiledInException(env);
|
|
#endif
|
|
|
|
return result;
|
|
}
|
|
|
|
JNIEXPORT void JNICALL
|
|
Java_com_wolfssl_wolfcrypt_Ecc_wc_1EccPublicKeyDecode(
|
|
JNIEnv* env, jobject this, jbyteArray key_object)
|
|
{
|
|
#if defined(HAVE_ECC) && !defined(NO_ASN)
|
|
int ret = 0;
|
|
word32 idx = 0;
|
|
ecc_key* ecc = NULL;
|
|
byte* key = NULL;
|
|
word32 keySz = 0;
|
|
|
|
ecc = (ecc_key*) getNativeStruct(env, this);
|
|
if ((*env)->ExceptionOccurred(env)) {
|
|
/* getNativeStruct may throw exception, prevent throwing another */
|
|
return;
|
|
}
|
|
|
|
key = getByteArray(env, key_object);
|
|
keySz = getByteArrayLength(env, key_object);
|
|
|
|
if (ecc == NULL || key == NULL) {
|
|
ret = BAD_FUNC_ARG;
|
|
}
|
|
else {
|
|
ret = wc_EccPublicKeyDecode(key, &idx, ecc, keySz);
|
|
}
|
|
|
|
if (ret != 0) {
|
|
throwWolfCryptExceptionFromError(env, ret);
|
|
}
|
|
|
|
LogStr("wc_EccPublicKeyDecode(key = %p, keySz = %d, ecc = %p) = %d\n",
|
|
key, (int)keySz, ecc, ret);
|
|
|
|
releaseByteArray(env, key_object, key, JNI_ABORT);
|
|
#else
|
|
throwNotCompiledInException(env);
|
|
#endif
|
|
}
|
|
|
|
JNIEXPORT jbyteArray JNICALL
|
|
Java_com_wolfssl_wolfcrypt_Ecc_wc_1EccPublicKeyToDer(
|
|
JNIEnv* env, jobject this)
|
|
{
|
|
jbyteArray result = NULL;
|
|
|
|
#if !defined(NO_ASN) && (defined(WOLFSSL_CERT_GEN) || defined(WOLFSSL_KEY_GEN))
|
|
int ret = 0;
|
|
ecc_key* ecc = NULL;
|
|
byte* output = NULL;
|
|
word32 outputSz = 0;
|
|
|
|
ecc = (ecc_key*) getNativeStruct(env, this);
|
|
if ((*env)->ExceptionOccurred(env)) {
|
|
/* getNativeStruct may throw exception, prevent throwing another */
|
|
ret = BAD_FUNC_ARG;
|
|
}
|
|
|
|
if (ret == 0 && ecc == NULL) {
|
|
ret = BAD_FUNC_ARG;
|
|
}
|
|
|
|
/* Calculate ECC DER size */
|
|
if (ret == 0) {
|
|
ret = wc_EccPublicKeyDerSize(ecc, 1);
|
|
if (ret > 0) {
|
|
outputSz = ret;
|
|
ret = 0;
|
|
}
|
|
}
|
|
|
|
if (ret == 0) {
|
|
output = (byte*)XMALLOC(outputSz, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
if (output == NULL) {
|
|
ret = MEMORY_E;
|
|
}
|
|
else {
|
|
XMEMSET(output, 0, outputSz);
|
|
}
|
|
}
|
|
|
|
if (ret == 0) {
|
|
ret = wc_EccPublicKeyToDer(ecc, output, outputSz, 1);
|
|
if (ret > 0) {
|
|
outputSz = ret;
|
|
ret = 0;
|
|
}
|
|
}
|
|
|
|
if (ret == 0) {
|
|
result = (*env)->NewByteArray(env, outputSz);
|
|
|
|
if (result) {
|
|
(*env)->SetByteArrayRegion(env, result, 0, outputSz,
|
|
(const jbyte*) output);
|
|
} else {
|
|
throwWolfCryptException(env, "Failed to allocate ECC DER key");
|
|
}
|
|
} else {
|
|
throwWolfCryptExceptionFromError(env, ret);
|
|
}
|
|
|
|
LogStr("wc_EccPublicKeyToDer(ecc = %p, output = %p, outputSz = %d) = %d\n",
|
|
ecc, output, (int)outputSz, ret);
|
|
LogStr("output[%u]: [%p]\n", outputSz, output);
|
|
LogHex((byte*) output, 0, outputSz);
|
|
|
|
if (output != NULL) {
|
|
XFREE(output, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
}
|
|
#else
|
|
throwNotCompiledInException(env);
|
|
#endif
|
|
|
|
return result;
|
|
}
|
|
|
|
JNIEXPORT jbyteArray JNICALL
|
|
Java_com_wolfssl_wolfcrypt_Ecc_wc_1ecc_1shared_1secret(
|
|
JNIEnv* env, jobject this, jobject pub_object, jobject rng_object)
|
|
{
|
|
jbyteArray result = NULL;
|
|
|
|
#ifdef HAVE_ECC_DHE
|
|
int ret = 0;
|
|
RNG* rng = NULL;
|
|
ecc_key* ecc = NULL;
|
|
ecc_key* pub = NULL;
|
|
byte* output = NULL;
|
|
word32 outputSz = 0;
|
|
word32 outputBufSz = 0;
|
|
|
|
ecc = (ecc_key*) getNativeStruct(env, this);
|
|
if ((*env)->ExceptionOccurred(env)) {
|
|
/* getNativeStruct may throw exception, prevent throwing another */
|
|
return NULL;
|
|
}
|
|
|
|
rng = (RNG*) getNativeStruct(env, rng_object);
|
|
if ((*env)->ExceptionOccurred(env)) {
|
|
/* getNativeStruct may throw exception, prevent throwing another */
|
|
return NULL;
|
|
}
|
|
|
|
pub = (ecc_key*) getNativeStruct(env, pub_object);
|
|
if ((*env)->ExceptionOccurred(env)) {
|
|
/* getNativeStruct may throw exception, prevent throwing another */
|
|
return NULL;
|
|
}
|
|
|
|
if (ecc == NULL || rng == NULL || pub == NULL) {
|
|
ret = BAD_FUNC_ARG;
|
|
}
|
|
|
|
if (ret == 0) {
|
|
outputSz = wc_ecc_size(ecc);
|
|
outputBufSz = outputSz;
|
|
output = (byte*)XMALLOC(outputSz, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
if (output == NULL) {
|
|
ret = MEMORY_E;
|
|
}
|
|
else {
|
|
XMEMSET(output, 0, outputSz);
|
|
}
|
|
}
|
|
|
|
#if defined(ECC_TIMING_RESISTANT) && (!defined(HAVE_FIPS) || \
|
|
(!defined(HAVE_FIPS_VERSION) || (HAVE_FIPS_VERSION != 2))) && \
|
|
!defined(HAVE_SELFTEST)
|
|
if (ret == 0) {
|
|
ret = wc_ecc_set_rng(ecc, rng);
|
|
}
|
|
#else
|
|
(void)rng;
|
|
#endif
|
|
|
|
if (ret == 0) {
|
|
PRIVATE_KEY_UNLOCK();
|
|
ret = wc_ecc_shared_secret(ecc, pub, output, &outputSz);
|
|
PRIVATE_KEY_LOCK();
|
|
}
|
|
|
|
if (ret == 0) {
|
|
result = (*env)->NewByteArray(env, outputSz);
|
|
|
|
if (result) {
|
|
(*env)->SetByteArrayRegion(env, result, 0, outputSz,
|
|
(const jbyte*) output);
|
|
} else {
|
|
throwWolfCryptException(env, "Failed to allocate shared secret");
|
|
}
|
|
} else {
|
|
throwWolfCryptExceptionFromError(env, ret);
|
|
}
|
|
|
|
LogStr("wc_ecc_shared_secret(priv, pub, output=%p, outputSz) = %d\n",
|
|
output, ret);
|
|
LogStr("output[%u]: [%p]\n", (word32)outputSz, output);
|
|
LogHex((byte*) output, 0, outputSz);
|
|
|
|
if (output != NULL) {
|
|
XMEMSET(output, 0, outputBufSz);
|
|
XFREE(output, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
}
|
|
#else
|
|
throwNotCompiledInException(env);
|
|
#endif
|
|
|
|
return result;
|
|
}
|
|
|
|
JNIEXPORT jbyteArray JNICALL
|
|
Java_com_wolfssl_wolfcrypt_Ecc_wc_1ecc_1sign_1hash(
|
|
JNIEnv* env, jobject this, jbyteArray hash_object, jobject rng_object)
|
|
{
|
|
jbyteArray result = NULL;
|
|
|
|
#ifdef HAVE_ECC_SIGN
|
|
int ret = 0;
|
|
ecc_key* ecc = NULL;
|
|
RNG* rng = NULL;
|
|
byte* hash = NULL;
|
|
byte* signature = NULL;
|
|
word32 hashSz = 0;
|
|
word32 expectedSigSz = 0;
|
|
word32 signatureSz = 0;
|
|
word32 signatureBufSz = 0;
|
|
|
|
ecc = (ecc_key*) getNativeStruct(env, this);
|
|
if ((*env)->ExceptionOccurred(env)) {
|
|
/* getNativeStruct may throw exception, prevent throwing another */
|
|
return NULL;
|
|
}
|
|
|
|
rng = (RNG*) getNativeStruct(env, rng_object);
|
|
if ((*env)->ExceptionOccurred(env)) {
|
|
/* getNativeStruct may throw exception, prevent throwing another */
|
|
return NULL;
|
|
}
|
|
|
|
hash = getByteArray(env, hash_object);
|
|
hashSz = getByteArrayLength(env, hash_object);
|
|
|
|
if (ecc == NULL || rng == NULL || hash == NULL) {
|
|
ret = BAD_FUNC_ARG;
|
|
}
|
|
|
|
if (ret == 0) {
|
|
expectedSigSz = wc_ecc_sig_size(ecc);
|
|
signatureSz = expectedSigSz;
|
|
signatureBufSz = signatureSz;
|
|
|
|
signature = (byte*)XMALLOC(signatureSz, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
if (signature == NULL) {
|
|
ret = MEMORY_E;
|
|
}
|
|
else {
|
|
XMEMSET(signature, 0, signatureSz);
|
|
}
|
|
}
|
|
|
|
if (ret == 0) {
|
|
ret = wc_ecc_sign_hash(hash, hashSz, signature, &signatureSz, rng, ecc);
|
|
}
|
|
|
|
if (ret == 0) {
|
|
/* Sanity check on wc_ecc_sig_size() and actual length */
|
|
if (expectedSigSz < signatureSz) {
|
|
ret = BUFFER_E;
|
|
throwWolfCryptException(env,
|
|
"wc_ecc_sig_size() less than actual sig size");
|
|
}
|
|
}
|
|
|
|
if (ret == 0) {
|
|
result = (*env)->NewByteArray(env, signatureSz);
|
|
|
|
if (result != NULL) {
|
|
(*env)->SetByteArrayRegion(env, result, 0, signatureSz,
|
|
(const jbyte*)signature);
|
|
} else {
|
|
releaseByteArray(env, hash_object, hash, JNI_ABORT);
|
|
throwWolfCryptException(env, "Failed to allocate signature");
|
|
return NULL;
|
|
}
|
|
} else {
|
|
releaseByteArray(env, hash_object, hash, JNI_ABORT);
|
|
throwWolfCryptExceptionFromError(env, ret);
|
|
return NULL;
|
|
}
|
|
|
|
LogStr("wc_ecc_sign_hash(input, inSz, output, &outSz, rng, ecc) = %d\n",
|
|
ret);
|
|
|
|
if (signature != NULL) {
|
|
LogStr("signature[%u]: [%p]\n", (word32)signatureSz, signature);
|
|
LogHex((byte*) signature, 0, signatureSz);
|
|
|
|
XMEMSET(signature, 0, signatureBufSz);
|
|
XFREE(signature, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
}
|
|
|
|
releaseByteArray(env, hash_object, hash, JNI_ABORT);
|
|
#else
|
|
throwNotCompiledInException(env);
|
|
#endif
|
|
|
|
return result;
|
|
}
|
|
|
|
JNIEXPORT jboolean JNICALL
|
|
Java_com_wolfssl_wolfcrypt_Ecc_wc_1ecc_1verify_1hash(
|
|
JNIEnv* env, jobject this, jbyteArray hash_object,
|
|
jbyteArray signature_object)
|
|
{
|
|
#ifdef HAVE_ECC_VERIFY
|
|
int ret = 0;
|
|
int status = 0;
|
|
ecc_key* ecc = NULL;
|
|
byte* hash = NULL;
|
|
byte* signature = NULL;
|
|
word32 hashSz = 0, signatureSz = 0;
|
|
|
|
ecc = (ecc_key*) getNativeStruct(env, this);
|
|
if ((*env)->ExceptionOccurred(env)) {
|
|
/* getNativeStruct may throw exception, prevent throwing another */
|
|
return JNI_FALSE;
|
|
}
|
|
|
|
hash = getByteArray(env, hash_object);
|
|
hashSz = getByteArrayLength(env, hash_object);
|
|
|
|
signature = getByteArray(env, signature_object);
|
|
signatureSz = getByteArrayLength(env, signature_object);
|
|
|
|
if (ecc == NULL || hash == NULL || signature == NULL) {
|
|
ret = BAD_FUNC_ARG;
|
|
}
|
|
else {
|
|
ret = wc_ecc_verify_hash(signature, signatureSz, hash,
|
|
hashSz, &status, ecc);
|
|
}
|
|
|
|
releaseByteArray(env, hash_object, hash, JNI_ABORT);
|
|
releaseByteArray(env, signature_object, signature, JNI_ABORT);
|
|
|
|
LogStr(
|
|
"wc_ecc_verify_hash(sig, sigSz, hash, hashSz, &status, ecc); = %d\n",
|
|
ret);
|
|
|
|
if (ret != 0) {
|
|
throwWolfCryptExceptionFromError(env, ret);
|
|
}
|
|
|
|
if (status == 1) {
|
|
return JNI_TRUE;
|
|
} else {
|
|
return JNI_FALSE;
|
|
}
|
|
#else
|
|
throwNotCompiledInException(env);
|
|
return JNI_FALSE;
|
|
#endif
|
|
}
|
|
|
|
JNIEXPORT jint JNICALL Java_com_wolfssl_wolfcrypt_Ecc_wc_1ecc_1get_1curve_1size_1from_1name
|
|
(JNIEnv* env, jobject this, jstring curveName)
|
|
{
|
|
jint ret = 0;
|
|
#ifdef HAVE_ECC
|
|
const char* name;
|
|
|
|
if (curveName == NULL) {
|
|
ret = BAD_FUNC_ARG;
|
|
} else {
|
|
name = (*env)->GetStringUTFChars(env, curveName, 0);
|
|
ret = wc_ecc_get_curve_size_from_name(name);
|
|
(*env)->ReleaseStringUTFChars(env, curveName, name);
|
|
}
|
|
|
|
#else
|
|
throwNotCompiledInException(env);
|
|
#endif
|
|
return ret;
|
|
}
|
|
|
|
JNIEXPORT jstring JNICALL Java_com_wolfssl_wolfcrypt_Ecc_wc_1ecc_1get_1curve_1name_1from_1id
|
|
(JNIEnv* env, jclass this, jint curve_id)
|
|
{
|
|
jstring name = NULL;
|
|
#ifdef HAVE_ECC
|
|
const char* tmp = NULL;
|
|
|
|
tmp = wc_ecc_get_curve_name_from_id(curve_id);
|
|
if (tmp != NULL) {
|
|
name = (*env)->NewStringUTF(env, tmp);
|
|
}
|
|
|
|
#else
|
|
throwNotCompiledInException(env);
|
|
#endif
|
|
|
|
return name;
|
|
}
|
|
|
|
JNIEXPORT jbyteArray JNICALL Java_com_wolfssl_wolfcrypt_Ecc_wc_1ecc_1private_1key_1to_1pkcs8
|
|
(JNIEnv* env, jobject this)
|
|
{
|
|
jbyteArray result = NULL;
|
|
|
|
#if defined(HAVE_ECC) && defined(WOLFSSL_KEY_GEN)
|
|
int ret = 0;
|
|
ecc_key* ecc = NULL;
|
|
byte* derKey = NULL;
|
|
byte* pkcs8 = NULL;
|
|
word32 derKeySz = MAX_ECC_PRIVATE_DER_SZ;
|
|
word32 pkcs8Sz = 0;
|
|
|
|
word32 derKeyBufSz = 0;
|
|
word32 pkcs8BufSz = 0;
|
|
|
|
int algoID = ECDSAk;
|
|
word32 oidSz = 0;
|
|
const byte* curveOID = NULL;
|
|
|
|
ecc = (ecc_key*) getNativeStruct(env, this);
|
|
if ((*env)->ExceptionOccurred(env)) {
|
|
/* getNativeStruct may throw exception, prevent throwing another */
|
|
ret = BAD_FUNC_ARG;
|
|
}
|
|
|
|
if (ret == 0 && ecc == NULL) {
|
|
ret = BAD_FUNC_ARG;
|
|
}
|
|
|
|
/* Calculate length of private key DER */
|
|
if (ret == 0) {
|
|
ret = wc_EccKeyDerSize(ecc, 0);
|
|
if (ret > 0) {
|
|
derKeySz = ret;
|
|
ret = 0;
|
|
}
|
|
}
|
|
|
|
if (ret == 0) {
|
|
derKeyBufSz = derKeySz;
|
|
derKey = (byte*)XMALLOC(derKeySz, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
if (derKey == NULL) {
|
|
ret = MEMORY_E;
|
|
}
|
|
else {
|
|
XMEMSET(derKey, 0, derKeySz);
|
|
}
|
|
}
|
|
|
|
if (ret == 0) {
|
|
PRIVATE_KEY_UNLOCK();
|
|
ret = wc_EccPrivateKeyToDer(ecc, derKey, derKeySz);
|
|
PRIVATE_KEY_LOCK();
|
|
if (ret >= 0) {
|
|
derKeySz = ret;
|
|
ret = 0;
|
|
}
|
|
}
|
|
|
|
if (ret == 0) {
|
|
ret = wc_ecc_get_oid(ecc->dp->oidSum, &curveOID, &oidSz);
|
|
if (ret > 0) {
|
|
/* reset ret, returns oid as well as setting curveOID */
|
|
ret = 0;
|
|
}
|
|
}
|
|
|
|
if (ret == 0) {
|
|
/* get pkcs8 output size, into pkcs8Sz */
|
|
ret = wc_CreatePKCS8Key(NULL, &pkcs8Sz, derKey, derKeySz, algoID,
|
|
curveOID, oidSz);
|
|
if (ret == LENGTH_ONLY_E) {
|
|
ret = 0;
|
|
}
|
|
|
|
pkcs8 = (byte*)XMALLOC(pkcs8Sz, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
if (pkcs8 == NULL) {
|
|
ret = MEMORY_E;
|
|
}
|
|
else {
|
|
XMEMSET(pkcs8, 0, pkcs8Sz);
|
|
}
|
|
}
|
|
|
|
if (ret == 0) {
|
|
ret = wc_CreatePKCS8Key(pkcs8, &pkcs8Sz, derKey, derKeySz,
|
|
algoID, curveOID, oidSz);
|
|
if (ret > 0) {
|
|
/* reset ret, PKCS#8 size stored in pkcs8Sz */
|
|
ret = 0;
|
|
}
|
|
}
|
|
|
|
if (ret == 0) {
|
|
result = (*env)->NewByteArray(env, pkcs8Sz);
|
|
|
|
if (result) {
|
|
(*env)->SetByteArrayRegion(env, result, 0, pkcs8Sz,
|
|
(const jbyte*) pkcs8);
|
|
}
|
|
}
|
|
|
|
if (derKey != NULL) {
|
|
XMEMSET(derKey, 0, derKeyBufSz);
|
|
XFREE(derKey, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
}
|
|
if (pkcs8 != NULL) {
|
|
XMEMSET(pkcs8, 0, pkcs8BufSz);
|
|
XFREE(pkcs8, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
|
}
|
|
|
|
if (ret < 0) {
|
|
throwWolfCryptExceptionFromError(env, ret);
|
|
}
|
|
#else
|
|
throwNotCompiledInException(env);
|
|
#endif
|
|
|
|
return result;
|
|
}
|
|
|
|
JNIEXPORT jint JNICALL Java_com_wolfssl_wolfcrypt_Ecc_wc_1ecc_1get_1curve_1id_1from_1params
|
|
(JNIEnv* env, jclass this, jint fieldSz, jbyteArray prime_object,
|
|
jbyteArray af_object, jbyteArray bf_object, jbyteArray order_object,
|
|
jbyteArray gx_object, jbyteArray gy_object, jint cofactor)
|
|
{
|
|
int ret = 0;
|
|
#ifdef HAVE_ECC
|
|
byte* prime = getByteArray(env, prime_object);
|
|
word32 primeSz = getByteArrayLength(env, prime_object);
|
|
byte* Af = getByteArray(env, af_object);
|
|
word32 AfSz = getByteArrayLength(env, af_object);
|
|
byte* Bf = getByteArray(env, bf_object);
|
|
word32 BfSz = getByteArrayLength(env, bf_object);
|
|
byte* order = getByteArray(env, order_object);
|
|
word32 orderSz = getByteArrayLength(env, order_object);
|
|
byte* Gx = getByteArray(env, gx_object);
|
|
word32 GxSz = getByteArrayLength(env, gx_object);
|
|
byte* Gy = getByteArray(env, gy_object);
|
|
word32 GySz = getByteArrayLength(env, gy_object);
|
|
|
|
if (prime == NULL || Af == NULL || Bf == NULL ||
|
|
order == NULL || Gx == NULL || Gy == NULL) {
|
|
ret = BAD_FUNC_ARG;
|
|
}
|
|
else {
|
|
ret = wc_ecc_get_curve_id_from_params(fieldSz, prime, primeSz,
|
|
Af, AfSz, Bf, BfSz, order, orderSz, Gx, GxSz,
|
|
Gy, GySz, cofactor);
|
|
}
|
|
|
|
if (ret < 0) {
|
|
throwWolfCryptExceptionFromError(env, ret);
|
|
}
|
|
|
|
LogStr("wc_ecc_get_curve_id_from_params() = %d\n", ret);
|
|
#else
|
|
throwNotCompiledInException(env);
|
|
#endif
|
|
|
|
return ret;
|
|
}
|
|
|