diff options
6 files changed, 188 insertions, 42 deletions
diff --git a/build-standalone.xml b/build-standalone.xml index 8098ce2..ef6ab2a 100644 --- a/build-standalone.xml +++ b/build-standalone.xml @@ -101,6 +101,7 @@ <class name="cz.crcs.ectester.standalone.libs.jni.NativeECPublicKey$TomCrypt"/> <class name="cz.crcs.ectester.standalone.libs.jni.NativeECPrivateKey$TomCrypt"/> <class name="cz.crcs.ectester.standalone.libs.jni.NativeKeyAgreementSpi$TomCrypt"/> + <class name="cz.crcs.ectester.standalone.libs.jni.NativeSignatureSpi$TomCryptRaw"/> </javah> </target> </project> diff --git a/src/cz/crcs/ectester/standalone/ECTesterStandalone.java b/src/cz/crcs/ectester/standalone/ECTesterStandalone.java index 3ad7141..5ecff9b 100644 --- a/src/cz/crcs/ectester/standalone/ECTesterStandalone.java +++ b/src/cz/crcs/ectester/standalone/ECTesterStandalone.java @@ -116,6 +116,8 @@ public class ECTesterStandalone { Options ecdsaOpts = new Options(); ecdsaOpts.addOption(Option.builder("t").longOpt("type").desc("Set Signature object [type].").hasArg().argName("type").optionalArg(false).build()); ecdsaOpts.addOption(Option.builder("n").longOpt("amount").hasArg().argName("amount").optionalArg(false).desc("Do ECDSA [amount] times.").build()); + ecdsaOpts.addOption(Option.builder("b").longOpt("bits").hasArg().argName("n").optionalArg(false).desc("What size of curve to use.").build()); + ecdsaOpts.addOption(Option.builder("nc").longOpt("named-curve").desc("Use a named curve, from CurveDB: <cat/id>").hasArg().argName("cat/id").build()); ecdsaOpts.addOption(Option.builder("f").longOpt("file").hasArg().argName("file").optionalArg(false).desc("Input [file] to sign.").build()); ParserOptions ecdsa = new ParserOptions(new DefaultParser(), ecdsaOpts); actions.put("ecdsa", ecdsa); @@ -271,7 +273,7 @@ public class ECTesterStandalone { dataString = ""; } else { SecureRandom random = new SecureRandom(); - data = new byte[128]; + data = new byte[32]; random.nextBytes(data); dataString = ByteUtil.bytesToHex(data, false); } @@ -449,7 +451,7 @@ public class ECTesterStandalone { } boolean readOptions(TreeCommandLine cli) { - if (cli.isNext("generate") || cli.isNext("export") || cli.isNext("ecdh")) { + if (cli.isNext("generate") || cli.isNext("export") || cli.isNext("ecdh") || cli.isNext("ecdsa")) { if (!cli.hasArg(-1)) { System.err.println("Missing library name argument."); return false; diff --git a/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyAgreementSpi.java b/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyAgreementSpi.java index 47eeabd..913f73e 100644 --- a/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyAgreementSpi.java +++ b/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyAgreementSpi.java @@ -23,7 +23,7 @@ public abstract class NativeKeyAgreementSpi extends KeyAgreementSpi { protected void engineInit(Key key, SecureRandom random) throws InvalidKeyException { if (!(key instanceof ECPrivateKey)) { throw new InvalidKeyException - ("Key must be instance of PrivateKey"); + ("Key must be instance of ECPrivateKey"); } privateKey = (ECPrivateKey) key; this.params = privateKey.getParams(); @@ -52,7 +52,7 @@ public abstract class NativeKeyAgreementSpi extends KeyAgreementSpi { } if (!(key instanceof ECPublicKey)) { throw new InvalidKeyException - ("Key must be a PublicKey with algorithm EC"); + ("Key must be an instance of ECPublicKey"); } ECParameterSpec publicParams = ((ECPublicKey) key).getParams(); if (!(params.getCurve().equals(publicParams.getCurve()) && diff --git a/src/cz/crcs/ectester/standalone/libs/jni/NativeSignatureSpi.java b/src/cz/crcs/ectester/standalone/libs/jni/NativeSignatureSpi.java index 0c6332e..a9ec8a6 100644 --- a/src/cz/crcs/ectester/standalone/libs/jni/NativeSignatureSpi.java +++ b/src/cz/crcs/ectester/standalone/libs/jni/NativeSignatureSpi.java @@ -1,49 +1,86 @@ package cz.crcs.ectester.standalone.libs.jni; +import cz.crcs.ectester.common.util.ECUtil; + +import java.io.ByteArrayOutputStream; import java.security.*; +import java.security.interfaces.ECPrivateKey; +import java.security.interfaces.ECPublicKey; +import java.security.spec.ECParameterSpec; +/** + * @author Jan Jancar johny@neuromancer.sk + */ public abstract class NativeSignatureSpi extends SignatureSpi { + private ECPublicKey verifyKey; + private ECPrivateKey signKey; + private ECParameterSpec params; + + private ByteArrayOutputStream buffer = new ByteArrayOutputStream(); + @Override protected void engineInitVerify(PublicKey publicKey) throws InvalidKeyException { - + if (!(publicKey instanceof ECPublicKey)) { + throw new InvalidKeyException + ("Key must be an instance of ECPublicKey"); + } + verifyKey = (ECPublicKey) publicKey; + params = verifyKey.getParams(); + buffer.reset(); } @Override protected void engineInitSign(PrivateKey privateKey) throws InvalidKeyException { - + if (!(privateKey instanceof ECPrivateKey)) { + throw new InvalidKeyException + ("Key must be an instance of ECPrivateKey"); + } + signKey = (ECPrivateKey) privateKey; + params = signKey.getParams(); + buffer.reset(); } @Override protected void engineUpdate(byte b) throws SignatureException { - + buffer.write(b); } @Override protected void engineUpdate(byte[] b, int off, int len) throws SignatureException { - + buffer.write(b, off, len); } @Override protected byte[] engineSign() throws SignatureException { - return new byte[0]; + return sign(buffer.toByteArray(), ECUtil.toByteArray(signKey.getS(), params.getCurve().getField().getFieldSize()), params); } @Override protected boolean engineVerify(byte[] sigBytes) throws SignatureException { - return false; + return verify(sigBytes, buffer.toByteArray(), ECUtil.toX962Uncompressed(verifyKey.getW(), params), params); } @Override protected void engineSetParameter(String param, Object value) throws InvalidParameterException { - + throw new UnsupportedOperationException("setParameter() not supported"); } @Override protected Object engineGetParameter(String param) throws InvalidParameterException { - return null; + throw new UnsupportedOperationException("getParameter() not supported"); } - public static class TomCrypt extends NativeSignatureSpi { - + abstract byte[] sign(byte[] data, byte[] privkey, ECParameterSpec params); + + abstract boolean verify(byte[] signature, byte[] data, byte[] pubkey, ECParameterSpec params); + + public static class TomCryptRaw extends NativeSignatureSpi { + + @Override + native byte[] sign(byte[] data, byte[] privkey, ECParameterSpec params); + + @Override + native boolean verify(byte[] signature, byte[] data, byte[] pubkey, ECParameterSpec params); + } } diff --git a/src/cz/crcs/ectester/standalone/libs/jni/native.h b/src/cz/crcs/ectester/standalone/libs/jni/native.h index 7f63f61..852dd53 100644 --- a/src/cz/crcs/ectester/standalone/libs/jni/native.h +++ b/src/cz/crcs/ectester/standalone/libs/jni/native.h @@ -144,3 +144,30 @@ JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKey } #endif #endif +/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_TomCryptRaw */ + +#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_TomCryptRaw +#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_TomCryptRaw +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_TomCryptRaw + * Method: sign + * Signature: ([B[BLjava/security/spec/ECParameterSpec;)[B + */ +JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024TomCryptRaw_sign + (JNIEnv *, jobject, jbyteArray, jbyteArray, jobject); + +/* + * Class: cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_TomCryptRaw + * Method: verify + * Signature: ([B[B[BLjava/security/spec/ECParameterSpec;)Z + */ +JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024TomCryptRaw_verify + (JNIEnv *, jobject, jbyteArray, jbyteArray, jbyteArray, jobject); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/cz/crcs/ectester/standalone/libs/jni/tomcrypt.c b/src/cz/crcs/ectester/standalone/libs/jni/tomcrypt.c index d32c6a6..629ffc1 100644 --- a/src/cz/crcs/ectester/standalone/libs/jni/tomcrypt.c +++ b/src/cz/crcs/ectester/standalone/libs/jni/tomcrypt.c @@ -45,8 +45,8 @@ JNIEXPORT void JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeProvider_ jstring ecdh_value = (*env)->NewStringUTF(env, "cz.crcs.ectester.standalone.libs.jni.NativeKeyAgreementSpi$TomCrypt"); (*env)->CallObjectMethod(env, this, provider_put, ecdh, ecdh_value); - jstring ecdsa = (*env)->NewStringUTF(env, "Signature.ECDSA"); - jstring ecdsa_value = (*env)->NewStringUTF(env, "cz.crcs.ectester.standalone.libs.jni.NativeSignatureSpi$TomCrypt"); + jstring ecdsa = (*env)->NewStringUTF(env, "Signature.NONEwithECDSA"); + jstring ecdsa_value = (*env)->NewStringUTF(env, "cz.crcs.ectester.standalone.libs.jni.NativeSignatureSpi$TomCryptRaw"); (*env)->CallObjectMethod(env, this, provider_put, ecdsa, ecdsa_value); int err; @@ -112,9 +112,10 @@ JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_TomcryptLib_getC } JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024TomCrypt_keysizeSupported(JNIEnv *env, jobject this, jint keysize){ + int key_bytes = (keysize + 7) / 8; const ltc_ecc_set_type * curve = ltc_ecc_sets; while (curve->size != 0) { - if (curve->size * 8 == keysize) { + if (curve->size == key_bytes) { return JNI_TRUE; } curve++; @@ -309,7 +310,7 @@ static jobject generate_from_curve(JNIEnv *env, const ltc_ecc_set_type *curve) { } 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; + int key_bytes = (keysize + 7) / 8; const ltc_ecc_set_type *curve = ltc_ecc_sets; while (curve->size != 0) { @@ -351,49 +352,63 @@ JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPai } } -JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_00024TomCrypt_generateSecret(JNIEnv *env, jobject this, jbyteArray pubkey, jbyteArray privkey, jobject params){ - ltc_ecc_set_type *curve = create_curve(env, params); +static jboolean privkey_from_bytes(JNIEnv *env, jbyteArray privkey, const ltc_ecc_set_type *curve, ecc_key *out) { + jsize priv_size = (*env)->GetArrayLength(env, privkey); + jbyte *priv_data = (*env)->GetByteArrayElements(env, privkey, NULL); + if (curve->size != priv_size) { + throw_new(env, "java/lang/IllegalStateException", "Curve size does not match the private key size."); + (*env)->ReleaseByteArrayElements(env, privkey, priv_data, JNI_ABORT); + return JNI_FALSE; + } + + out->type = PK_PRIVATE; + out->idx = -1; + out->dp = curve; + ltc_mp.init(&out->k); + ltc_mp.unsigned_read(out->k, priv_data, (unsigned long) curve->size); + + (*env)->ReleaseByteArrayElements(env, privkey, priv_data, JNI_ABORT); + return JNI_TRUE; +} + +static jboolean pubkey_from_bytes(JNIEnv *env, jbyteArray pubkey, const ltc_ecc_set_type *curve, ecc_key *out) { jsize pub_size = (*env)->GetArrayLength(env, pubkey); jbyte *pub_data = (*env)->GetByteArrayElements(env, pubkey, NULL); if (curve->size != (pub_size - 1) / 2) { throw_new(env, "java/lang/IllegalStateException", "Curve size does not match the public key size."); (*env)->ReleaseByteArrayElements(env, pubkey, pub_data, JNI_ABORT); - free(curve); - return NULL; + return JNI_FALSE; } - ecc_key pub; - pub.type = PK_PUBLIC; - pub.idx = -1; - 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) curve->size); - ltc_mp.unsigned_read(pub.pubkey.y, pub_data + 1 + curve->size, (unsigned long) curve->size); + out->type = PK_PUBLIC; + out->idx = -1; + out->dp = curve; + ltc_init_multi(&out->pubkey.x, &out->pubkey.y, &out->pubkey.z, NULL); + ltc_mp.set_int(out->pubkey.z, 1); + ltc_mp.unsigned_read(out->pubkey.x, pub_data + 1, (unsigned long) curve->size); + ltc_mp.unsigned_read(out->pubkey.y, pub_data + 1 + curve->size, (unsigned long) curve->size); (*env)->ReleaseByteArrayElements(env, pubkey, pub_data, JNI_ABORT); + return JNI_TRUE; +} - jsize priv_size = (*env)->GetArrayLength(env, privkey); - jbyte *priv_data = (*env)->GetByteArrayElements(env, privkey, NULL); +JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_00024TomCrypt_generateSecret(JNIEnv *env, jobject this, jbyteArray pubkey, jbyteArray privkey, jobject params){ + ltc_ecc_set_type *curve = create_curve(env, params); - 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); + ecc_key pub; + if (!pubkey_from_bytes(env, pubkey, curve, &pub)) { 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) curve->size); - - (*env)->ReleaseByteArrayElements(env, privkey, priv_data, JNI_ABORT); + if (!privkey_from_bytes(env, privkey, curve, &priv)) { + free(curve); + return NULL; + } unsigned char result[curve->size]; unsigned long output_len = curve->size; @@ -412,4 +427,68 @@ JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKey ltc_cleanup_multi(&pub.pubkey.x, &pub.pubkey.y, &pub.pubkey.z, &priv.k, NULL); free(curve); return output; +} + +JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024TomCryptRaw_sign(JNIEnv *env, jobject this, jbyteArray data, jbyteArray privkey, jobject params) { + ltc_ecc_set_type *curve = create_curve(env, params); + + ecc_key priv; + if (!privkey_from_bytes(env, privkey, curve, &priv)) { + free(curve); + return NULL; + } + + jsize data_size = (*env)->GetArrayLength(env, data); + jbyte *data_data = (*env)->GetByteArrayElements(env, data, NULL); + + unsigned char result[curve->size*4]; + unsigned long output_len = curve->size*4; + int err; + if ((err = ecc_sign_hash(data_data, data_size, result, &output_len, <c_prng, find_prng("yarrow"), &priv)) != CRYPT_OK) { + throw_new(env, "java/security/GeneralSecurityException", error_to_string(err)); + free(curve); + (*env)->ReleaseByteArrayElements(env, data, data_data, JNI_ABORT); + return NULL; + } + + (*env)->ReleaseByteArrayElements(env, data, data_data, JNI_ABORT); + + jbyteArray output = (*env)->NewByteArray(env, output_len); + jbyte *output_data = (*env)->GetByteArrayElements(env, output, NULL); + memcpy(output_data, result, output_len); + (*env)->ReleaseByteArrayElements(env, output, output_data, JNI_COMMIT); + + free(curve); + return output; +} + +JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024TomCryptRaw_verify(JNIEnv *env, jobject this, jbyteArray signature, jbyteArray data, jbyteArray pubkey, jobject params) { + ltc_ecc_set_type *curve = create_curve(env, params); + + ecc_key pub; + if (!pubkey_from_bytes(env, pubkey, curve, &pub)) { + free(curve); + return JNI_FALSE; + } + + jsize data_size = (*env)->GetArrayLength(env, data); + jbyte *data_data = (*env)->GetByteArrayElements(env, data, NULL); + + jsize sig_size = (*env)->GetArrayLength(env, signature); + jbyte *sig_data = (*env)->GetByteArrayElements(env, signature, NULL); + + int err; + int result; + if ((err = ecc_verify_hash(sig_data, sig_size, data_data, data_size, &result, &pub)) != CRYPT_OK) { + throw_new(env, "java/security/GeneralSecurityException", error_to_string(err)); + free(curve); + (*env)->ReleaseByteArrayElements(env, data, data_data, JNI_ABORT); + (*env)->ReleaseByteArrayElements(env, signature, sig_data, JNI_ABORT); + return JNI_FALSE; + } + + (*env)->ReleaseByteArrayElements(env, data, data_data, JNI_ABORT); + (*env)->ReleaseByteArrayElements(env, signature, sig_data, JNI_ABORT); + free(curve); + return result; }
\ No newline at end of file |
