aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJ08nY2018-10-17 22:41:19 +0200
committerJ08nY2018-10-21 13:30:48 +0200
commitba5cfcc98d7bf5107e6aac3a4e5c7416ab7b76a7 (patch)
treea69e6b18ccdcc05baa1d9154c2cf5fb30cd776f7
parent030629076791f517622f7fc8fcfcf51e10f6e063 (diff)
downloadECTester-ba5cfcc98d7bf5107e6aac3a4e5c7416ab7b76a7.tar.gz
ECTester-ba5cfcc98d7bf5107e6aac3a4e5c7416ab7b76a7.tar.zst
ECTester-ba5cfcc98d7bf5107e6aac3a4e5c7416ab7b76a7.zip
-rw-r--r--build-standalone.xml2
-rw-r--r--src/cz/crcs/ectester/standalone/ECTesterStandalone.java2
-rw-r--r--src/cz/crcs/ectester/standalone/consts/SignatureIdent.java2
-rw-r--r--src/cz/crcs/ectester/standalone/libs/jni/NativeKeyAgreementSpi.java23
-rw-r--r--src/cz/crcs/ectester/standalone/libs/jni/NativeSignatureSpi.java91
-rw-r--r--src/cz/crcs/ectester/standalone/libs/jni/c_utils.c101
-rw-r--r--src/cz/crcs/ectester/standalone/libs/jni/c_utils.h11
-rw-r--r--src/cz/crcs/ectester/standalone/libs/jni/gcrypt.c360
-rw-r--r--src/cz/crcs/ectester/standalone/libs/jni/native.h76
9 files changed, 645 insertions, 23 deletions
diff --git a/build-standalone.xml b/build-standalone.xml
index 84f4595..9a47642 100644
--- a/build-standalone.xml
+++ b/build-standalone.xml
@@ -169,6 +169,8 @@
<class name="cz.crcs.ectester.standalone.libs.jni.NativeKeyPairGeneratorSpi$Gcrypt"/>
<class name="cz.crcs.ectester.standalone.libs.jni.NativeECPublicKey$Gcrypt"/>
<class name="cz.crcs.ectester.standalone.libs.jni.NativeECPrivateKey$Gcrypt"/>
+ <class name="cz.crcs.ectester.standalone.libs.jni.NativeKeyAgreementSpi$Gcrypt"/>
+ <class name="cz.crcs.ectester.standalone.libs.jni.NativeSignatureSpi$Gcrypt"/>
</javah>
</target>
</project>
diff --git a/src/cz/crcs/ectester/standalone/ECTesterStandalone.java b/src/cz/crcs/ectester/standalone/ECTesterStandalone.java
index cc0e465..7480215 100644
--- a/src/cz/crcs/ectester/standalone/ECTesterStandalone.java
+++ b/src/cz/crcs/ectester/standalone/ECTesterStandalone.java
@@ -325,7 +325,7 @@ public class ECTesterStandalone {
ECPublicKey pubkey = (ECPublicKey) other.getPublic();
long elapsed = -System.nanoTime();
- if (spec != null) {
+ if (spec instanceof ECParameterSpec) {
ka.init(privkey, spec);
} else {
ka.init(privkey);
diff --git a/src/cz/crcs/ectester/standalone/consts/SignatureIdent.java b/src/cz/crcs/ectester/standalone/consts/SignatureIdent.java
index dea8abe..93b7f99 100644
--- a/src/cz/crcs/ectester/standalone/consts/SignatureIdent.java
+++ b/src/cz/crcs/ectester/standalone/consts/SignatureIdent.java
@@ -52,7 +52,7 @@ public class SignatureIdent extends Ident {
ALL.add(new SignatureIdent("ECGOST3410-2012-512", "GOST-3410-2012-512"));
ALL.add(new SignatureIdent("GOST3411-2012-512withECGOST3410-2012-512", "GOST3411-2012-512/ECGOST3410-2012-5120", "1.2.643.7.1.1.3.3"));
ALL.add(new SignatureIdent("SM3withSM2"));
- // ECDDSA
+ // ECDDSA (rfc6979?)
ALL.add(new SignatureIdent("ECDDSA", "DETECDSA", "ECDETDSA"));
ALL.add(new SignatureIdent("SHA1withECDDSA", "SHA1withDETECDSA"));
ALL.add(new SignatureIdent("SHA224withECDDSA", "SHA224withDETECDSA"));
diff --git a/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyAgreementSpi.java b/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyAgreementSpi.java
index 5fca448..7b531f5 100644
--- a/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyAgreementSpi.java
+++ b/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyAgreementSpi.java
@@ -65,7 +65,7 @@ public abstract class NativeKeyAgreementSpi extends KeyAgreementSpi {
@Override
protected void engineInit(Key key, AlgorithmParameterSpec params, SecureRandom random) throws InvalidKeyException, InvalidAlgorithmParameterException {
if (!(params instanceof ECParameterSpec)) {
- throw new InvalidAlgorithmParameterException();
+ throw new InvalidAlgorithmParameterException(params.toString());
}
engineInit(key, random);
this.params = params;
@@ -254,6 +254,27 @@ public abstract class NativeKeyAgreementSpi extends KeyAgreementSpi {
}
}
+ public abstract static class Gcrypt extends SimpleKeyAgreementSpi {
+ private String type;
+
+ public Gcrypt(String type) {
+ this.type = type;
+ }
+
+ @Override
+ native byte[] generateSecret(byte[] pubkey, byte[] privkey, ECParameterSpec params);
+
+ @Override
+ native SecretKey generateSecret(byte[] pubkey, byte[] privkey, ECParameterSpec params, String algorithm);
+ }
+
+ public static class GcryptECDH extends Gcrypt {
+ public GcryptECDH() {
+ super("ECDH");
+ }
+ }
+
+
public abstract static class Mscng extends ExtendedKeyAgreementSpi {
private String type;
diff --git a/src/cz/crcs/ectester/standalone/libs/jni/NativeSignatureSpi.java b/src/cz/crcs/ectester/standalone/libs/jni/NativeSignatureSpi.java
index 3f99771..f2b1ab9 100644
--- a/src/cz/crcs/ectester/standalone/libs/jni/NativeSignatureSpi.java
+++ b/src/cz/crcs/ectester/standalone/libs/jni/NativeSignatureSpi.java
@@ -349,6 +349,97 @@ public abstract class NativeSignatureSpi extends SignatureSpi {
}
}
+ public abstract static class Gcrypt extends SimpleSignatureSpi {
+ private String type;
+
+ public Gcrypt(String type) {
+ this.type = type;
+ }
+
+ @Override
+ native byte[] sign(byte[] data, byte[] privkey, ECParameterSpec params);
+
+ @Override
+ native boolean verify(byte[] signature, byte[] data, byte[] pubkey, ECParameterSpec params);
+ }
+
+ public static class GcryptECDSAwithNONE extends Gcrypt {
+
+ public GcryptECDSAwithNONE() {
+ super("NONEwithECDSA");
+ }
+ }
+
+ public static class GcryptECDSAwithSHA1 extends Gcrypt {
+
+ public GcryptECDSAwithSHA1() {
+ super("SHA1withECDSA");
+ }
+ }
+
+ public static class GcryptECDSAwithSHA224 extends Gcrypt {
+
+ public GcryptECDSAwithSHA224() {
+ super("SHA224withECDSA");
+ }
+ }
+
+ public static class GcryptECDSAwithSHA256 extends Gcrypt {
+
+ public GcryptECDSAwithSHA256() {
+ super("SHA256withECDSA");
+ }
+ }
+
+ public static class GcryptECDSAwithSHA384 extends Gcrypt {
+
+ public GcryptECDSAwithSHA384() {
+ super("SHA384withECDSA");
+ }
+ }
+
+ public static class GcryptECDSAwithSHA512 extends Gcrypt {
+
+ public GcryptECDSAwithSHA512() {
+ super("SHA512withECDSA");
+ }
+ }
+
+ public static class GcryptECDDSAwithSHA1 extends Gcrypt {
+
+ public GcryptECDDSAwithSHA1() {
+ super("SHA1withECDDSA");
+ }
+ }
+
+ public static class GcryptECDDSAwithSHA224 extends Gcrypt {
+
+ public GcryptECDDSAwithSHA224() {
+ super("SHA224withECDDSA");
+ }
+ }
+
+ public static class GcryptECDDSAwithSHA256 extends Gcrypt {
+
+ public GcryptECDDSAwithSHA256() {
+ super("SHA256withECDDSA");
+ }
+ }
+
+ public static class GcryptECDDSAwithSHA384 extends Gcrypt {
+
+ public GcryptECDDSAwithSHA384() {
+ super("SHA384withECDDSA");
+ }
+ }
+
+ public static class GcryptECDDSAwithSHA512 extends Gcrypt {
+
+ public GcryptECDDSAwithSHA512() {
+ super("SHA512withECDDSA");
+ }
+ }
+
public abstract static class Mscng extends ExtendedSignatureSpi {
private String type;
diff --git a/src/cz/crcs/ectester/standalone/libs/jni/c_utils.c b/src/cz/crcs/ectester/standalone/libs/jni/c_utils.c
index 49cab44..c36d3c9 100644
--- a/src/cz/crcs/ectester/standalone/libs/jni/c_utils.c
+++ b/src/cz/crcs/ectester/standalone/libs/jni/c_utils.c
@@ -75,7 +75,7 @@ void throw_new_var(JNIEnv *env, const char *class, const char *format, ...) {
char buffer[2048];
va_list args;
va_start(args, format);
- int res = vsnprintf(buffer, 2048, format, args);
+ vsnprintf(buffer, 2048, format, args);
va_end(args);
throw_new(env, class, buffer);
}
@@ -105,4 +105,103 @@ jint get_kdf_bits(JNIEnv *env, jstring algorithm) {
}
(*env)->ReleaseStringUTFChars(env, algorithm, algo_data);
return result;
+}
+
+jbyteArray asn1_der_encode(JNIEnv *env, const jbyte *r, size_t r_len, const jbyte *s, size_t s_len) {
+ jbyte r_length = (jbyte) r_len + (r[0] & 0x80 ? 1 : 0);
+ jbyte s_length = (jbyte) s_len + (s[0] & 0x80 ? 1 : 0);
+
+ // R and S are < 128 bytes, so 1 byte tag + 1 byte len + len bytes value
+ size_t seq_value_len = 2 + r_length + 2 + s_length;
+ size_t whole_len = seq_value_len;
+
+ // The SEQUENCE length might be >= 128, so more bytes of length
+ size_t seq_len_len = 0;
+ if (seq_value_len >= 128) {
+ size_t s = seq_value_len;
+ while ((s = s >> 8)) {
+ seq_len_len++;
+ }
+ }
+ // seq_len_len bytes for length and one for length of length
+ whole_len += seq_len_len + 1;
+
+ // 1 byte tag for SEQUENCE
+ whole_len += 1;
+
+ jbyteArray result = (jbyteArray) (*env)->NewByteArray(env, whole_len);
+ jbyte *data = (*env)->GetByteArrayElements(env, result, NULL);
+ size_t i = 0;
+ data[i++] = 0x30; // SEQUENCE
+ if (seq_value_len < 128) {
+ data[i++] = (jbyte) seq_value_len;
+ } else {
+ data[i++] = (jbyte) (seq_len_len | (1 << 7));
+ for (size_t j = 0; j < seq_len_len; ++j) {
+ data[i++] = (jbyte) (seq_value_len & (0xff << (seq_len_len - j)));
+ }
+ }
+ data[i++] = 0x02; //INTEGER
+ data[i++] = r_length;
+ if (r[0] & 0x80) {
+ data[i++] = 0;
+ }
+ memcpy(data + i, r, r_len);
+ i += r_len;
+ data[i++] = 0x02; //INTEGER
+ data[i++] = s_length;
+ if (s[0] & 0x80) {
+ data[i++] = 0;
+ }
+ memcpy(data + i, s, s_len);
+ i += s_len;
+ (*env)->ReleaseByteArrayElements(env, result, data, 0);
+
+ return result;
+}
+
+bool asn1_der_decode(JNIEnv *env, jbyteArray sig, jbyte **r_data, size_t *r_len, jbyte **s_data, size_t *s_len) {
+ size_t sig_len = (*env)->GetArrayLength(env, sig);
+ jbyte *data = (*env)->GetByteArrayElements(env, sig, NULL);
+ size_t i = 0;
+ if (data[i++] != 0x30) {//SEQUENCE
+ (*env)->ReleaseByteArrayElements(env, sig, data, JNI_ABORT);
+ return false;
+ }
+ size_t seq_value_len = 0;
+ if (!(data[i] & 0x80)) {
+ seq_value_len = data[i++];
+ } else {
+ size_t seq_len_len = data[i++] & 0x7f;
+ while (seq_len_len > 0) {
+ seq_value_len |= (data[i++] << (seq_len_len - 1));
+ seq_len_len--;
+ }
+ }
+
+ if (data[i++] != 0x02) {//INTEGER
+ (*env)->ReleaseByteArrayElements(env, sig, data, JNI_ABORT);
+ return false;
+ }
+ size_t r_length = data[i++];
+ jbyte *r_out = malloc(r_length);
+ memcpy(r_out, data + i, r_length);
+ i += r_length;
+
+ if (data[i++] != 0x02) {//INTEGER
+ free(r_out);
+ (*env)->ReleaseByteArrayElements(env, sig, data, JNI_ABORT);
+ return false;
+ }
+ size_t s_length = data[i++];
+ jbyte *s_out = malloc(s_length);
+ memcpy(s_out, data + i, s_length);
+ i += s_length;
+
+ *r_len = r_length;
+ *r_data = r_out;
+ *s_len = s_length;
+ *s_data = s_out;
+ (*env)->ReleaseByteArrayElements(env, sig, data, JNI_ABORT);
+ return true;
} \ No newline at end of file
diff --git a/src/cz/crcs/ectester/standalone/libs/jni/c_utils.h b/src/cz/crcs/ectester/standalone/libs/jni/c_utils.h
index b767b61..82c3538 100644
--- a/src/cz/crcs/ectester/standalone/libs/jni/c_utils.h
+++ b/src/cz/crcs/ectester/standalone/libs/jni/c_utils.h
@@ -1,6 +1,7 @@
#pragma once
#include "native.h"
+#include <stdbool.h>
/**
* Classes that are accessed alot are cached here, manually.
@@ -39,6 +40,16 @@ void throw_new_var(JNIEnv *env, const char *class, const char *format, ...);
jint get_kdf_bits(JNIEnv *env, jstring algorithm);
/**
+ * DER encode the r and s values.
+ */
+jbyteArray asn1_der_encode(JNIEnv *env, const jbyte *r, size_t r_len, const jbyte *s, size_t s_len);
+
+/**
+ * DER decode a signature into r and s values.
+ */
+bool asn1_der_decode(JNIEnv *env, jbyteArray sig, jbyte **r_data, size_t *r_len, jbyte **s_data, size_t *s_len);
+
+/**
* Some useful defines to init the provider.
*/
#define INIT_PROVIDER(env, provider_class) jmethodID provider_put = (*env)->GetMethodID(env, provider_class, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;")
diff --git a/src/cz/crcs/ectester/standalone/libs/jni/gcrypt.c b/src/cz/crcs/ectester/standalone/libs/jni/gcrypt.c
index 0705df6..0ba94c6 100644
--- a/src/cz/crcs/ectester/standalone/libs/jni/gcrypt.c
+++ b/src/cz/crcs/ectester/standalone/libs/jni/gcrypt.c
@@ -1,5 +1,7 @@
#include "native.h"
#include <stdio.h>
+#include <ctype.h>
+#include <stdbool.h>
#include <gcrypt.h>
#include "c_utils.h"
@@ -13,7 +15,6 @@ JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_GcryptLib_create
jmethodID init = (*env)->GetMethodID(env, local_provider_class, "<init>", "(Ljava/lang/String;DLjava/lang/String;)V");
- const char *built_with = GCRYPT_VERSION;
const char *running_with = gcry_check_version(GCRYPT_VERSION);
if (!running_with) {
return NULL;
@@ -36,8 +37,18 @@ JNIEXPORT void JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeProvider_
INIT_PROVIDER(env, provider_class);
ADD_KPG(env, this, "EC", "Gcrypt");
- //ADD_KA(env, self, "ECDH", "OpensslECDH");
- //ADD_SIG(env, self, "NONEwithECDSA", "OpensslECDSAwithNONE");
+ ADD_KA(env, this, "ECDH", "GcryptECDH");
+ ADD_SIG(env, this, "NONEwithECDSA", "GcryptECDSAwithNONE");
+ ADD_SIG(env, this, "SHA1withECDSA", "GcryptECDSAwithSHA1");
+ ADD_SIG(env, this, "SHA224withECDSA", "GcryptECDSAwithSHA224");
+ ADD_SIG(env, this, "SHA256withECDSA", "GcryptECDSAwithSHA256");
+ ADD_SIG(env, this, "SHA384withECDSA", "GcryptECDSAwithSHA384");
+ ADD_SIG(env, this, "SHA512withECDSA", "GcryptECDSAwithSHA512");
+ ADD_SIG(env, this, "SHA1withECDDSA", "GcryptECDDSAwithSHA1");
+ ADD_SIG(env, this, "SHA224withECDDSA", "GcryptECDDSAwithSHA224");
+ ADD_SIG(env, this, "SHA256withECDDSA", "GcryptECDDSAwithSHA256");
+ ADD_SIG(env, this, "SHA384withECDDSA", "GcryptECDDSAwithSHA384");
+ ADD_SIG(env, this, "SHA512withECDDSA", "GcryptECDDSAwithSHA512");
init_classes(env, "Gcrypt");
}
@@ -82,6 +93,13 @@ static void print_sexp(gcry_sexp_t sexp) {
fflush(stdout);
}
+static void print_chrray(unsigned char *arr, size_t len) {
+ for (size_t i = 0; i < len; ++i) {
+ printf("%02x,", ((unsigned char) arr[i] & 0xff));
+ }
+ printf("\n");
+}
+
JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Gcrypt_paramsSupported(JNIEnv *env, jobject this, jobject params) {
if (params == NULL) {
return JNI_FALSE;
@@ -105,28 +123,66 @@ JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPa
}
}
-static jobject mpi_to_biginteger(JNIEnv *env, gcry_mpi_t mpi) {
- jmethodID biginteger_init = (*env)->GetMethodID(env, biginteger_class, "<init>", "(I[B)V");
- size_t len = 0;
- gcry_mpi_print(GCRYMPI_FMT_USG, NULL, 0, &len, mpi);
- jbyteArray bytes = (*env)->NewByteArray(env, len);
+static gcry_mpi_t bytearray_to_mpi(JNIEnv *env, jbyteArray array) {
+ if (!array) {
+ return NULL;
+ }
+
+ gcry_mpi_t result;
+
+ size_t length = (*env)->GetArrayLength(env, array);
+ char data[length + 1];
+ data[0] = 0;
+ (*env)->GetByteArrayRegion(env, array, 0, length, data + 1);
+ gcry_mpi_scan(&result, GCRYMPI_FMT_USG, data, length + 1, NULL);
+ return result;
+}
+
+static jbyteArray mpi_to_bytearray0(JNIEnv *env, gcry_mpi_t mpi, size_t start, size_t len) {
+ if (!mpi) {
+ return NULL;
+ }
+
+ size_t mpi_len = 0;
+ gcry_mpi_print(GCRYMPI_FMT_USG, NULL, 0, &mpi_len, mpi);
+ if (start >= mpi_len) {
+ return NULL;
+ }
+ if (start + len > mpi_len || len == 0) {
+ len = mpi_len - start;
+ }
+ unsigned char buff[mpi_len];
+ gcry_mpi_print(GCRYMPI_FMT_USG, buff, mpi_len, NULL, mpi);
+ jbyteArray bytes = (*env)->NewByteArray(env, len);
jbyte *data = (*env)->GetByteArrayElements(env, bytes, NULL);
- gcry_mpi_print(GCRYMPI_FMT_USG, data, len, &len, mpi);
+ memcpy(data, buff + start, len);
(*env)->ReleaseByteArrayElements(env, bytes, data, 0);
+ return bytes;
+}
+
+static jbyteArray mpi_to_bytearray(JNIEnv *env, gcry_mpi_t mpi) {
+ return mpi_to_bytearray0(env, mpi, 0, 0);
+}
+
+static jobject mpi_to_biginteger(JNIEnv *env, gcry_mpi_t mpi) {
+ if (!mpi) {
+ return NULL;
+ }
+
+ jmethodID biginteger_init = (*env)->GetMethodID(env, biginteger_class, "<init>", "(I[B)V");
+ jbyteArray bytes = mpi_to_bytearray(env, mpi);
jobject result = (*env)->NewObject(env, biginteger_class, biginteger_init, 1, bytes);
return result;
}
static gcry_mpi_t biginteger_to_mpi(JNIEnv *env, jobject bigint) {
- jmethodID to_byte_array = (*env)->GetMethodID(env, biginteger_class, "toByteArray", "()[B");
+ if (!bigint) {
+ return NULL;
+ }
+ jmethodID to_byte_array = (*env)->GetMethodID(env, biginteger_class, "toByteArray", "()[B");
jbyteArray byte_array = (jbyteArray) (*env)->CallObjectMethod(env, bigint, to_byte_array);
- jsize byte_length = (*env)->GetArrayLength(env, byte_array);
- jbyte *byte_data = (*env)->GetByteArrayElements(env, byte_array, NULL);
- gcry_mpi_t result;
- gcry_mpi_scan(&result, GCRYMPI_FMT_USG, byte_data, byte_length, NULL);
- (*env)->ReleaseByteArrayElements(env, byte_array, byte_data, JNI_ABORT);
- return result;
+ return bytearray_to_mpi(env, byte_array);
}
static jint mpi_to_jint(gcry_mpi_t mpi) {
@@ -144,7 +200,7 @@ static jint mpi_to_jint(gcry_mpi_t mpi) {
}
static jobject buff_to_ecpoint(JNIEnv *env, gcry_buffer_t buff) {
- jint coord_size = (buff.size - 1) / 2;
+ jint coord_size = (buff.len - 1) / 2;
jmethodID biginteger_init = (*env)->GetMethodID(env, biginteger_class, "<init>", "(I[B)V");
jbyteArray x_bytes = (*env)->NewByteArray(env, coord_size);
@@ -235,7 +291,7 @@ static jobject generate_from_sexp(JNIEnv *env, gcry_sexp_t gen_sexp) {
jobject ec_pub_param_spec = (*env)->NewLocalRef(env, ec_param_spec);
jmethodID ec_pub_init = (*env)->GetMethodID(env, pubkey_class, "<init>", "([BLjava/security/spec/ECParameterSpec;)V");
- jobject pubkey = (*env)->NewObject(env, pubkey_class, ec_pub_init, pub_bytes, ec_param_spec);
+ jobject pubkey = (*env)->NewObject(env, pubkey_class, ec_pub_init, pub_bytes, ec_pub_param_spec);
jobject ec_priv_param_spec = (*env)->NewLocalRef(env, ec_param_spec);
jmethodID ec_priv_init = (*env)->GetMethodID(env, privkey_class, "<init>", "([BLjava/security/spec/ECParameterSpec;)V");
@@ -265,7 +321,6 @@ JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPai
}
JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Gcrypt_generate__Ljava_security_spec_AlgorithmParameterSpec_2Ljava_security_SecureRandom_2(JNIEnv *env, jobject this, jobject params, jobject random) {
-
if ((*env)->IsInstanceOf(env, params, ec_parameter_spec_class)) {
return NULL;
} else if ((*env)->IsInstanceOf(env, params, ecgen_parameter_spec_class)) {
@@ -281,4 +336,271 @@ JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPai
} else {
return NULL;
}
+}
+
+static gcry_sexp_t create_key(JNIEnv *env, jobject ec_param_spec, const char *key_fmt, gcry_mpi_t q, gcry_mpi_t d) {
+ gcry_sexp_t inner;
+ gcry_mpi_t p, a, b, g, n, h;
+
+ jmethodID get_curve = (*env)->GetMethodID(env, ec_parameter_spec_class, "getCurve", "()Ljava/security/spec/EllipticCurve;");
+ jobject elliptic_curve = (*env)->CallObjectMethod(env, ec_param_spec, get_curve);
+
+ jmethodID get_field = (*env)->GetMethodID(env, elliptic_curve_class, "getField", "()Ljava/security/spec/ECField;");
+ jobject field = (*env)->CallObjectMethod(env, elliptic_curve, get_field);
+
+ jmethodID get_bits = (*env)->GetMethodID(env, fp_field_class, "getFieldSize", "()I");
+ jint bits = (*env)->CallIntMethod(env, field, get_bits);
+ jint bytes = (bits + 7) / 8;
+
+ jmethodID get_a = (*env)->GetMethodID(env, elliptic_curve_class, "getA", "()Ljava/math/BigInteger;");
+ jobject big_a = (*env)->CallObjectMethod(env, elliptic_curve, get_a);
+ a = biginteger_to_mpi(env, big_a);
+
+ jmethodID get_b = (*env)->GetMethodID(env, elliptic_curve_class, "getB", "()Ljava/math/BigInteger;");
+ jobject big_b = (*env)->CallObjectMethod(env, elliptic_curve, get_b);
+ b = biginteger_to_mpi(env, big_b);
+
+ jmethodID get_p = (*env)->GetMethodID(env, fp_field_class, "getP", "()Ljava/math/BigInteger;");
+ jobject big_p = (*env)->CallObjectMethod(env, field, get_p);
+ p = biginteger_to_mpi(env, big_p);
+
+ jmethodID get_g = (*env)->GetMethodID(env, ec_parameter_spec_class, "getGenerator", "()Ljava/security/spec/ECPoint;");
+ jobject g_point = (*env)->CallObjectMethod(env, ec_param_spec, get_g);
+
+ jmethodID get_x = (*env)->GetMethodID(env, point_class, "getAffineX", "()Ljava/math/BigInteger;");
+ jobject gx = (*env)->CallObjectMethod(env, g_point, get_x);
+
+ jmethodID get_y = (*env)->GetMethodID(env, point_class, "getAffineY", "()Ljava/math/BigInteger;");
+ jobject gy = (*env)->CallObjectMethod(env, g_point, get_y);
+
+ jmethodID to_byte_array = (*env)->GetMethodID(env, biginteger_class, "toByteArray", "()[B");
+
+ jbyteArray gx_bytes = (jbyteArray) (*env)->CallObjectMethod(env, gx, to_byte_array);
+ size_t gx_len = (*env)->GetArrayLength(env, gx_bytes);
+ jbyteArray gy_bytes = (jbyteArray) (*env)->CallObjectMethod(env, gy, to_byte_array);
+ size_t gy_len = (*env)->GetArrayLength(env, gy_bytes);
+ unsigned char g_data[1 + 2 * bytes];
+ g_data[0] = 0x04;
+ jbyte *gx_data = (*env)->GetByteArrayElements(env, gx_bytes, NULL);
+ memcpy(g_data + 1, gx_data + (gx_len - bytes), bytes);
+ (*env)->ReleaseByteArrayElements(env, gx_bytes, gx_data, JNI_ABORT);
+ jbyte *gy_data = (*env)->GetByteArrayElements(env, gy_bytes, NULL);
+ memcpy(g_data + 1 + bytes, gy_data + (gy_len - bytes), bytes);
+ (*env)->ReleaseByteArrayElements(env, gy_bytes, gy_data, JNI_ABORT);
+
+ gcry_mpi_scan(&g, GCRYMPI_FMT_USG, g_data, 1 + 2 * bytes, NULL);
+
+ jmethodID get_n = (*env)->GetMethodID(env, ec_parameter_spec_class, "getOrder", "()Ljava/math/BigInteger;");
+ jobject big_n = (*env)->CallObjectMethod(env, ec_param_spec, get_n);
+ n = biginteger_to_mpi(env, big_n);
+
+ jmethodID get_h = (*env)->GetMethodID(env, ec_parameter_spec_class, "getCofactor", "()I");
+ jint jh = (*env)->CallIntMethod(env, ec_param_spec, get_h);
+ h = gcry_mpi_set_ui(NULL, jh);
+
+ if (q && d) {
+ gcry_sexp_build(&inner, NULL, "(ecc (flags param) (p %M) (a %M) (b %M) (g %M) (n %M) (h %M) (q %M) (d %M))", p, a, b, g, n, h, q, d, NULL);
+ } else if (q && !d) {
+ gcry_sexp_build(&inner, NULL, "(ecc (flags param) (p %M) (a %M) (b %M) (g %M) (n %M) (h %M) (q %M))", p, a, b, g, n, h, q, NULL);
+ } else if (!q && d) {
+ gcry_sexp_build(&inner, NULL, "(ecc (flags param) (p %M) (a %M) (b %M) (g %M) (n %M) (h %M) (d %M))", p, a, b, g, n, h, d, NULL);
+ }
+ gcry_sexp_t result;
+ gcry_sexp_build(&result, NULL, key_fmt, inner, NULL);
+ gcry_sexp_release(inner);
+ return result;
+}
+
+static gcry_sexp_t create_pubkey(JNIEnv *env, jobject ec_param_spec, jbyteArray pubkey) {
+ gcry_mpi_t q = bytearray_to_mpi(env, pubkey);
+ gcry_sexp_t result = create_key(env, ec_param_spec, "(public-key %S)", q, NULL);
+ gcry_mpi_release(q);
+ return result;
+}
+
+static gcry_sexp_t create_privkey(JNIEnv *env, jobject ec_param_spec, jbyteArray pubkey, jbyteArray privkey) {
+ gcry_mpi_t q = bytearray_to_mpi(env, pubkey);
+ gcry_mpi_t d = bytearray_to_mpi(env, privkey);
+ gcry_sexp_t result = create_key(env, ec_param_spec, "(private-key %S)", q, d);
+ gcry_mpi_release(q);
+ gcry_mpi_release(d);
+ return result;
+}
+
+JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_00024Gcrypt_generateSecret___3B_3BLjava_security_spec_ECParameterSpec_2(JNIEnv *env, jobject this, jbyteArray pubkey, jbyteArray privkey, jobject params) {
+ jbyteArray result = NULL;
+ gcry_sexp_t pub = create_pubkey(env, params, pubkey);
+ gcry_mpi_t priv = bytearray_to_mpi(env, privkey);
+
+ gcry_sexp_t enc_sexp;
+ gcry_sexp_build(&enc_sexp, NULL, "(data (flags raw) (value %M))", priv, NULL);
+ gcry_sexp_t res_sexp;
+ // TODO: figure out why ecc_encrypt_raw takes signed representation.. Nobody uses that., everybody uses unsigned reduced mod p.
+ gcry_error_t err = gcry_pk_encrypt(&res_sexp, enc_sexp, pub);
+ if (gcry_err_code(err) != GPG_ERR_NO_ERROR) {
+ throw_new_var(env, "java/security/GeneralSecurityException", "Error performing ECDH. Error: %ui", gcry_err_code(err));
+ goto end;
+ }
+
+ gcry_mpi_t derived;
+ err = gcry_sexp_extract_param(res_sexp, NULL, "s", &derived, NULL);
+
+ size_t derived_bytes;
+ gcry_mpi_print(GCRYMPI_FMT_USG, NULL, 0, &derived_bytes, derived);
+ size_t coord_bytes = (derived_bytes - 1) / 2;
+ result = mpi_to_bytearray0(env, derived, 1, coord_bytes);
+
+ gcry_mpi_release(derived);
+end:
+ gcry_sexp_release(enc_sexp);
+ gcry_sexp_release(res_sexp);
+ gcry_sexp_release(pub);
+ gcry_mpi_release(priv);
+ return result;
+}
+
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_00024Gcrypt_generateSecret___3B_3BLjava_security_spec_ECParameterSpec_2Ljava_lang_String_2(JNIEnv *env, jobject this, jbyteArray pubkey, jbyteArray privkey, jobject params, jstring algorithm) {
+ throw_new(env, "java/lang/UnsupportedOperationException", "Not supported.");
+ return NULL;
+}
+
+static int starts_with(const char *whole, const char *prefix) {
+ return !strncmp(whole, prefix, strlen(prefix));
+}
+
+static int get_hash_algo(const char *sig_type) {
+ if (starts_with(sig_type, "SHA1")) {
+ return GCRY_MD_SHA1;
+ } else if (starts_with(sig_type, "SHA224")) {
+ return GCRY_MD_SHA224;
+ } else if (starts_with(sig_type, "SHA256")) {
+ return GCRY_MD_SHA256;
+ } else if (starts_with(sig_type, "SHA384")) {
+ return GCRY_MD_SHA384;
+ } else if (starts_with(sig_type, "SHA512")) {
+ return GCRY_MD_SHA512;
+ } else {
+ return GCRY_MD_NONE;
+ }
+}
+
+static const char *get_sig_algo(const char *sig_type) {
+ const char *start = strstr(sig_type, "with") + strlen("with");
+ if (starts_with(start, "ECDSA")) {
+ return NULL;
+ } else if (starts_with(start, "ECDDSA")) {
+ return "rfc6979";
+ } else {
+ return NULL;
+ }
+}
+
+static void get_sign_data_sexp(JNIEnv *env, gcry_sexp_t *result, jobject this, jbyteArray data) {
+ jclass sig_class = (*env)->FindClass(env, "cz/crcs/ectester/standalone/libs/jni/NativeSignatureSpi$Gcrypt");
+ jfieldID type_id = (*env)->GetFieldID(env, sig_class, "type", "Ljava/lang/String;");
+ jstring type = (jstring)(*env)->GetObjectField(env, this, type_id);
+ const char* type_data = (*env)->GetStringUTFChars(env, type, NULL);
+ int hash_algo = get_hash_algo(type_data);
+ const char *sig_algo = get_sig_algo(type_data);
+ const char *with = strstr(type_data, "with");
+ char hash_name[with - type_data + 1];
+ memcpy(hash_name, type_data, with - type_data);
+ for (size_t i = 0; i < with - type_data; ++i) {
+ hash_name[i] = tolower(hash_name[i]);
+ }
+ hash_name[with - type_data] = 0;
+ (*env)->ReleaseStringUTFChars(env, type, type_data);
+
+ if (hash_algo == GCRY_MD_NONE) {
+ gcry_mpi_t data_mpi = bytearray_to_mpi(env, data);
+ gcry_sexp_build(result, NULL, "(data (flags raw param) (value %M))", data_mpi);
+ gcry_mpi_release(data_mpi);
+ } else {
+ unsigned int hash_len = gcry_md_get_algo_dlen(hash_algo);
+ size_t data_len = (*env)->GetArrayLength(env, data);
+ jbyte *data_bytes = (*env)->GetByteArrayElements(env, data, NULL);
+ unsigned char out_hash[hash_len];
+ gcry_md_hash_buffer(hash_algo, out_hash, data_bytes, data_len);
+ (*env)->ReleaseByteArrayElements(env, data, data_bytes, JNI_ABORT);
+ gcry_mpi_t hash_mpi;
+ gcry_mpi_scan(&hash_mpi, GCRYMPI_FMT_USG, out_hash, hash_len, NULL);
+ if (!sig_algo) {
+ gcry_sexp_build(result, NULL, "(data (flags raw param) (value %M))", hash_mpi);
+ } else {
+ gcry_sexp_build(result, NULL, "(data (flags %s param) (hash %s %M))", sig_algo, hash_name, hash_mpi);
+ }
+ gcry_mpi_release(hash_mpi);
+ }
+}
+
+JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024Gcrypt_sign(JNIEnv *env, jobject this, jbyteArray data, jbyteArray privkey, jobject params) {
+ jbyteArray result = NULL;
+ gcry_sexp_t priv_sexp = create_privkey(env, params, NULL, privkey);
+
+ gcry_sexp_t data_sexp;
+ get_sign_data_sexp(env, &data_sexp, this, data);
+
+ gcry_sexp_t res_sexp;
+ gcry_error_t err = gcry_pk_sign(&res_sexp, data_sexp, priv_sexp);
+ if (gcry_err_code(err) != GPG_ERR_NO_ERROR) {
+ throw_new_var(env, "java/security/GeneralSecurityException", "Error performing ECDSA. Error: %ui", gcry_err_code(err));
+ goto release_init;
+ }
+
+ gcry_buffer_t r_buf = {0};
+ gcry_buffer_t s_buf = {0};
+ err = gcry_sexp_extract_param(res_sexp, "ecdsa", "&rs", &r_buf, &s_buf, NULL);
+ if (gcry_err_code(err) != GPG_ERR_NO_ERROR) {
+ throw_new_var(env, "java/security/GeneralSecurityException", "Error extracting ECDSA output. Error: %ui", gcry_err_code(err));
+ goto release_res;
+ }
+ result = asn1_der_encode(env, r_buf.data, r_buf.len, s_buf.data, s_buf.len);
+
+ gcry_free(r_buf.data);
+ gcry_free(s_buf.data);
+release_res:
+ gcry_sexp_release(res_sexp);
+release_init:
+ gcry_sexp_release(priv_sexp);
+ gcry_sexp_release(data_sexp);
+ return result;
+}
+
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024Gcrypt_verify(JNIEnv *env, jobject this, jbyteArray sig, jbyteArray data, jbyteArray pubkey, jobject params) {
+ jboolean result = JNI_FALSE;
+ gcry_sexp_t pub_sexp = create_pubkey(env, params, pubkey);
+
+ gcry_sexp_t data_sexp;
+ get_sign_data_sexp(env, &data_sexp, this, data);
+
+ size_t r_len, s_len;
+ jbyte *r_data, *s_data;
+ bool decode = asn1_der_decode(env, sig, &r_data, &r_len, &s_data, &s_len);
+ if (!decode) {
+ throw_new(env, "java/security/GeneralSecurityException", "Error decoding sig.");
+ goto release_init;
+ }
+
+ gcry_mpi_t r_mpi, s_mpi;
+ gcry_mpi_scan(&r_mpi, GCRYMPI_FMT_USG, r_data, r_len, NULL);
+ gcry_mpi_scan(&s_mpi, GCRYMPI_FMT_USG, s_data, s_len, NULL);
+ free(r_data);
+ free(s_data);
+
+ gcry_sexp_t sig_sexp;
+ gcry_sexp_build(&sig_sexp, NULL, "(sig-val (ecdsa (r %M) (s %M)))", r_mpi, s_mpi);
+ gcry_error_t err = gcry_pk_verify(sig_sexp, data_sexp, pub_sexp);
+ if (gcry_err_code(err) != GPG_ERR_NO_ERROR) {
+ if (gcry_err_code(err) != GPG_ERR_BAD_SIGNATURE) {
+ throw_new(env, "java/security/GeneralSecurityException", "Error verif sig.");
+ goto release_init;
+ }
+ } else {
+ result = JNI_TRUE;
+ }
+
+release_init:
+ gcry_sexp_release(pub_sexp);
+ gcry_sexp_release(data_sexp);
+ return result;
} \ No newline at end of file
diff --git a/src/cz/crcs/ectester/standalone/libs/jni/native.h b/src/cz/crcs/ectester/standalone/libs/jni/native.h
index e86a847..47031e4 100644
--- a/src/cz/crcs/ectester/standalone/libs/jni/native.h
+++ b/src/cz/crcs/ectester/standalone/libs/jni/native.h
@@ -1191,3 +1191,79 @@ JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPai
}
#endif
#endif
+/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeECPublicKey_Gcrypt */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPublicKey_Gcrypt
+#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPublicKey_Gcrypt
+#ifdef __cplusplus
+extern "C" {
+#endif
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeECPrivateKey_Gcrypt */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPrivateKey_Gcrypt
+#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPrivateKey_Gcrypt
+#ifdef __cplusplus
+extern "C" {
+#endif
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Gcrypt */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Gcrypt
+#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Gcrypt
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Gcrypt
+ * Method: generateSecret
+ * Signature: ([B[BLjava/security/spec/ECParameterSpec;)[B
+ */
+JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_00024Gcrypt_generateSecret___3B_3BLjava_security_spec_ECParameterSpec_2
+ (JNIEnv *, jobject, jbyteArray, jbyteArray, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Gcrypt
+ * Method: generateSecret
+ * Signature: ([B[BLjava/security/spec/ECParameterSpec;Ljava/lang/String;)Ljavax/crypto/SecretKey;
+ */
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_00024Gcrypt_generateSecret___3B_3BLjava_security_spec_ECParameterSpec_2Ljava_lang_String_2
+ (JNIEnv *, jobject, jbyteArray, jbyteArray, jobject, jstring);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Gcrypt */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Gcrypt
+#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Gcrypt
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Gcrypt
+ * Method: sign
+ * Signature: ([B[BLjava/security/spec/ECParameterSpec;)[B
+ */
+JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024Gcrypt_sign
+ (JNIEnv *, jobject, jbyteArray, jbyteArray, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Gcrypt
+ * Method: verify
+ * Signature: ([B[B[BLjava/security/spec/ECParameterSpec;)Z
+ */
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024Gcrypt_verify
+ (JNIEnv *, jobject, jbyteArray, jbyteArray, jbyteArray, jobject);
+
+#ifdef __cplusplus
+}
+#endif
+#endif