aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMichal Čech2019-12-25 20:46:52 +0100
committerJán Jančár2019-12-25 20:46:52 +0100
commit79143562568a91ea7c3db66b9e97eb4a46c3ea04 (patch)
treec27818ba28d5be3b619c41b415d00bf14e341d75 /src
parentd4611ac11ac0cbb91e5a0b27ef8799ec686eea7b (diff)
downloadECTester-79143562568a91ea7c3db66b9e97eb4a46c3ea04.tar.gz
ECTester-79143562568a91ea7c3db66b9e97eb4a46c3ea04.tar.zst
ECTester-79143562568a91ea7c3db66b9e97eb4a46c3ea04.zip
Diffstat (limited to 'src')
-rw-r--r--src/cz/crcs/ectester/standalone/ECTesterStandalone.java4
-rw-r--r--src/cz/crcs/ectester/standalone/libs/NettleLib.java20
-rw-r--r--src/cz/crcs/ectester/standalone/libs/jni/Makefile16
-rwxr-xr-xsrc/cz/crcs/ectester/standalone/libs/jni/Makefile.bat2
-rw-r--r--src/cz/crcs/ectester/standalone/libs/jni/NativeECPrivateKey.java7
-rw-r--r--src/cz/crcs/ectester/standalone/libs/jni/NativeECPublicKey.java6
-rw-r--r--src/cz/crcs/ectester/standalone/libs/jni/NativeKeyAgreementSpi.java55
-rw-r--r--src/cz/crcs/ectester/standalone/libs/jni/NativeKeyPairGeneratorSpi.java42
-rw-r--r--src/cz/crcs/ectester/standalone/libs/jni/NativeProvider.java12
-rw-r--r--src/cz/crcs/ectester/standalone/libs/jni/NativeSignatureSpi.java89
-rw-r--r--src/cz/crcs/ectester/standalone/libs/jni/nettle.c515
11 files changed, 759 insertions, 9 deletions
diff --git a/src/cz/crcs/ectester/standalone/ECTesterStandalone.java b/src/cz/crcs/ectester/standalone/ECTesterStandalone.java
index 3049a70..7c1d76b 100644
--- a/src/cz/crcs/ectester/standalone/ECTesterStandalone.java
+++ b/src/cz/crcs/ectester/standalone/ECTesterStandalone.java
@@ -83,6 +83,7 @@ public class ECTesterStandalone {
new MbedTLSLib(),
new IppcpLib(),
new MatrixsslLib(),
+ new NettleLib(),
new LibresslLib()};
private Config cfg;
@@ -502,9 +503,7 @@ public class ECTesterStandalone {
random.nextBytes(data);
dataString = ByteUtil.bytesToHex(data, false);
}
-
ProviderECLibrary lib = cfg.selected;
-
String algo = cli.getOptionValue("ecdsa.type", "ECDSA");
SignatureIdent sigIdent = lib.getSigs().stream()
.filter((ident) -> ident.contains(algo))
@@ -517,7 +516,6 @@ public class ECTesterStandalone {
} else {
baseAlgo = algo;
}
-
KeyPairGeneratorIdent kpIdent = lib.getKPGs().stream()
.filter((ident) -> ident.contains(algo))
.findFirst()
diff --git a/src/cz/crcs/ectester/standalone/libs/NettleLib.java b/src/cz/crcs/ectester/standalone/libs/NettleLib.java
new file mode 100644
index 0000000..00e3b39
--- /dev/null
+++ b/src/cz/crcs/ectester/standalone/libs/NettleLib.java
@@ -0,0 +1,20 @@
+package cz.crcs.ectester.standalone.libs;
+
+import java.security.Provider;
+import java.util.Set;
+
+/**
+ * @author Michal Cech 445431@mail.muni.cz
+ */
+public class NettleLib extends NativeECLibrary {
+
+ public NettleLib() {
+ super("nettle_provider", "nettle","hogweed", "gmp");
+ }
+
+ @Override
+ native Provider createProvider();
+
+ @Override
+ public native Set<String> getCurves();
+}
diff --git a/src/cz/crcs/ectester/standalone/libs/jni/Makefile b/src/cz/crcs/ectester/standalone/libs/jni/Makefile
index aa24460..bc27c95 100644
--- a/src/cz/crcs/ectester/standalone/libs/jni/Makefile
+++ b/src/cz/crcs/ectester/standalone/libs/jni/Makefile
@@ -58,7 +58,7 @@ JNI_PLATFORMINCLUDEDIR ?= $(JNI_INCLUDEDIR)/$(JNI_PLATFORM)
###############################################################################
## Targets.
-all: tomcrypt botan cryptopp openssl boringssl gcrypt mbedtls ippcp matrixssl libressl
+all: tomcrypt botan cryptopp openssl boringssl gcrypt mbedtls ippcp matrixssl nettle libressl
# Common utils
c_utils.o: c_utils.c
@@ -165,6 +165,16 @@ matrixssl.o: matrixssl.c
$(CC) $(CFLAGS) -Imatrixssl/ -c $<
+# Nettle shim
+nettle: nettle_provider.so
+
+nettle_provider.so: nettle.o c_utils.o | lib_timing.so
+ $(CC) $(LFLAGS) -o $@ -Wl,-rpath,'$$ORIGIN/lib' $^ -L. $(shell pkg-config --libs nettle) -l:lib_timing.so $(shell pkg-config --libs hogweed) -lgmp
+
+nettle.o: nettle.c
+ $(CC) $(shell pkg-config --cflags nettle) $(shell pkg-config --libs hogweed) -lgmp $(CFLAGS) -c $<
+
+
# LibreSSL shim
libressl: libressl_provider.so
@@ -190,10 +200,12 @@ help:
@echo " - mbedtls"
@echo " - ippcp"
@echo " - matrixssl"
+ @echo " - nettle"
@echo " - libressl"
+
clean:
rm -rf *.o
rm -rf *.so
-.PHONY: all help clean openssl boringssl gcrypt tomcrypt botan cryptopp mbedtls ippcp matrixssl libressl
+.PHONY: all help clean openssl boringssl gcrypt tomcrypt botan cryptopp mbedtls ippcp matrixssl nettle libressl
diff --git a/src/cz/crcs/ectester/standalone/libs/jni/Makefile.bat b/src/cz/crcs/ectester/standalone/libs/jni/Makefile.bat
index a5fe78e..a8b51f4 100755
--- a/src/cz/crcs/ectester/standalone/libs/jni/Makefile.bat
+++ b/src/cz/crcs/ectester/standalone/libs/jni/Makefile.bat
@@ -160,4 +160,4 @@ echo.
echo ^>^> %CC% /W2 /EHsc %OTHER_CLI% %INCLUDE_CLI% mscng.c c_utils.c c_timing.c bcrypt.lib jvm.lib kernel32.lib /Femscng_provider.dll /LD /link %LIBPATH% /nologo
echo.
-%CC% /W2 /EHsc %OTHER_CLI% %INCLUDE_CLI% mscng.c c_utils.c c_timing.c bcrypt.lib jvm.lib kernel32.lib /Femscng_provider.dll /LD /link %LIBPATH% /nologo \ No newline at end of file
+%CC% /W2 /EHsc %OTHER_CLI% %INCLUDE_CLI% mscng.c c_utils.c c_timing.c bcrypt.lib jvm.lib kernel32.lib /Femscng_provider.dll /LD /link %LIBPATH% /nologo
diff --git a/src/cz/crcs/ectester/standalone/libs/jni/NativeECPrivateKey.java b/src/cz/crcs/ectester/standalone/libs/jni/NativeECPrivateKey.java
index ef26b8c..7885c0d 100644
--- a/src/cz/crcs/ectester/standalone/libs/jni/NativeECPrivateKey.java
+++ b/src/cz/crcs/ectester/standalone/libs/jni/NativeECPrivateKey.java
@@ -161,4 +161,11 @@ public abstract class NativeECPrivateKey implements ECPrivateKey {
return getBlob();
}
}
+
+ public static class Nettle extends Raw {
+ public Nettle(byte[] keyData, ECParameterSpec params) {
+ super(keyData, params);
+ }
+ }
+
}
diff --git a/src/cz/crcs/ectester/standalone/libs/jni/NativeECPublicKey.java b/src/cz/crcs/ectester/standalone/libs/jni/NativeECPublicKey.java
index 62db5c4..aec68d0 100644
--- a/src/cz/crcs/ectester/standalone/libs/jni/NativeECPublicKey.java
+++ b/src/cz/crcs/ectester/standalone/libs/jni/NativeECPublicKey.java
@@ -162,4 +162,10 @@ public abstract class NativeECPublicKey implements ECPublicKey {
return getBlob();
}
}
+
+ public static class Nettle extends ANSIX962 {
+ public Nettle(byte[] keyData, ECParameterSpec params) {
+ super(keyData, params);
+ }
+ }
}
diff --git a/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyAgreementSpi.java b/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyAgreementSpi.java
index dda9af8..1e68f78 100644
--- a/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyAgreementSpi.java
+++ b/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyAgreementSpi.java
@@ -11,6 +11,7 @@ import java.security.interfaces.ECPublicKey;
import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.ECGenParameterSpec;
import java.security.spec.ECParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
/**
* @author Jan Jancar johny@neuromancer.sk
@@ -377,16 +378,68 @@ public abstract class NativeKeyAgreementSpi extends KeyAgreementSpi {
private String type;
public Libressl(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 abstract static class Nettle extends SimpleKeyAgreementSpi {
+ private String type;
+
+ public Nettle(String type) {
this.type = type;
}
@Override
- native byte[] generateSecret(byte[] pubkey, byte[] privkey, ECParameterSpec params);
+ byte[] generateSecret(byte[] pubkey, byte[] privkey, ECParameterSpec params) {
+ try {
+ AlgorithmParameters tmp = AlgorithmParameters.getInstance("EC");
+ tmp.init(params);
+ ECGenParameterSpec spec = tmp.getParameterSpec(ECGenParameterSpec.class);
+ switch (spec.getName()) {
+ case "1.2.840.10045.3.1.7":
+ spec = new ECGenParameterSpec("secp256r1");
+ break;
+ case "1.2.840.10045.3.1.1":
+ spec = new ECGenParameterSpec("secp192r1");
+ break;
+ case "1.3.132.0.33":
+ spec = new ECGenParameterSpec("secp224r1");
+ break;
+ case "1.3.132.0.34":
+ spec = new ECGenParameterSpec("secp384r1");
+ break;
+ case "1.3.132.0.35":
+ spec = new ECGenParameterSpec("secp521r1");
+ break;
+ default:
+ return null;
+
+ }
+ return generateSecret(pubkey, privkey, spec);
+
+ } catch (NoSuchAlgorithmException | InvalidParameterSpecException e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ native byte[] generateSecret(byte[] pubkey, byte[] privkey, ECGenParameterSpec params);
@Override
native SecretKey generateSecret(byte[] pubkey, byte[] privkey, ECParameterSpec params, String algorithm);
}
+ public static class NettleECDH extends Nettle {
+ public NettleECDH() {
+ super("ECDH");
+ }
+ }
public static class LibresslECDH extends Libressl {
public LibresslECDH() {
super("ECDH");
diff --git a/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyPairGeneratorSpi.java b/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyPairGeneratorSpi.java
index 3598d61..636f423 100644
--- a/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyPairGeneratorSpi.java
+++ b/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyPairGeneratorSpi.java
@@ -1,7 +1,14 @@
package cz.crcs.ectester.standalone.libs.jni;
+import cz.crcs.ectester.common.ec.EC_Curve;
+import cz.crcs.ectester.data.EC_Store;
+
import java.security.*;
import java.security.spec.AlgorithmParameterSpec;
+import java.security.AlgorithmParameters;
+import java.security.spec.ECGenParameterSpec;
+import java.security.spec.ECParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
/**
* @author Jan Jancar johny@neuromancer.sk
@@ -62,6 +69,7 @@ public abstract class NativeKeyPairGeneratorSpi extends KeyPairGeneratorSpi {
abstract KeyPair generate(AlgorithmParameterSpec params, SecureRandom random);
+
public static class TomCrypt extends NativeKeyPairGeneratorSpi {
public TomCrypt() {
@@ -306,8 +314,9 @@ public abstract class NativeKeyPairGeneratorSpi extends KeyPairGeneratorSpi {
@Override
native KeyPair generate(AlgorithmParameterSpec params, SecureRandom random);
}
-
+
public static class Libressl extends NativeKeyPairGeneratorSpi {
+
public Libressl() {
initialize(256, new SecureRandom());
}
@@ -324,4 +333,35 @@ public abstract class NativeKeyPairGeneratorSpi extends KeyPairGeneratorSpi {
@Override
native KeyPair generate(AlgorithmParameterSpec params, SecureRandom random);
}
+
+ public static class Nettle extends NativeKeyPairGeneratorSpi {
+ public Nettle() {
+ initialize(256, new SecureRandom());
+ }
+
+ @Override
+ native boolean keysizeSupported(int keysize);
+
+ @Override
+ native boolean paramsSupported(AlgorithmParameterSpec params);
+
+ @Override
+ native KeyPair generate(int keysize, SecureRandom random);
+
+ @Override
+ KeyPair generate(AlgorithmParameterSpec params, SecureRandom random) {
+ if (params instanceof ECGenParameterSpec) {
+ String curveName = ((ECGenParameterSpec) params).getName();
+ if (curveName.contains("secp")) {
+ curveName = "secg/" + curveName;
+ }
+ EC_Curve curve = EC_Store.getInstance().getObject(EC_Curve.class, curveName);
+ ECParameterSpec spec = curve.toSpec();
+ return generate(params, random, spec);
+ }
+ return null;
+ }
+
+ native KeyPair generate(AlgorithmParameterSpec params, SecureRandom random, AlgorithmParameterSpec spec);
+ }
}
diff --git a/src/cz/crcs/ectester/standalone/libs/jni/NativeProvider.java b/src/cz/crcs/ectester/standalone/libs/jni/NativeProvider.java
index 1a67e1f..3d9a38a 100644
--- a/src/cz/crcs/ectester/standalone/libs/jni/NativeProvider.java
+++ b/src/cz/crcs/ectester/standalone/libs/jni/NativeProvider.java
@@ -123,7 +123,7 @@ public abstract class NativeProvider extends Provider {
@Override
native void setup();
}
-
+
public static class Libressl extends NativeProvider {
public Libressl(String name, double version, String info) {
@@ -133,4 +133,14 @@ public abstract class NativeProvider extends Provider {
@Override
native void setup();
}
+
+ public static class Nettle extends NativeProvider {
+
+ public Nettle(String name, double version, String info) {
+ super(name, version, info);
+ }
+
+ @Override
+ native void setup();
+ }
}
diff --git a/src/cz/crcs/ectester/standalone/libs/jni/NativeSignatureSpi.java b/src/cz/crcs/ectester/standalone/libs/jni/NativeSignatureSpi.java
index 36cefdc..d6e814c 100644
--- a/src/cz/crcs/ectester/standalone/libs/jni/NativeSignatureSpi.java
+++ b/src/cz/crcs/ectester/standalone/libs/jni/NativeSignatureSpi.java
@@ -6,7 +6,9 @@ import java.io.ByteArrayOutputStream;
import java.security.*;
import java.security.interfaces.ECPrivateKey;
import java.security.interfaces.ECPublicKey;
+import java.security.spec.ECGenParameterSpec;
import java.security.spec.ECParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
/**
* @author Jan Jancar johny@neuromancer.sk
@@ -565,4 +567,91 @@ public abstract class NativeSignatureSpi extends SignatureSpi {
super("SHA512withECDSA");
}
}
+
+ public abstract static class Nettle extends SimpleSignatureSpi {
+ private String type;
+
+ public Nettle(String type) {
+ this.type = type;
+ }
+
+ @Override
+ byte[] sign(byte[] data, byte[] privKey, ECParameterSpec params) {
+ try {
+ AlgorithmParameters tmp = AlgorithmParameters.getInstance("EC");
+ tmp.init(params);
+ ECGenParameterSpec spec = tmp.getParameterSpec(ECGenParameterSpec.class);
+ switch (spec.getName()) {
+ case "1.2.840.10045.3.1.7":
+ spec = new ECGenParameterSpec("secp256r1");
+ break;
+ case "1.2.840.10045.3.1.1":
+ spec = new ECGenParameterSpec("secp192r1");
+ break;
+ case "1.3.132.0.33":
+ spec = new ECGenParameterSpec("secp224r1");
+ break;
+ case "1.3.132.0.34":
+ spec = new ECGenParameterSpec("secp384r1");
+ break;
+ case "1.3.132.0.35":
+ spec = new ECGenParameterSpec("secp521r1");
+ break;
+ default:
+ return null;
+
+ }
+ return sign(data, privKey, spec);
+
+ } catch (NoSuchAlgorithmException | InvalidParameterSpecException e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ native byte[] sign(byte[] data, byte[] privKey, ECGenParameterSpec params);
+
+ @Override
+ boolean verify(byte[] signature, byte[] data, byte[] pubkey, ECParameterSpec params) {
+ try {
+ AlgorithmParameters tmp = AlgorithmParameters.getInstance("EC");
+ tmp.init(params);
+ ECGenParameterSpec spec = tmp.getParameterSpec(ECGenParameterSpec.class);
+ switch (spec.getName()) {
+ case "1.2.840.10045.3.1.7":
+ spec = new ECGenParameterSpec("secp256r1");
+ break;
+ case "1.2.840.10045.3.1.1":
+ spec = new ECGenParameterSpec("secp192r1");
+ break;
+ case "1.3.132.0.33":
+ spec = new ECGenParameterSpec("secp224r1");
+ break;
+ case "1.3.132.0.34":
+ spec = new ECGenParameterSpec("secp384r1");
+ break;
+ case "1.3.132.0.35":
+ spec = new ECGenParameterSpec("secp521r1");
+ break;
+ default:
+ return false;
+ }
+ return verify(signature, data, pubkey, spec);
+
+ } catch (NoSuchAlgorithmException | InvalidParameterSpecException e) {
+ e.printStackTrace();
+ return false;
+ }
+ }
+
+ native boolean verify(byte[] signature, byte[] data, byte[] pubkey, ECGenParameterSpec params);
+ }
+
+ public static class NettleECDSAwithNONE extends Nettle {
+
+ public NettleECDSAwithNONE() {
+ super("NONEwithECDSA");
+ }
+ }
+
}
diff --git a/src/cz/crcs/ectester/standalone/libs/jni/nettle.c b/src/cz/crcs/ectester/standalone/libs/jni/nettle.c
new file mode 100644
index 0000000..137f392
--- /dev/null
+++ b/src/cz/crcs/ectester/standalone/libs/jni/nettle.c
@@ -0,0 +1,515 @@
+#include "native.h"
+#include <string.h>
+
+#include <nettle/version.h>
+#include <nettle/ecc.h>
+#include <nettle/ecc-curve.h>
+#include <nettle/ecdsa.h>
+#include <nettle/yarrow.h>
+#include <nettle/dsa.h>
+#include <gmp.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "c_utils.h"
+#include "c_timing.h"
+
+static struct yarrow256_ctx yarrow;
+
+
+static jclass provider_class;
+
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_NettleLib_createProvider(JNIEnv *env, jobject self) {
+ /* Create the custom provider. */
+ jclass local_provider_class = (*env)->FindClass(env, "cz/crcs/ectester/standalone/libs/jni/NativeProvider$Nettle");
+ provider_class = (*env)->NewGlobalRef(env, local_provider_class);
+
+ jmethodID init = (*env)->GetMethodID(env, local_provider_class, "<init>", "(Ljava/lang/String;DLjava/lang/String;)V");
+
+ jstring name = (*env)->NewStringUTF(env, "Nettle");
+
+ double version = NETTLE_VERSION_MAJOR + (double) NETTLE_VERSION_MINOR / 10;
+ return (*env)->NewObject(env, provider_class, init, name, version, name);
+
+}
+
+JNIEXPORT void JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeProvider_00024Nettle_setup(JNIEnv *env, jobject self) {
+
+ INIT_PROVIDER(env, provider_class);
+ ADD_KPG(env, self, "EC", "Nettle");
+ ADD_KA(env, self, "ECDH", "NettleECDH");
+ ADD_SIG(env, self, "NONEwithECDSA", "NettleECDSAwithNONE");
+
+ init_classes(env, "Nettle");
+
+ yarrow256_init(&yarrow, 0, NULL);
+ uint8_t file = open("/dev/random", O_RDONLY);
+ yarrow256_seed(&yarrow, YARROW256_SEED_FILE_SIZE, &file);
+ close(file);
+
+}
+
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_NettleLib_getCurves(JNIEnv *env, jobject self) {
+ jclass hash_set_class = (*env)->FindClass(env, "java/util/TreeSet");
+
+ jmethodID hash_set_ctr = (*env)->GetMethodID(env, hash_set_class, "<init>", "()V");
+ jmethodID hash_set_add = (*env)->GetMethodID(env, hash_set_class, "add", "(Ljava/lang/Object;)Z");
+
+ jobject result = (*env)->NewObject(env, hash_set_class, hash_set_ctr);
+ char *curve_names[] = {"secp192r1", "secp224r1", "secp256r1", "secp384r1", "secp521r1"};
+ for (int i = 0; i < 5; i++) {
+ jstring curve_name = (*env)->NewStringUTF(env, curve_names[i]);
+ (*env)->CallBooleanMethod(env, result, hash_set_add, curve_name);
+ }
+
+ return result;
+}
+
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Nettle_keysizeSupported(JNIEnv *env, jobject self, jint keysize) {
+ int supported[] = {192, 224, 256, 384, 521};
+ for (int i = 0; i < 5; i++) {
+ if (keysize == supported[i]) {
+ return JNI_TRUE;
+ }
+ }
+ return JNI_FALSE;
+}
+
+static const struct ecc_curve* create_curve(JNIEnv *env, const char* curve_name) {
+ const struct ecc_curve* curve = NULL;
+ if (curve_name) {
+ if (strcasecmp("secp192r1", curve_name) == 0) {
+ curve = nettle_get_secp_192r1();
+ }
+ if (strcasecmp("secp224r1", curve_name) == 0) {
+ curve = nettle_get_secp_224r1();
+ }
+ if (strcasecmp("secp256r1", curve_name) == 0) {
+ curve = nettle_get_secp_256r1();
+ }
+ if (strcasecmp("secp384r1", curve_name) == 0) {
+ curve = nettle_get_secp_384r1();
+ }
+ if (strcasecmp("secp521r1", curve_name) == 0) {
+ curve = nettle_get_secp_521r1();
+ }
+ return curve;
+ }
+ return NULL;
+}
+
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Nettle_paramsSupported(JNIEnv *env, jobject self, jobject params){
+ if (params == NULL) {
+ return JNI_FALSE;
+ }
+
+ if ((*env)->IsInstanceOf(env, params, ec_parameter_spec_class)) {
+ return JNI_FALSE;
+ } else if ((*env)->IsInstanceOf(env, params, ecgen_parameter_spec_class)) {
+ jmethodID get_name = (*env)->GetMethodID(env, ecgen_parameter_spec_class, "getName", "()Ljava/lang/String;");
+ jstring name = (*env)->CallObjectMethod(env, params, get_name);
+ const char *utf_name = (*env)->GetStringUTFChars(env, name, NULL);
+
+ char *curve_name[5] = {"secp192r1", "secp224r1", "secp256r1", "secp384r1", "secp521r1"};
+ for (int i = 0; i < sizeof(curve_name); i++) {
+ if (strcasecmp(utf_name, curve_name[i]) == 0) {
+ (*env)->ReleaseStringUTFChars(env, name, utf_name);
+ return JNI_TRUE;
+ }
+ }
+ (*env)->ReleaseStringUTFChars(env, name, utf_name);
+ return JNI_FALSE;
+ } else {
+ return JNI_FALSE;
+ }
+ return JNI_FALSE;
+
+}
+
+static jobject generate_from_curve(JNIEnv *env, const struct ecc_curve* curve, jobject spec, int byte_size) {
+
+ struct ecc_point pub;
+ struct ecc_scalar priv;
+
+ ecc_point_init(&pub, curve);
+ ecc_scalar_init(&priv, curve);
+ native_timing_start();
+ ecdsa_generate_keypair(&pub, &priv, (void *) &yarrow, (nettle_random_func *) yarrow256_random);
+ native_timing_stop();
+
+ mpz_t private_value;
+ mpz_init(private_value);
+ ecc_scalar_get(&priv, private_value);
+ size_t size = 0;
+ size_t xLen = 0;
+ size_t yLen = 0;
+ mpz_export(NULL, &size, 1, sizeof(unsigned char), 0, 0, private_value);
+ jbyteArray priv_bytes = (*env)->NewByteArray(env, byte_size);
+ jbyte *key_priv = (*env)->GetByteArrayElements(env, priv_bytes, NULL);
+
+ int diff = byte_size - size;
+ memset(key_priv, 0x00, diff);
+
+ mpz_export((unsigned char*) key_priv + diff, &size, 1, sizeof(unsigned char), 0, 0, private_value);
+ (*env)->ReleaseByteArrayElements(env, priv_bytes, key_priv, 0);
+
+
+ unsigned long key_len = 2*byte_size + 1;
+ jbyteArray pub_bytes = (*env)->NewByteArray(env, key_len);
+ mpz_t pub_value_x;
+ mpz_init(pub_value_x);
+ mpz_t pub_value_y;
+ mpz_init(pub_value_y);
+ ecc_point_get(&pub, pub_value_x, pub_value_y);
+ jbyte *key_pub = (*env)->GetByteArrayElements(env, pub_bytes, NULL);
+ key_pub[0] = 0x04;
+
+ mpz_export(NULL, &xLen, 1, sizeof(unsigned char), 0, 0, pub_value_x);
+ diff = byte_size - xLen;
+ memset(key_pub + 1, 0x00, diff);
+ mpz_export((unsigned char*) key_pub + 1+diff, &xLen, 1, sizeof(unsigned char), 0, 0, pub_value_x);
+
+ mpz_export(NULL, &yLen, 1, sizeof(unsigned char), 0, 0, pub_value_y);
+ diff = byte_size - yLen;
+ memset(key_pub + 1 + byte_size, 0x00, diff);
+ mpz_export((unsigned char*) key_pub + 1 + byte_size + diff, &yLen, 1, sizeof(unsigned char), 0, 0, pub_value_y);
+ (*env)->ReleaseByteArrayElements(env, pub_bytes, key_pub, 0);
+
+
+ jobject ec_pub_param_spec = (*env)->NewLocalRef(env, 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_pub_param_spec);
+
+ jobject ec_priv_param_spec = (*env)->NewLocalRef(env, spec);
+ jmethodID ec_priv_init = (*env)->GetMethodID(env, privkey_class, "<init>", "([BLjava/security/spec/ECParameterSpec;)V");
+ jobject privkey = (*env)->NewObject(env, privkey_class, ec_priv_init, priv_bytes, ec_priv_param_spec);
+
+ jmethodID keypair_init = (*env)->GetMethodID(env, keypair_class, "<init>", "(Ljava/security/PublicKey;Ljava/security/PrivateKey;)V");
+ mpz_clears(private_value, pub_value_x, pub_value_y);
+ ecc_point_clear(&pub);
+ ecc_scalar_clear(&priv);
+ return (*env)->NewObject(env, keypair_class, keypair_init, pubkey, privkey);
+
+
+}
+
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Nettle_generate__ILjava_security_SecureRandom_2(JNIEnv *env, jobject self, jint keysize, jobject random) {
+ throw_new(env, "java/lang/UnsupportedOperationException", "Not supported.");
+ return NULL;
+}
+
+
+
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Nettle_generate__Ljava_security_spec_AlgorithmParameterSpec_2Ljava_security_SecureRandom_2Ljava_security_spec_AlgorithmParameterSpec_2(JNIEnv *env, jobject self, jobject params, jobject random, jobject spec) {
+
+ if ((*env)->IsInstanceOf(env, params, ec_parameter_spec_class)) {
+ return NULL;
+ } else if ((*env)->IsInstanceOf(env, params, ecgen_parameter_spec_class)) {
+ jmethodID get_name = (*env)->GetMethodID(env, ecgen_parameter_spec_class, "getName", "()Ljava/lang/String;");
+ jstring name = (*env)->CallObjectMethod(env, params, get_name);
+ const char* utf_name = (*env)->GetStringUTFChars(env, name, NULL);
+ const struct ecc_curve* curve;
+ int byte_size;
+ int rc;
+ char *curve_name[5] = {"secp192r1", "secp224r1", "secp256r1", "secp384r1", "secp521r1"};
+ int byte_sizes[] = {24, 28, 32, 48, 66};
+ for (int i = 0; i < sizeof(curve_name); i++) {
+ if (strcasecmp(utf_name, curve_name[i]) == 0) {
+ curve = create_curve(env, curve_name[i]);
+ byte_size = byte_sizes[i];
+ break;
+ }
+ }
+ (*env)->ReleaseStringUTFChars(env, name, utf_name);
+ if (!curve) {
+ throw_new(env, "java/security/InvalidAlgorithmParameterException", "Curve for given bitsize not found.");
+ return NULL;
+ }
+ jobject result = generate_from_curve(env, curve, spec, byte_size);
+ return result;
+ } else {
+ throw_new(env, "java/security/InvalidAlgorithmParameterException", "Curve not found.");
+ return NULL;
+ }
+ return NULL;
+}
+
+int barray_to_pubkey(JNIEnv *env, struct ecc_point* pubKey , jbyteArray pub) {
+ jsize pub_len = (*env)->GetArrayLength(env, pub);
+ jbyte *pub_data = (*env)->GetByteArrayElements(env, pub, NULL);
+ int pointLength = (pub_len - 1) / 2;
+ mpz_t x;
+ mpz_t y;
+ mpz_init(x);
+ mpz_init(y);
+ mpz_import(x, pointLength, 1, sizeof(unsigned char), 0, 0, pub_data+1);
+ mpz_import(y, pointLength, 1, sizeof(unsigned char), 0, 0, pub_data+1+pointLength);
+ (*env)->ReleaseByteArrayElements(env, pub, pub_data, JNI_ABORT);
+ ecc_point_set(pubKey, x, y);
+ return pointLength;
+}
+
+int barray_to_privkey(JNIEnv *env, struct ecc_scalar* privKey, jbyteArray priv) {
+ jsize priv_len = (*env)->GetArrayLength(env, priv);
+ jbyte *priv_data = (*env)->GetByteArrayElements(env, priv, NULL);
+ mpz_t mp;
+ mpz_init(mp);
+ mpz_import(mp, priv_len, 1, sizeof(unsigned char), 0, 0, priv_data);
+ (*env)->ReleaseByteArrayElements(env, priv, priv_data, JNI_ABORT);
+ ecc_scalar_set(privKey, mp);
+ return priv_len;
+}
+
+JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_00024Nettle_generateSecret___3B_3BLjava_security_spec_ECGenParameterSpec_2(JNIEnv *env, jobject self, jbyteArray pubkey, jbyteArray privkey, jobject params) {
+ jmethodID get_name = (*env)->GetMethodID(env, ecgen_parameter_spec_class, "getName", "()Ljava/lang/String;");
+ jstring name = (*env)->CallObjectMethod(env, params, get_name);
+ const char* utf_name = (*env)->GetStringUTFChars(env, name, NULL);
+ const struct ecc_curve* curve;
+ int rc;
+ char *curve_name[5] = {"secp192r1", "secp224r1", "secp256r1", "secp384r1", "secp521r1"};
+ int byte_sizes[] = {24, 28, 32, 48, 66};
+ int byte_size;
+ for (int i = 0; i < sizeof(curve_name); i++) {
+ if (strcasecmp(utf_name, curve_name[i]) == 0) {
+ curve = create_curve(env, curve_name[i]);
+ byte_size = byte_sizes[i];
+ break;
+ }
+ }
+ (*env)->ReleaseStringUTFChars(env, name, utf_name);
+ if (!curve) {
+ throw_new(env, "java/security/InvalidAlgorithmParameterException", "Curve for given bitsize not found.");
+ return NULL;
+ }
+
+ struct ecc_scalar privScalar;
+ ecc_scalar_init(&privScalar, curve);
+ barray_to_privkey(env, &privScalar, privkey);
+
+ struct ecc_point eccPubPoint;
+ ecc_point_init(&eccPubPoint, curve);
+ barray_to_pubkey(env, &eccPubPoint, pubkey);
+
+ struct ecc_point resultPoint;
+ ecc_point_init(&resultPoint, curve);
+
+ jbyteArray result = (*env)->NewByteArray(env, byte_size);
+ jbyte *result_data = (*env)->GetByteArrayElements(env, result, NULL);
+
+ native_timing_start();
+ ecc_point_mul(&resultPoint, &privScalar, &eccPubPoint);
+ native_timing_stop();
+
+ mpz_t x;
+ mpz_init(x);
+ ecc_point_get(&resultPoint, x, NULL);
+
+ size_t size;
+
+ mpz_export(NULL, &size, 1, sizeof(unsigned char), 0, 0, x);
+ int diff = byte_size - size;
+ memset(result_data, 0x00, diff);
+ mpz_export((unsigned char*) result_data + diff, &size, 1, sizeof(unsigned char), 0, 0, x);
+ (*env)->ReleaseByteArrayElements(env, result, result_data, 0);
+ ecc_scalar_clear(&privScalar);
+ ecc_point_clear(&eccPubPoint);
+ ecc_point_clear(&resultPoint);
+ mpz_clear(x);
+ return result;
+}
+
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_00024Nettle_generateSecret___3B_3BLjava_security_spec_ECParameterSpec_2Ljava_lang_String_2(JNIEnv *env, jobject self, jbyteArray pubkey, jbyteArray privkey, jobject params, jstring algorithm) {
+ throw_new(env, "java/lang/UnsupportedOperationException", "Not supported.");
+ return NULL;
+}
+
+// credit to https://github.com/crocs-muni/ECTester/blob/master/src/cz/crcs/ectester/standalone/libs/jni/c_utils.c
+size_t signature_to_der(struct dsa_signature* signature, unsigned char *result, int byte_size) {
+ size_t r_tmpSize;
+ size_t s_tmpSize;
+ size_t sequenceSize;
+ size_t sequenceSizeSize = 0;
+ size_t wholeSize;
+
+ mpz_export(NULL, &r_tmpSize, 1, sizeof(unsigned char), 0, 0, signature->r);
+ mpz_export(NULL, &s_tmpSize, 1, sizeof(unsigned char), 0, 0, signature->s);
+
+ unsigned char r_tmp[r_tmpSize];
+ unsigned char s_tmp[s_tmpSize];
+ mpz_export(r_tmp, &r_tmpSize, 1, sizeof(unsigned char), 0, 0, signature->r);
+ mpz_export(s_tmp, &s_tmpSize, 1, sizeof(unsigned char), 0, 0, signature->s);
+
+ size_t rSize = r_tmpSize + (r_tmp[0] & 0x80 ? 1 : 0);
+ size_t sSize = s_tmpSize + (s_tmp[0] & 0x80 ? 1 : 0);
+
+ sequenceSize = 2 + rSize + 2 + sSize;
+
+ if (sequenceSize > 127) {
+ size_t s = sequenceSize;
+ do {
+ sequenceSizeSize++;
+ } while ((s = s >> 8));
+ }
+
+ wholeSize = sequenceSize + sequenceSizeSize + 2;
+ if (!result) {
+ return wholeSize;
+ }
+
+ int index = 0;
+ result[index++] = 0x30;
+ if (sequenceSize < 128) {
+ result[index++] = sequenceSize;
+ } else {
+ result[index++] = sequenceSizeSize | 0x80;
+ for (size_t i = 0; i < sequenceSizeSize; i++) {
+ result[index++] = sequenceSize & (0xff << (8 * (sequenceSizeSize - i - 1)));
+ }
+ }
+ result[index++] = 0x02;
+ result[index++] = rSize;
+ if (r_tmp[0] & 0x80) {
+ result[index++] = 0x00;
+ }
+ memcpy(result + index, r_tmp, r_tmpSize);
+ index += r_tmpSize;
+ result[index++] = 0x02;
+ result[index++] = sSize;
+ if (s_tmp[0] & 0x80) {
+ result[index++] = 0x00;
+ }
+ memcpy(result + index, s_tmp, s_tmpSize);
+ return wholeSize;
+}
+// credit to https://github.com/crocs-muni/ECTester/blob/master/src/cz/crcs/ectester/standalone/libs/jni/c_utils.cs
+int der_to_signature(struct dsa_signature* signature, unsigned char* der) {
+ int index = 0;
+ size_t sequenceSize;
+ size_t sequenceSizeSize;
+ if (der[index++] != 0x30) {
+ return 0;
+ }
+
+ if (!(der[index] & 0x80)) {
+ sequenceSize = der[index++];
+ } else {
+ sequenceSizeSize = der[index++] & 0x7f;
+ while(sequenceSizeSize > 0) {
+ sequenceSizeSize--;
+ sequenceSize |= der[index++] << (sequenceSizeSize);
+ }
+ }
+
+ if (der[index++] != 0x02) {
+ return 0;
+ }
+
+ size_t rLength = der[index++];
+ mpz_import(signature->r, rLength, 1, sizeof(unsigned char), 0, 0, der + index);
+ index += rLength;
+ if (der[index++] != 0x02) {
+ return 0;
+ }
+ size_t sLength = der[index++];
+ mpz_import(signature->s, sLength, 1, sizeof(unsigned char), 0, 0, der + index);
+ return 1;
+
+}
+
+JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024Nettle_sign(JNIEnv *env, jobject self, jbyteArray data, jbyteArray privkey, jobject params) {
+ jmethodID get_name = (*env)->GetMethodID(env, ecgen_parameter_spec_class, "getName", "()Ljava/lang/String;");
+ jstring name = (*env)->CallObjectMethod(env, params, get_name);
+ const char* utf_name = (*env)->GetStringUTFChars(env, name, NULL);
+ const struct ecc_curve* curve;
+ int rc;
+ int byte_size;
+ char *curve_name[5] = {"secp192r1", "secp224r1", "secp256r1", "secp384r1", "secp521r1"};
+ int byte_sizes[] = {24, 28, 32, 48, 66};
+ for (int i = 0; i < sizeof(curve_name); i++) {
+ if (strcasecmp(utf_name, curve_name[i]) == 0) {
+ curve = create_curve(env, curve_name[i]);
+ byte_size = byte_sizes[i] + 1;
+ break;
+ }
+ }
+ (*env)->ReleaseStringUTFChars(env, name, utf_name);
+ if (!curve) {
+ throw_new(env, "java/security/InvalidAlgorithmParameterException", "Curve for given bitsize not found.");
+ return NULL;
+ }
+ struct ecc_scalar privScalar;
+ ecc_scalar_init(&privScalar, curve);
+ barray_to_privkey(env, &privScalar, privkey);
+
+ jsize data_size = (*env)->GetArrayLength(env, data);
+ jbyte *data_data = (*env)->GetByteArrayElements(env, data, NULL);
+
+ struct dsa_signature signature;
+ dsa_signature_init(&signature);
+
+ native_timing_start();
+ ecdsa_sign(&privScalar, (void *) &yarrow, (nettle_random_func *) yarrow256_random, data_size, (unsigned char*)data_data, &signature);
+ native_timing_stop();
+
+ (*env)->ReleaseByteArrayElements(env, data, data_data, JNI_ABORT);
+
+
+ jsize sig_len = signature_to_der(&signature, NULL, byte_size);
+ jbyteArray result = (*env)->NewByteArray(env, sig_len);
+ jbyte *result_data = (*env)->GetByteArrayElements(env, result, NULL);
+ signature_to_der(&signature, (unsigned char *)result_data, byte_size);
+ (*env)->ReleaseByteArrayElements(env, result, result_data, 0);
+
+ ecc_scalar_clear(&privScalar);
+ dsa_signature_clear(&signature);
+ return result;
+}
+
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024Nettle_verify(JNIEnv *env, jobject self, jbyteArray signature, jbyteArray data, jbyteArray pubkey, jobject params) {
+ jmethodID get_name = (*env)->GetMethodID(env, ecgen_parameter_spec_class, "getName", "()Ljava/lang/String;");
+ jstring name = (*env)->CallObjectMethod(env, params, get_name);
+ const char* utf_name = (*env)->GetStringUTFChars(env, name, NULL);
+ const struct ecc_curve* curve;
+ int rc;
+ char *curve_name[5] = {"secp192r1", "secp224r1", "secp256r1", "secp384r1", "secp521r1"};
+ for (int i = 0; i < sizeof(curve_name); i++) {
+ if (strcasecmp(utf_name, curve_name[i]) == 0) {
+ curve = create_curve(env, curve_name[i]);
+ break;
+ }
+ }
+ (*env)->ReleaseStringUTFChars(env, name, utf_name);
+ if (!curve) {
+ throw_new(env, "java/security/InvalidAlgorithmParameterException", "Curve for given bitsize not found.");
+ return false;
+ }
+
+ struct ecc_point eccPubPoint;
+ ecc_point_init(&eccPubPoint, curve);
+ barray_to_pubkey(env, &eccPubPoint, pubkey);
+
+ jsize sig_len = (*env)->GetArrayLength(env, signature);
+ jbyte *sig_data = (*env)->GetByteArrayElements(env, signature, NULL);
+
+ struct dsa_signature eccSignature;
+ dsa_signature_init(&eccSignature);
+
+ if (!der_to_signature(&eccSignature, (unsigned char*) sig_data)) {
+ throw_new(env, "java/security/InvalidAlgorithmParameterException", "Invalid DER encoding of the signature.");
+ return false;
+ }
+
+ (*env)->ReleaseByteArrayElements(env, signature, sig_data, JNI_ABORT);
+
+ jsize data_size = (*env)->GetArrayLength(env, data);
+ jbyte *data_data = (*env)->GetByteArrayElements(env, data, NULL);
+
+ native_timing_start();
+ int result = ecdsa_verify(&eccPubPoint, data_size, (unsigned char*)data_data, &eccSignature);
+ native_timing_stop();
+ (*env)->ReleaseByteArrayElements(env, data, data_data, JNI_ABORT);
+
+ ecc_point_clear(&eccPubPoint);
+ dsa_signature_clear(&eccSignature);
+ return (result == 1) ? JNI_TRUE : JNI_FALSE;
+}