Skip to content
Merged
8 changes: 8 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,11 @@
- Example .jks files are located under "examples/certs"
- Example .wk files are located under "examples/certs"
- Example .jks files are updated using the update-jks-wks.sh script

# Adding new JUnit test files
- All new wolfCrypt JUnit test files must be added to src/test/java/com/wolfssl/wolfcrypt/test/WolfCryptTestSuite.java
- All new wolfJCE JUnit test files must be added to src/test/java/com/wolfssl/provider/jce/test/WolfJCETestSuite.java
- New JUnit test classes must define TestRule like existing ones do

# Adding new Java files
- MUST add all new JNI or JCE Java files to scripts/infer.sh for Infer static analysis
6 changes: 6 additions & 0 deletions README_JCE.md
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,12 @@ The JCE provider currently supports the following algorithms:
SHA3-256withECDSA
SHA3-384withECDSA
SHA3-512withECDSA
SHA256withECDSAinP1363Format
SHA384withECDSAinP1363Format
SHA512withECDSAinP1363Format
SHA3-256withECDSAinP1363Format
SHA3-384withECDSAinP1363Format
SHA3-512withECDSAinP1363Format

KeyAgreement Class
DiffieHellman
Expand Down
24 changes: 24 additions & 0 deletions jni/include/com_wolfssl_wolfcrypt_Ecc.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

258 changes: 258 additions & 0 deletions jni/jni_ecc.c
Original file line number Diff line number Diff line change
Expand Up @@ -1769,3 +1769,261 @@ JNIEXPORT jobjectArray JNICALL Java_com_wolfssl_wolfcrypt_Ecc_wc_1ecc_1get_1all_
return result;
}

JNIEXPORT jint JNICALL Java_com_wolfssl_wolfcrypt_Ecc_wc_1ecc_1size(
JNIEnv* env, jobject this)
{
jint ret = 0;

#ifdef HAVE_ECC
ecc_key* ecc = NULL;

ecc = (ecc_key*) getNativeStruct(env, this);
if ((*env)->ExceptionOccurred(env)) {
/* getNativeStruct may throw exception, prevent throwing another */
return 0;
}

if (ecc == NULL) {
throwWolfCryptException(env, "ECC key is NULL");
return 0;
}

ret = wc_ecc_size(ecc);

LogStr("wc_ecc_size(ecc) = %d\n", ret);

#else
(void)this;
throwNotCompiledInException(env);
#endif

return ret;
}

/*
* Convert DER-encoded ECDSA signature to raw {r,s} values.
* Used for IEEE P1363 signature format conversion.
*
* Returns byte[][] where [0] is r value and [1] is s value, or NULL on error.
*/
JNIEXPORT jobjectArray JNICALL
Java_com_wolfssl_wolfcrypt_Ecc_wc_1ecc_1sig_1to_1rs_1raw(
JNIEnv* env, jobject this, jbyteArray signature_object)
{
jobjectArray result = NULL;

#if defined(HAVE_ECC) && defined(HAVE_ECC_SIGN)
int ret = 0;
ecc_key* ecc = NULL;
byte* signature = NULL;
byte* r = NULL;
byte* s = NULL;
word32 signatureSz = 0;
word32 rSz = 0;
word32 sSz = 0;
word32 keySz = 0;
jbyteArray rArray = NULL;
jbyteArray sArray = NULL;
jclass byteArrayClass = NULL;

ecc = (ecc_key*) getNativeStruct(env, this);
if ((*env)->ExceptionOccurred(env)) {
/* getNativeStruct may throw exception, prevent throwing another */
return NULL;
}

if (ecc == NULL) {
throwWolfCryptException(env, "ECC key is NULL");
return NULL;
}

signature = getByteArray(env, signature_object);
signatureSz = getByteArrayLength(env, signature_object);

if (signature == NULL) {
throwWolfCryptException(env, "Input signature is NULL");
return NULL;
}

/* Get key size to determine buffer sizes for r and s */
keySz = wc_ecc_size(ecc);
if (keySz == 0) {
releaseByteArray(env, signature_object, signature, JNI_ABORT);
throwWolfCryptException(env, "Invalid ECC key size");
return NULL;
}

/* Allocate buffers for r and s (should be at most key size) */
rSz = sSz = keySz;
r = (byte*)XMALLOC(rSz, NULL, DYNAMIC_TYPE_TMP_BUFFER);
s = (byte*)XMALLOC(sSz, NULL, DYNAMIC_TYPE_TMP_BUFFER);

if (r == NULL || s == NULL) {
ret = MEMORY_E;

} else {
XMEMSET(r, 0, rSz);
XMEMSET(s, 0, sSz);
}

if (ret == 0) {
ret = wc_ecc_sig_to_rs(signature, signatureSz, r, &rSz, s, &sSz);
}

if (ret == 0) {
byteArrayClass = (*env)->FindClass(env, "[B");
if (byteArrayClass == NULL) {
ret = MEMORY_E;
} else {
result = (*env)->NewObjectArray(env, 2, byteArrayClass, NULL);
}
}

if ((ret == 0) && (result != NULL)) {
rArray = (*env)->NewByteArray(env, rSz);
sArray = (*env)->NewByteArray(env, sSz);

if ((rArray != NULL) && (sArray != NULL)) {
(*env)->SetByteArrayRegion(env, rArray, 0, rSz, (const jbyte*)r);
(*env)->SetByteArrayRegion(env, sArray, 0, sSz, (const jbyte*)s);
(*env)->SetObjectArrayElement(env, result, 0, rArray);
(*env)->SetObjectArrayElement(env, result, 1, sArray);
} else {
ret = MEMORY_E;
}
}

/* Clean up */
if (r != NULL) {
XMEMSET(r, 0, keySz);
XFREE(r, NULL, DYNAMIC_TYPE_TMP_BUFFER);
}
if (s != NULL) {
XMEMSET(s, 0, keySz);
XFREE(s, NULL, DYNAMIC_TYPE_TMP_BUFFER);
}

releaseByteArray(env, signature_object, signature, JNI_ABORT);

if (ret != 0) {
throwWolfCryptExceptionFromError(env, ret);
return NULL;
}

LogStr("wc_ecc_sig_to_rs(sig, sigLen, r, &rLen, s, &sLen) = %d\n", ret);

#else
(void)this;
(void)signature_object;
throwNotCompiledInException(env);
#endif

return result;
}

/*
* Convert raw {r,s} values to DER-encoded ECDSA signature.
* Used for IEEE P1363 signature format conversion.
*
* Returns DER-encoded signature byte array, or NULL on error.
*/
JNIEXPORT jbyteArray JNICALL
Java_com_wolfssl_wolfcrypt_Ecc_wc_1ecc_1rs_1raw_1to_1sig(
JNIEnv* env, jobject this, jbyteArray r_object, jbyteArray s_object)
{
jbyteArray result = NULL;

#if defined(HAVE_ECC) && defined(HAVE_ECC_SIGN)
int ret = 0;
ecc_key* ecc = NULL;
byte* r = NULL;
byte* s = NULL;
byte* signature = NULL;
word32 rSz = 0;
word32 sSz = 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;
}

if (ecc == NULL) {
throwWolfCryptException(env, "ECC key is NULL");
return NULL;
}

r = getByteArray(env, r_object);
rSz = getByteArrayLength(env, r_object);
s = getByteArray(env, s_object);
sSz = getByteArrayLength(env, s_object);

if (r == NULL || s == NULL) {
LogStr("Input r or s is NULL\n");
ret = BAD_FUNC_ARG;
}

if (ret == 0) {
/* Estimate signature size based on ECC key size */
signatureBufSz = wc_ecc_sig_size(ecc);
if (signatureBufSz == 0) {
LogStr("Invalid signature size estimate\n");
ret = BAD_FUNC_ARG;
}
}

if (ret == 0) {
signatureSz = signatureBufSz;
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_rs_raw_to_sig(r, rSz, s, sSz, signature, &signatureSz);
}

if (ret == 0) {
result = (*env)->NewByteArray(env, signatureSz);
if (result != NULL) {
(*env)->SetByteArrayRegion(env, result, 0, signatureSz,
(const jbyte*)signature);
} else {
ret = MEMORY_E;
}
}

LogStr("wc_ecc_rs_raw_to_sig(r, rSz, s, sSz, sig, &sigLen) = %d\n", ret);

if (signature != NULL) {
XMEMSET(signature, 0, signatureBufSz);
XFREE(signature, NULL, DYNAMIC_TYPE_TMP_BUFFER);
}

if (r != NULL) {
releaseByteArray(env, r_object, r, JNI_ABORT);
}
if (s != NULL) {
releaseByteArray(env, s_object, s, JNI_ABORT);
}

if (ret != 0) {
throwWolfCryptExceptionFromError(env, ret);
return NULL;
}

#else
(void)this;
(void)r_object;
(void)s_object;
throwNotCompiledInException(env);
#endif /* HAVE_ECC && HAVE_ECC_SIGN */

return result;
}

Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
import java.security.spec.X509EncodedKeySpec;
import java.security.spec.ECPrivateKeySpec;
import java.security.spec.ECPublicKeySpec;
import java.security.spec.ECParameterSpec;
import java.security.interfaces.ECPrivateKey;
import java.security.interfaces.ECPublicKey;
import java.security.InvalidAlgorithmParameterException;
Expand Down Expand Up @@ -442,7 +443,8 @@ else if (bytes.length < expectedSz) {
* Convert BigInteger private key to byte[].
*
* @param privateValue private key BigInteger
* @param curveName curve name for size validation
* @param curveName curve name for size validation, used to get
* expected byte array size
*
* @return properly formatted byte array for wolfCrypt import
*
Expand All @@ -451,7 +453,8 @@ else if (bytes.length < expectedSz) {
private byte[] convertPrivateValueToBytes(BigInteger privateValue,
String curveName) throws InvalidKeySpecException {

/* Validate private key is within valid range (1 <= d < order) */
/* Validate private key is positive. Other validation done at time of
* use to match Sun behavior. */
if (privateValue.signum() <= 0) {
throw new InvalidKeySpecException(
"Private key value must be positive");
Expand Down
Loading
Loading