From 7737039d8c1ad743ed1f5dc5e40224e297acd08d Mon Sep 17 00:00:00 2001
From: J08nY
Date: Sun, 26 Nov 2017 23:50:00 +0100
Subject: Export generated keys in ANSI X9.62 uncompressed format.
---
src/cz/crcs/ectester/common/util/ECUtil.java | 37 ++++++++++++++++++++++++++++
1 file changed, 37 insertions(+)
create mode 100644 src/cz/crcs/ectester/common/util/ECUtil.java
(limited to 'src/cz/crcs/ectester/common/util/ECUtil.java')
diff --git a/src/cz/crcs/ectester/common/util/ECUtil.java b/src/cz/crcs/ectester/common/util/ECUtil.java
new file mode 100644
index 0000000..713effe
--- /dev/null
+++ b/src/cz/crcs/ectester/common/util/ECUtil.java
@@ -0,0 +1,37 @@
+package cz.crcs.ectester.common.util;
+
+import java.math.BigInteger;
+import java.security.spec.ECPoint;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public class ECUtil {
+ public static byte[] toX962Compressed(ECPoint point) {
+ if (point.equals(ECPoint.POINT_INFINITY)) {
+ return new byte[]{0};
+ }
+ byte[] x = point.getAffineX().toByteArray();
+ byte marker = (byte) (0x02 | point.getAffineY().mod(BigInteger.valueOf(2)).byteValue());
+ return ByteUtil.concatenate(new byte[]{marker}, x);
+ }
+
+ public static byte[] toX962Uncompressed(ECPoint point) {
+ if (point.equals(ECPoint.POINT_INFINITY)) {
+ return new byte[]{0};
+ }
+ byte[] x = point.getAffineX().toByteArray();
+ byte[] y = point.getAffineY().toByteArray();
+ return ByteUtil.concatenate(new byte[]{0x04}, x, y);
+ }
+
+ public static byte[] toX962Hybrid(ECPoint point) {
+ if (point.equals(ECPoint.POINT_INFINITY)) {
+ return new byte[]{0};
+ }
+ byte[] x = point.getAffineX().toByteArray();
+ byte[] y = point.getAffineY().toByteArray();
+ byte marker = (byte) (0x06 | point.getAffineY().mod(BigInteger.valueOf(2)).byteValue());
+ return ByteUtil.concatenate(new byte[]{marker}, x, y);
+ }
+}
--
cgit v1.2.3-70-g09d2
From 5026cc9f03f11fc2a473124e32867f3302f901f7 Mon Sep 17 00:00:00 2001
From: J08nY
Date: Wed, 29 Nov 2017 20:43:57 +0100
Subject: Implement KeyPairGeneration for LibTomCrypt.
---
build-standalone.xml | 6 +-
src/cz/crcs/ectester/common/util/ECUtil.java | 95 ++++++-
.../ectester/standalone/ECTesterStandalone.java | 3 +-
src/cz/crcs/ectester/standalone/libs/jni/Makefile | 4 +-
.../standalone/libs/jni/NativeECPrivateKey.java | 56 ++++
.../standalone/libs/jni/NativeECPublicKey.java | 57 ++++
.../libs/jni/NativeKeyPairGeneratorSpi.java | 57 +++-
src/cz/crcs/ectester/standalone/libs/jni/native.h | 65 +++++
.../crcs/ectester/standalone/libs/jni/tomcrypt.c | 299 ++++++++++++++++++++-
9 files changed, 626 insertions(+), 16 deletions(-)
create mode 100644 src/cz/crcs/ectester/standalone/libs/jni/NativeECPrivateKey.java
create mode 100644 src/cz/crcs/ectester/standalone/libs/jni/NativeECPublicKey.java
(limited to 'src/cz/crcs/ectester/common/util/ECUtil.java')
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.
-->
-
+
@@ -87,6 +87,7 @@
+
@@ -96,6 +97,9 @@
+
+
+
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
+#include
#define LTM_DESC
#include
+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, "", "(Ljava/lang/String;DLjava/lang/String;)V");
+ jmethodID init = (*env)->GetMethodID(env, local_provider_class, "", "(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"), <c_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, "", "(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, "", "(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, "", "(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, "", "(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, "", "(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(<c_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, "", "([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, "", "([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, "", "(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
--
cgit v1.2.3-70-g09d2
From d571f404e51356239cdb7d23de95074b271016e1 Mon Sep 17 00:00:00 2001
From: J08nY
Date: Thu, 30 Nov 2017 19:42:20 +0100
Subject: Fix NativeKeyAgreement keysize mismatch on BigInteger conversion.
---
src/cz/crcs/ectester/common/util/ECUtil.java | 62 ++++++++++++++++++----
.../ectester/standalone/ECTesterStandalone.java | 7 ++-
.../standalone/libs/jni/NativeKeyAgreementSpi.java | 4 +-
.../crcs/ectester/standalone/libs/jni/tomcrypt.c | 51 +++++++++++++-----
4 files changed, 94 insertions(+), 30 deletions(-)
(limited to 'src/cz/crcs/ectester/common/util/ECUtil.java')
diff --git a/src/cz/crcs/ectester/common/util/ECUtil.java b/src/cz/crcs/ectester/common/util/ECUtil.java
index 80ba34e..662720a 100644
--- a/src/cz/crcs/ectester/common/util/ECUtil.java
+++ b/src/cz/crcs/ectester/common/util/ECUtil.java
@@ -7,34 +7,75 @@ import java.security.spec.*;
* @author Jan Jancar johny@neuromancer.sk
*/
public class ECUtil {
- public static byte[] toX962Compressed(ECPoint point) {
+
+ public static byte[] toByteArray(BigInteger what, int bits) {
+ byte[] raw = what.toByteArray();
+ int bytes = (bits + 7) / 8;
+ if (raw.length < bytes) {
+ byte[] result = new byte[bytes];
+ System.arraycopy(raw,0, result, bytes - raw.length, raw.length);
+ return result;
+ }
+ if (bytes < raw.length) {
+ byte[] result = new byte[bytes];
+ System.arraycopy(raw, raw.length - bytes, result, 0, bytes);
+ return result;
+ }
+ return raw;
+ }
+
+ public static byte[] toX962Compressed(ECPoint point, int bits) {
if (point.equals(ECPoint.POINT_INFINITY)) {
return new byte[]{0};
}
- byte[] x = point.getAffineX().toByteArray();
+ byte[] x = toByteArray(point.getAffineX(), bits);
byte marker = (byte) (0x02 | point.getAffineY().mod(BigInteger.valueOf(2)).byteValue());
return ByteUtil.concatenate(new byte[]{marker}, x);
}
- public static byte[] toX962Uncompressed(ECPoint point) {
+ public static byte[] toX962Compressed(ECPoint point, EllipticCurve curve) {
+ return toX962Compressed(point, curve.getField().getFieldSize());
+ }
+
+ public static byte[] toX962Compressed(ECPoint point, ECParameterSpec spec) {
+ return toX962Compressed(point, spec.getCurve());
+ }
+
+ public static byte[] toX962Uncompressed(ECPoint point, int bits) {
if (point.equals(ECPoint.POINT_INFINITY)) {
return new byte[]{0};
}
- byte[] x = point.getAffineX().toByteArray();
- byte[] y = point.getAffineY().toByteArray();
+ byte[] x = toByteArray(point.getAffineX(), bits);
+ byte[] y = toByteArray(point.getAffineY(), bits);
return ByteUtil.concatenate(new byte[]{0x04}, x, y);
}
- public static byte[] toX962Hybrid(ECPoint point) {
+ public static byte[] toX962Uncompressed(ECPoint point, EllipticCurve curve) {
+ return toX962Uncompressed(point, curve.getField().getFieldSize());
+ }
+
+ public static byte[] toX962Uncompressed(ECPoint point, ECParameterSpec spec) {
+ return toX962Uncompressed(point, spec.getCurve());
+ }
+
+ public static byte[] toX962Hybrid(ECPoint point, int bits) {
if (point.equals(ECPoint.POINT_INFINITY)) {
return new byte[]{0};
}
- byte[] x = point.getAffineX().toByteArray();
- byte[] y = point.getAffineY().toByteArray();
+ byte[] x = toByteArray(point.getAffineX(), bits);
+ byte[] y = toByteArray(point.getAffineY(), bits);
byte marker = (byte) (0x06 | point.getAffineY().mod(BigInteger.valueOf(2)).byteValue());
return ByteUtil.concatenate(new byte[]{marker}, x, y);
}
+ public static byte[] toX962Hybrid(ECPoint point, EllipticCurve curve) {
+ return toX962Hybrid(point, curve.getField().getFieldSize());
+ }
+
+ public static byte[] toX962Hybrid(ECPoint point, ECParameterSpec spec) {
+ return toX962Hybrid(point, spec.getCurve());
+ }
+
private static boolean isResidue(BigInteger a, BigInteger p) {
BigInteger exponent = p.subtract(BigInteger.ONE).divide(BigInteger.valueOf(2));
BigInteger result = a.modPow(exponent, p);
@@ -64,7 +105,7 @@ public class ECUtil {
int i = 0;
BigInteger exponent;
do {
- exponent = BigInteger.valueOf(2).pow(++i);
+ exponent = BigInteger.valueOf(2).pow(++i);
} while (!t.modPow(exponent, p).equals(BigInteger.ONE));
BigInteger twoExponent = m.subtract(BigInteger.valueOf(i + 1));
@@ -120,7 +161,8 @@ public class ECUtil {
return new ECPoint(x, beta);
} else if (field instanceof ECFieldF2m) {
-
+ //TODO
+ throw new UnsupportedOperationException();
}
return null;
} else {
diff --git a/src/cz/crcs/ectester/standalone/ECTesterStandalone.java b/src/cz/crcs/ectester/standalone/ECTesterStandalone.java
index 8605158..3ad7141 100644
--- a/src/cz/crcs/ectester/standalone/ECTesterStandalone.java
+++ b/src/cz/crcs/ectester/standalone/ECTesterStandalone.java
@@ -23,7 +23,6 @@ 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;
@@ -246,7 +245,7 @@ public class ECTesterStandalone {
byte[] result = ka.generateSecret();
ka = kaIdent.getInstance(lib.getProvider());
- String pub = ByteUtil.bytesToHex(ECUtil.toX962Uncompressed(pubkey.getW()), false);
+ String pub = ByteUtil.bytesToHex(ECUtil.toX962Uncompressed(pubkey.getW(), pubkey.getParams()), false);
String priv = ByteUtil.bytesToHex(privkey.getS().toByteArray(), false);
String dh = ByteUtil.bytesToHex(result, false);
System.out.println(String.format("%d;%d;%s;%s;%s", i, elapsed, pub, priv, dh));
@@ -336,7 +335,7 @@ public class ECTesterStandalone {
verifyTime += System.nanoTime();
- String pub = ByteUtil.bytesToHex(ECUtil.toX962Uncompressed(pubkey.getW()), false);
+ String pub = ByteUtil.bytesToHex(ECUtil.toX962Uncompressed(pubkey.getW(), pubkey.getParams()), false);
String priv = ByteUtil.bytesToHex(privkey.getS().toByteArray(), false);
String sign = ByteUtil.bytesToHex(signature, false);
System.out.println(String.format("%d;%s;%d;%d;%s;%s;%s;%d", i, dataString, signTime, verifyTime, pub, priv, sign, verified ? 1 : 0));
@@ -385,7 +384,7 @@ public class ECTesterStandalone {
ECPublicKey publicKey = (ECPublicKey) kp.getPublic();
ECPrivateKey privateKey = (ECPrivateKey) kp.getPrivate();
- String pub = ByteUtil.bytesToHex(ECUtil.toX962Uncompressed(publicKey.getW()), false);
+ String pub = ByteUtil.bytesToHex(ECUtil.toX962Uncompressed(publicKey.getW(), publicKey.getParams()), false);
String priv = ByteUtil.bytesToHex(privateKey.getS().toByteArray(), false);
System.out.println(String.format("%d;%d;%s;%s", i, elapsed, pub, priv));
}
diff --git a/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyAgreementSpi.java b/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyAgreementSpi.java
index fee0ea8..47eeabd 100644
--- a/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyAgreementSpi.java
+++ b/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyAgreementSpi.java
@@ -67,8 +67,8 @@ public abstract class NativeKeyAgreementSpi extends KeyAgreementSpi {
@Override
protected byte[] engineGenerateSecret() throws IllegalStateException {
- byte[] pubkey = ECUtil.toX962Uncompressed(publicKey.getW());
- byte[] privkey = privateKey.getS().toByteArray();
+ byte[] pubkey = ECUtil.toX962Uncompressed(publicKey.getW(), params.getCurve());
+ byte[] privkey = ECUtil.toByteArray(privateKey.getS(), params.getCurve().getField().getFieldSize());
return generateSecret(pubkey, privkey, params);
}
diff --git a/src/cz/crcs/ectester/standalone/libs/jni/tomcrypt.c b/src/cz/crcs/ectester/standalone/libs/jni/tomcrypt.c
index b43b05a..d32c6a6 100644
--- a/src/cz/crcs/ectester/standalone/libs/jni/tomcrypt.c
+++ b/src/cz/crcs/ectester/standalone/libs/jni/tomcrypt.c
@@ -15,6 +15,7 @@ static jclass fp_field_class;
static jclass f2m_field_class;
static jclass point_class;
static jclass biginteger_class;
+static jclass illegal_state_exception_class;
JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_TomcryptLib_createProvider(JNIEnv *env, jobject this) {
/* Create the custom provider. */
@@ -88,6 +89,9 @@ JNIEXPORT void JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeProvider_
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);
}
JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_TomcryptLib_getCurves(JNIEnv *env, jobject this) {
@@ -233,7 +237,7 @@ static ltc_ecc_set_type* create_curve(JNIEnv *env, jobject params) {
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;
+ 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);
@@ -265,18 +269,23 @@ static ltc_ecc_set_type* create_curve(JNIEnv *env, jobject params) {
return curve;
}
+static void throw_new(JNIEnv *env, const char *class, const char *message) {
+ jclass clazz = (*env)->FindClass(env, class);
+ (*env)->ThrowNew(env, clazz, message);
+}
+
static jobject generate_from_curve(JNIEnv *env, const ltc_ecc_set_type *curve) {
ecc_key key;
int err;
if ((err = ecc_make_key_ex(<c_prng, find_prng("yarrow"), &key, curve)) != CRYPT_OK) {
- printf("Error making key: %s\n", error_to_string(err));
+ 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, 0);
+ (*env)->ReleaseByteArrayElements(env, pub_bytes, key_pub, JNI_COMMIT);
jobject ec_param_spec = create_ec_param_spec(env, curve);
@@ -287,7 +296,7 @@ static jobject generate_from_curve(JNIEnv *env, const ltc_ecc_set_type *curve) {
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, 0);
+ (*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, "", "([BLjava/security/spec/ECParameterSpec;)V");
@@ -347,7 +356,13 @@ JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKey
jsize pub_size = (*env)->GetArrayLength(env, pubkey);
jbyte *pub_data = (*env)->GetByteArrayElements(env, pubkey, NULL);
- jsize pub_half = (pub_size - 1) / 2;
+
+ 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);
+ free(curve);
+ return NULL;
+ }
ecc_key pub;
pub.type = PK_PUBLIC;
@@ -355,38 +370,46 @@ JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKey
pub.dp = curve;
ltc_init_multi(&pub.pubkey.x, &pub.pubkey.y, &pub.pubkey.z, NULL);
ltc_mp.set_int(pub.pubkey.z, 1);
- ltc_mp.unsigned_read(pub.pubkey.x, pub_data + 1, (unsigned long) pub_half);
- ltc_mp.unsigned_read(pub.pubkey.y, pub_data + 1 + pub_half, (unsigned long) pub_half);
+ ltc_mp.unsigned_read(pub.pubkey.x, pub_data + 1, (unsigned long) curve->size);
+ ltc_mp.unsigned_read(pub.pubkey.y, pub_data + 1 + curve->size, (unsigned long) curve->size);
(*env)->ReleaseByteArrayElements(env, pubkey, pub_data, JNI_ABORT);
+
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);
+ free(curve);
+ return NULL;
+ }
+
ecc_key priv;
priv.type = PK_PRIVATE;
priv.idx = -1;
priv.dp = curve;
ltc_mp.init(&priv.k);
- ltc_mp.unsigned_read(priv.k, priv_data, (unsigned long) priv_size);
+ ltc_mp.unsigned_read(priv.k, priv_data, (unsigned long) curve->size);
(*env)->ReleaseByteArrayElements(env, privkey, priv_data, JNI_ABORT);
- unsigned char result[pub_half];
-
- unsigned long output_len = pub_half;
+ 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) {
- printf("Error during shared secret computation: %s\n", error_to_string(err));
+ throw_new(env, "java/security/GeneralSecurityException", error_to_string(err));
free(curve);
return NULL;
}
- jbyteArray output = (*env)->NewByteArray(env, pub_half);
+ jbyteArray output = (*env)->NewByteArray(env, curve->size);
jbyte *output_data = (*env)->GetByteArrayElements(env, output, NULL);
- memcpy(output_data, result, pub_half);
+ 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;
}
\ No newline at end of file
--
cgit v1.2.3-70-g09d2
From 018771cbd0b104918012c473a2590e0ef8e89a25 Mon Sep 17 00:00:00 2001
From: J08nY
Date: Fri, 1 Dec 2017 00:24:25 +0100
Subject: Make sure byteArrays are of positive BigIntegers.
---
src/cz/crcs/ectester/common/util/ECUtil.java | 6 +++---
src/cz/crcs/ectester/standalone/libs/jni/NativeECPrivateKey.java | 2 +-
2 files changed, 4 insertions(+), 4 deletions(-)
(limited to 'src/cz/crcs/ectester/common/util/ECUtil.java')
diff --git a/src/cz/crcs/ectester/common/util/ECUtil.java b/src/cz/crcs/ectester/common/util/ECUtil.java
index 662720a..973b813 100644
--- a/src/cz/crcs/ectester/common/util/ECUtil.java
+++ b/src/cz/crcs/ectester/common/util/ECUtil.java
@@ -13,7 +13,7 @@ public class ECUtil {
int bytes = (bits + 7) / 8;
if (raw.length < bytes) {
byte[] result = new byte[bytes];
- System.arraycopy(raw,0, result, bytes - raw.length, raw.length);
+ System.arraycopy(raw, 0, result, bytes - raw.length, raw.length);
return result;
}
if (bytes < raw.length) {
@@ -128,14 +128,14 @@ public class ECUtil {
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));
+ return new ECPoint(new BigInteger(1, xbytes), new BigInteger(1, 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 x = new BigInteger(1, xbytes);
BigInteger a = curve.getA();
BigInteger b = curve.getB();
diff --git a/src/cz/crcs/ectester/standalone/libs/jni/NativeECPrivateKey.java b/src/cz/crcs/ectester/standalone/libs/jni/NativeECPrivateKey.java
index 359b6b0..6f6cde3 100644
--- a/src/cz/crcs/ectester/standalone/libs/jni/NativeECPrivateKey.java
+++ b/src/cz/crcs/ectester/standalone/libs/jni/NativeECPrivateKey.java
@@ -40,7 +40,7 @@ public abstract class NativeECPrivateKey implements ECPrivateKey {
@Override
public BigInteger getS() {
- return new BigInteger(keyData);
+ return new BigInteger(1, keyData);
}
@Override
--
cgit v1.2.3-70-g09d2