aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJ08nY2017-11-29 20:43:57 +0100
committerJ08nY2017-11-29 20:43:57 +0100
commit5026cc9f03f11fc2a473124e32867f3302f901f7 (patch)
treec317da55f300770d8e84dbf6cc2cc41c53efda33
parent9250f269d6a8ffa7f3714d60a0437a112ad7a924 (diff)
downloadECTester-5026cc9f03f11fc2a473124e32867f3302f901f7.tar.gz
ECTester-5026cc9f03f11fc2a473124e32867f3302f901f7.tar.zst
ECTester-5026cc9f03f11fc2a473124e32867f3302f901f7.zip
-rw-r--r--build-standalone.xml6
-rw-r--r--src/cz/crcs/ectester/common/util/ECUtil.java95
-rw-r--r--src/cz/crcs/ectester/standalone/ECTesterStandalone.java3
-rw-r--r--src/cz/crcs/ectester/standalone/libs/jni/Makefile4
-rw-r--r--src/cz/crcs/ectester/standalone/libs/jni/NativeECPrivateKey.java56
-rw-r--r--src/cz/crcs/ectester/standalone/libs/jni/NativeECPublicKey.java57
-rw-r--r--src/cz/crcs/ectester/standalone/libs/jni/NativeKeyPairGeneratorSpi.java57
-rw-r--r--src/cz/crcs/ectester/standalone/libs/jni/native.h65
-rw-r--r--src/cz/crcs/ectester/standalone/libs/jni/tomcrypt.c299
9 files changed, 626 insertions, 16 deletions
diff --git a/build-standalone.xml b/build-standalone.xml
index a745ca9..7261eee 100644
--- a/build-standalone.xml
+++ b/build-standalone.xml
@@ -71,7 +71,7 @@
nbproject/build-impl.xml file.
-->
- <target name="package" depends="jar,libs-try">
+ <target name="package" depends="jar">
<property name="store.jar.name" value="ECTesterStandalone-dist"/>
<antcall target="dist-build.package"/>
</target>
@@ -87,6 +87,7 @@
</exec>
</target>
+ <target name="-post-compile" depends="libs-try"/>
<target name="-post-clean">
<exec dir="src/cz/crcs/ectester/standalone/libs/jni" failonerror="true" executable="make clean"
osfamily="unix"/>
@@ -96,6 +97,9 @@
<javah classpath="${build.classes.dir}" outputfile="src/cz/crcs/ectester/standalone/libs/jni/native.h">
<class name="cz.crcs.ectester.standalone.libs.TomcryptLib"/>
<class name="cz.crcs.ectester.standalone.libs.jni.NativeProvider$TomCrypt"/>
+ <class name="cz.crcs.ectester.standalone.libs.jni.NativeKeyPairGeneratorSpi$TomCrypt"/>
+ <class name="cz.crcs.ectester.standalone.libs.jni.NativeECPublicKey$TomCrypt"/>
+ <class name="cz.crcs.ectester.standalone.libs.jni.NativeECPrivateKey$TomCrypt"/>
</javah>
</target>
</project>
diff --git a/src/cz/crcs/ectester/common/util/ECUtil.java b/src/cz/crcs/ectester/common/util/ECUtil.java
index 713effe..80ba34e 100644
--- a/src/cz/crcs/ectester/common/util/ECUtil.java
+++ b/src/cz/crcs/ectester/common/util/ECUtil.java
@@ -1,7 +1,7 @@
package cz.crcs.ectester.common.util;
import java.math.BigInteger;
-import java.security.spec.ECPoint;
+import java.security.spec.*;
/**
* @author Jan Jancar johny@neuromancer.sk
@@ -34,4 +34,97 @@ public class ECUtil {
byte marker = (byte) (0x06 | point.getAffineY().mod(BigInteger.valueOf(2)).byteValue());
return ByteUtil.concatenate(new byte[]{marker}, x, y);
}
+
+ private static boolean isResidue(BigInteger a, BigInteger p) {
+ BigInteger exponent = p.subtract(BigInteger.ONE).divide(BigInteger.valueOf(2));
+ BigInteger result = a.modPow(exponent, p);
+ return result.intValueExact() == 1;
+ }
+
+ private static BigInteger modSqrt(BigInteger a, BigInteger p) {
+ BigInteger q = p.subtract(BigInteger.ONE);
+ int s = 0;
+ while (q.mod(BigInteger.valueOf(2)).equals(BigInteger.ZERO)) {
+ q = q.divide(BigInteger.valueOf(2));
+ s++;
+ }
+
+ BigInteger z = BigInteger.ONE;
+ do {
+ z = z.add(BigInteger.ONE);
+ } while (isResidue(z, p));
+
+ BigInteger m = BigInteger.valueOf(s);
+ BigInteger c = z.modPow(q, p);
+ BigInteger t = a.modPow(q, p);
+ BigInteger rExponent = q.add(BigInteger.ONE).divide(BigInteger.valueOf(2));
+ BigInteger r = a.modPow(rExponent, p);
+
+ while (!t.equals(BigInteger.ONE)) {
+ int i = 0;
+ BigInteger exponent;
+ do {
+ exponent = BigInteger.valueOf(2).pow(++i);
+ } while (!t.modPow(exponent, p).equals(BigInteger.ONE));
+
+ BigInteger twoExponent = m.subtract(BigInteger.valueOf(i + 1));
+ BigInteger b = c.modPow(BigInteger.valueOf(2).modPow(twoExponent, p), p);
+ m = BigInteger.valueOf(i);
+ c = b.modPow(BigInteger.valueOf(2), p);
+ t = t.multiply(c).mod(p);
+ r = r.multiply(b).mod(p);
+ }
+ return r;
+ }
+
+ public static ECPoint fromX962(byte[] data, EllipticCurve curve) {
+ if (data == null) {
+ return null;
+ }
+ if (data[0] == 0x04 || data[0] == 0x06 || data[0] == 0x07) {
+ int len = (data.length - 1) / 2;
+ byte[] xbytes = new byte[len];
+ System.arraycopy(data, 1, xbytes, 0, len);
+ byte[] ybytes = new byte[len];
+ System.arraycopy(data, 1 + len, ybytes, 0, len);
+ return new ECPoint(new BigInteger(xbytes), new BigInteger(ybytes));
+ } else if (data[0] == 0x02 || data[0] == 0x03) {
+ if (curve == null) {
+ throw new IllegalArgumentException();
+ }
+ byte[] xbytes = new byte[data.length - 1];
+ System.arraycopy(data, 1, xbytes, 0, data.length - 1);
+ BigInteger x = new BigInteger(xbytes);
+ BigInteger a = curve.getA();
+ BigInteger b = curve.getB();
+
+ ECField field = curve.getField();
+ if (field instanceof ECFieldFp) {
+ BigInteger p = ((ECFieldFp) field).getP();
+ BigInteger alpha = x.modPow(BigInteger.valueOf(3), p);
+ alpha = alpha.add(x.multiply(a));
+ alpha = alpha.add(b);
+
+ BigInteger beta = modSqrt(alpha, p);
+ if (beta.getLowestSetBit() == 0) {
+ // rightmost bit is one
+ if (data[0] == 0x02) {
+ beta = beta.negate();
+ }
+ } else {
+ // rightmost bit is zero
+ if (data[0] == 0x03) {
+ beta = beta.negate();
+ }
+ }
+
+ return new ECPoint(x, beta);
+ } else if (field instanceof ECFieldF2m) {
+
+ }
+ return null;
+ } else {
+ throw new IllegalArgumentException();
+ }
+ }
}
diff --git a/src/cz/crcs/ectester/standalone/ECTesterStandalone.java b/src/cz/crcs/ectester/standalone/ECTesterStandalone.java
index 8125485..8605158 100644
--- a/src/cz/crcs/ectester/standalone/ECTesterStandalone.java
+++ b/src/cz/crcs/ectester/standalone/ECTesterStandalone.java
@@ -23,6 +23,7 @@ import java.security.*;
import java.security.interfaces.ECPrivateKey;
import java.security.interfaces.ECPublicKey;
import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.ECGenParameterSpec;
import java.security.spec.ECParameterSpec;
import java.util.*;
import java.util.stream.Collectors;
@@ -87,7 +88,7 @@ public class ECTesterStandalone {
} catch (ParseException | IOException ex) {
System.err.println(ex.getMessage());
- } catch (InvalidAlgorithmParameterException e) {
+ } catch (InvalidAlgorithmParameterException | InvalidParameterException e) {
System.err.println("Invalid algorithm parameter: " + e.getMessage());
} catch (NoSuchAlgorithmException nsaex) {
System.err.println("Algorithm not supported by the selected library: " + nsaex.getMessage());
diff --git a/src/cz/crcs/ectester/standalone/libs/jni/Makefile b/src/cz/crcs/ectester/standalone/libs/jni/Makefile
index 837078c..8750dd5 100644
--- a/src/cz/crcs/ectester/standalone/libs/jni/Makefile
+++ b/src/cz/crcs/ectester/standalone/libs/jni/Makefile
@@ -36,10 +36,10 @@ JNI_PLATFORMINCLUDEDIR ?= $(JNI_INCLUDEDIR)/$(JNI_PLATFORM)
all: tomcrypt_provider.so
tomcrypt_provider.so: tomcrypt.o
- gcc -DLTM_DESC -DUSE_LTM -fPIC -shared -o $@ $< -ltommath -ltomcrypt
+ gcc -DLTM_DESC -DUSE_LTM -fPIC -g -shared -o $@ $< -ltommath -ltomcrypt
%.o: %.c
- gcc -fPIC -I"$(JNI_INCLUDEDIR)" -I"$(JNI_PLATFORMINCLUDEDIR)" -I. -c $<
+ gcc -fPIC -g -I"$(JNI_INCLUDEDIR)" -I"$(JNI_PLATFORMINCLUDEDIR)" -I. -c $<
clean:
rm -rf *.o
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..359b6b0
--- /dev/null
+++ b/src/cz/crcs/ectester/standalone/libs/jni/NativeECPrivateKey.java
@@ -0,0 +1,56 @@
+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;
+ }
+
+ public static class TomCrypt extends NativeECPrivateKey {
+ private byte[] keyData;
+ private ECParameterSpec params;
+
+ public TomCrypt(byte[] keyData, ECParameterSpec params) {
+ super("EC", "raw");
+ this.keyData = keyData;
+ this.params = params;
+ }
+
+ @Override
+ public BigInteger getS() {
+ return new BigInteger(keyData);
+ }
+
+ @Override
+ public byte[] getEncoded() {
+ return Arrays.clone(keyData);
+ }
+
+ @Override
+ public ECParameterSpec getParams() {
+ return 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..c3791c4
--- /dev/null
+++ b/src/cz/crcs/ectester/standalone/libs/jni/NativeECPublicKey.java
@@ -0,0 +1,57 @@
+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;
+ }
+
+ public static class TomCrypt extends NativeECPublicKey {
+ private byte[] keyData;
+ private ECParameterSpec params;
+
+ public TomCrypt(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;
+ }
+ }
+}
diff --git a/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyPairGeneratorSpi.java b/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyPairGeneratorSpi.java
index 6b4e5e0..d2cc59d 100644
--- a/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyPairGeneratorSpi.java
+++ b/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyPairGeneratorSpi.java
@@ -1,31 +1,74 @@
package cz.crcs.ectester.standalone.libs.jni;
-import java.security.InvalidAlgorithmParameterException;
-import java.security.KeyPair;
-import java.security.KeyPairGeneratorSpi;
-import java.security.SecureRandom;
+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);
}
}
diff --git a/src/cz/crcs/ectester/standalone/libs/jni/native.h b/src/cz/crcs/ectester/standalone/libs/jni/native.h
index e607738..da3a89c 100644
--- a/src/cz/crcs/ectester/standalone/libs/jni/native.h
+++ b/src/cz/crcs/ectester/standalone/libs/jni/native.h
@@ -60,3 +60,68 @@ JNIEXPORT void JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeProvider_
}
#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
diff --git a/src/cz/crcs/ectester/standalone/libs/jni/tomcrypt.c b/src/cz/crcs/ectester/standalone/libs/jni/tomcrypt.c
index f59c1bd..f7dedce 100644
--- a/src/cz/crcs/ectester/standalone/libs/jni/tomcrypt.c
+++ b/src/cz/crcs/ectester/standalone/libs/jni/tomcrypt.c
@@ -1,12 +1,28 @@
#include "native.h"
#include <stdio.h>
+#include <string.h>
#define LTM_DESC
#include <tomcrypt.h>
+static prng_state ltc_prng;
+static jclass provider_class;
+static jclass ec_parameter_spec_class;
+static jclass ecgen_parameter_spec_class;
+static jclass pubkey_class;
+static jclass privkey_class;
+static jclass keypair_class;
+static jclass elliptic_curve_class;
+static jclass fp_field_class;
+static jclass f2m_field_class;
+static jclass point_class;
+static jclass biginteger_class;
+
JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_TomcryptLib_createProvider(JNIEnv *env, jobject this) {
- jclass provider_class = (*env)->FindClass(env, "cz/crcs/ectester/standalone/libs/jni/NativeProvider$TomCrypt");
+ /* 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, provider_class, "<init>", "(Ljava/lang/String;DLjava/lang/String;)V");
+ 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);
@@ -14,12 +30,11 @@ JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_TomcryptLib_crea
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;
- jclass provider_class = (*env)->FindClass(env, "cz/crcs/ectester/standalone/libs/jni/NativeProvider$TomCrypt");
-
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");
@@ -33,6 +48,47 @@ JNIEXPORT void JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeProvider_
jstring ecdsa = (*env)->NewStringUTF(env, "Signature.ECDSA");
jstring ecdsa_value = (*env)->NewStringUTF(env, "cz.crcs.ectester.standalone.libs.jni.NativeSignatureSpi$TomCrypt");
(*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));
+ }
+
+ 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);
+
+ jclass local_pubkey_class = (*env)->FindClass(env, "cz/crcs/ectester/standalone/libs/jni/NativeECPublicKey$TomCrypt");
+ pubkey_class = (*env)->NewGlobalRef(env, local_pubkey_class);
+
+ jclass local_privkey_class = (*env)->FindClass(env, "cz/crcs/ectester/standalone/libs/jni/NativeECPrivateKey$TomCrypt");
+ 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);
}
JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_TomcryptLib_getCurves(JNIEnv *env, jobject this) {
@@ -50,4 +106,239 @@ JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_TomcryptLib_getC
}
return result;
+}
+
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024TomCrypt_keysizeSupported(JNIEnv *env, jobject this, jint keysize){
+ const ltc_ecc_set_type * curve = ltc_ecc_sets;
+ while (curve->size != 0) {
+ if (curve->size * 8 == keysize) {
+ 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 + (8 - bits % 8)) / 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) {
+ printf("Error making key: %s\n", 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, 0);
+
+ 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);
+ mp_to_unsigned_bin(key.k, key_priv);
+ (*env)->ReleaseByteArrayElements(env, priv_bytes, key_priv, 0);
+
+ 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 / 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) {
+ 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 {
+ return NULL;
+ }
} \ No newline at end of file