diff options
| author | J08nY | 2017-11-29 20:43:57 +0100 |
|---|---|---|
| committer | J08nY | 2017-11-29 20:43:57 +0100 |
| commit | 5026cc9f03f11fc2a473124e32867f3302f901f7 (patch) | |
| tree | c317da55f300770d8e84dbf6cc2cc41c53efda33 | |
| parent | 9250f269d6a8ffa7f3714d60a0437a112ad7a924 (diff) | |
| download | ECTester-5026cc9f03f11fc2a473124e32867f3302f901f7.tar.gz ECTester-5026cc9f03f11fc2a473124e32867f3302f901f7.tar.zst ECTester-5026cc9f03f11fc2a473124e32867f3302f901f7.zip | |
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"), <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, "<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(<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, "<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 |
