summaryrefslogtreecommitdiff
path: root/src/cz/crcs/ectester/standalone/libs/jni
diff options
context:
space:
mode:
authorJ08nY2018-01-23 17:31:15 +0100
committerJ08nY2018-01-23 17:31:15 +0100
commitcb6c6b8b1274fe5a340c4317a4b015ea0ef15396 (patch)
tree864a54dcdf07da33cd139312c8b0ee693e1a0eff /src/cz/crcs/ectester/standalone/libs/jni
parent6c46a27a52854aee24f7a37e74002bd6f4485723 (diff)
parentc581e39e539e6dadb49d9f83f563ab2b375f6e0b (diff)
downloadECTester-0.2.0.tar.gz
ECTester-0.2.0.tar.zst
ECTester-0.2.0.zip
Diffstat (limited to 'src/cz/crcs/ectester/standalone/libs/jni')
-rw-r--r--src/cz/crcs/ectester/standalone/libs/jni/Makefile70
-rw-r--r--src/cz/crcs/ectester/standalone/libs/jni/NativeECPrivateKey.java68
-rw-r--r--src/cz/crcs/ectester/standalone/libs/jni/NativeECPublicKey.java69
-rw-r--r--src/cz/crcs/ectester/standalone/libs/jni/NativeKeyAgreementSpi.java137
-rw-r--r--src/cz/crcs/ectester/standalone/libs/jni/NativeKeyPairGeneratorSpi.java123
-rw-r--r--src/cz/crcs/ectester/standalone/libs/jni/NativeProvider.java42
-rw-r--r--src/cz/crcs/ectester/standalone/libs/jni/NativeSignatureSpi.java227
-rw-r--r--src/cz/crcs/ectester/standalone/libs/jni/botan.cpp631
-rw-r--r--src/cz/crcs/ectester/standalone/libs/jni/c_utils.c66
-rw-r--r--src/cz/crcs/ectester/standalone/libs/jni/c_utils.h28
-rw-r--r--src/cz/crcs/ectester/standalone/libs/jni/cpp_utils.cpp59
-rw-r--r--src/cz/crcs/ectester/standalone/libs/jni/cpp_utils.hpp29
-rw-r--r--src/cz/crcs/ectester/standalone/libs/jni/native.h344
-rw-r--r--src/cz/crcs/ectester/standalone/libs/jni/tomcrypt.c450
14 files changed, 2343 insertions, 0 deletions
diff --git a/src/cz/crcs/ectester/standalone/libs/jni/Makefile b/src/cz/crcs/ectester/standalone/libs/jni/Makefile
new file mode 100644
index 0000000..3530499
--- /dev/null
+++ b/src/cz/crcs/ectester/standalone/libs/jni/Makefile
@@ -0,0 +1,70 @@
+ifeq ($(JAVA_HOME),)
+ifeq ($(OS),Windows_NT)
+which = $(shell where $1)
+else
+which = $(shell which $1)
+endif
+JAVAC ?= $(realpath $(call which,javac))
+JAVA_HOME = $(abspath $(dir $(JAVAC))..)
+endif
+
+ifneq ($(JAVA_HOME),)
+JNI_INCLUDEDIR ?= $(JAVA_HOME)/include
+endif
+
+ifeq ($(JNI_INCLUDEDIR),)
+$(error could not determine JNI include dir, try specifying either \
+ JAVA_HOME or JNI_INCLUDEDIR)
+endif
+
+TARGETTRIPLET := $(shell $(CC) -dumpmachine)
+ifeq ($(JNI_PLATFORM),)
+ifeq ($(findstring mingw,$(TARGETTRIPLET)),mingw)
+JNI_PLATFORM:= win32
+else
+ifeq ($(findstring linux,$(TARGETTRIPLET)),linux)
+JNI_PLATFORM:= linux
+# add more checks here
+endif
+endif
+endif
+
+JNI_PLATFORMINCLUDEDIR ?= $(JNI_INCLUDEDIR)/$(JNI_PLATFORM)
+
+LOCAL_INCLUDES = /usr/local/include
+LOCAL_LIBS = /usr/local/lib
+
+CC?=gcc
+CXX?=g++
+
+CFLAGS+=-fPIC -g -I"$(JNI_INCLUDEDIR)" -I"$(JNI_PLATFORMINCLUDEDIR)" -I.
+CXXFLAGS+=-fPIC -g -I"$(JNI_INCLUDEDIR)" -I"$(JNI_PLATFORMINCLUDEDIR)" -I.
+
+
+all: tomcrypt_provider.so botan_provider.so
+
+c_utils.o: c_utils.c
+ $(CC) $(CFLAGS) -c $<
+
+cpp_utils.o: cpp_utils.cpp
+ $(CXX) $(CXXFLAGS) -c $<
+
+
+tomcrypt_provider.so: tomcrypt.o c_utils.o
+ $(CC) -fPIC -g -shared -o $@ $^ -L. -ltommath -ltomcrypt
+
+tomcrypt.o: tomcrypt.c
+ $(CC) -DLTM_DESC $(CFLAGS) -c $<
+
+
+botan_provider.so: botan.o cpp_utils.o
+ $(CXX) -fPIC -g -shared -o $@ $^ -L. -L"$(LOCAL_LIBS)" -lbotan-2 -fstack-protector -m64 -pthread
+
+botan.o: botan.cpp
+ $(CXX) -I"$(LOCAL_INCLUDES)/botan-2" $(CFLAGS) -c $<
+
+clean:
+ rm -rf *.o
+ rm -rf *.so
+
+.PHONY: all clean \ No newline at end of file
diff --git a/src/cz/crcs/ectester/standalone/libs/jni/NativeECPrivateKey.java b/src/cz/crcs/ectester/standalone/libs/jni/NativeECPrivateKey.java
new file mode 100644
index 0000000..22e5329
--- /dev/null
+++ b/src/cz/crcs/ectester/standalone/libs/jni/NativeECPrivateKey.java
@@ -0,0 +1,68 @@
+package cz.crcs.ectester.standalone.libs.jni;
+
+import org.bouncycastle.util.Arrays;
+
+import java.math.BigInteger;
+import java.security.interfaces.ECPrivateKey;
+import java.security.spec.ECParameterSpec;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public abstract class NativeECPrivateKey implements ECPrivateKey {
+ private String algorithm;
+ private String format;
+
+ public NativeECPrivateKey(String algorithm, String format) {
+ this.algorithm = algorithm;
+ this.format = format;
+ }
+
+ @Override
+ public String getAlgorithm() {
+ return algorithm;
+ }
+
+ @Override
+ public String getFormat() {
+ return format;
+ }
+
+ private static class Raw extends NativeECPrivateKey {
+ private byte[] keyData;
+ private ECParameterSpec params;
+
+ public Raw(byte[] keyData, ECParameterSpec params) {
+ super("EC", "raw");
+ this.keyData = keyData;
+ this.params = params;
+ }
+
+ @Override
+ public BigInteger getS() {
+ return new BigInteger(1, keyData);
+ }
+
+ @Override
+ public byte[] getEncoded() {
+ return Arrays.clone(keyData);
+ }
+
+ @Override
+ public ECParameterSpec getParams() {
+ return params;
+ }
+ }
+
+ public static class TomCrypt extends Raw {
+ public TomCrypt(byte[] keyData, ECParameterSpec params) {
+ super(keyData, params);
+ }
+ }
+
+ public static class Botan extends Raw {
+ public Botan(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
new file mode 100644
index 0000000..8fc4747
--- /dev/null
+++ b/src/cz/crcs/ectester/standalone/libs/jni/NativeECPublicKey.java
@@ -0,0 +1,69 @@
+package cz.crcs.ectester.standalone.libs.jni;
+
+import cz.crcs.ectester.common.util.ECUtil;
+import org.bouncycastle.util.Arrays;
+
+import java.security.interfaces.ECPublicKey;
+import java.security.spec.ECParameterSpec;
+import java.security.spec.ECPoint;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public abstract class NativeECPublicKey implements ECPublicKey {
+ private String algorithm;
+ private String format;
+
+ public NativeECPublicKey(String algorithm, String format) {
+ this.algorithm = algorithm;
+ this.format = format;
+ }
+
+ @Override
+ public String getAlgorithm() {
+ return algorithm;
+ }
+
+ @Override
+ public String getFormat() {
+ return format;
+ }
+
+ private static class ANSIX962 extends NativeECPublicKey {
+ private byte[] keyData;
+ private ECParameterSpec params;
+
+ public ANSIX962(byte[] keyData, ECParameterSpec params) {
+ super("EC", "ANSI X9.62");
+ this.keyData = keyData;
+ this.params = params;
+ }
+
+ @Override
+ public ECPoint getW() {
+ return ECUtil.fromX962(keyData, params.getCurve());
+ }
+
+ @Override
+ public byte[] getEncoded() {
+ return Arrays.clone(keyData);
+ }
+
+ @Override
+ public ECParameterSpec getParams() {
+ return params;
+ }
+ }
+
+ public static class TomCrypt extends ANSIX962 {
+ public TomCrypt(byte[] keyData, ECParameterSpec params) {
+ super(keyData, params);
+ }
+ }
+
+ public static class Botan extends ANSIX962 {
+ public Botan(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
new file mode 100644
index 0000000..37c9add
--- /dev/null
+++ b/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyAgreementSpi.java
@@ -0,0 +1,137 @@
+package cz.crcs.ectester.standalone.libs.jni;
+
+import cz.crcs.ectester.common.util.ECUtil;
+
+import javax.crypto.KeyAgreementSpi;
+import javax.crypto.SecretKey;
+import javax.crypto.ShortBufferException;
+import java.security.*;
+import java.security.interfaces.ECPrivateKey;
+import java.security.interfaces.ECPublicKey;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.ECParameterSpec;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public abstract class NativeKeyAgreementSpi extends KeyAgreementSpi {
+ private ECPrivateKey privateKey;
+ private ECPublicKey publicKey;
+ private ECParameterSpec params;
+
+ @Override
+ protected void engineInit(Key key, SecureRandom random) throws InvalidKeyException {
+ if (!(key instanceof ECPrivateKey)) {
+ throw new InvalidKeyException
+ ("Key must be instance of ECPrivateKey");
+ }
+ privateKey = (ECPrivateKey) key;
+ this.params = privateKey.getParams();
+ }
+
+ @Override
+ protected void engineInit(Key key, AlgorithmParameterSpec params, SecureRandom random) throws InvalidKeyException, InvalidAlgorithmParameterException {
+ if (!(params instanceof ECParameterSpec)) {
+ throw new InvalidAlgorithmParameterException();
+ }
+ engineInit(key, random);
+ this.params = (ECParameterSpec) params;
+ }
+
+ @Override
+ protected Key engineDoPhase(Key key, boolean lastPhase) throws InvalidKeyException, IllegalStateException {
+ if (privateKey == null) {
+ throw new IllegalStateException("Not initialized");
+ }
+ if (publicKey != null) {
+ throw new IllegalStateException("Phase already executed");
+ }
+ if (!lastPhase) {
+ throw new IllegalStateException
+ ("Only two party agreement supported, lastPhase must be true");
+ }
+ if (!(key instanceof ECPublicKey)) {
+ throw new InvalidKeyException
+ ("Key must be an instance of ECPublicKey");
+ }
+ publicKey = (ECPublicKey) key;
+ return null;
+ }
+
+ @Override
+ protected byte[] engineGenerateSecret() throws IllegalStateException {
+ byte[] pubkey = ECUtil.toX962Uncompressed(publicKey.getW(), params.getCurve());
+ byte[] privkey = ECUtil.toByteArray(privateKey.getS(), params.getCurve().getField().getFieldSize());
+ return generateSecret(pubkey, privkey, params);
+ }
+
+ @Override
+ protected int engineGenerateSecret(byte[] sharedSecret, int offset) throws IllegalStateException, ShortBufferException {
+ byte[] secret = engineGenerateSecret();
+ if (sharedSecret.length < offset + secret.length) {
+ throw new ShortBufferException();
+ }
+ System.arraycopy(secret, 0, sharedSecret, offset, secret.length);
+ return secret.length;
+ }
+
+ @Override
+ protected SecretKey engineGenerateSecret(String algorithm) throws IllegalStateException, NoSuchAlgorithmException, InvalidKeyException {
+ throw new NoSuchAlgorithmException(algorithm);
+ }
+
+ abstract byte[] generateSecret(byte[] pubkey, byte[] privkey, ECParameterSpec params);
+
+
+ public static class TomCrypt extends NativeKeyAgreementSpi {
+
+ @Override
+ native byte[] generateSecret(byte[] pubkey, byte[] privkey, ECParameterSpec params);
+ }
+
+ public abstract static class Botan extends NativeKeyAgreementSpi {
+ private String type;
+ public Botan(String type) {
+ this.type = type;
+ }
+
+ @Override
+ native byte[] generateSecret(byte[] pubkey, byte[] privkey, ECParameterSpec params);
+ }
+
+ public static class BotanECDH extends Botan {
+ public BotanECDH() {
+ super("ECDH");
+ }
+ }
+
+ public static class BotanECDHwithSHA1KDF extends Botan {
+ public BotanECDHwithSHA1KDF() {
+ super("ECDHwithSHA1KDF");
+ }
+ }
+
+ public static class BotanECDHwithSHA224KDF extends Botan {
+ public BotanECDHwithSHA224KDF() {
+ super("ECDHwithSHA224KDF");
+ }
+ }
+
+ public static class BotanECDHwithSHA256KDF extends Botan {
+ public BotanECDHwithSHA256KDF() {
+ super("ECDHwithSHA256KDF");
+ }
+ }
+
+ public static class BotanECDHwithSHA384KDF extends Botan {
+ public BotanECDHwithSHA384KDF() {
+ super("ECDHwithSHA384KDF");
+ }
+ }
+
+ public static class BotanECDHwithSHA512KDF extends Botan {
+ public BotanECDHwithSHA512KDF() {
+ super("ECDHwithSHA512KDF");
+ }
+ }
+}
diff --git a/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyPairGeneratorSpi.java b/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyPairGeneratorSpi.java
new file mode 100644
index 0000000..9461251
--- /dev/null
+++ b/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyPairGeneratorSpi.java
@@ -0,0 +1,123 @@
+package cz.crcs.ectester.standalone.libs.jni;
+
+import java.security.*;
+import java.security.spec.AlgorithmParameterSpec;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public abstract class NativeKeyPairGeneratorSpi extends KeyPairGeneratorSpi {
+ private int keysize;
+ private SecureRandom random;
+ private AlgorithmParameterSpec params;
+ private boolean useKeysize;
+ private boolean useParams;
+
+ @Override
+ public void initialize(int keysize, SecureRandom random) {
+ if (!keysizeSupported(keysize)) {
+ throw new InvalidParameterException("Keysize " + keysize + " not supported.");
+ }
+ this.keysize = keysize;
+ this.random = random;
+ this.useKeysize = true;
+ this.useParams = false;
+ }
+
+ @Override
+ public void initialize(AlgorithmParameterSpec params, SecureRandom random) throws InvalidAlgorithmParameterException {
+ if (!paramsSupported(params)) {
+ throw new InvalidAlgorithmParameterException("not supported.");
+ }
+ this.params = params;
+ this.random = random;
+ this.useParams = true;
+ this.useKeysize = false;
+ }
+
+ @Override
+ public KeyPair generateKeyPair() {
+ if (useKeysize) {
+ return generate(keysize, random);
+ } else if (useParams) {
+ return generate(params, random);
+ }
+ return null;
+ }
+
+ abstract boolean keysizeSupported(int keysize);
+
+ abstract boolean paramsSupported(AlgorithmParameterSpec params);
+
+ abstract KeyPair generate(int keysize, SecureRandom random);
+
+ abstract KeyPair generate(AlgorithmParameterSpec params, SecureRandom random);
+
+ public static class TomCrypt extends NativeKeyPairGeneratorSpi {
+
+ public TomCrypt() {
+ 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
+ native KeyPair generate(AlgorithmParameterSpec params, SecureRandom random);
+ }
+
+ public static abstract class Botan extends NativeKeyPairGeneratorSpi {
+ private String type;
+
+ public Botan(String type) {
+ this.type = type;
+ 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
+ native KeyPair generate(AlgorithmParameterSpec params, SecureRandom random);
+ }
+
+ public static class BotanECDH extends Botan {
+
+ public BotanECDH() {
+ super("ECDH");
+ }
+ }
+
+ public static class BotanECDSA extends Botan {
+
+ public BotanECDSA() {
+ super("ECDSA");
+ }
+ }
+
+ public static class BotanECKCDSA extends Botan {
+
+ public BotanECKCDSA() {
+ super("ECKCDSA");
+ }
+ }
+
+ public static class BotanECGDSA extends Botan {
+
+ public BotanECGDSA() {
+ super("ECGDSA");
+ }
+ }
+}
diff --git a/src/cz/crcs/ectester/standalone/libs/jni/NativeProvider.java b/src/cz/crcs/ectester/standalone/libs/jni/NativeProvider.java
new file mode 100644
index 0000000..a0689d6
--- /dev/null
+++ b/src/cz/crcs/ectester/standalone/libs/jni/NativeProvider.java
@@ -0,0 +1,42 @@
+package cz.crcs.ectester.standalone.libs.jni;
+
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.security.Provider;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public abstract class NativeProvider extends Provider {
+
+ public NativeProvider(String name, double version, String info) {
+ super(name, version, info);
+
+ AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
+ setup();
+ return null;
+ });
+ }
+
+ abstract void setup();
+
+ public static class TomCrypt extends NativeProvider {
+
+ public TomCrypt(String name, double version, String info) {
+ super(name, version, info);
+ }
+
+ @Override
+ native void setup();
+ }
+
+ public static class Botan extends NativeProvider {
+
+ public Botan(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
new file mode 100644
index 0000000..b212697
--- /dev/null
+++ b/src/cz/crcs/ectester/standalone/libs/jni/NativeSignatureSpi.java
@@ -0,0 +1,227 @@
+package cz.crcs.ectester.standalone.libs.jni;
+
+import cz.crcs.ectester.common.util.ECUtil;
+
+import java.io.ByteArrayOutputStream;
+import java.security.*;
+import java.security.interfaces.ECPrivateKey;
+import java.security.interfaces.ECPublicKey;
+import java.security.spec.ECParameterSpec;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public abstract class NativeSignatureSpi extends SignatureSpi {
+ private ECPublicKey verifyKey;
+ private ECPrivateKey signKey;
+ private ECParameterSpec params;
+
+ private ByteArrayOutputStream buffer = new ByteArrayOutputStream();
+
+ @Override
+ protected void engineInitVerify(PublicKey publicKey) throws InvalidKeyException {
+ if (!(publicKey instanceof ECPublicKey)) {
+ throw new InvalidKeyException
+ ("Key must be an instance of ECPublicKey");
+ }
+ verifyKey = (ECPublicKey) publicKey;
+ params = verifyKey.getParams();
+ buffer.reset();
+ }
+
+ @Override
+ protected void engineInitSign(PrivateKey privateKey) throws InvalidKeyException {
+ if (!(privateKey instanceof ECPrivateKey)) {
+ throw new InvalidKeyException
+ ("Key must be an instance of ECPrivateKey");
+ }
+ signKey = (ECPrivateKey) privateKey;
+ params = signKey.getParams();
+ buffer.reset();
+ }
+
+ @Override
+ protected void engineUpdate(byte b) throws SignatureException {
+ buffer.write(b);
+ }
+
+ @Override
+ protected void engineUpdate(byte[] b, int off, int len) throws SignatureException {
+ buffer.write(b, off, len);
+ }
+
+ @Override
+ protected byte[] engineSign() throws SignatureException {
+ return sign(buffer.toByteArray(), ECUtil.toByteArray(signKey.getS(), params.getCurve().getField().getFieldSize()), params);
+ }
+
+ @Override
+ protected boolean engineVerify(byte[] sigBytes) throws SignatureException {
+ return verify(sigBytes, buffer.toByteArray(), ECUtil.toX962Uncompressed(verifyKey.getW(), params), params);
+ }
+
+ @Override
+ @Deprecated
+ protected void engineSetParameter(String param, Object value) throws InvalidParameterException {
+ throw new UnsupportedOperationException("setParameter() not supported");
+ }
+
+ @Override
+ @Deprecated
+ protected Object engineGetParameter(String param) throws InvalidParameterException {
+ throw new UnsupportedOperationException("getParameter() not supported");
+ }
+
+ abstract byte[] sign(byte[] data, byte[] privkey, ECParameterSpec params);
+
+ abstract boolean verify(byte[] signature, byte[] data, byte[] pubkey, ECParameterSpec params);
+
+ public static class TomCryptRaw extends NativeSignatureSpi {
+
+ @Override
+ native byte[] sign(byte[] data, byte[] privkey, ECParameterSpec params);
+
+ @Override
+ native boolean verify(byte[] signature, byte[] data, byte[] pubkey, ECParameterSpec params);
+ }
+
+ public abstract static class Botan extends NativeSignatureSpi {
+ private String type;
+
+ public Botan(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 BotanECDSAwithNONE extends Botan {
+
+ public BotanECDSAwithNONE() {
+ super("NONEwithECDSA");
+ }
+ }
+
+ public static class BotanECDSAwithSHA1 extends Botan {
+
+ public BotanECDSAwithSHA1() {
+ super("SHA1withECDSA");
+ }
+ }
+
+ public static class BotanECDSAwithSHA224 extends Botan {
+
+ public BotanECDSAwithSHA224() {
+ super("SHA224withECDSA");
+ }
+ }
+
+ public static class BotanECDSAwithSHA256 extends Botan {
+
+ public BotanECDSAwithSHA256() {
+ super("SHA256withECDSA");
+ }
+ }
+
+ public static class BotanECDSAwithSHA384 extends Botan {
+
+ public BotanECDSAwithSHA384() {
+ super("SHA384withECDSA");
+ }
+ }
+
+ public static class BotanECDSAwithSHA512 extends Botan {
+
+ public BotanECDSAwithSHA512() {
+ super("SHA512withECDSA");
+ }
+ }
+
+ public static class BotanECKCDSAwithNONE extends Botan {
+
+ public BotanECKCDSAwithNONE() {
+ super("NONEwithECKCDSA");
+ }
+ }
+
+ public static class BotanECKCDSAwithSHA1 extends Botan {
+
+ public BotanECKCDSAwithSHA1() {
+ super("SHA1withECKCDSA");
+ }
+ }
+
+ public static class BotanECKCDSAwithSHA224 extends Botan {
+
+ public BotanECKCDSAwithSHA224() {
+ super("SHA224withECKCDSA");
+ }
+ }
+
+ public static class BotanECKCDSAwithSHA256 extends Botan {
+
+ public BotanECKCDSAwithSHA256() {
+ super("SHA256withECKCDSA");
+ }
+ }
+
+ public static class BotanECKCDSAwithSHA384 extends Botan {
+
+ public BotanECKCDSAwithSHA384() {
+ super("SHA384withECKCDSA");
+ }
+ }
+
+ public static class BotanECKCDSAwithSHA512 extends Botan {
+
+ public BotanECKCDSAwithSHA512() {
+ super("SHA512withECKCDSA");
+ }
+ }
+
+ public static class BotanECGDSAwithNONE extends Botan {
+
+ public BotanECGDSAwithNONE() {
+ super("NONEwithECGDSA");
+ }
+ }
+
+ public static class BotanECGDSAwithSHA1 extends Botan {
+
+ public BotanECGDSAwithSHA1() {
+ super("SHA1withECGDSA");
+ }
+ }
+
+ public static class BotanECGDSAwithSHA224 extends Botan {
+
+ public BotanECGDSAwithSHA224() {
+ super("SHA224withECGDSA");
+ }
+ }
+
+ public static class BotanECGDSAwithSHA256 extends Botan {
+
+ public BotanECGDSAwithSHA256() {
+ super("SHA256withECGDSA");
+ }
+ }
+
+ public static class BotanECGDSAwithSHA384 extends Botan {
+
+ public BotanECGDSAwithSHA384() {
+ super("SHA384withECGDSA");
+ }
+ }
+
+ public static class BotanECGDSAwithSHA512 extends Botan {
+
+ public BotanECGDSAwithSHA512() {
+ super("SHA512withECGDSA");
+ }
+ }
+}
diff --git a/src/cz/crcs/ectester/standalone/libs/jni/botan.cpp b/src/cz/crcs/ectester/standalone/libs/jni/botan.cpp
new file mode 100644
index 0000000..8e666d6
--- /dev/null
+++ b/src/cz/crcs/ectester/standalone/libs/jni/botan.cpp
@@ -0,0 +1,631 @@
+#include "native.h"
+#include <string>
+#include <botan/botan.h>
+#include <botan/ec_group.h>
+#include <botan/ecc_key.h>
+#include <botan/ecdsa.h>
+#include <botan/eckcdsa.h>
+#include <botan/ecgdsa.h>
+#include <botan/ecdh.h>
+#include <botan/pubkey.h>
+#include "cpp_utils.hpp"
+
+static jclass provider_class;
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_BotanLib
+ * Method: createProvider
+ * Signature: ()Ljava/security/Provider;
+ */
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_BotanLib_createProvider(JNIEnv *env, jobject self) {
+ /* Create the custom provider. */
+ jclass local_provider_class = env->FindClass("cz/crcs/ectester/standalone/libs/jni/NativeProvider$Botan");
+ provider_class = (jclass) env->NewGlobalRef(local_provider_class);
+
+ jmethodID init = env->GetMethodID(local_provider_class, "<init>", "(Ljava/lang/String;DLjava/lang/String;)V");
+
+ const char* info_str = Botan::version_cstr();
+ const char* v_str = Botan::short_version_cstr();
+ std::string name_str = Botan::short_version_string();
+ name_str.insert(0, "Botan ");
+
+ jstring name = env->NewStringUTF(name_str.c_str());
+ double version = strtod(v_str, NULL);
+ jstring info = env->NewStringUTF(info_str);
+
+ return env->NewObject(provider_class, init, name, version, info);
+}
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeProvider_Botan
+ * Method: setup
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeProvider_00024Botan_setup(JNIEnv *env, jobject self){
+ jmethodID provider_put = env->GetMethodID(provider_class, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
+
+ jstring ecdh = env->NewStringUTF("KeyPairGenerator.ECDH");
+ jstring ecdh_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeKeyPairGeneratorSpi$BotanECDH");
+ env->CallObjectMethod(self, provider_put, ecdh, ecdh_value);
+
+ jstring ecdsa = env->NewStringUTF("KeyPairGenerator.ECDSA");
+ jstring ecdsa_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeKeyPairGeneratorSpi$BotanECDSA");
+ env->CallObjectMethod(self, provider_put, ecdsa, ecdsa_value);
+
+ jstring eckcdsa = env->NewStringUTF("KeyPairGenerator.ECKCDSA");
+ jstring eckcdsa_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeKeyPairGeneratorSpi$BotanECKCDSA");
+ env->CallObjectMethod(self, provider_put, eckcdsa, eckcdsa_value);
+
+ jstring ecgdsa = env->NewStringUTF("KeyPairGenerator.ECGDSA");
+ jstring ecgdsa_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeKeyPairGeneratorSpi$BotanECGDSA");
+ env->CallObjectMethod(self, provider_put, ecgdsa, ecgdsa_value);
+
+ jstring ecdh_ka = env->NewStringUTF("KeyAgreement.ECDH");
+ jstring ecdh_ka_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeKeyAgreementSpi$BotanECDH");
+ env->CallObjectMethod(self, provider_put, ecdh_ka, ecdh_ka_value);
+
+ jstring ecdh_sha1_ka = env->NewStringUTF("KeyAgreement.ECDHwithSHA1KDF");
+ jstring ecdh_sha1_ka_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeKeyAgreementSpi$BotanECDHwithSHA1KDF");
+ env->CallObjectMethod(self, provider_put, ecdh_sha1_ka, ecdh_sha1_ka_value);
+
+ jstring ecdh_sha224_ka = env->NewStringUTF("KeyAgreement.ECDHwithSHA224KDF");
+ jstring ecdh_sha224_ka_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeKeyAgreementSpi$BotanECDHwithSHA224KDF");
+ env->CallObjectMethod(self, provider_put, ecdh_sha224_ka, ecdh_sha224_ka_value);
+
+ jstring ecdh_sha256_ka = env->NewStringUTF("KeyAgreement.ECDHwithSHA256KDF");
+ jstring ecdh_sha256_ka_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeKeyAgreementSpi$BotanECDHwithSHA256KDF");
+ env->CallObjectMethod(self, provider_put, ecdh_sha256_ka, ecdh_sha256_ka_value);
+
+ jstring ecdh_sha384_ka = env->NewStringUTF("KeyAgreement.ECDHwithSHA384KDF");
+ jstring ecdh_sha384_ka_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeKeyAgreementSpi$BotanECDHwithSHA384KDF");
+ env->CallObjectMethod(self, provider_put, ecdh_sha384_ka, ecdh_sha384_ka_value);
+
+ jstring ecdh_sha512_ka = env->NewStringUTF("KeyAgreement.ECDHwithSHA512KDF");
+ jstring ecdh_sha512_ka_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeKeyAgreementSpi$BotanECDHwithSHA512KDF");
+ env->CallObjectMethod(self, provider_put, ecdh_sha512_ka, ecdh_sha512_ka_value);
+
+ jstring ecdsa_sig = env->NewStringUTF("Signature.NONEwithECDSA");
+ jstring ecdsa_sig_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeSignatureSpi$BotanECDSAwithNONE");
+ env->CallObjectMethod(self, provider_put, ecdsa_sig, ecdsa_sig_value);
+
+ jstring ecdsa_sha1_sig = env->NewStringUTF("Signature.SHA1withECDSA");
+ jstring ecdsa_sha1_sig_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeSignatureSpi$BotanECDSAwithSHA1");
+ env->CallObjectMethod(self, provider_put, ecdsa_sha1_sig, ecdsa_sha1_sig_value);
+
+ jstring ecdsa_sha224_sig = env->NewStringUTF("Signature.SHA224withECDSA");
+ jstring ecdsa_sha224_sig_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeSignatureSpi$BotanECDSAwithSHA224");
+ env->CallObjectMethod(self, provider_put, ecdsa_sha224_sig, ecdsa_sha224_sig_value);
+
+ jstring ecdsa_sha256_sig = env->NewStringUTF("Signature.SHA256withECDSA");
+ jstring ecdsa_sha256_sig_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeSignatureSpi$BotanECDSAwithSHA256");
+ env->CallObjectMethod(self, provider_put, ecdsa_sha256_sig, ecdsa_sha256_sig_value);
+
+ jstring ecdsa_sha384_sig = env->NewStringUTF("Signature.SHA384withECDSA");
+ jstring ecdsa_sha384_sig_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeSignatureSpi$BotanECDSAwithSHA384");
+ env->CallObjectMethod(self, provider_put, ecdsa_sha384_sig, ecdsa_sha384_sig_value);
+
+ jstring ecdsa_sha512_sig = env->NewStringUTF("Signature.SHA512withECDSA");
+ jstring ecdsa_sha512_sig_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeSignatureSpi$BotanECDSAwithSHA512");
+ env->CallObjectMethod(self, provider_put, ecdsa_sha512_sig, ecdsa_sha512_sig_value);
+
+ jstring eckcdsa_sig = env->NewStringUTF("Signature.NONEwithECKCDSA");
+ jstring eckcdsa_sig_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeSignatureSpi$BotanECKCDSAwithNONE");
+ env->CallObjectMethod(self, provider_put, eckcdsa_sig, eckcdsa_sig_value);
+
+ jstring eckcdsa_sha1_sig = env->NewStringUTF("Signature.SHA1withECKCDSA");
+ jstring eckcdsa_sha1_sig_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeSignatureSpi$BotanECKCDSAwithSHA1");
+ env->CallObjectMethod(self, provider_put, eckcdsa_sha1_sig, eckcdsa_sha1_sig_value);
+
+ jstring eckcdsa_sha224_sig = env->NewStringUTF("Signature.SHA224withECKCDSA");
+ jstring eckcdsa_sha224_sig_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeSignatureSpi$BotanECKCDSAwithSHA224");
+ env->CallObjectMethod(self, provider_put, eckcdsa_sha224_sig, eckcdsa_sha224_sig_value);
+
+ jstring eckcdsa_sha256_sig = env->NewStringUTF("Signature.SHA256withECKCDSA");
+ jstring eckcdsa_sha256_sig_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeSignatureSpi$BotanECKCDSAwithSHA256");
+ env->CallObjectMethod(self, provider_put, eckcdsa_sha256_sig, eckcdsa_sha256_sig_value);
+
+ jstring eckcdsa_sha384_sig = env->NewStringUTF("Signature.SHA384withECKCDSA");
+ jstring eckcdsa_sha384_sig_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeSignatureSpi$BotanECKCDSAwithSHA384");
+ env->CallObjectMethod(self, provider_put, eckcdsa_sha384_sig, eckcdsa_sha384_sig_value);
+
+ jstring eckcdsa_sha512_sig = env->NewStringUTF("Signature.SHA512withECKCDSA");
+ jstring eckcdsa_sha512_sig_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeSignatureSpi$BotanECKCDSAwithSHA512");
+ env->CallObjectMethod(self, provider_put, eckcdsa_sha512_sig, eckcdsa_sha512_sig_value);
+
+ jstring ecgdsa_sig = env->NewStringUTF("Signature.NONEwithECGDSA");
+ jstring ecgdsa_sig_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeSignatureSpi$BotanECGDSAwithNONE");
+ env->CallObjectMethod(self, provider_put, ecgdsa_sig, ecgdsa_sig_value);
+
+ jstring ecgdsa_sha1_sig = env->NewStringUTF("Signature.SHA1withECGDSA");
+ jstring ecgdsa_sha1_sig_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeSignatureSpi$BotanECGDSAwithSHA1");
+ env->CallObjectMethod(self, provider_put, ecgdsa_sha1_sig, ecgdsa_sha1_sig_value);
+
+ jstring ecgdsa_sha224_sig = env->NewStringUTF("Signature.SHA224withECGDSA");
+ jstring ecgdsa_sha224_sig_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeSignatureSpi$BotanECGDSAwithSHA224");
+ env->CallObjectMethod(self, provider_put, ecgdsa_sha224_sig, ecgdsa_sha224_sig_value);
+
+ jstring ecgdsa_sha256_sig = env->NewStringUTF("Signature.SHA256withECGDSA");
+ jstring ecgdsa_sha256_sig_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeSignatureSpi$BotanECGDSAwithSHA256");
+ env->CallObjectMethod(self, provider_put, ecgdsa_sha256_sig, ecgdsa_sha256_sig_value);
+
+ jstring ecgdsa_sha384_sig = env->NewStringUTF("Signature.SHA384withECGDSA");
+ jstring ecgdsa_sha384_sig_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeSignatureSpi$BotanECGDSAwithSHA384");
+ env->CallObjectMethod(self, provider_put, ecgdsa_sha384_sig, ecgdsa_sha384_sig_value);
+
+ jstring ecgdsa_sha512_sig = env->NewStringUTF("Signature.SHA512withECGDSA");
+ jstring ecgdsa_sha512_sig_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeSignatureSpi$BotanECGDSAwithSHA512");
+ env->CallObjectMethod(self, provider_put, ecgdsa_sha512_sig, ecgdsa_sha512_sig_value);
+
+ init_classes(env, "Botan");
+}
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_BotanLib
+ * Method: getCurves
+ * Signature: ()Ljava/util/Set;
+ */
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_BotanLib_getCurves(JNIEnv *env, jobject self){
+ jclass hash_set_class = env->FindClass("java/util/TreeSet");
+
+ jmethodID hash_set_ctr = env->GetMethodID(hash_set_class, "<init>", "()V");
+ jmethodID hash_set_add = env->GetMethodID(hash_set_class, "add", "(Ljava/lang/Object;)Z");
+
+ jobject result = env->NewObject(hash_set_class, hash_set_ctr);
+
+ const std::set<std::string>& curves = Botan::EC_Group::known_named_groups();
+ for (auto it = curves.begin(); it != curves.end(); ++it) {
+ std::string curve_name = *it;
+ jstring name_str = env->NewStringUTF(curve_name.c_str());
+ env->CallBooleanMethod(result, hash_set_add, name_str);
+ }
+
+ return result;
+}
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Botan
+ * Method: keysizeSupported
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Botan_keysizeSupported(JNIEnv *env, jobject self, jint keysize){
+ return JNI_TRUE;
+}
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Botan
+ * Method: paramsSupported
+ * Signature: (Ljava/security/spec/AlgorithmParameterSpec;)Z
+ */
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Botan_paramsSupported(JNIEnv *env, jobject self, jobject params){
+ if (params == NULL) {
+ return JNI_FALSE;
+ }
+
+ if (env->IsInstanceOf(params, ec_parameter_spec_class)) {
+ jmethodID get_curve = env->GetMethodID(ec_parameter_spec_class, "getCurve", "()Ljava/security/spec/EllipticCurve;");
+ jobject curve = env->CallObjectMethod(params, get_curve);
+
+ jmethodID get_field = env->GetMethodID(elliptic_curve_class, "getField", "()Ljava/security/spec/ECField;");
+ jobject field = env->CallObjectMethod(curve, get_field);
+
+ if (env->IsInstanceOf(field, fp_field_class)) {
+ return JNI_TRUE;
+ }
+ } else if (env->IsInstanceOf(params, ecgen_parameter_spec_class)) {
+ const std::set<std::string>& curves = Botan::EC_Group::known_named_groups();
+ jmethodID get_name = env->GetMethodID(ecgen_parameter_spec_class, "getName", "()Ljava/lang/String;");
+ jstring name = (jstring) env->CallObjectMethod(params, get_name);
+ const char *utf_name = env->GetStringUTFChars(name, NULL);
+ std::string str_name(utf_name);
+ env->ReleaseStringUTFChars(name, utf_name);
+ if (curves.find(str_name) != curves.end()) {
+ return JNI_TRUE;
+ }
+ }
+ return JNI_FALSE;
+}
+
+static jobject biginteger_from_bigint(JNIEnv *env, const Botan::BigInt& bigint) {
+ std::vector<uint8_t> bigint_data = Botan::BigInt::encode(bigint);
+ jbyteArray bigint_array = env->NewByteArray(bigint_data.size());
+ jbyte * bigint_bytes = env->GetByteArrayElements(bigint_array, NULL);
+ std::copy(bigint_data.begin(), bigint_data.end(), bigint_bytes);
+ env->ReleaseByteArrayElements(bigint_array, bigint_bytes, JNI_COMMIT);
+
+ jmethodID biginteger_init = env->GetMethodID(biginteger_class, "<init>", "(I[B)V");
+ return env->NewObject(biginteger_class, biginteger_init, (jint) 1, bigint_array);
+}
+
+static Botan::BigInt bigint_from_biginteger(JNIEnv *env, jobject biginteger) {
+ jmethodID to_byte_array = env->GetMethodID(biginteger_class, "toByteArray", "()[B");
+ jbyteArray byte_array = (jbyteArray) env->CallObjectMethod(biginteger, to_byte_array);
+ jsize byte_length = env->GetArrayLength(byte_array);
+ jbyte *byte_data = env->GetByteArrayElements(byte_array, NULL);
+ Botan::BigInt result((unsigned uint8_t*) byte_data, byte_length);
+ env->ReleaseByteArrayElements(byte_array, byte_data, JNI_ABORT);
+ return result;
+}
+
+static Botan::EC_Group group_from_params(JNIEnv *env, jobject params) {
+ if (env->IsInstanceOf(params, ec_parameter_spec_class)) {
+ jmethodID get_curve = env->GetMethodID(ec_parameter_spec_class, "getCurve", "()Ljava/security/spec/EllipticCurve;");
+ jobject elliptic_curve = env->CallObjectMethod(params, get_curve);
+
+ jmethodID get_field = env->GetMethodID(elliptic_curve_class, "getField", "()Ljava/security/spec/ECField;");
+ jobject field = env->CallObjectMethod(elliptic_curve, get_field);
+
+ jmethodID get_bits = env->GetMethodID(fp_field_class, "getFieldSize", "()I");
+ jint bits = env->CallIntMethod(field, get_bits);
+ jint bytes = (bits + 7) / 8;
+
+ jmethodID get_a = env->GetMethodID(elliptic_curve_class, "getA", "()Ljava/math/BigInteger;");
+ jobject a = env->CallObjectMethod(elliptic_curve, get_a);
+
+ jmethodID get_b = env->GetMethodID(elliptic_curve_class, "getB", "()Ljava/math/BigInteger;");
+ jobject b = env->CallObjectMethod(elliptic_curve, get_b);
+
+ jmethodID get_p = env->GetMethodID(fp_field_class, "getP", "()Ljava/math/BigInteger;");
+ jobject p = env->CallObjectMethod(field, get_p);
+
+ jmethodID get_g = env->GetMethodID(ec_parameter_spec_class, "getGenerator", "()Ljava/security/spec/ECPoint;");
+ jobject g = env->CallObjectMethod(params, get_g);
+
+ jmethodID get_x = env->GetMethodID(point_class, "getAffineX", "()Ljava/math/BigInteger;");
+ jobject gx = env->CallObjectMethod(g, get_x);
+
+ jmethodID get_y = env->GetMethodID(point_class, "getAffineY", "()Ljava/math/BigInteger;");
+ jobject gy = env->CallObjectMethod(g, get_y);
+
+ jmethodID get_n = env->GetMethodID(ec_parameter_spec_class, "getOrder", "()Ljava/math/BigInteger;");
+ jobject n = env->CallObjectMethod(params, get_n);
+
+ jmethodID get_h = env->GetMethodID(ec_parameter_spec_class, "getCofactor", "()I");
+ jint h = env->CallIntMethod(params, get_h);
+
+ Botan::BigInt pi = bigint_from_biginteger(env, p);
+ Botan::BigInt ai = bigint_from_biginteger(env, a);
+ Botan::BigInt bi = bigint_from_biginteger(env, b);
+ Botan::CurveGFp curve(pi, ai, bi);
+
+ Botan::BigInt gxi = bigint_from_biginteger(env, gx);
+ Botan::BigInt gyi = bigint_from_biginteger(env, gy);
+ Botan::PointGFp generator(curve, gxi, gyi);
+
+ Botan::BigInt ni = bigint_from_biginteger(env, n);
+ Botan::BigInt hi(h);
+
+ return Botan::EC_Group(curve, generator, ni, hi);
+ } else if (env->IsInstanceOf(params, ecgen_parameter_spec_class)) {
+ jmethodID get_name = env->GetMethodID(ecgen_parameter_spec_class, "getName", "()Ljava/lang/String;");
+ jstring name = (jstring) env->CallObjectMethod(params, get_name);
+ const char *utf_name = env->GetStringUTFChars(name, NULL);
+ std::string curve_name(utf_name);
+ env->ReleaseStringUTFChars(name, utf_name);
+ return Botan::EC_Group(curve_name);
+ }
+ return Botan::EC_Group();
+}
+
+static jobject params_from_group(JNIEnv *env, Botan::EC_Group group) {
+ const Botan::CurveGFp& curve = group.get_curve();
+ jobject p = biginteger_from_bigint(env, curve.get_p());
+
+ jmethodID fp_field_init = env->GetMethodID(fp_field_class, "<init>", "(Ljava/math/BigInteger;)V");
+ jobject fp_field = env->NewObject(fp_field_class, fp_field_init, p);
+
+ jobject a = biginteger_from_bigint(env, curve.get_a());
+ jobject b = biginteger_from_bigint(env, curve.get_b());
+
+ jmethodID elliptic_curve_init = env->GetMethodID(elliptic_curve_class, "<init>", "(Ljava/security/spec/ECField;Ljava/math/BigInteger;Ljava/math/BigInteger;)V");
+ jobject elliptic_curve = env->NewObject(elliptic_curve_class, elliptic_curve_init, fp_field, a, b);
+
+ const Botan::PointGFp& generator = group.get_base_point();
+ jobject gx = biginteger_from_bigint(env, generator.get_affine_x());
+ jobject gy = biginteger_from_bigint(env, generator.get_affine_y());
+
+ jmethodID point_init = env->GetMethodID(point_class, "<init>", "(Ljava/math/BigInteger;Ljava/math/BigInteger;)V");
+ jobject g = env->NewObject(point_class, point_init, gx, gy);
+
+ const Botan::BigInt& order = group.get_order();
+ jobject n = biginteger_from_bigint(env, order);
+
+ const Botan::BigInt& cofactor = group.get_cofactor();
+ jint h = (jint) cofactor.to_u32bit();
+
+ jmethodID ec_parameter_spec_init = env->GetMethodID(ec_parameter_spec_class, "<init>", "(Ljava/security/spec/EllipticCurve;Ljava/security/spec/ECPoint;Ljava/math/BigInteger;I)V");
+ return env->NewObject(ec_parameter_spec_class, ec_parameter_spec_init, elliptic_curve, g, n, h);
+}
+
+static jobject generate_from_group(JNIEnv* env, jobject self, Botan::EC_Group group) {
+ Botan::AutoSeeded_RNG rng;
+
+ jclass botan_kpg_class = env->FindClass("cz/crcs/ectester/standalone/libs/jni/NativeKeyPairGeneratorSpi$Botan");
+ jfieldID type_id = env->GetFieldID(botan_kpg_class, "type", "Ljava/lang/String;");
+ jstring type = (jstring) env->GetObjectField(self, type_id);
+ const char* type_data = env->GetStringUTFChars(type, NULL);
+ std::string type_str(type_data);
+ env->ReleaseStringUTFChars(type, type_data);
+
+ std::unique_ptr<Botan::EC_PrivateKey> skey;
+ try {
+ if (type_str == "ECDH") {
+ skey = std::make_unique<Botan::ECDH_PrivateKey>(rng, group);
+ } else if (type_str == "ECDSA") {
+ skey = std::make_unique<Botan::ECDSA_PrivateKey>(rng, group);
+ } else if (type_str == "ECKCDSA") {
+ skey = std::make_unique<Botan::ECKCDSA_PrivateKey>(rng, group);
+ } else if (type_str == "ECGDSA") {
+ skey = std::make_unique<Botan::ECGDSA_PrivateKey>(rng, group);
+ }
+ } catch (Botan::Exception & ex) {
+ throw_new(env, "java/security/GeneralSecurityException", ex.what());
+ return NULL;
+ }
+
+ jobject ec_param_spec = params_from_group(env, group);
+
+ const Botan::PointGFp& pub_point = skey->public_point();
+ std::vector<uint8_t> pub_data = Botan::unlock(Botan::EC2OSP(pub_point, Botan::PointGFp::UNCOMPRESSED));
+
+ jbyteArray pub_bytearray = env->NewByteArray(pub_data.size());
+ jbyte *pub_bytes = env->GetByteArrayElements(pub_bytearray, NULL);
+ std::copy(pub_data.begin(), pub_data.end(), pub_bytes);
+ env->ReleaseByteArrayElements(pub_bytearray, pub_bytes, JNI_COMMIT);
+
+ jobject ec_pub_param_spec = env->NewLocalRef(ec_param_spec);
+ jmethodID ec_pub_init = env->GetMethodID(pubkey_class, "<init>", "([BLjava/security/spec/ECParameterSpec;)V");
+ jobject pubkey = env->NewObject(pubkey_class, ec_pub_init, pub_bytearray, ec_pub_param_spec);
+
+ const Botan::BigInt& priv_scalar = skey->private_value();
+ std::vector<uint8_t> priv_data = Botan::BigInt::encode(priv_scalar);
+
+ jbyteArray priv_bytearray = env->NewByteArray(priv_data.size());
+ jbyte *priv_bytes = env->GetByteArrayElements(priv_bytearray, NULL);
+ std::copy(priv_data.begin(), priv_data.end(), priv_bytes);
+ env->ReleaseByteArrayElements(priv_bytearray, priv_bytes, JNI_COMMIT);
+
+ jobject ec_priv_param_spec = env->NewLocalRef(ec_param_spec);
+ jmethodID ec_priv_init = env->GetMethodID(privkey_class, "<init>", "([BLjava/security/spec/ECParameterSpec;)V");
+ jobject privkey = env->NewObject(privkey_class, ec_priv_init, priv_bytearray, ec_priv_param_spec);
+
+ jmethodID keypair_init = env->GetMethodID(keypair_class, "<init>", "(Ljava/security/PublicKey;Ljava/security/PrivateKey;)V");
+
+ return env->NewObject(keypair_class, keypair_init, pubkey, privkey);
+}
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Botan
+ * Method: generate
+ * Signature: (ILjava/security/SecureRandom;)Ljava/security/KeyPair;
+ */
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Botan_generate__ILjava_security_SecureRandom_2(JNIEnv *env, jobject self, jint keysize, jobject random){
+ const std::set<std::string>& curves = Botan::EC_Group::known_named_groups();
+ for (auto it = curves.begin(); it != curves.end(); ++it) {
+ Botan::EC_Group curve_group = Botan::EC_Group(*it);
+ size_t curve_size = curve_group.get_curve().get_p().bits();
+ if (curve_size == keysize) {
+ //generate on this group. Even thou no default groups are present...
+ return generate_from_group(env, self, curve_group);
+ }
+ }
+
+ throw_new(env, "java/security/InvalidAlgorithmParameterException", "Curve not found.");
+ return NULL;
+}
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Botan
+ * Method: generate
+ * Signature: (Ljava/security/spec/AlgorithmParameterSpec;Ljava/security/SecureRandom;)Ljava/security/KeyPair;
+ */
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Botan_generate__Ljava_security_spec_AlgorithmParameterSpec_2Ljava_security_SecureRandom_2(JNIEnv *env, jobject self, jobject params, jobject random){
+ Botan::EC_Group curve_group = group_from_params(env, params);
+ return generate_from_group(env, self, curve_group);
+}
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Botan
+ * Method: generateSecret
+ * Signature: ([B[BLjava/security/spec/ECParameterSpec;)[B
+ */
+JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_00024Botan_generateSecret(JNIEnv *env, jobject self, jbyteArray pubkey, jbyteArray privkey, jobject params){
+ Botan::EC_Group curve_group = group_from_params(env, params);
+
+ jsize privkey_length = env->GetArrayLength(privkey);
+ jbyte *privkey_data = env->GetByteArrayElements(privkey, NULL);
+ Botan::BigInt privkey_scalar((unsigned uint8_t*) privkey_data, privkey_length);
+ env->ReleaseByteArrayElements(privkey, privkey_data, JNI_ABORT);
+
+ Botan::AutoSeeded_RNG rng;
+
+ Botan::ECDH_PrivateKey skey(rng, curve_group, privkey_scalar);
+
+ jsize pubkey_length = env->GetArrayLength(pubkey);
+ jbyte *pubkey_data = env->GetByteArrayElements(pubkey, NULL);
+ Botan::PointGFp public_point = Botan::OS2ECP((uint8_t*) pubkey_data, pubkey_length, curve_group.get_curve());
+ env->ReleaseByteArrayElements(pubkey, pubkey_data, JNI_ABORT);
+
+ Botan::ECDH_PublicKey pkey(curve_group, public_point);
+ //TODO: do check_key here?
+
+ jclass botan_ka_class = env->FindClass("cz/crcs/ectester/standalone/libs/jni/NativeKeyAgreementSpi$Botan");
+ jfieldID type_id = env->GetFieldID(botan_ka_class, "type", "Ljava/lang/String;");
+ jstring type = (jstring) env->GetObjectField(self, type_id);
+ const char *type_data = env->GetStringUTFChars(type, NULL);
+ std::string type_str(type_data);
+ env->ReleaseStringUTFChars(type, type_data);
+
+ std::string kdf;
+ size_t key_len = 0;
+ if (type_str == "ECDH") {
+ kdf = "Raw";
+ //key len unused
+ } else if (type_str == "ECDHwithSHA1KDF") {
+ kdf = "KDF1(SHA-1)";
+ key_len = 20;
+ } else if (type_str == "ECDHwithSHA224KDF") {
+ kdf = "KDF1(SHA-224)";
+ key_len = 28;
+ } else if (type_str == "ECDHwithSHA256KDF") {
+ kdf = "KDF1(SHA-256)";
+ key_len = 32;
+ } else if (type_str == "ECDHwithSHA384KDF") {
+ kdf = "KDF1(SHA-384)";
+ key_len = 48;
+ } else if (type_str == "ECDHwithSHA512KDF") {
+ kdf = "KDF1(SHA-512)";
+ key_len = 64;
+ }
+
+ Botan::PK_Key_Agreement ka(skey, rng, kdf);
+
+ std::vector<uint8_t> derived;
+ try {
+ derived = Botan::unlock(ka.derive_key(key_len, pkey.public_value()).bits_of());
+ } catch (Botan::Exception & ex) {
+ throw_new(env, "java/security/GeneralSecurityException", ex.what());
+ return NULL;
+ }
+ jbyteArray result = env->NewByteArray(derived.size());
+ jbyte *result_data = env->GetByteArrayElements(result, NULL);
+ std::copy(derived.begin(), derived.end(), result_data);
+ env->ReleaseByteArrayElements(result, result_data, JNI_COMMIT);
+
+ return result;
+}
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Botan
+ * Method: sign
+ * Signature: ([B[BLjava/security/spec/ECParameterSpec;)[B
+ */
+JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024Botan_sign(JNIEnv *env, jobject self, jbyteArray data, jbyteArray privkey, jobject params){
+ Botan::EC_Group curve_group = group_from_params(env, params);
+
+ jclass botan_sig_class = env->FindClass("cz/crcs/ectester/standalone/libs/jni/NativeSignatureSpi$Botan");
+ jfieldID type_id = env->GetFieldID(botan_sig_class, "type", "Ljava/lang/String;");
+ jstring type = (jstring) env->GetObjectField(self, type_id);
+ const char *type_data = env->GetStringUTFChars(type, NULL);
+ std::string type_str(type_data);
+ env->ReleaseStringUTFChars(type, type_data);
+
+ jsize privkey_length = env->GetArrayLength(privkey);
+ jbyte *privkey_bytes = env->GetByteArrayElements(privkey, NULL);
+ Botan::BigInt privkey_scalar((uint8_t*) privkey_bytes, privkey_length);
+ env->ReleaseByteArrayElements(privkey, privkey_bytes, JNI_ABORT);
+
+ Botan::AutoSeeded_RNG rng;
+
+ std::unique_ptr<Botan::EC_PrivateKey> skey;
+ if (type_str.find("ECDSA") != std::string::npos) {
+ skey = std::make_unique<Botan::ECDSA_PrivateKey>(rng, curve_group, privkey_scalar);
+ } else if (type_str.find("ECKCDSA") != std::string::npos) {
+ skey = std::make_unique<Botan::ECKCDSA_PrivateKey>(rng, curve_group, privkey_scalar);
+ } else if (type_str.find("ECGDSA") != std::string::npos) {
+ skey = std::make_unique<Botan::ECGDSA_PrivateKey>(rng, curve_group, privkey_scalar);
+ }
+
+ std::string kdf;
+ if (type_str.find("NONE") != std::string::npos) {
+ kdf = "Raw";
+ } else if (type_str.find("SHA1") != std::string::npos) {
+ kdf = "EMSA1(SHA-1)";
+ } else if (type_str.find("SHA224") != std::string::npos) {
+ kdf = "EMSA1(SHA-224)";
+ } else if (type_str.find("SHA256") != std::string::npos) {
+ kdf = "EMSA1(SHA-256)";
+ } else if (type_str.find("SHA384") != std::string::npos) {
+ kdf = "EMSA1(SHA-384)";
+ } else if (type_str.find("SHA512") != std::string::npos) {
+ kdf = "EMSA1(SHA-512)";
+ }
+
+ Botan::PK_Signer signer(*skey, rng, kdf, Botan::DER_SEQUENCE);
+
+ jsize data_length = env->GetArrayLength(data);
+ jbyte *data_bytes = env->GetByteArrayElements(data, NULL);
+ std::vector<uint8_t> sig;
+ try {
+ sig = signer.sign_message((uint8_t*) data_bytes, data_length, rng);
+ } catch (Botan::Exception & ex) {
+ throw_new(env, "java/security/GeneralSecurityException", ex.what());
+ env->ReleaseByteArrayElements(data, data_bytes, JNI_ABORT);
+ return NULL;
+ }
+ env->ReleaseByteArrayElements(data, data_bytes, JNI_ABORT);
+
+ jbyteArray result = env->NewByteArray(sig.size());
+ jbyte *result_data = env->GetByteArrayElements(result, NULL);
+ std::copy(sig.begin(), sig.end(), result_data);
+ env->ReleaseByteArrayElements(result, result_data, JNI_COMMIT);
+
+ return result;
+}
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Botan
+ * Method: verify
+ * Signature: ([B[B[BLjava/security/spec/ECParameterSpec;)Z
+ */
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024Botan_verify(JNIEnv *env, jobject self, jbyteArray signature, jbyteArray data, jbyteArray pubkey, jobject params){
+ Botan::EC_Group curve_group = group_from_params(env, params);
+
+ jclass botan_sig_class = env->FindClass("cz/crcs/ectester/standalone/libs/jni/NativeSignatureSpi$Botan");
+ jfieldID type_id = env->GetFieldID(botan_sig_class, "type", "Ljava/lang/String;");
+ jstring type = (jstring) env->GetObjectField(self, type_id);
+ const char *type_data = env->GetStringUTFChars(type, NULL);
+ std::string type_str(type_data);
+ env->ReleaseStringUTFChars(type, type_data);
+
+ jsize pubkey_length = env->GetArrayLength(pubkey);
+ jbyte *pubkey_data = env->GetByteArrayElements(pubkey, NULL);
+ Botan::PointGFp public_point = Botan::OS2ECP((uint8_t*) pubkey_data, pubkey_length, curve_group.get_curve());
+ env->ReleaseByteArrayElements(pubkey, pubkey_data, JNI_ABORT);
+
+ std::unique_ptr<Botan::EC_PublicKey> pkey;
+ if (type_str.find("ECDSA") != std::string::npos) {
+ pkey = std::make_unique<Botan::ECDSA_PublicKey>(curve_group, public_point);
+ } else if (type_str.find("ECKCDSA") != std::string::npos) {
+ pkey = std::make_unique<Botan::ECKCDSA_PublicKey>(curve_group, public_point);
+ } else if (type_str.find("ECGDSA") != std::string::npos) {
+ pkey = std::make_unique<Botan::ECGDSA_PublicKey>(curve_group, public_point);
+ }
+
+ std::string kdf;
+ if (type_str.find("NONE") != std::string::npos) {
+ kdf = "Raw";
+ } else if (type_str.find("SHA1") != std::string::npos) {
+ kdf = "EMSA1(SHA-1)";
+ } else if (type_str.find("SHA224") != std::string::npos) {
+ kdf = "EMSA1(SHA-224)";
+ } else if (type_str.find("SHA256") != std::string::npos) {
+ kdf = "EMSA1(SHA-256)";
+ } else if (type_str.find("SHA384") != std::string::npos) {
+ kdf = "EMSA1(SHA-384)";
+ } else if (type_str.find("SHA512") != std::string::npos) {
+ kdf = "EMSA1(SHA-512)";
+ }
+
+ Botan::PK_Verifier verifier(*pkey, kdf, Botan::DER_SEQUENCE);
+
+ jsize data_length = env->GetArrayLength(data);
+ jsize sig_length = env->GetArrayLength(signature);
+ jbyte *data_bytes = env->GetByteArrayElements(data, NULL);
+ jbyte *sig_bytes = env->GetByteArrayElements(signature, NULL);
+
+ bool result;
+ try {
+ result = verifier.verify_message((uint8_t*)data_bytes, data_length, (uint8_t*)sig_bytes, sig_length);
+ } catch (Botan::Exception & ex) {
+ throw_new(env, "java/security/GeneralSecurityException", ex.what());
+ env->ReleaseByteArrayElements(data, data_bytes, JNI_ABORT);
+ env->ReleaseByteArrayElements(signature, sig_bytes, JNI_ABORT);
+ return JNI_FALSE;
+ }
+ env->ReleaseByteArrayElements(data, data_bytes, JNI_ABORT);
+ env->ReleaseByteArrayElements(signature, sig_bytes, JNI_ABORT);
+ if (result) {
+ return JNI_TRUE;
+ }
+ return JNI_FALSE;
+} \ No newline at end of file
diff --git a/src/cz/crcs/ectester/standalone/libs/jni/c_utils.c b/src/cz/crcs/ectester/standalone/libs/jni/c_utils.c
new file mode 100644
index 0000000..336f4a1
--- /dev/null
+++ b/src/cz/crcs/ectester/standalone/libs/jni/c_utils.c
@@ -0,0 +1,66 @@
+#include "c_utils.h"
+#include <string.h>
+
+jclass ec_parameter_spec_class;
+jclass ecgen_parameter_spec_class;
+jclass pubkey_class;
+jclass privkey_class;
+jclass keypair_class;
+jclass elliptic_curve_class;
+jclass fp_field_class;
+jclass f2m_field_class;
+jclass point_class;
+jclass biginteger_class;
+jclass illegal_state_exception_class;
+
+void init_classes(JNIEnv *env, const char* lib_name) {
+ jclass local_ec_parameter_spec_class = (*env)->FindClass(env, "java/security/spec/ECParameterSpec");
+ ec_parameter_spec_class = (*env)->NewGlobalRef(env, local_ec_parameter_spec_class);
+
+ jclass local_ecgen_parameter_spec_class = (*env)->FindClass(env, "java/security/spec/ECGenParameterSpec");
+ ecgen_parameter_spec_class = (*env)->NewGlobalRef(env, local_ecgen_parameter_spec_class);
+
+ const char *pubkey_base = "cz/crcs/ectester/standalone/libs/jni/NativeECPublicKey$";
+ char pubkey_class_name[strlen(pubkey_base) + strlen(lib_name) + 1];
+ pubkey_class_name[0] = 0;
+ strcat(pubkey_class_name, pubkey_base);
+ strcat(pubkey_class_name, lib_name);
+
+ jclass local_pubkey_class = (*env)->FindClass(env, pubkey_class_name);
+ pubkey_class = (*env)->NewGlobalRef(env, local_pubkey_class);
+
+ const char *privkey_base = "cz/crcs/ectester/standalone/libs/jni/NativeECPrivateKey$";
+ char privkey_class_name[strlen(privkey_base) + strlen(lib_name) + 1];
+ privkey_class_name[0] = 0;
+ strcat(privkey_class_name, privkey_base);
+ strcat(privkey_class_name, lib_name);
+
+ jclass local_privkey_class = (*env)->FindClass(env, privkey_class_name);
+ privkey_class = (*env)->NewGlobalRef(env, local_privkey_class);
+
+ jclass local_keypair_class = (*env)->FindClass(env, "java/security/KeyPair");
+ keypair_class = (*env)->NewGlobalRef(env, local_keypair_class);
+
+ jclass local_elliptic_curve_class = (*env)->FindClass(env, "java/security/spec/EllipticCurve");
+ elliptic_curve_class = (*env)->NewGlobalRef(env, local_elliptic_curve_class);
+
+ jclass local_fp_field_class = (*env)->FindClass(env, "java/security/spec/ECFieldFp");
+ fp_field_class = (*env)->NewGlobalRef(env, local_fp_field_class);
+
+ jclass local_f2m_field_class = (*env)->FindClass(env, "java/security/spec/ECFieldF2m");
+ f2m_field_class = (*env)->NewGlobalRef(env, local_f2m_field_class);
+
+ jclass local_biginteger_class = (*env)->FindClass(env, "java/math/BigInteger");
+ biginteger_class = (*env)->NewGlobalRef(env, local_biginteger_class);
+
+ jclass local_point_class = (*env)->FindClass(env, "java/security/spec/ECPoint");
+ point_class = (*env)->NewGlobalRef(env, local_point_class);
+
+ jclass local_illegal_state_exception_class = (*env)->FindClass(env, "java/lang/IllegalStateException");
+ illegal_state_exception_class = (*env)->NewGlobalRef(env, local_illegal_state_exception_class);
+}
+
+void throw_new(JNIEnv *env, const char *class, const char *message) {
+ jclass clazz = (*env)->FindClass(env, class);
+ (*env)->ThrowNew(env, clazz, message);
+}
diff --git a/src/cz/crcs/ectester/standalone/libs/jni/c_utils.h b/src/cz/crcs/ectester/standalone/libs/jni/c_utils.h
new file mode 100644
index 0000000..d925dfe
--- /dev/null
+++ b/src/cz/crcs/ectester/standalone/libs/jni/c_utils.h
@@ -0,0 +1,28 @@
+#pragma once
+
+#include "native.h"
+
+/**
+ * Classes that are accessed alot are cached here, manually.
+ */
+extern jclass ec_parameter_spec_class;
+extern jclass ecgen_parameter_spec_class;
+extern jclass pubkey_class;
+extern jclass privkey_class;
+extern jclass keypair_class;
+extern jclass elliptic_curve_class;
+extern jclass fp_field_class;
+extern jclass f2m_field_class;
+extern jclass point_class;
+extern jclass biginteger_class;
+extern jclass illegal_state_exception_class;
+
+/**
+ * Initialize the classes.
+ */
+void init_classes(JNIEnv *env, const char* lib_name);
+
+/**
+ * Throw a new exception of class with message.
+ */
+void throw_new(JNIEnv *env, const char *class, const char *message); \ No newline at end of file
diff --git a/src/cz/crcs/ectester/standalone/libs/jni/cpp_utils.cpp b/src/cz/crcs/ectester/standalone/libs/jni/cpp_utils.cpp
new file mode 100644
index 0000000..cef4bfe
--- /dev/null
+++ b/src/cz/crcs/ectester/standalone/libs/jni/cpp_utils.cpp
@@ -0,0 +1,59 @@
+#include "cpp_utils.hpp"
+
+jclass ec_parameter_spec_class;
+jclass ecgen_parameter_spec_class;
+jclass pubkey_class;
+jclass privkey_class;
+jclass keypair_class;
+jclass elliptic_curve_class;
+jclass fp_field_class;
+jclass f2m_field_class;
+jclass point_class;
+jclass biginteger_class;
+jclass illegal_state_exception_class;
+
+void init_classes(JNIEnv *env, std::string lib_name) {
+ jclass local_ec_parameter_spec_class = env->FindClass("java/security/spec/ECParameterSpec");
+ ec_parameter_spec_class = (jclass) env->NewGlobalRef(local_ec_parameter_spec_class);
+
+ jclass local_ecgen_parameter_spec_class = env->FindClass("java/security/spec/ECGenParameterSpec");
+ ecgen_parameter_spec_class = (jclass) env->NewGlobalRef(local_ecgen_parameter_spec_class);
+
+ std::string pubkey_class_name("cz/crcs/ectester/standalone/libs/jni/NativeECPublicKey$");
+ pubkey_class_name += lib_name;
+
+ jclass local_pubkey_class = env->FindClass(pubkey_class_name.c_str());
+ pubkey_class = (jclass) env->NewGlobalRef(local_pubkey_class);
+
+ std::string privkey_class_name("cz/crcs/ectester/standalone/libs/jni/NativeECPrivateKey$");
+ privkey_class_name += lib_name;
+
+ jclass local_privkey_class = env->FindClass(privkey_class_name.c_str());
+ privkey_class = (jclass) env->NewGlobalRef(local_privkey_class);
+
+ jclass local_keypair_class = env->FindClass("java/security/KeyPair");
+ keypair_class = (jclass) env->NewGlobalRef(local_keypair_class);
+
+ jclass local_elliptic_curve_class = env->FindClass("java/security/spec/EllipticCurve");
+ elliptic_curve_class = (jclass) env->NewGlobalRef(local_elliptic_curve_class);
+
+ jclass local_fp_field_class = env->FindClass("java/security/spec/ECFieldFp");
+ fp_field_class = (jclass) env->NewGlobalRef(local_fp_field_class);
+
+ jclass local_f2m_field_class = env->FindClass("java/security/spec/ECFieldF2m");
+ f2m_field_class = (jclass) env->NewGlobalRef(local_f2m_field_class);
+
+ jclass local_biginteger_class = env->FindClass("java/math/BigInteger");
+ biginteger_class = (jclass) env->NewGlobalRef(local_biginteger_class);
+
+ jclass local_point_class = env->FindClass("java/security/spec/ECPoint");
+ point_class = (jclass) env->NewGlobalRef(local_point_class);
+
+ jclass local_illegal_state_exception_class = env->FindClass("java/lang/IllegalStateException");
+ illegal_state_exception_class = (jclass) env->NewGlobalRef(local_illegal_state_exception_class);
+}
+
+void throw_new(JNIEnv *env, const std::string& klass, const std::string& message) {
+ jclass clazz = env->FindClass(klass.c_str());
+ env->ThrowNew(clazz, message.c_str());
+} \ No newline at end of file
diff --git a/src/cz/crcs/ectester/standalone/libs/jni/cpp_utils.hpp b/src/cz/crcs/ectester/standalone/libs/jni/cpp_utils.hpp
new file mode 100644
index 0000000..bbca521
--- /dev/null
+++ b/src/cz/crcs/ectester/standalone/libs/jni/cpp_utils.hpp
@@ -0,0 +1,29 @@
+#pragma once
+
+#include "native.h"
+#include <string>
+
+/**
+ * Classes that are accessed alot are cached here, manually.
+ */
+extern jclass ec_parameter_spec_class;
+extern jclass ecgen_parameter_spec_class;
+extern jclass pubkey_class;
+extern jclass privkey_class;
+extern jclass keypair_class;
+extern jclass elliptic_curve_class;
+extern jclass fp_field_class;
+extern jclass f2m_field_class;
+extern jclass point_class;
+extern jclass biginteger_class;
+extern jclass illegal_state_exception_class;
+
+/**
+ * Initialize the classes.
+ */
+void init_classes(JNIEnv *env, std::string lib_name);
+
+/**
+ * Throw a new exception of class with message.
+ */
+void throw_new(JNIEnv *env, const std::string& klass, const std::string& message); \ 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
new file mode 100644
index 0000000..d714b39
--- /dev/null
+++ b/src/cz/crcs/ectester/standalone/libs/jni/native.h
@@ -0,0 +1,344 @@
+/* DO NOT EDIT THIS FILE - it is machine generated */
+#include <jni.h>
+/* Header for class cz_crcs_ectester_standalone_libs_TomcryptLib */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_TomcryptLib
+#define _Included_cz_crcs_ectester_standalone_libs_TomcryptLib
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class: cz_crcs_ectester_standalone_libs_TomcryptLib
+ * Method: createProvider
+ * Signature: ()Ljava/security/Provider;
+ */
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_TomcryptLib_createProvider
+ (JNIEnv *, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_TomcryptLib
+ * Method: getCurves
+ * Signature: ()Ljava/util/Set;
+ */
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_TomcryptLib_getCurves
+ (JNIEnv *, jobject);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeProvider_TomCrypt */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeProvider_TomCrypt
+#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeProvider_TomCrypt
+#ifdef __cplusplus
+extern "C" {
+#endif
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_TomCrypt_serialVersionUID
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_TomCrypt_serialVersionUID 1421746759512286392LL
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_TomCrypt_MAX_ARRAY_SIZE
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_TomCrypt_MAX_ARRAY_SIZE 2147483639L
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_TomCrypt_KEYS
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_TomCrypt_KEYS 0L
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_TomCrypt_VALUES
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_TomCrypt_VALUES 1L
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_TomCrypt_ENTRIES
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_TomCrypt_ENTRIES 2L
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_TomCrypt_serialVersionUID
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_TomCrypt_serialVersionUID 4112578634029874840LL
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_TomCrypt_serialVersionUID
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_TomCrypt_serialVersionUID -4298000515446427739LL
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeProvider_TomCrypt
+ * Method: setup
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeProvider_00024TomCrypt_setup
+ (JNIEnv *, jobject);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_TomCrypt */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_TomCrypt
+#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_TomCrypt
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_TomCrypt
+ * Method: keysizeSupported
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024TomCrypt_keysizeSupported
+ (JNIEnv *, jobject, jint);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_TomCrypt
+ * Method: paramsSupported
+ * Signature: (Ljava/security/spec/AlgorithmParameterSpec;)Z
+ */
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024TomCrypt_paramsSupported
+ (JNIEnv *, jobject, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_TomCrypt
+ * Method: generate
+ * Signature: (ILjava/security/SecureRandom;)Ljava/security/KeyPair;
+ */
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024TomCrypt_generate__ILjava_security_SecureRandom_2
+ (JNIEnv *, jobject, jint, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_TomCrypt
+ * Method: generate
+ * Signature: (Ljava/security/spec/AlgorithmParameterSpec;Ljava/security/SecureRandom;)Ljava/security/KeyPair;
+ */
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024TomCrypt_generate__Ljava_security_spec_AlgorithmParameterSpec_2Ljava_security_SecureRandom_2
+ (JNIEnv *, jobject, jobject, jobject);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeECPublicKey_TomCrypt */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPublicKey_TomCrypt
+#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPublicKey_TomCrypt
+#ifdef __cplusplus
+extern "C" {
+#endif
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeECPrivateKey_TomCrypt */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPrivateKey_TomCrypt
+#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPrivateKey_TomCrypt
+#ifdef __cplusplus
+extern "C" {
+#endif
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_TomCrypt */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_TomCrypt
+#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_TomCrypt
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_TomCrypt
+ * Method: generateSecret
+ * Signature: ([B[BLjava/security/spec/ECParameterSpec;)[B
+ */
+JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_00024TomCrypt_generateSecret
+ (JNIEnv *, jobject, jbyteArray, jbyteArray, jobject);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_TomCryptRaw */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_TomCryptRaw
+#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_TomCryptRaw
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_TomCryptRaw
+ * Method: sign
+ * Signature: ([B[BLjava/security/spec/ECParameterSpec;)[B
+ */
+JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024TomCryptRaw_sign
+ (JNIEnv *, jobject, jbyteArray, jbyteArray, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_TomCryptRaw
+ * Method: verify
+ * Signature: ([B[B[BLjava/security/spec/ECParameterSpec;)Z
+ */
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024TomCryptRaw_verify
+ (JNIEnv *, jobject, jbyteArray, jbyteArray, jbyteArray, jobject);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_BotanLib */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_BotanLib
+#define _Included_cz_crcs_ectester_standalone_libs_BotanLib
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class: cz_crcs_ectester_standalone_libs_BotanLib
+ * Method: createProvider
+ * Signature: ()Ljava/security/Provider;
+ */
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_BotanLib_createProvider
+ (JNIEnv *, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_BotanLib
+ * Method: getCurves
+ * Signature: ()Ljava/util/Set;
+ */
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_BotanLib_getCurves
+ (JNIEnv *, jobject);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeProvider_Botan */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeProvider_Botan
+#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeProvider_Botan
+#ifdef __cplusplus
+extern "C" {
+#endif
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Botan_serialVersionUID
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Botan_serialVersionUID 1421746759512286392LL
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Botan_MAX_ARRAY_SIZE
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Botan_MAX_ARRAY_SIZE 2147483639L
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Botan_KEYS
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Botan_KEYS 0L
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Botan_VALUES
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Botan_VALUES 1L
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Botan_ENTRIES
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Botan_ENTRIES 2L
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Botan_serialVersionUID
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Botan_serialVersionUID 4112578634029874840LL
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Botan_serialVersionUID
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Botan_serialVersionUID -4298000515446427739LL
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeProvider_Botan
+ * Method: setup
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeProvider_00024Botan_setup
+ (JNIEnv *, jobject);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Botan */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Botan
+#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Botan
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Botan
+ * Method: keysizeSupported
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Botan_keysizeSupported
+ (JNIEnv *, jobject, jint);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Botan
+ * Method: paramsSupported
+ * Signature: (Ljava/security/spec/AlgorithmParameterSpec;)Z
+ */
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Botan_paramsSupported
+ (JNIEnv *, jobject, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Botan
+ * Method: generate
+ * Signature: (ILjava/security/SecureRandom;)Ljava/security/KeyPair;
+ */
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Botan_generate__ILjava_security_SecureRandom_2
+ (JNIEnv *, jobject, jint, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Botan
+ * Method: generate
+ * Signature: (Ljava/security/spec/AlgorithmParameterSpec;Ljava/security/SecureRandom;)Ljava/security/KeyPair;
+ */
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Botan_generate__Ljava_security_spec_AlgorithmParameterSpec_2Ljava_security_SecureRandom_2
+ (JNIEnv *, jobject, jobject, jobject);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeECPublicKey_Botan */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPublicKey_Botan
+#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPublicKey_Botan
+#ifdef __cplusplus
+extern "C" {
+#endif
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeECPrivateKey_Botan */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPrivateKey_Botan
+#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPrivateKey_Botan
+#ifdef __cplusplus
+extern "C" {
+#endif
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Botan */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Botan
+#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Botan
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Botan
+ * Method: generateSecret
+ * Signature: ([B[BLjava/security/spec/ECParameterSpec;)[B
+ */
+JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_00024Botan_generateSecret
+ (JNIEnv *, jobject, jbyteArray, jbyteArray, jobject);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Botan */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Botan
+#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Botan
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Botan
+ * Method: sign
+ * Signature: ([B[BLjava/security/spec/ECParameterSpec;)[B
+ */
+JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024Botan_sign
+ (JNIEnv *, jobject, jbyteArray, jbyteArray, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Botan
+ * Method: verify
+ * Signature: ([B[B[BLjava/security/spec/ECParameterSpec;)Z
+ */
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024Botan_verify
+ (JNIEnv *, jobject, jbyteArray, jbyteArray, jbyteArray, jobject);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/src/cz/crcs/ectester/standalone/libs/jni/tomcrypt.c b/src/cz/crcs/ectester/standalone/libs/jni/tomcrypt.c
new file mode 100644
index 0000000..29ee707
--- /dev/null
+++ b/src/cz/crcs/ectester/standalone/libs/jni/tomcrypt.c
@@ -0,0 +1,450 @@
+#include "native.h"
+#include <stdio.h>
+#include <string.h>
+#include <tomcrypt.h>
+#include "c_utils.h"
+
+static prng_state ltc_prng;
+static jclass provider_class;
+
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_TomcryptLib_createProvider(JNIEnv *env, jobject this) {
+ /* Create the custom provider. */
+ jclass local_provider_class = (*env)->FindClass(env, "cz/crcs/ectester/standalone/libs/jni/NativeProvider$TomCrypt");
+ 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, "libtomcrypt " SCRYPT);
+ double version = strtod(SCRYPT, NULL);
+
+ return (*env)->NewObject(env, provider_class, init, name, version, name);
+}
+
+
+JNIEXPORT void JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeProvider_00024TomCrypt_setup(JNIEnv *env, jobject this) {
+ /* Initialize libtommath as the math lib. */
+ ltc_mp = ltm_desc;
+
+ jmethodID provider_put = (*env)->GetMethodID(env, provider_class, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
+
+ jstring ec = (*env)->NewStringUTF(env, "KeyPairGenerator.EC");
+ jstring ec_value = (*env)->NewStringUTF(env, "cz.crcs.ectester.standalone.libs.jni.NativeKeyPairGeneratorSpi$TomCrypt");
+ (*env)->CallObjectMethod(env, this, provider_put, ec, ec_value);
+
+ jstring ecdh = (*env)->NewStringUTF(env, "KeyAgreement.ECDH");
+ jstring ecdh_value = (*env)->NewStringUTF(env, "cz.crcs.ectester.standalone.libs.jni.NativeKeyAgreementSpi$TomCrypt");
+ (*env)->CallObjectMethod(env, this, provider_put, ecdh, ecdh_value);
+
+ jstring ecdsa = (*env)->NewStringUTF(env, "Signature.NONEwithECDSA");
+ jstring ecdsa_value = (*env)->NewStringUTF(env, "cz.crcs.ectester.standalone.libs.jni.NativeSignatureSpi$TomCryptRaw");
+ (*env)->CallObjectMethod(env, this, provider_put, ecdsa, ecdsa_value);
+
+ int err;
+ /* register yarrow */
+ if (register_prng(&yarrow_desc) == -1) {
+ fprintf(stderr, "Error registering Yarrow\n");
+ return;
+ }
+ /* setup the PRNG */
+ if ((err = rng_make_prng(128, find_prng("yarrow"), &ltc_prng, NULL)) != CRYPT_OK) {
+ fprintf(stderr, "Error setting up PRNG, %s\n", error_to_string(err));
+ }
+
+ init_classes(env, "TomCrypt");
+}
+
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_TomcryptLib_getCurves(JNIEnv *env, jobject this) {
+ 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);
+ const ltc_ecc_set_type * curve = ltc_ecc_sets;
+ while (curve->size != 0) {
+ jstring curve_name = (*env)->NewStringUTF(env, curve->name);
+ (*env)->CallBooleanMethod(env, result, hash_set_add, curve_name);
+ curve++;
+ }
+
+ return result;
+}
+
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024TomCrypt_keysizeSupported(JNIEnv *env, jobject this, jint keysize){
+ int key_bytes = (keysize + 7) / 8;
+ const ltc_ecc_set_type * curve = ltc_ecc_sets;
+ while (curve->size != 0) {
+ if (curve->size == key_bytes) {
+ return JNI_TRUE;
+ }
+ curve++;
+ }
+
+ return JNI_FALSE;
+}
+
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024TomCrypt_paramsSupported(JNIEnv *env, jobject this, jobject params){
+ if (params == NULL) {
+ return JNI_FALSE;
+ }
+
+ if ((*env)->IsInstanceOf(env, params, ec_parameter_spec_class)) {
+ jmethodID get_curve = (*env)->GetMethodID(env, ec_parameter_spec_class, "getCurve", "()Ljava/security/spec/EllipticCurve;");
+ jobject curve = (*env)->CallObjectMethod(env, params, get_curve);
+
+ jmethodID get_field = (*env)->GetMethodID(env, elliptic_curve_class, "getField", "()Ljava/security/spec/ECField;");
+ jobject field = (*env)->CallObjectMethod(env, curve, get_field);
+
+ if ((*env)->IsInstanceOf(env, field, fp_field_class)) {
+ jmethodID get_p = (*env)->GetMethodID(env, fp_field_class, "getP", "()Ljava/math/BigInteger;");
+ jobject p = (*env)->CallObjectMethod(env, field, get_p);
+
+ jmethodID get_a = (*env)->GetMethodID(env, elliptic_curve_class, "getA", "()Ljava/math/BigInteger;");
+ jobject a = (*env)->CallObjectMethod(env, curve, get_a);
+
+ jmethodID biginteger_valueof = (*env)->GetStaticMethodID(env, biginteger_class, "valueOf", "(J)Ljava/math/BigInteger;");
+ jobject three = (*env)->CallStaticObjectMethod(env, biginteger_class, biginteger_valueof, (jlong)3);
+
+ jmethodID biginteger_add = (*env)->GetMethodID(env, biginteger_class, "add", "(Ljava/math/BigInteger;)Ljava/math/BigInteger;");
+ jobject a_3 = (*env)->CallObjectMethod(env, a, biginteger_add, three);
+
+ jmethodID biginteger_equals = (*env)->GetMethodID(env, biginteger_class, "equals", "(Ljava/lang/Object;)Z");
+ jboolean eq = (*env)->CallBooleanMethod(env, p, biginteger_equals, a_3);
+ return eq;
+ } else if ((*env)->IsInstanceOf(env, field, f2m_field_class)) {
+ return JNI_FALSE;
+ } else {
+ 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);
+ const ltc_ecc_set_type * curve = ltc_ecc_sets;
+ while (curve->size != 0) {
+ if (strcasecmp(utf_name, curve->name) == 0) {
+ (*env)->ReleaseStringUTFChars(env, name, utf_name);
+ return JNI_TRUE;
+ }
+ curve++;
+ }
+ return JNI_FALSE;
+ } else {
+ return JNI_FALSE;
+ }
+}
+
+static jobject create_ec_param_spec(JNIEnv *env, const ltc_ecc_set_type *curve) {
+ jstring p_string = (*env)->NewStringUTF(env, curve->prime);
+ jmethodID biginteger_init = (*env)->GetMethodID(env, biginteger_class, "<init>", "(Ljava/lang/String;I)V");
+ jobject p = (*env)->NewObject(env, biginteger_class, biginteger_init, p_string, (jint) 16);
+
+ jmethodID fp_field_init = (*env)->GetMethodID(env, fp_field_class, "<init>", "(Ljava/math/BigInteger;)V");
+ jobject field = (*env)->NewObject(env, fp_field_class, fp_field_init, p);
+
+ jmethodID biginteger_subtract = (*env)->GetMethodID(env, biginteger_class, "subtract", "(Ljava/math/BigInteger;)Ljava/math/BigInteger;");
+ jmethodID biginteger_valueof = (*env)->GetStaticMethodID(env, biginteger_class, "valueOf", "(J)Ljava/math/BigInteger;");
+ jobject three = (*env)->CallStaticObjectMethod(env, biginteger_class, biginteger_valueof, (jlong) 3);
+ jobject a = (*env)->CallObjectMethod(env, p, biginteger_subtract, three);
+
+ jstring b_string = (*env)->NewStringUTF(env, curve->B);
+ jobject b = (*env)->NewObject(env, biginteger_class, biginteger_init, b_string, (jint) 16);
+
+ jmethodID elliptic_curve_init = (*env)->GetMethodID(env, elliptic_curve_class, "<init>", "(Ljava/security/spec/ECField;Ljava/math/BigInteger;Ljava/math/BigInteger;)V");
+ jobject elliptic_curve = (*env)->NewObject(env, elliptic_curve_class, elliptic_curve_init, field, a, b);
+
+ jstring gx_string = (*env)->NewStringUTF(env, curve->Gx);
+ jstring gy_string = (*env)->NewStringUTF(env, curve->Gy);
+ jobject gx = (*env)->NewObject(env, biginteger_class, biginteger_init, gx_string, (jint) 16);
+ jobject gy = (*env)->NewObject(env, biginteger_class, biginteger_init, gy_string, (jint) 16);
+
+ jmethodID point_init = (*env)->GetMethodID(env, point_class, "<init>", "(Ljava/math/BigInteger;Ljava/math/BigInteger;)V");
+ jobject g = (*env)->NewObject(env, point_class, point_init, gx, gy);
+
+ jstring n_string = (*env)->NewStringUTF(env, curve->order);
+ jobject n = (*env)->NewObject(env, biginteger_class, biginteger_init, n_string, (jint) 16);
+
+ jmethodID ec_parameter_spec_init = (*env)->GetMethodID(env, ec_parameter_spec_class, "<init>", "(Ljava/security/spec/EllipticCurve;Ljava/security/spec/ECPoint;Ljava/math/BigInteger;I)V");
+ return (*env)->NewObject(env, ec_parameter_spec_class, ec_parameter_spec_init, elliptic_curve, g, n, (jint) 1);
+}
+
+static char *biginteger_to_hex(JNIEnv *env, jobject big, jint bytes) {
+ jmethodID to_string = (*env)->GetMethodID(env, biginteger_class, "toString", "(I)Ljava/lang/String;");
+ jstring big_string = (*env)->CallObjectMethod(env, big, to_string, (jint) 16);
+
+ jsize len = (*env)->GetStringUTFLength(env, big_string);
+ char raw_string[len];
+ (*env)->GetStringUTFRegion(env, big_string, 0, len, raw_string);
+
+ char *result = calloc(bytes, 2);
+ if (len >= bytes) {
+ return strncpy(result, raw_string, 2*bytes);
+ } else {
+ jsize diff = bytes - len;
+ for (jint i = 0; i < diff*2; ++i) {
+ result[i] = '0';
+ }
+ return strncpy(result + diff*2, raw_string, 2*bytes);
+ }
+}
+
+static ltc_ecc_set_type* create_curve(JNIEnv *env, jobject params) {
+ jmethodID get_curve = (*env)->GetMethodID(env, ec_parameter_spec_class, "getCurve", "()Ljava/security/spec/EllipticCurve;");
+ jobject elliptic_curve = (*env)->CallObjectMethod(env, params, 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_b = (*env)->GetMethodID(env, elliptic_curve_class, "getB", "()Ljava/math/BigInteger;");
+ jobject b = (*env)->CallObjectMethod(env, elliptic_curve, get_b);
+
+ jmethodID get_p = (*env)->GetMethodID(env, fp_field_class, "getP", "()Ljava/math/BigInteger;");
+ jobject p = (*env)->CallObjectMethod(env, field, get_p);
+
+ jmethodID get_g = (*env)->GetMethodID(env, ec_parameter_spec_class, "getGenerator", "()Ljava/security/spec/ECPoint;");
+ jobject g = (*env)->CallObjectMethod(env, params, get_g);
+
+ jmethodID get_x = (*env)->GetMethodID(env, point_class, "getAffineX", "()Ljava/math/BigInteger;");
+ jobject gx = (*env)->CallObjectMethod(env, g, get_x);
+
+ jmethodID get_y = (*env)->GetMethodID(env, point_class, "getAffineY", "()Ljava/math/BigInteger;");
+ jobject gy = (*env)->CallObjectMethod(env, g, get_y);
+
+ jmethodID get_n = (*env)->GetMethodID(env, ec_parameter_spec_class, "getOrder", "()Ljava/math/BigInteger;");
+ jobject n = (*env)->CallObjectMethod(env, params, get_n);
+
+ ltc_ecc_set_type *curve = calloc(sizeof(ltc_ecc_set_type), 1);
+ curve->size = bytes;
+ curve->name = "";
+ curve->prime = biginteger_to_hex(env, p, bytes);
+ curve->B = biginteger_to_hex(env, b, bytes);
+ curve->order = biginteger_to_hex(env, n, bytes);
+ curve->Gx = biginteger_to_hex(env, gx, bytes);
+ curve->Gy = biginteger_to_hex(env, gy, bytes);
+
+ return curve;
+}
+
+static jobject generate_from_curve(JNIEnv *env, const ltc_ecc_set_type *curve) {
+ ecc_key key;
+ int err;
+ if ((err = ecc_make_key_ex(&ltc_prng, find_prng("yarrow"), &key, curve)) != CRYPT_OK) {
+ throw_new(env, "java/security/GeneralSecurityException", error_to_string(err));
+ return NULL;
+ }
+ unsigned long key_len = 2*curve->size + 1;
+ jbyteArray pub_bytes = (*env)->NewByteArray(env, key_len);
+ jbyte *key_pub = (*env)->GetByteArrayElements(env, pub_bytes, NULL);
+ ecc_ansi_x963_export(&key, key_pub, &key_len);
+ (*env)->ReleaseByteArrayElements(env, pub_bytes, key_pub, JNI_COMMIT);
+
+ jobject ec_param_spec = create_ec_param_spec(env, curve);
+
+ 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);
+
+ jbyteArray priv_bytes = (*env)->NewByteArray(env, curve->size);
+ jbyte *key_priv = (*env)->GetByteArrayElements(env, priv_bytes, NULL);
+ ltc_mp.unsigned_write(key.k, key_priv);
+ (*env)->ReleaseByteArrayElements(env, priv_bytes, key_priv, JNI_COMMIT);
+
+ 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");
+ 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");
+
+ ecc_free(&key);
+ return (*env)->NewObject(env, keypair_class, keypair_init, pubkey, privkey);
+}
+
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024TomCrypt_generate__ILjava_security_SecureRandom_2(JNIEnv *env, jobject this, jint keysize, jobject random){
+ int key_bytes = (keysize + 7) / 8;
+
+ const ltc_ecc_set_type *curve = ltc_ecc_sets;
+ while (curve->size != 0) {
+ if (curve->size == key_bytes) {
+ break;
+ }
+ curve++;
+ }
+
+ if (curve->size == 0) {
+ throw_new(env, "java/security/InvalidAlgorithmParameterException", "Curve for given bitsize not found.");
+ return NULL;
+ }
+
+ return generate_from_curve(env, curve);
+}
+
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024TomCrypt_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)) {
+ ltc_ecc_set_type *curve = create_curve(env, params);
+ jobject result = generate_from_curve(env, curve);
+ free(curve);
+ return result;
+ } 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 ltc_ecc_set_type* curve = ltc_ecc_sets;
+ while (curve->size != 0) {
+ if (strcasecmp(utf_name, curve->name) == 0) {
+ break;
+ }
+ curve++;
+ }
+ (*env)->ReleaseStringUTFChars(env, name, utf_name);
+
+ return generate_from_curve(env, curve);
+ } else {
+ throw_new(env, "java/security/InvalidAlgorithmParameterException", "Curve not found.");
+ return NULL;
+ }
+}
+
+static jboolean privkey_from_bytes(JNIEnv *env, jbyteArray privkey, const ltc_ecc_set_type *curve, ecc_key *out) {
+ jsize priv_size = (*env)->GetArrayLength(env, privkey);
+ jbyte *priv_data = (*env)->GetByteArrayElements(env, privkey, NULL);
+
+ if (curve->size != priv_size) {
+ throw_new(env, "java/lang/IllegalStateException", "Curve size does not match the private key size.");
+ (*env)->ReleaseByteArrayElements(env, privkey, priv_data, JNI_ABORT);
+ return JNI_FALSE;
+ }
+
+ out->type = PK_PRIVATE;
+ out->idx = -1;
+ out->dp = curve;
+ ltc_mp.init(&out->k);
+ ltc_mp.unsigned_read(out->k, priv_data, (unsigned long) curve->size);
+
+ (*env)->ReleaseByteArrayElements(env, privkey, priv_data, JNI_ABORT);
+ return JNI_TRUE;
+}
+
+static jboolean pubkey_from_bytes(JNIEnv *env, jbyteArray pubkey, const ltc_ecc_set_type *curve, ecc_key *out) {
+ jsize pub_size = (*env)->GetArrayLength(env, pubkey);
+ jbyte *pub_data = (*env)->GetByteArrayElements(env, pubkey, NULL);
+
+ if (curve->size != (pub_size - 1) / 2) {
+ throw_new(env, "java/lang/IllegalStateException", "Curve size does not match the public key size.");
+ (*env)->ReleaseByteArrayElements(env, pubkey, pub_data, JNI_ABORT);
+ return JNI_FALSE;
+ }
+
+ out->type = PK_PUBLIC;
+ out->idx = -1;
+ out->dp = curve;
+ ltc_init_multi(&out->pubkey.x, &out->pubkey.y, &out->pubkey.z, NULL);
+ ltc_mp.set_int(out->pubkey.z, 1);
+ ltc_mp.unsigned_read(out->pubkey.x, pub_data + 1, (unsigned long) curve->size);
+ ltc_mp.unsigned_read(out->pubkey.y, pub_data + 1 + curve->size, (unsigned long) curve->size);
+
+ (*env)->ReleaseByteArrayElements(env, pubkey, pub_data, JNI_ABORT);
+
+ return JNI_TRUE;
+}
+
+JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_00024TomCrypt_generateSecret(JNIEnv *env, jobject this, jbyteArray pubkey, jbyteArray privkey, jobject params){
+ ltc_ecc_set_type *curve = create_curve(env, params);
+
+ ecc_key pub;
+ if (!pubkey_from_bytes(env, pubkey, curve, &pub)) {
+ free(curve);
+ return NULL;
+ }
+
+ ecc_key priv;
+ if (!privkey_from_bytes(env, privkey, curve, &priv)) {
+ free(curve);
+ return NULL;
+ }
+
+ unsigned char result[curve->size];
+ unsigned long output_len = curve->size;
+ int err;
+ if ((err = ecc_shared_secret(&priv, &pub, result, &output_len)) != CRYPT_OK) {
+ throw_new(env, "java/security/GeneralSecurityException", error_to_string(err));
+ free(curve);
+ return NULL;
+ }
+
+ jbyteArray output = (*env)->NewByteArray(env, curve->size);
+ jbyte *output_data = (*env)->GetByteArrayElements(env, output, NULL);
+ memcpy(output_data, result, curve->size);
+ (*env)->ReleaseByteArrayElements(env, output, output_data, JNI_COMMIT);
+
+ ltc_cleanup_multi(&pub.pubkey.x, &pub.pubkey.y, &pub.pubkey.z, &priv.k, NULL);
+ free(curve);
+ return output;
+}
+
+JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024TomCryptRaw_sign(JNIEnv *env, jobject this, jbyteArray data, jbyteArray privkey, jobject params) {
+ ltc_ecc_set_type *curve = create_curve(env, params);
+
+ ecc_key priv;
+ if (!privkey_from_bytes(env, privkey, curve, &priv)) {
+ free(curve);
+ return NULL;
+ }
+
+ jsize data_size = (*env)->GetArrayLength(env, data);
+ jbyte *data_data = (*env)->GetByteArrayElements(env, data, NULL);
+
+ unsigned char result[curve->size*4];
+ unsigned long output_len = curve->size*4;
+ int err;
+ if ((err = ecc_sign_hash(data_data, data_size, result, &output_len, &ltc_prng, find_prng("yarrow"), &priv)) != CRYPT_OK) {
+ throw_new(env, "java/security/GeneralSecurityException", error_to_string(err));
+ free(curve);
+ (*env)->ReleaseByteArrayElements(env, data, data_data, JNI_ABORT);
+ return NULL;
+ }
+
+ (*env)->ReleaseByteArrayElements(env, data, data_data, JNI_ABORT);
+
+ jbyteArray output = (*env)->NewByteArray(env, output_len);
+ jbyte *output_data = (*env)->GetByteArrayElements(env, output, NULL);
+ memcpy(output_data, result, output_len);
+ (*env)->ReleaseByteArrayElements(env, output, output_data, JNI_COMMIT);
+
+ free(curve);
+ return output;
+}
+
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024TomCryptRaw_verify(JNIEnv *env, jobject this, jbyteArray signature, jbyteArray data, jbyteArray pubkey, jobject params) {
+ ltc_ecc_set_type *curve = create_curve(env, params);
+
+ ecc_key pub;
+ if (!pubkey_from_bytes(env, pubkey, curve, &pub)) {
+ free(curve);
+ return JNI_FALSE;
+ }
+
+ jsize data_size = (*env)->GetArrayLength(env, data);
+ jbyte *data_data = (*env)->GetByteArrayElements(env, data, NULL);
+
+ jsize sig_size = (*env)->GetArrayLength(env, signature);
+ jbyte *sig_data = (*env)->GetByteArrayElements(env, signature, NULL);
+
+ int err;
+ int result;
+ if ((err = ecc_verify_hash(sig_data, sig_size, data_data, data_size, &result, &pub)) != CRYPT_OK) {
+ throw_new(env, "java/security/GeneralSecurityException", error_to_string(err));
+ free(curve);
+ (*env)->ReleaseByteArrayElements(env, data, data_data, JNI_ABORT);
+ (*env)->ReleaseByteArrayElements(env, signature, sig_data, JNI_ABORT);
+ return JNI_FALSE;
+ }
+
+ (*env)->ReleaseByteArrayElements(env, data, data_data, JNI_ABORT);
+ (*env)->ReleaseByteArrayElements(env, signature, sig_data, JNI_ABORT);
+ free(curve);
+ return result;
+} \ No newline at end of file