From 40ec0fea381a6538f5498b9fb75706ef9fa79f59 Mon Sep 17 00:00:00 2001 From: J08nY Date: Tue, 16 Oct 2018 00:57:24 +0200 Subject: Add support for BoringSSL. --- .../ectester/standalone/libs/BoringsslLib.java | 19 + .../ectester/standalone/libs/NativeECLibrary.java | 82 ++-- src/cz/crcs/ectester/standalone/libs/jni/Makefile | 11 +- .../standalone/libs/jni/NativeECPrivateKey.java | 6 + .../standalone/libs/jni/NativeECPublicKey.java | 6 + .../standalone/libs/jni/NativeKeyAgreementSpi.java | 20 + .../libs/jni/NativeKeyPairGeneratorSpi.java | 18 + .../standalone/libs/jni/NativeProvider.java | 10 + .../standalone/libs/jni/NativeSignatureSpi.java | 21 + .../crcs/ectester/standalone/libs/jni/boringssl.c | 504 +++++++++++++++++++++ src/cz/crcs/ectester/standalone/libs/jni/native.h | 181 ++++++++ 11 files changed, 843 insertions(+), 35 deletions(-) create mode 100644 src/cz/crcs/ectester/standalone/libs/BoringsslLib.java create mode 100644 src/cz/crcs/ectester/standalone/libs/jni/boringssl.c (limited to 'src/cz/crcs/ectester/standalone/libs') diff --git a/src/cz/crcs/ectester/standalone/libs/BoringsslLib.java b/src/cz/crcs/ectester/standalone/libs/BoringsslLib.java new file mode 100644 index 0000000..60ca5d9 --- /dev/null +++ b/src/cz/crcs/ectester/standalone/libs/BoringsslLib.java @@ -0,0 +1,19 @@ +package cz.crcs.ectester.standalone.libs; + +import java.security.Provider; +import java.util.Set; + +/** + * @author Jan Jancar johny@neuromancer.sk + */ +public class BoringsslLib extends NativeECLibrary { + public BoringsslLib() { + super("boringssl_provider", "lib_boringssl.so"); + } + + @Override + native Provider createProvider(); + + @Override + public native Set getCurves(); +} diff --git a/src/cz/crcs/ectester/standalone/libs/NativeECLibrary.java b/src/cz/crcs/ectester/standalone/libs/NativeECLibrary.java index 6b98cc1..ff23fd9 100644 --- a/src/cz/crcs/ectester/standalone/libs/NativeECLibrary.java +++ b/src/cz/crcs/ectester/standalone/libs/NativeECLibrary.java @@ -47,39 +47,19 @@ public abstract class NativeECLibrary extends ProviderECLibrary { appData = Paths.get(System.getProperty("user.home"), ".local", "share"); } } + /* Resolve and create the ECTester directories in appData. */ Path libDir = appData.resolve("ECTesterStandalone"); File libDirFile = libDir.toFile(); + Path libReqDir = libDir.resolve("lib"); + File libReqDirFile = libReqDir.toFile(); Path libPath = libDir.resolve(resource + "." + suffix); - File libFile = libPath.toFile(); - URL jarURL = NativeECLibrary.class.getResource(LIB_RESOURCE_DIR + resource + "." + suffix); - if (jarURL == null) { - return false; - } - URLConnection jarConnection = jarURL.openConnection(); - - /* Only write the file if it does not exist, - * or if the existing one is older than the - * one in the JAR. - */ - boolean write = false; - if (libDirFile.isDirectory() && libFile.isFile()) { - long jarModified = jarConnection.getLastModified(); - - long libModified = Files.getLastModifiedTime(libPath).toMillis(); - if (jarModified > libModified) { - write = true; - } - } else { - libDir.toFile().mkdirs(); - libFile.createNewFile(); - write = true; - } + /* Create directory for shims and for requirements. */ + libDirFile.mkdirs(); + libReqDirFile.mkdirs(); - if (write) { - Files.copy(jarConnection.getInputStream(), libPath, StandardCopyOption.REPLACE_EXISTING); - } - jarConnection.getInputStream().close(); + /* Write the shim. */ + writeNewer(resource + "." + suffix, libPath); /* * Need to hack in /usr/local/lib to path. @@ -98,12 +78,24 @@ public abstract class NativeECLibrary extends ProviderECLibrary { } } - for (String requirement : requriements) { - System.loadLibrary(requirement); - } - - if (suffix.equals("so")) { - System.setProperty("java.library.path", path); + /* Load the requirements, if they are bundled, write them in and load them. */ + try { + for (String requirement : requriements) { + if (requirement.endsWith(suffix)) { + /* The requirement is bundled, write it */ + Path reqPath = libReqDir.resolve(requirement); + writeNewer(requirement, reqPath); + System.load(reqPath.toString()); + } else { + System.loadLibrary(requirement); + } + } + } catch (UnsatisfiedLinkError ule) { + return false; + } finally { + if (suffix.equals("so")) { + System.setProperty("java.library.path", path); + } } System.load(libPath.toString()); @@ -116,5 +108,27 @@ public abstract class NativeECLibrary extends ProviderECLibrary { return false; } + private boolean isNewer(URLConnection jarConn, Path realPath) throws IOException { + if (realPath.toFile().isFile()) { + long jarModified = jarConn.getLastModified(); + long realModified = Files.getLastModifiedTime(realPath).toMillis(); + return jarModified > realModified; + } + return true; + } + + private boolean writeNewer(String resource, Path outPath) throws IOException { + URL reqURL = NativeECLibrary.class.getResource(LIB_RESOURCE_DIR + resource); + if (reqURL == null) { + return false; + } + URLConnection reqConn = reqURL.openConnection(); + if (isNewer(reqConn, outPath)) { + Files.copy(reqConn.getInputStream(), outPath, StandardCopyOption.REPLACE_EXISTING); + } + reqConn.getInputStream().close(); + return true; + } + abstract Provider createProvider(); } diff --git a/src/cz/crcs/ectester/standalone/libs/jni/Makefile b/src/cz/crcs/ectester/standalone/libs/jni/Makefile index 006a3b1..189a6dd 100644 --- a/src/cz/crcs/ectester/standalone/libs/jni/Makefile +++ b/src/cz/crcs/ectester/standalone/libs/jni/Makefile @@ -54,7 +54,7 @@ else CXXFLAGS+=-O2 endif -all: tomcrypt_provider.so botan_provider.so cryptopp_provider.so openssl_provider.so +all: tomcrypt_provider.so botan_provider.so cryptopp_provider.so openssl_provider.so boringssl_provider.so # Common utils c_utils.o: c_utils.c @@ -72,6 +72,15 @@ openssl.o: openssl.c $(CC) $(shell pkg-config --cflags openssl) $(CFLAGS) -c $< +# BoringSSL shim +boringssl_provider.so: boringssl.o c_utils.o + $(CC) $(LFLAGS) -o $@ $^ -L. ../../../../../../../ext/boringssl/build/crypto/libcrypto.so + cp ../../../../../../../ext/boringssl/build/crypto/libcrypto.so lib_boringssl.so + +boringssl.o: boringssl.c + $(CC) -I../../../../../../../ext/boringssl/include/ $(CFLAGS) -c $< + + # Libtomcrypt shim tomcrypt_provider.so: tomcrypt.o c_utils.o $(CC) $(LFLAGS) -o $@ $^ -L. -ltommath $(shell pkg-config --libs libtomcrypt) diff --git a/src/cz/crcs/ectester/standalone/libs/jni/NativeECPrivateKey.java b/src/cz/crcs/ectester/standalone/libs/jni/NativeECPrivateKey.java index 4cd4a9d..a74c155 100644 --- a/src/cz/crcs/ectester/standalone/libs/jni/NativeECPrivateKey.java +++ b/src/cz/crcs/ectester/standalone/libs/jni/NativeECPrivateKey.java @@ -85,6 +85,12 @@ public abstract class NativeECPrivateKey implements ECPrivateKey { } } + public static class Boringssl extends Raw { + public Boringssl(byte[] keyData, ECParameterSpec params) { + super(keyData, params); + } + } + public static class Mscng extends Raw { // 0 -> implicit (meta = curveName UTF16, header = full); // 1 -> explicit (meta = null, header = full); diff --git a/src/cz/crcs/ectester/standalone/libs/jni/NativeECPublicKey.java b/src/cz/crcs/ectester/standalone/libs/jni/NativeECPublicKey.java index 33dd3ef..7c17646 100644 --- a/src/cz/crcs/ectester/standalone/libs/jni/NativeECPublicKey.java +++ b/src/cz/crcs/ectester/standalone/libs/jni/NativeECPublicKey.java @@ -86,6 +86,12 @@ public abstract class NativeECPublicKey implements ECPublicKey { } } + public static class Boringssl extends ANSIX962 { + public Boringssl(byte[] keyData, ECParameterSpec params) { + super(keyData, params); + } + } + public static class Mscng extends ANSIX962 { // 0 -> implicit (meta = curveName UTF16, header = full); // 1 -> explicit (meta = null, header = full); diff --git a/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyAgreementSpi.java b/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyAgreementSpi.java index fdbdccf..5fca448 100644 --- a/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyAgreementSpi.java +++ b/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyAgreementSpi.java @@ -234,6 +234,26 @@ public abstract class NativeKeyAgreementSpi extends KeyAgreementSpi { } } + public abstract static class Boringssl extends SimpleKeyAgreementSpi { + private String type; + + public Boringssl(String type) { + this.type = type; + } + + @Override + native byte[] generateSecret(byte[] pubkey, byte[] privkey, ECParameterSpec params); + + @Override + native SecretKey generateSecret(byte[] pubkey, byte[] privkey, ECParameterSpec params, String algorithm); + } + + public static class BoringsslECDH extends Boringssl { + public BoringsslECDH() { + super("ECDH"); + } + } + public abstract static class Mscng extends ExtendedKeyAgreementSpi { private String type; diff --git a/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyPairGeneratorSpi.java b/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyPairGeneratorSpi.java index aa83479..77f0d18 100644 --- a/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyPairGeneratorSpi.java +++ b/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyPairGeneratorSpi.java @@ -180,6 +180,24 @@ public abstract class NativeKeyPairGeneratorSpi extends KeyPairGeneratorSpi { native KeyPair generate(AlgorithmParameterSpec params, SecureRandom random); } + public static class Boringssl extends NativeKeyPairGeneratorSpi { + public Boringssl() { + initialize(256, new SecureRandom()); + } + + @Override + native boolean keysizeSupported(int keysize); + + @Override + native boolean paramsSupported(AlgorithmParameterSpec params); + + @Override + native KeyPair generate(int keysize, SecureRandom random); + + @Override + native KeyPair generate(AlgorithmParameterSpec params, SecureRandom random); + } + public static abstract class Mscng extends NativeKeyPairGeneratorSpi { private String type; diff --git a/src/cz/crcs/ectester/standalone/libs/jni/NativeProvider.java b/src/cz/crcs/ectester/standalone/libs/jni/NativeProvider.java index fef2930..1399500 100644 --- a/src/cz/crcs/ectester/standalone/libs/jni/NativeProvider.java +++ b/src/cz/crcs/ectester/standalone/libs/jni/NativeProvider.java @@ -64,6 +64,16 @@ public abstract class NativeProvider extends Provider { native void setup(); } + public static class Boringssl extends NativeProvider { + + public Boringssl(String name, double version, String info) { + super(name, version, info); + } + + @Override + native void setup(); + } + public static class Mscng extends NativeProvider { public Mscng(String name, double version, String info) { diff --git a/src/cz/crcs/ectester/standalone/libs/jni/NativeSignatureSpi.java b/src/cz/crcs/ectester/standalone/libs/jni/NativeSignatureSpi.java index 602b1c4..3f99771 100644 --- a/src/cz/crcs/ectester/standalone/libs/jni/NativeSignatureSpi.java +++ b/src/cz/crcs/ectester/standalone/libs/jni/NativeSignatureSpi.java @@ -328,6 +328,27 @@ public abstract class NativeSignatureSpi extends SignatureSpi { } } + public abstract static class Boringssl extends SimpleSignatureSpi { + private String type; + + public Boringssl(String type) { + this.type = type; + } + + @Override + native byte[] sign(byte[] data, byte[] privkey, ECParameterSpec params); + + @Override + native boolean verify(byte[] signature, byte[] data, byte[] pubkey, ECParameterSpec params); + } + + public static class BoringsslECDSAwithNONE extends Boringssl { + + public BoringsslECDSAwithNONE() { + super("NONEwithECDSA"); + } + } + public abstract static class Mscng extends ExtendedSignatureSpi { private String type; diff --git a/src/cz/crcs/ectester/standalone/libs/jni/boringssl.c b/src/cz/crcs/ectester/standalone/libs/jni/boringssl.c new file mode 100644 index 0000000..0353741 --- /dev/null +++ b/src/cz/crcs/ectester/standalone/libs/jni/boringssl.c @@ -0,0 +1,504 @@ +#include "native.h" +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "c_utils.h" + + +static jclass provider_class; + +JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_BoringsslLib_createProvider(JNIEnv *env, jobject self) { + /* Create the custom provider. */ + jclass local_provider_class = (*env)->FindClass(env, "cz/crcs/ectester/standalone/libs/jni/NativeProvider$Boringssl"); + provider_class = (*env)->NewGlobalRef(env, local_provider_class); + + jmethodID init = (*env)->GetMethodID(env, local_provider_class, "", "(Ljava/lang/String;DLjava/lang/String;)V"); + + jstring name = (*env)->NewStringUTF(env, OPENSSL_VERSION_TEXT); + long ver_hi = (OPENSSL_VERSION_NUMBER & 0xff000000L) >> 28; + long ver_mid = (OPENSSL_VERSION_NUMBER & 0xff0000L) >> 20; + long ver_low = (OPENSSL_VERSION_NUMBER & 0xff00L) >> 12; + double version = (double)ver_hi + ((double)ver_mid/10) + ((double)ver_low/100); + + return (*env)->NewObject(env, provider_class, init, name, version, name); +} + +JNIEXPORT void JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeProvider_00024Boringssl_setup(JNIEnv *env, jobject self) { + ERR_load_crypto_strings(); + CRYPTO_library_init(); + + INIT_PROVIDER(env, provider_class); + + ADD_KPG(env, self, "EC", "Boringssl"); + ADD_KA(env, self, "ECDH", "BoringsslECDH"); + ADD_SIG(env, self, "NONEwithECDSA", "BoringsslECDSAwithNONE"); + + init_classes(env, "Boringssl"); +} + +JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_BoringsslLib_getCurves(JNIEnv *env, jobject self) { + jclass hash_set_class = (*env)->FindClass(env, "java/util/TreeSet"); + + jmethodID hash_set_ctr = (*env)->GetMethodID(env, hash_set_class, "", "()V"); + jmethodID hash_set_add = (*env)->GetMethodID(env, hash_set_class, "add", "(Ljava/lang/Object;)Z"); + + jobject result = (*env)->NewObject(env, hash_set_class, hash_set_ctr); + + size_t ncurves = EC_get_builtin_curves(NULL, 0); + EC_builtin_curve curves[ncurves]; + EC_get_builtin_curves(curves, ncurves); + + for (size_t i = 0; i < ncurves; ++i) { + jstring curve_name = (*env)->NewStringUTF(env, OBJ_nid2sn(curves[i].nid)); + (*env)->CallBooleanMethod(env, result, hash_set_add, curve_name); + } + + return result; +} + +JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Boringssl_keysizeSupported(JNIEnv *env, jobject self, jint keysize) { + size_t ncurves = EC_get_builtin_curves(NULL, 0); + EC_builtin_curve curves[ncurves]; + EC_get_builtin_curves(curves, ncurves); + + for (size_t i = 0; i < ncurves; ++i) { + EC_GROUP *curve = EC_GROUP_new_by_curve_name(curves[i].nid); + if (EC_GROUP_get_degree(curve) == keysize) { + EC_GROUP_free(curve); + return JNI_TRUE; + } + EC_GROUP_free(curve); + } + return JNI_FALSE; +} + +static jobject bignum_to_biginteger(JNIEnv *env, const BIGNUM *bn) { + jmethodID biginteger_init = (*env)->GetMethodID(env, biginteger_class, "", "(I[B)V"); + int size = BN_num_bytes(bn); + jbyteArray bytes = (*env)->NewByteArray(env, size); + jbyte *data = (*env)->GetByteArrayElements(env, bytes, NULL); + BN_bn2bin(bn, data); + (*env)->ReleaseByteArrayElements(env, bytes, data, 0); + jobject result = (*env)->NewObject(env, biginteger_class, biginteger_init, 1, bytes); + return result; +} + +static BIGNUM *biginteger_to_bignum(JNIEnv *env, jobject bigint) { + jmethodID to_byte_array = (*env)->GetMethodID(env, biginteger_class, "toByteArray", "()[B"); + + jbyteArray byte_array = (jbyteArray) (*env)->CallObjectMethod(env, bigint, to_byte_array); + jsize byte_length = (*env)->GetArrayLength(env, byte_array); + jbyte *byte_data = (*env)->GetByteArrayElements(env, byte_array, NULL); + BIGNUM *result = BN_bin2bn(byte_data, byte_length, NULL); + (*env)->ReleaseByteArrayElements(env, byte_array, byte_data, JNI_ABORT); + return result; +} + +static EC_GROUP *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); + + if ((*env)->IsInstanceOf(env, field, f2m_field_class)) { + return NULL; + } + + jmethodID get_bits = (*env)->GetMethodID(env, fp_field_class, "getFieldSize", "()I"); + jint bits = (*env)->CallIntMethod(env, field, get_bits); + jint bytes = (bits + 7) / 8; + + jmethodID get_a = (*env)->GetMethodID(env, elliptic_curve_class, "getA", "()Ljava/math/BigInteger;"); + jobject a = (*env)->CallObjectMethod(env, elliptic_curve, get_a); + BIGNUM *a_bn = biginteger_to_bignum(env, a); + + jmethodID get_b = (*env)->GetMethodID(env, elliptic_curve_class, "getB", "()Ljava/math/BigInteger;"); + jobject b = (*env)->CallObjectMethod(env, elliptic_curve, get_b); + BIGNUM *b_bn = biginteger_to_bignum(env, b); + + 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); + BIGNUM *gx_bn = biginteger_to_bignum(env, gx); + + jmethodID get_y = (*env)->GetMethodID(env, point_class, "getAffineY", "()Ljava/math/BigInteger;"); + jobject gy = (*env)->CallObjectMethod(env, g, get_y); + BIGNUM *gy_bn = biginteger_to_bignum(env, gy); + + EC_GROUP *result; + EC_POINT *g_point; + + jmethodID get_p = (*env)->GetMethodID(env, fp_field_class, "getP", "()Ljava/math/BigInteger;"); + jobject p = (*env)->CallObjectMethod(env, field, get_p); + + BIGNUM *p_bn = biginteger_to_bignum(env, p); + result = EC_GROUP_new_curve_GFp(p_bn, a_bn, b_bn, NULL); + BN_free(p_bn); + BN_free(a_bn); + BN_free(b_bn); + + if (!result) { + throw_new(env, "java/security/InvalidAlgorithmParameterException", "Error creating EC_GROUP, EC_GROUP_new_curve_GFp."); + BN_free(gx_bn); BN_free(gy_bn); + return NULL; + } + + g_point = EC_POINT_new(result); + if(!EC_POINT_set_affine_coordinates_GFp(result, g_point, gx_bn, gy_bn, NULL)) { + throw_new(env, "java/security/InvalidAlgorithmParameterException", "Error creating EC_GROUP, EC_POINT_set_affine_coordinates_GFp."); + BN_free(gx_bn); BN_free(gy_bn); EC_POINT_free(g_point); EC_GROUP_free(result); + return NULL; + } + + jmethodID get_n = (*env)->GetMethodID(env, ec_parameter_spec_class, "getOrder", "()Ljava/math/BigInteger;"); + jobject n = (*env)->CallObjectMethod(env, params, get_n); + BIGNUM *n_bn = biginteger_to_bignum(env, n); + + jmethodID get_h = (*env)->GetMethodID(env, ec_parameter_spec_class, "getCofactor", "()I"); + jint h = (*env)->CallIntMethod(env, params, get_h); + BIGNUM *h_bn = BN_new(); + BN_set_word(h_bn, h); + + if (!EC_GROUP_set_generator(result, g_point, n_bn, h_bn)) { + throw_new(env, "java/security/InvalidAlgorithmParameterException", "Error creating EC_GROUP, EC_GROUP_set_generator."); + BN_free(n_bn); BN_free(h_bn); BN_free(gx_bn); BN_free(gy_bn); EC_POINT_free(g_point); EC_GROUP_free(result); + return NULL; + } + + EC_POINT_free(g_point); + BN_free(gx_bn); + BN_free(gy_bn); + BN_free(n_bn); + BN_free(h_bn); + + return result; +} + +JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Boringssl_paramsSupported(JNIEnv *env, jobject self, jobject params){ + if (params == NULL) { + return JNI_FALSE; + } + + if ((*env)->IsInstanceOf(env, params, ec_parameter_spec_class)) { + EC_GROUP *curve = create_curve(env, params); + jboolean result = !curve; + EC_GROUP_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); + size_t ncurves = EC_get_builtin_curves(NULL, 0); + EC_builtin_curve curves[ncurves]; + EC_get_builtin_curves(curves, ncurves); + for (size_t i = 0; i < ncurves; ++i) { + if (strcasecmp(utf_name, OBJ_nid2sn(curves[i].nid)) == 0) { + (*env)->ReleaseStringUTFChars(env, name, utf_name); + return JNI_TRUE; + } + } + (*env)->ReleaseStringUTFChars(env, name, utf_name); + return JNI_FALSE; + } else { + return JNI_FALSE; + } +} + +static jobject create_ec_param_spec(JNIEnv *env, const EC_GROUP *curve) { + int field_type = EC_METHOD_get_field_type(EC_GROUP_method_of(curve)); + BIGNUM *a; + BIGNUM *b; + + BIGNUM *gx; + BIGNUM *gy; + jobject field; + + BIGNUM *p = BN_new(); + a = BN_new(); + b = BN_new(); + if (!EC_GROUP_get_curve_GFp(curve, p, a, b, NULL)) { + throw_new(env, "java/security/InvalidAlgorithmParameterException", "Error creating ECParameterSpec, EC_GROUP_get_curve_GFp."); + BN_free(p); BN_free(a); BN_free(b); + return NULL; + } + + jobject p_int = bignum_to_biginteger(env, p); + + jmethodID fp_field_init = (*env)->GetMethodID(env, fp_field_class, "", "(Ljava/math/BigInteger;)V"); + field = (*env)->NewObject(env, fp_field_class, fp_field_init, p_int); + + BN_free(p); + + gx = BN_new(); + gy = BN_new(); + if (!EC_POINT_get_affine_coordinates_GFp(curve, EC_GROUP_get0_generator(curve), gx, gy, NULL)) { + throw_new(env, "java/security/InvalidAlgorithmParameterException", "Error creating ECParameterSpec, EC_POINT_get_affine_coordinates_GFp."); + BN_free(a); BN_free(b); BN_free(gx); BN_free(gy); + return NULL; + } + + jobject a_int = bignum_to_biginteger(env, a); + jobject b_int = bignum_to_biginteger(env, b); + + 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_int, b_int); + fflush(stderr); + + BN_free(a); + BN_free(b); + + jobject gx_int = bignum_to_biginteger(env, gx); + jobject gy_int = bignum_to_biginteger(env, gy); + + BN_free(gx); + BN_free(gy); + + 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_int, gy_int); + + jobject order = bignum_to_biginteger(env, EC_GROUP_get0_order(curve)); + BIGNUM *h = BN_new(); + EC_GROUP_get_cofactor(curve, h, NULL); + jint cofactor = BN_get_word(h); + BN_free(h); + + 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, order, cofactor); +} + +static jobject generate_from_curve(JNIEnv *env, const EC_GROUP *curve) { + jint keysize = EC_GROUP_get_degree(curve); + unsigned long key_bytes = (keysize + 7) / 8; + + EC_KEY *key = EC_KEY_new(); + EC_KEY_set_group(key, curve); + if (!EC_KEY_generate_key(key)) { + throw_new(env, "java/security/GeneralSecurityException", "Error generating key, EC_KEY_generate_key."); + EC_KEY_free(key); + return NULL; + } + + jbyteArray priv_bytes = (*env)->NewByteArray(env, key_bytes); + jbyte *key_priv = (*env)->GetByteArrayElements(env, priv_bytes, NULL); + BN_bn2bin_padded(key_priv, key_bytes, EC_KEY_get0_private_key(key)); + (*env)->ReleaseByteArrayElements(env, priv_bytes, key_priv, 0); + + unsigned long key_len = 2*key_bytes + 1; + jbyteArray pub_bytes = (*env)->NewByteArray(env, key_len); + jbyte *key_pub = (*env)->GetByteArrayElements(env, pub_bytes, NULL); + EC_POINT_point2oct(curve, EC_KEY_get0_public_key(key), POINT_CONVERSION_UNCOMPRESSED, key_pub, key_len, NULL); + (*env)->ReleaseByteArrayElements(env, pub_bytes, key_pub, 0); + + EC_KEY_free(key); + + 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); + + 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"); + return (*env)->NewObject(env, keypair_class, keypair_init, pubkey, privkey); +} + +JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Boringssl_generate__ILjava_security_SecureRandom_2(JNIEnv *env, jobject self, jint keysize, jobject random) { + size_t ncurves = EC_get_builtin_curves(NULL, 0); + EC_builtin_curve curves[ncurves]; + EC_get_builtin_curves(curves, ncurves); + + EC_GROUP *curve = NULL; + for (size_t i = 0; i < ncurves; ++i) { + curve = EC_GROUP_new_by_curve_name(curves[i].nid); + if (EC_GROUP_get_degree(curve) == keysize) { + break; + } + EC_GROUP_free(curve); + } + + if (!curve) { + throw_new(env, "java/security/InvalidAlgorithmParameterException", "Curve for given bitsize not found."); + return NULL; + } + + jobject result = generate_from_curve(env, curve); + EC_GROUP_free(curve); + return result; +} + +JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Boringssl_generate__Ljava_security_spec_AlgorithmParameterSpec_2Ljava_security_SecureRandom_2(JNIEnv *env, jobject self, jobject params, jobject random) { + if ((*env)->IsInstanceOf(env, params, ec_parameter_spec_class)) { + EC_GROUP *curve = create_curve(env, params); + jobject result = generate_from_curve(env, curve); + EC_GROUP_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); + size_t ncurves = EC_get_builtin_curves(NULL, 0); + EC_builtin_curve curves[ncurves]; + EC_get_builtin_curves(curves, ncurves); + EC_GROUP *curve; + for (size_t i = 0; i < ncurves; ++i) { + if (strcasecmp(utf_name, OBJ_nid2sn(curves[i].nid)) == 0) { + curve = EC_GROUP_new_by_curve_name(curves[i].nid); + break; + } + } + (*env)->ReleaseStringUTFChars(env, name, utf_name); + if (!curve) { + throw_new(env, "java/security/InvalidAlgorithmParameterException", "Curve for given bitsize not found."); + return NULL; + } + jobject result = generate_from_curve(env, curve); + EC_GROUP_free(curve); + return result; + } else { + throw_new(env, "java/security/InvalidAlgorithmParameterException", "Curve not found."); + return NULL; + } +} + +EC_KEY *barray_to_pubkey(JNIEnv *env, const EC_GROUP *curve, jbyteArray pub) { + EC_KEY *result = EC_KEY_new(); + EC_KEY_set_group(result, curve); + jsize pub_len = (*env)->GetArrayLength(env, pub); + jbyte *pub_data = (*env)->GetByteArrayElements(env, pub, NULL); + EC_POINT *pub_point = EC_POINT_new(curve); + EC_POINT_oct2point(curve, pub_point, pub_data, pub_len, NULL); + (*env)->ReleaseByteArrayElements(env, pub, pub_data, JNI_ABORT); + EC_KEY_set_public_key(result, pub_point); + EC_POINT_free(pub_point); + return result; +} + +EC_KEY *barray_to_privkey(JNIEnv *env, const EC_GROUP *curve, jbyteArray priv) { + EC_KEY *result = EC_KEY_new(); + EC_KEY_set_group(result, curve); + jsize priv_len = (*env)->GetArrayLength(env, priv); + jbyte *priv_data = (*env)->GetByteArrayElements(env, priv, NULL); + BIGNUM *s = BN_bin2bn(priv_data, priv_len, NULL); + (*env)->ReleaseByteArrayElements(env, priv, priv_data, JNI_ABORT); + EC_KEY_set_private_key(result, s); + BN_free(s); + return result; +} + +JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_00024Boringssl_generateSecret___3B_3BLjava_security_spec_ECParameterSpec_2(JNIEnv *env, jobject self, jbyteArray pubkey, jbyteArray privkey, jobject params) { + EC_GROUP *curve = create_curve(env, params); + if (!curve) { + throw_new(env, "java/security/InvalidAlgorithmParameterException", "Curve not found."); + return NULL; + } + + EC_KEY *pub = barray_to_pubkey(env, curve, pubkey); + EC_KEY *priv = barray_to_privkey(env, curve, privkey); + + int field_size = EC_GROUP_get_degree(curve); + size_t secret_len = (field_size + 7)/8; + + //TODO: Do more KeyAgreements here, but will have to do the hash-fun manually, + // probably using the ECDH_KDF_X9_62 by wrapping it and dynamically choosing the EVP_MD. from the type string. + jbyteArray result = (*env)->NewByteArray(env, secret_len); + jbyte *result_data = (*env)->GetByteArrayElements(env, result, NULL); + if (ECDH_compute_key(result_data, secret_len, EC_KEY_get0_public_key(pub), priv, NULL) <= 0) { + throw_new(env, "java/security/GeneralSecurityException", "Error computing ECDH, ECDH_compute_key."); + EC_KEY_free(pub); EC_KEY_free(priv); EC_GROUP_free(curve); + (*env)->ReleaseByteArrayElements(env, result, result_data, JNI_ABORT); + return NULL; + } + (*env)->ReleaseByteArrayElements(env, result, result_data, 0); + + EC_KEY_free(pub); + EC_KEY_free(priv); + EC_GROUP_free(curve); + return result; +} + +JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_00024Boringssl_generateSecret___3B_3BLjava_security_spec_ECParameterSpec_2Ljava_lang_String_2(JNIEnv *env, jobject self, jbyteArray pubkey, jbyteArray privkey, jobject params, jstring algorithm) { + throw_new(env, "java/lang/UnsupportedOperationException", "Not supported."); + return NULL; +} + +JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024Boringssl_sign(JNIEnv *env, jobject self, jbyteArray data, jbyteArray privkey, jobject params) { + EC_GROUP *curve = create_curve(env, params); + if (!curve) { + throw_new(env, "java/security/InvalidAlgorithmParameterException", "Curve not found."); + return NULL; + } + + EC_KEY *priv = barray_to_privkey(env, curve, privkey); + + jsize data_size = (*env)->GetArrayLength(env, data); + jbyte *data_data = (*env)->GetByteArrayElements(env, data, NULL); + // TODO: Do more Signatures here, maybe use the EVP interface to get to the hashes easier and not hash manually? + ECDSA_SIG *signature = ECDSA_do_sign(data_data, data_size, priv); + (*env)->ReleaseByteArrayElements(env, data, data_data, JNI_ABORT); + if (!signature) { + throw_new(env, "java/security/GeneralSecurityException", "Error signing, ECDSA_do_sign."); + EC_KEY_free(priv); EC_GROUP_free(curve); + return NULL; + } + + jsize sig_len = i2d_ECDSA_SIG(signature, NULL); + jbyteArray result = (*env)->NewByteArray(env, sig_len); + jbyte *result_data = (*env)->GetByteArrayElements(env, result, NULL); + jbyte *result_data_ptr = result_data; + i2d_ECDSA_SIG(signature, (unsigned char **)&result_data_ptr); + (*env)->ReleaseByteArrayElements(env, result, result_data, 0); + + ECDSA_SIG_free(signature); + EC_KEY_free(priv); + EC_GROUP_free(curve); + return result; +} + +JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024Boringssl_verify(JNIEnv *env, jobject self, jbyteArray signature, jbyteArray data, jbyteArray pubkey, jobject params) { + EC_GROUP *curve = create_curve(env, params); + if (!curve) { + throw_new(env, "java/security/InvalidAlgorithmParameterException", "Curve not found."); + return JNI_FALSE; + } + + EC_KEY *pub = barray_to_pubkey(env, curve, pubkey); + + jsize sig_len = (*env)->GetArrayLength(env, signature); + jbyte *sig_data = (*env)->GetByteArrayElements(env, signature, NULL); + jbyte *sig_data_ptr = sig_data; + ECDSA_SIG *sig_obj = d2i_ECDSA_SIG(NULL, (const unsigned char **)&sig_data_ptr, sig_len); + (*env)->ReleaseByteArrayElements(env, signature, sig_data, JNI_ABORT); + + jsize data_size = (*env)->GetArrayLength(env, data); + jbyte *data_data = (*env)->GetByteArrayElements(env, data, NULL); + int result = ECDSA_do_verify(data_data, data_size, sig_obj, pub); + if (result < 0) { + throw_new(env, "java/security/GeneralSecurityException", "Error verifying, ECDSA_do_verify."); + EC_KEY_free(pub); EC_GROUP_free(curve); ECDSA_SIG_free(sig_obj); + (*env)->ReleaseByteArrayElements(env, data, data_data, JNI_ABORT); + return JNI_FALSE; + } + (*env)->ReleaseByteArrayElements(env, data, data_data, JNI_ABORT); + + ECDSA_SIG_free(sig_obj); + EC_KEY_free(pub); + EC_GROUP_free(curve); + return (result == 1) ? JNI_TRUE : JNI_FALSE; +} diff --git a/src/cz/crcs/ectester/standalone/libs/jni/native.h b/src/cz/crcs/ectester/standalone/libs/jni/native.h index e3bf3d8..eb64b53 100644 --- a/src/cz/crcs/ectester/standalone/libs/jni/native.h +++ b/src/cz/crcs/ectester/standalone/libs/jni/native.h @@ -905,3 +905,184 @@ JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSigna } #endif #endif +/* Header for class cz_crcs_ectester_standalone_libs_BoringsslLib */ + +#ifndef _Included_cz_crcs_ectester_standalone_libs_BoringsslLib +#define _Included_cz_crcs_ectester_standalone_libs_BoringsslLib +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: cz_crcs_ectester_standalone_libs_BoringsslLib + * Method: createProvider + * Signature: ()Ljava/security/Provider; + */ +JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_BoringsslLib_createProvider + (JNIEnv *, jobject); + +/* + * Class: cz_crcs_ectester_standalone_libs_BoringsslLib + * Method: getCurves + * Signature: ()Ljava/util/Set; + */ +JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_BoringsslLib_getCurves + (JNIEnv *, jobject); + +#ifdef __cplusplus +} +#endif +#endif +/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeProvider_Boringssl */ + +#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeProvider_Boringssl +#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeProvider_Boringssl +#ifdef __cplusplus +extern "C" { +#endif +#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Boringssl_serialVersionUID +#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Boringssl_serialVersionUID 1421746759512286392LL +#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Boringssl_MAX_ARRAY_SIZE +#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Boringssl_MAX_ARRAY_SIZE 2147483639L +#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Boringssl_KEYS +#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Boringssl_KEYS 0L +#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Boringssl_VALUES +#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Boringssl_VALUES 1L +#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Boringssl_ENTRIES +#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Boringssl_ENTRIES 2L +#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Boringssl_serialVersionUID +#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Boringssl_serialVersionUID 4112578634029874840LL +#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Boringssl_serialVersionUID +#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Boringssl_serialVersionUID -4298000515446427739LL +/* + * Class: cz_crcs_ectester_standalone_libs_jni_NativeProvider_Boringssl + * Method: setup + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeProvider_00024Boringssl_setup + (JNIEnv *, jobject); + +#ifdef __cplusplus +} +#endif +#endif +/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Boringssl */ + +#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Boringssl +#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Boringssl +#ifdef __cplusplus +extern "C" { +#endif +#undef cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Boringssl_DEFAULT_KEYSIZE +#define cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Boringssl_DEFAULT_KEYSIZE 256L +/* + * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Boringssl + * Method: keysizeSupported + * Signature: (I)Z + */ +JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Boringssl_keysizeSupported + (JNIEnv *, jobject, jint); + +/* + * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Boringssl + * Method: paramsSupported + * Signature: (Ljava/security/spec/AlgorithmParameterSpec;)Z + */ +JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Boringssl_paramsSupported + (JNIEnv *, jobject, jobject); + +/* + * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Boringssl + * Method: generate + * Signature: (ILjava/security/SecureRandom;)Ljava/security/KeyPair; + */ +JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Boringssl_generate__ILjava_security_SecureRandom_2 + (JNIEnv *, jobject, jint, jobject); + +/* + * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Boringssl + * Method: generate + * Signature: (Ljava/security/spec/AlgorithmParameterSpec;Ljava/security/SecureRandom;)Ljava/security/KeyPair; + */ +JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Boringssl_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_Boringssl */ + +#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPublicKey_Boringssl +#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPublicKey_Boringssl +#ifdef __cplusplus +extern "C" { +#endif +#ifdef __cplusplus +} +#endif +#endif +/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeECPrivateKey_Boringssl */ + +#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPrivateKey_Boringssl +#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPrivateKey_Boringssl +#ifdef __cplusplus +extern "C" { +#endif +#ifdef __cplusplus +} +#endif +#endif +/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Boringssl */ + +#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Boringssl +#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Boringssl +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Boringssl + * Method: generateSecret + * Signature: ([B[BLjava/security/spec/ECParameterSpec;)[B + */ +JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_00024Boringssl_generateSecret___3B_3BLjava_security_spec_ECParameterSpec_2 + (JNIEnv *, jobject, jbyteArray, jbyteArray, jobject); + +/* + * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Boringssl + * Method: generateSecret + * Signature: ([B[BLjava/security/spec/ECParameterSpec;Ljava/lang/String;)Ljavax/crypto/SecretKey; + */ +JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_00024Boringssl_generateSecret___3B_3BLjava_security_spec_ECParameterSpec_2Ljava_lang_String_2 + (JNIEnv *, jobject, jbyteArray, jbyteArray, jobject, jstring); + +#ifdef __cplusplus +} +#endif +#endif +/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Boringssl */ + +#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Boringssl +#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Boringssl +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Boringssl + * Method: sign + * Signature: ([B[BLjava/security/spec/ECParameterSpec;)[B + */ +JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024Boringssl_sign + (JNIEnv *, jobject, jbyteArray, jbyteArray, jobject); + +/* + * Class: cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Boringssl + * Method: verify + * Signature: ([B[B[BLjava/security/spec/ECParameterSpec;)Z + */ +JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024Boringssl_verify + (JNIEnv *, jobject, jbyteArray, jbyteArray, jbyteArray, jobject); + +#ifdef __cplusplus +} +#endif +#endif -- cgit v1.2.3-70-g09d2 From 030629076791f517622f7fc8fcfcf51e10f6e063 Mon Sep 17 00:00:00 2001 From: J08nY Date: Wed, 17 Oct 2018 00:23:07 +0200 Subject: Add libgcrypt support, only keygen first. --- build-standalone.xml | 5 + .../ectester/standalone/ECTesterStandalone.java | 2 +- .../crcs/ectester/standalone/libs/GcryptLib.java | 20 ++ src/cz/crcs/ectester/standalone/libs/jni/Makefile | 71 ++++-- .../standalone/libs/jni/NativeECPrivateKey.java | 6 + .../standalone/libs/jni/NativeECPublicKey.java | 6 + .../libs/jni/NativeKeyPairGeneratorSpi.java | 18 ++ .../standalone/libs/jni/NativeProvider.java | 10 + .../crcs/ectester/standalone/libs/jni/boringssl.c | 2 - src/cz/crcs/ectester/standalone/libs/jni/gcrypt.c | 284 +++++++++++++++++++++ src/cz/crcs/ectester/standalone/libs/jni/native.h | 105 ++++++++ src/cz/crcs/ectester/standalone/libs/jni/openssl.c | 2 - 12 files changed, 501 insertions(+), 30 deletions(-) create mode 100644 src/cz/crcs/ectester/standalone/libs/GcryptLib.java create mode 100644 src/cz/crcs/ectester/standalone/libs/jni/gcrypt.c (limited to 'src/cz/crcs/ectester/standalone/libs') diff --git a/build-standalone.xml b/build-standalone.xml index c141509..84f4595 100644 --- a/build-standalone.xml +++ b/build-standalone.xml @@ -164,6 +164,11 @@ + + + + + diff --git a/src/cz/crcs/ectester/standalone/ECTesterStandalone.java b/src/cz/crcs/ectester/standalone/ECTesterStandalone.java index cb6728b..cc0e465 100644 --- a/src/cz/crcs/ectester/standalone/ECTesterStandalone.java +++ b/src/cz/crcs/ectester/standalone/ECTesterStandalone.java @@ -66,7 +66,7 @@ import java.util.stream.Collectors; * @version v0.3.0 */ public class ECTesterStandalone { - private ProviderECLibrary[] libs = new ProviderECLibrary[]{new SunECLib(), new BouncyCastleLib(), new TomcryptLib(), new BotanLib(), new CryptoppLib(), new OpensslLib(), new BoringsslLib(), new MscngLib()}; + private ProviderECLibrary[] libs = new ProviderECLibrary[]{new SunECLib(), new BouncyCastleLib(), new TomcryptLib(), new BotanLib(), new CryptoppLib(), new OpensslLib(), new BoringsslLib(), new GcryptLib(), new MscngLib()}; private Config cfg; private Options opts = new Options(); diff --git a/src/cz/crcs/ectester/standalone/libs/GcryptLib.java b/src/cz/crcs/ectester/standalone/libs/GcryptLib.java new file mode 100644 index 0000000..a0a7fc8 --- /dev/null +++ b/src/cz/crcs/ectester/standalone/libs/GcryptLib.java @@ -0,0 +1,20 @@ +package cz.crcs.ectester.standalone.libs; + +import java.security.Provider; +import java.util.Set; + +/** + * @author Jan Jancar johny@neuromancer.sk + */ +public class GcryptLib extends NativeECLibrary { + + public GcryptLib() { + super("gcrypt_provider", "gcrypt", "gpg-error"); + } + + @Override + native Provider createProvider(); + + @Override + public native Set getCurves(); +} diff --git a/src/cz/crcs/ectester/standalone/libs/jni/Makefile b/src/cz/crcs/ectester/standalone/libs/jni/Makefile index 189a6dd..2232e3d 100644 --- a/src/cz/crcs/ectester/standalone/libs/jni/Makefile +++ b/src/cz/crcs/ectester/standalone/libs/jni/Makefile @@ -1,3 +1,28 @@ +############################################################################### +## General CC setup. + +CC?=gcc +CXX?=g++ + +LFLAGS+=-fPIC -shared +CFLAGS+=-fPIC -I"$(JNI_INCLUDEDIR)" -I"$(JNI_PLATFORMINCLUDEDIR)" -I. +CXXFLAGS+=-fPIC -I"$(JNI_INCLUDEDIR)" -I"$(JNI_PLATFORMINCLUDEDIR)" -I. + +DEBUG ?= 0 + +ifeq ($(DEBUG), 1) + CFLAGS+=-g -Wall + LFLAGS+=-g + CXXFLAGS+=-g -Wall +else + CFLAGS+=-O2 + LFLAGS+=-O2 + CXXFLAGS+=-O2 +endif + +############################################################################### +## Java JNI setup. + ifeq ($(JAVA_HOME),) ifeq ($(OS),Windows_NT) which = $(shell where $1) @@ -24,37 +49,16 @@ ifeq ($(JNI_PLATFORM),) else ifeq ($(findstring linux,$(TARGETTRIPLET)),linux) JNI_PLATFORM:= linux - # add more checks here endif endif endif JNI_PLATFORMINCLUDEDIR ?= $(JNI_INCLUDEDIR)/$(JNI_PLATFORM) -LOCAL_INCLUDES = /usr/local/include -LOCAL_LIBS = /usr/local/lib +############################################################################### +## Targets. -CC?=gcc -CXX?=g++ -STRIP?=strip - -LFLAGS+=-fPIC -shared -CFLAGS+=-fPIC -I"$(JNI_INCLUDEDIR)" -I"$(JNI_PLATFORMINCLUDEDIR)" -I. -CXXFLAGS+=-fPIC -I"$(JNI_INCLUDEDIR)" -I"$(JNI_PLATFORMINCLUDEDIR)" -I. - -DEBUG ?= 0 - -ifeq ($(DEBUG), 1) - CFLAGS+=-g - LFLAGS+=-g - CXXFLAGS+=-g -else - CFLAGS+=-O2 - LFLAGS+=-O2 - CXXFLAGS+=-O2 -endif - -all: tomcrypt_provider.so botan_provider.so cryptopp_provider.so openssl_provider.so boringssl_provider.so +all: tomcrypt_provider.so botan_provider.so cryptopp_provider.so openssl_provider.so boringssl_provider.so gcrypt_provider.so # Common utils c_utils.o: c_utils.c @@ -81,6 +85,14 @@ boringssl.o: boringssl.c $(CC) -I../../../../../../../ext/boringssl/include/ $(CFLAGS) -c $< +# libgcrypt shim +gcrypt_provider.so: gcrypt.o c_utils.o + $(CC) $(LFLAGS) -o $@ $^ -L. $(shell libgcrypt-config --libs) + +gcrypt.o: gcrypt.c + $(CC) $(shell libgcrypt-config --cflags) $(CFLAGS) -c $< + + # Libtomcrypt shim tomcrypt_provider.so: tomcrypt.o c_utils.o $(CC) $(LFLAGS) -o $@ $^ -L. -ltommath $(shell pkg-config --libs libtomcrypt) @@ -104,9 +116,18 @@ cryptopp_provider.so: cryptopp.o cpp_utils.o cryptopp.o: cryptopp.cpp $(CXX) $(shell pkg-config --cflags libcrypto++) $(CXXFLAGS) -c $< +help: + @echo "# This makefile builds the JNI shims necessary to test native libraries." + @echo "# Targets:" + @echo " - openssl_provider.so" + @echo " - boringssl_provider.so" + @echo " - gcrypt_provider.so" + @echo " - tomcrypt_provider.so" + @echo " - botan_provider.so" + @echo " - cryptopp_provider.so" clean: rm -rf *.o rm -rf *.so -.PHONY: all clean \ No newline at end of file +.PHONY: all help clean \ No newline at end of file diff --git a/src/cz/crcs/ectester/standalone/libs/jni/NativeECPrivateKey.java b/src/cz/crcs/ectester/standalone/libs/jni/NativeECPrivateKey.java index a74c155..6d8101f 100644 --- a/src/cz/crcs/ectester/standalone/libs/jni/NativeECPrivateKey.java +++ b/src/cz/crcs/ectester/standalone/libs/jni/NativeECPrivateKey.java @@ -91,6 +91,12 @@ public abstract class NativeECPrivateKey implements ECPrivateKey { } } + public static class Gcrypt extends Raw { + public Gcrypt(byte[] keyData, ECParameterSpec params) { + super(keyData, params); + } + } + public static class Mscng extends Raw { // 0 -> implicit (meta = curveName UTF16, header = full); // 1 -> explicit (meta = null, header = full); diff --git a/src/cz/crcs/ectester/standalone/libs/jni/NativeECPublicKey.java b/src/cz/crcs/ectester/standalone/libs/jni/NativeECPublicKey.java index 7c17646..dcb8b3f 100644 --- a/src/cz/crcs/ectester/standalone/libs/jni/NativeECPublicKey.java +++ b/src/cz/crcs/ectester/standalone/libs/jni/NativeECPublicKey.java @@ -92,6 +92,12 @@ public abstract class NativeECPublicKey implements ECPublicKey { } } + public static class Gcrypt extends ANSIX962 { + public Gcrypt(byte[] keyData, ECParameterSpec params) { + super(keyData, params); + } + } + public static class Mscng extends ANSIX962 { // 0 -> implicit (meta = curveName UTF16, header = full); // 1 -> explicit (meta = null, header = full); diff --git a/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyPairGeneratorSpi.java b/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyPairGeneratorSpi.java index 77f0d18..78656fc 100644 --- a/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyPairGeneratorSpi.java +++ b/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyPairGeneratorSpi.java @@ -198,6 +198,24 @@ public abstract class NativeKeyPairGeneratorSpi extends KeyPairGeneratorSpi { native KeyPair generate(AlgorithmParameterSpec params, SecureRandom random); } + public static class Gcrypt extends NativeKeyPairGeneratorSpi { + + public Gcrypt() { + } + + @Override + native boolean keysizeSupported(int keysize); + + @Override + native boolean paramsSupported(AlgorithmParameterSpec params); + + @Override + native KeyPair generate(int keysize, SecureRandom random); + + @Override + native KeyPair generate(AlgorithmParameterSpec params, SecureRandom random); + } + public static abstract class Mscng extends NativeKeyPairGeneratorSpi { private String type; diff --git a/src/cz/crcs/ectester/standalone/libs/jni/NativeProvider.java b/src/cz/crcs/ectester/standalone/libs/jni/NativeProvider.java index 1399500..99baa97 100644 --- a/src/cz/crcs/ectester/standalone/libs/jni/NativeProvider.java +++ b/src/cz/crcs/ectester/standalone/libs/jni/NativeProvider.java @@ -74,6 +74,16 @@ public abstract class NativeProvider extends Provider { native void setup(); } + public static class Gcrypt extends NativeProvider { + + public Gcrypt(String name, double version, String info) { + super(name, version, info); + } + + @Override + native void setup(); + } + public static class Mscng extends NativeProvider { public Mscng(String name, double version, String info) { diff --git a/src/cz/crcs/ectester/standalone/libs/jni/boringssl.c b/src/cz/crcs/ectester/standalone/libs/jni/boringssl.c index 0353741..965e396 100644 --- a/src/cz/crcs/ectester/standalone/libs/jni/boringssl.c +++ b/src/cz/crcs/ectester/standalone/libs/jni/boringssl.c @@ -1,6 +1,5 @@ #include "native.h" #include -#include #include #include @@ -256,7 +255,6 @@ static jobject create_ec_param_spec(JNIEnv *env, const EC_GROUP *curve) { 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_int, b_int); - fflush(stderr); BN_free(a); BN_free(b); diff --git a/src/cz/crcs/ectester/standalone/libs/jni/gcrypt.c b/src/cz/crcs/ectester/standalone/libs/jni/gcrypt.c new file mode 100644 index 0000000..0705df6 --- /dev/null +++ b/src/cz/crcs/ectester/standalone/libs/jni/gcrypt.c @@ -0,0 +1,284 @@ +#include "native.h" +#include +#include +#include "c_utils.h" + +static jclass provider_class; + + +JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_GcryptLib_createProvider(JNIEnv *env, jobject this){ + /* Create the custom provider. */ + jclass local_provider_class = (*env)->FindClass(env, "cz/crcs/ectester/standalone/libs/jni/NativeProvider$Gcrypt"); + provider_class = (*env)->NewGlobalRef(env, local_provider_class); + + jmethodID init = (*env)->GetMethodID(env, local_provider_class, "", "(Ljava/lang/String;DLjava/lang/String;)V"); + + const char *built_with = GCRYPT_VERSION; + const char *running_with = gcry_check_version(GCRYPT_VERSION); + if (!running_with) { + return NULL; + } + char full_name[strlen("libgcrypt ") + strlen(running_with) + 1]; + strcpy(full_name, "libgcrypt "); + strcat(full_name, running_with); + jstring name = (*env)->NewStringUTF(env, full_name); + double version = strtod(running_with, NULL); + + return (*env)->NewObject(env, provider_class, init, name, version, name); +} + +JNIEXPORT void JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeProvider_00024Gcrypt_setup(JNIEnv *env, jobject this) { + gcry_control(GCRYCTL_DISABLE_SECMEM, 0); + //gcry_control(GCRYCTL_SET_DEBUG_FLAGS, 1); + gcry_control(GCRYCTL_ENABLE_QUICK_RANDOM, 0); + gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0); + + INIT_PROVIDER(env, provider_class); + + ADD_KPG(env, this, "EC", "Gcrypt"); + //ADD_KA(env, self, "ECDH", "OpensslECDH"); + //ADD_SIG(env, self, "NONEwithECDSA", "OpensslECDSAwithNONE"); + + init_classes(env, "Gcrypt"); +} + +JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_GcryptLib_getCurves(JNIEnv *env, jobject this) { + jclass hash_set_class = (*env)->FindClass(env, "java/util/TreeSet"); + + jmethodID hash_set_ctr = (*env)->GetMethodID(env, hash_set_class, "", "()V"); + jmethodID hash_set_add = (*env)->GetMethodID(env, hash_set_class, "add", "(Ljava/lang/Object;)Z"); + + jobject result = (*env)->NewObject(env, hash_set_class, hash_set_ctr); + + const char *name; + unsigned int nbits; + + for (size_t i = 0; (name = gcry_pk_get_curve(NULL, i, &nbits)); i++){ + jstring curve_name = (*env)->NewStringUTF(env, name); + (*env)->CallBooleanMethod(env, result, hash_set_add, curve_name); + } + + return result; +} + +JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Gcrypt_keysizeSupported(JNIEnv *env, jobject this, jint keysize) { + const char *name; + unsigned int nbits; + + for (size_t i = 0; (name = gcry_pk_get_curve(NULL, i, &nbits)); i++){ + if (nbits == keysize) { + return JNI_TRUE; + } + } + + return JNI_FALSE; +} + +static void print_sexp(gcry_sexp_t sexp) { + size_t len = gcry_sexp_sprint(sexp, GCRYSEXP_FMT_ADVANCED, NULL, 0); + char string[len]; + gcry_sexp_sprint(sexp, GCRYSEXP_FMT_ADVANCED, string, len); + printf("%s\n", string); + fflush(stdout); +} + +JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Gcrypt_paramsSupported(JNIEnv *env, jobject this, jobject params) { + if (params == NULL) { + return JNI_FALSE; + } + + if ((*env)->IsInstanceOf(env, params, ec_parameter_spec_class)) { + 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); + gcry_sexp_t curve_sexp; + gcry_sexp_build(&curve_sexp, NULL, "(public-key (ecc (curve %s)))", utf_name); + unsigned int nbits; + const char *ret_name = gcry_pk_get_curve(curve_sexp, 0, &nbits); + (*env)->ReleaseStringUTFChars(env, name, utf_name); + gcry_sexp_release(curve_sexp); + return ret_name ? JNI_TRUE : JNI_FALSE; + } else { + return JNI_FALSE; + } +} + +static jobject mpi_to_biginteger(JNIEnv *env, gcry_mpi_t mpi) { + jmethodID biginteger_init = (*env)->GetMethodID(env, biginteger_class, "", "(I[B)V"); + size_t len = 0; + gcry_mpi_print(GCRYMPI_FMT_USG, NULL, 0, &len, mpi); + jbyteArray bytes = (*env)->NewByteArray(env, len); + jbyte *data = (*env)->GetByteArrayElements(env, bytes, NULL); + gcry_mpi_print(GCRYMPI_FMT_USG, data, len, &len, mpi); + (*env)->ReleaseByteArrayElements(env, bytes, data, 0); + jobject result = (*env)->NewObject(env, biginteger_class, biginteger_init, 1, bytes); + return result; +} + +static gcry_mpi_t biginteger_to_mpi(JNIEnv *env, jobject bigint) { + jmethodID to_byte_array = (*env)->GetMethodID(env, biginteger_class, "toByteArray", "()[B"); + + jbyteArray byte_array = (jbyteArray) (*env)->CallObjectMethod(env, bigint, to_byte_array); + jsize byte_length = (*env)->GetArrayLength(env, byte_array); + jbyte *byte_data = (*env)->GetByteArrayElements(env, byte_array, NULL); + gcry_mpi_t result; + gcry_mpi_scan(&result, GCRYMPI_FMT_USG, byte_data, byte_length, NULL); + (*env)->ReleaseByteArrayElements(env, byte_array, byte_data, JNI_ABORT); + return result; +} + +static jint mpi_to_jint(gcry_mpi_t mpi) { + jint result = 0; + unsigned long nbits = gcry_mpi_get_nbits(mpi); + int max_bits = sizeof(jint) * 8; + for (size_t i = 0; i < nbits && i < max_bits; ++i) { + if (gcry_mpi_test_bit(mpi, nbits - i - 1)) { + result = ((result << 1) | 1); + } else { + result = (result << 1); + } + } + return result; +} + +static jobject buff_to_ecpoint(JNIEnv *env, gcry_buffer_t buff) { + jint coord_size = (buff.size - 1) / 2; + jmethodID biginteger_init = (*env)->GetMethodID(env, biginteger_class, "", "(I[B)V"); + + jbyteArray x_bytes = (*env)->NewByteArray(env, coord_size); + jbyte *x_data = (*env)->GetByteArrayElements(env, x_bytes, NULL); + memcpy(x_data, ((char *) buff.data) + 1, coord_size); + (*env)->ReleaseByteArrayElements(env, x_bytes, x_data, 0); + jobject xi = (*env)->NewObject(env, biginteger_class, biginteger_init, 1, x_bytes); + + jbyteArray y_bytes = (*env)->NewByteArray(env, coord_size); + jbyte *y_data = (*env)->GetByteArrayElements(env, y_bytes, NULL); + memcpy(y_data, ((char *) buff.data) + 1 + coord_size, coord_size); + (*env)->ReleaseByteArrayElements(env, y_bytes, y_data, 0); + jobject yi = (*env)->NewObject(env, biginteger_class, biginteger_init, 1, y_bytes); + + jmethodID point_init = (*env)->GetMethodID(env, point_class, "", "(Ljava/math/BigInteger;Ljava/math/BigInteger;)V"); + return (*env)->NewObject(env, point_class, point_init, xi, yi); +} + +static jobject create_ec_param_spec(JNIEnv *env, gcry_sexp_t key) { + jobject result = NULL; + gcry_mpi_t p, a, b, n, h; + gcry_buffer_t g = {0}; + gcry_error_t err = gcry_sexp_extract_param(key, "ecc", "pab&g+nh", &p, &a, &b, &g, &n, &h, NULL); + if (gcry_err_code(err) != GPG_ERR_NO_ERROR) { + throw_new_var(env, "java/security/GeneralSecurityException", "Error exporting domain parameters. Error: %ui", gcry_err_code(err)); + goto end; + } + + jobject pi = mpi_to_biginteger(env, p); + 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, pi); + + jobject ai = mpi_to_biginteger(env, a); + jobject bi = mpi_to_biginteger(env, b); + + 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, ai, bi); + + jobject gen = buff_to_ecpoint(env, g); + + jobject order = mpi_to_biginteger(env, n); + jint cofactor = mpi_to_jint(h); + + 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"); + result = (*env)->NewObject(env, ec_parameter_spec_class, ec_parameter_spec_init, elliptic_curve, gen, order, cofactor); + +end: + gcry_mpi_release(p); + gcry_mpi_release(a); + gcry_mpi_release(b); + gcry_free(g.data); + gcry_mpi_release(n); + gcry_mpi_release(h); + return result; +} + +static jobject generate_from_sexp(JNIEnv *env, gcry_sexp_t gen_sexp) { + jobject result = NULL; + gcry_sexp_t key_sexp; + gcry_error_t err = gcry_pk_genkey(&key_sexp, gen_sexp); + if (gcry_err_code(err) != GPG_ERR_NO_ERROR) { + throw_new_var(env, "java/security/GeneralSecurityException", "Error generating key. Error: %ui", gcry_err_code(err)); + goto release_sexp; + } + gcry_sexp_t pkey = gcry_sexp_find_token(key_sexp, "public-key", 0); + gcry_sexp_t skey = gcry_sexp_find_token(key_sexp, "private-key", 0); + + jobject ec_param_spec = create_ec_param_spec(env, skey); + if (!ec_param_spec) { + goto release_keypair; + } + + gcry_buffer_t q = {0}; + gcry_mpi_t d; + err = gcry_sexp_extract_param(skey, "ecc", "&q+d", &q, &d, NULL); + + jbyteArray pub_bytes = (*env)->NewByteArray(env, q.size); + jbyte *key_pub = (*env)->GetByteArrayElements(env, pub_bytes, NULL); + memcpy(key_pub, q.data, q.size); + (*env)->ReleaseByteArrayElements(env, pub_bytes, key_pub, 0); + + size_t priv_len = 0; + gcry_mpi_print(GCRYMPI_FMT_USG, NULL, 0, &priv_len, d); + jbyteArray priv_bytes = (*env)->NewByteArray(env, priv_len); + jbyte *key_priv = (*env)->GetByteArrayElements(env, priv_bytes, NULL); + gcry_mpi_print(GCRYMPI_FMT_USG, key_priv, priv_len, NULL, d); + (*env)->ReleaseByteArrayElements(env, priv_bytes, key_priv, 0); + + 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); + + 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"); + result = (*env)->NewObject(env, keypair_class, keypair_init, pubkey, privkey); + + gcry_mpi_release(d); + gcry_free(q.data); + +release_keypair: + gcry_sexp_release(pkey); + gcry_sexp_release(skey); +release_sexp: + gcry_sexp_release(key_sexp); + return result; +} + +JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Gcrypt_generate__ILjava_security_SecureRandom_2(JNIEnv *env, jobject this, jint keysize, jobject random) { + gcry_sexp_t gen_sexp; + gcry_sexp_build(&gen_sexp, NULL, "(genkey (ecc (flags no-keytest param) (nbits %d)))", keysize); + + jobject result = generate_from_sexp(env, gen_sexp); + gcry_sexp_release(gen_sexp); + return result; +} + +JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Gcrypt_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)) { + return NULL; + } 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); + gcry_sexp_t gen_sexp; + gcry_sexp_build(&gen_sexp, NULL, "(genkey (ecc (flags no-keytest param) (curve %s)))", utf_name); + (*env)->ReleaseStringUTFChars(env, name, utf_name); + jobject result = generate_from_sexp(env, gen_sexp); + gcry_sexp_release(gen_sexp); + return result; + } else { + return NULL; + } +} \ No newline at end of file diff --git a/src/cz/crcs/ectester/standalone/libs/jni/native.h b/src/cz/crcs/ectester/standalone/libs/jni/native.h index eb64b53..e86a847 100644 --- a/src/cz/crcs/ectester/standalone/libs/jni/native.h +++ b/src/cz/crcs/ectester/standalone/libs/jni/native.h @@ -1086,3 +1086,108 @@ JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSigna } #endif #endif +/* Header for class cz_crcs_ectester_standalone_libs_GcryptLib */ + +#ifndef _Included_cz_crcs_ectester_standalone_libs_GcryptLib +#define _Included_cz_crcs_ectester_standalone_libs_GcryptLib +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: cz_crcs_ectester_standalone_libs_GcryptLib + * Method: createProvider + * Signature: ()Ljava/security/Provider; + */ +JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_GcryptLib_createProvider + (JNIEnv *, jobject); + +/* + * Class: cz_crcs_ectester_standalone_libs_GcryptLib + * Method: getCurves + * Signature: ()Ljava/util/Set; + */ +JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_GcryptLib_getCurves + (JNIEnv *, jobject); + +#ifdef __cplusplus +} +#endif +#endif +/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeProvider_Gcrypt */ + +#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeProvider_Gcrypt +#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeProvider_Gcrypt +#ifdef __cplusplus +extern "C" { +#endif +#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Gcrypt_serialVersionUID +#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Gcrypt_serialVersionUID 1421746759512286392LL +#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Gcrypt_MAX_ARRAY_SIZE +#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Gcrypt_MAX_ARRAY_SIZE 2147483639L +#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Gcrypt_KEYS +#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Gcrypt_KEYS 0L +#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Gcrypt_VALUES +#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Gcrypt_VALUES 1L +#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Gcrypt_ENTRIES +#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Gcrypt_ENTRIES 2L +#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Gcrypt_serialVersionUID +#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Gcrypt_serialVersionUID 4112578634029874840LL +#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Gcrypt_serialVersionUID +#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Gcrypt_serialVersionUID -4298000515446427739LL +/* + * Class: cz_crcs_ectester_standalone_libs_jni_NativeProvider_Gcrypt + * Method: setup + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeProvider_00024Gcrypt_setup + (JNIEnv *, jobject); + +#ifdef __cplusplus +} +#endif +#endif +/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Gcrypt */ + +#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Gcrypt +#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Gcrypt +#ifdef __cplusplus +extern "C" { +#endif +#undef cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Gcrypt_DEFAULT_KEYSIZE +#define cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Gcrypt_DEFAULT_KEYSIZE 256L +/* + * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Gcrypt + * Method: keysizeSupported + * Signature: (I)Z + */ +JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Gcrypt_keysizeSupported + (JNIEnv *, jobject, jint); + +/* + * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Gcrypt + * Method: paramsSupported + * Signature: (Ljava/security/spec/AlgorithmParameterSpec;)Z + */ +JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Gcrypt_paramsSupported + (JNIEnv *, jobject, jobject); + +/* + * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Gcrypt + * Method: generate + * Signature: (ILjava/security/SecureRandom;)Ljava/security/KeyPair; + */ +JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Gcrypt_generate__ILjava_security_SecureRandom_2 + (JNIEnv *, jobject, jint, jobject); + +/* + * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Gcrypt + * Method: generate + * Signature: (Ljava/security/spec/AlgorithmParameterSpec;Ljava/security/SecureRandom;)Ljava/security/KeyPair; + */ +JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Gcrypt_generate__Ljava_security_spec_AlgorithmParameterSpec_2Ljava_security_SecureRandom_2 + (JNIEnv *, jobject, jobject, jobject); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/cz/crcs/ectester/standalone/libs/jni/openssl.c b/src/cz/crcs/ectester/standalone/libs/jni/openssl.c index 255834a..4ea5f6c 100644 --- a/src/cz/crcs/ectester/standalone/libs/jni/openssl.c +++ b/src/cz/crcs/ectester/standalone/libs/jni/openssl.c @@ -1,6 +1,5 @@ #include "native.h" #include -#include #include #include @@ -327,7 +326,6 @@ static jobject create_ec_param_spec(JNIEnv *env, const EC_GROUP *curve) { 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_int, b_int); - fflush(stderr); BN_free(a); BN_free(b); -- cgit v1.2.3-70-g09d2 From ba5cfcc98d7bf5107e6aac3a4e5c7416ab7b76a7 Mon Sep 17 00:00:00 2001 From: J08nY Date: Wed, 17 Oct 2018 22:41:19 +0200 Subject: Add support for libgcrypt ecdh and ecdsa. --- build-standalone.xml | 2 + .../ectester/standalone/ECTesterStandalone.java | 2 +- .../ectester/standalone/consts/SignatureIdent.java | 2 +- .../standalone/libs/jni/NativeKeyAgreementSpi.java | 23 +- .../standalone/libs/jni/NativeSignatureSpi.java | 91 ++++++ src/cz/crcs/ectester/standalone/libs/jni/c_utils.c | 101 +++++- src/cz/crcs/ectester/standalone/libs/jni/c_utils.h | 11 + src/cz/crcs/ectester/standalone/libs/jni/gcrypt.c | 360 +++++++++++++++++++-- src/cz/crcs/ectester/standalone/libs/jni/native.h | 76 +++++ 9 files changed, 645 insertions(+), 23 deletions(-) (limited to 'src/cz/crcs/ectester/standalone/libs') diff --git a/build-standalone.xml b/build-standalone.xml index 84f4595..9a47642 100644 --- a/build-standalone.xml +++ b/build-standalone.xml @@ -169,6 +169,8 @@ + + diff --git a/src/cz/crcs/ectester/standalone/ECTesterStandalone.java b/src/cz/crcs/ectester/standalone/ECTesterStandalone.java index cc0e465..7480215 100644 --- a/src/cz/crcs/ectester/standalone/ECTesterStandalone.java +++ b/src/cz/crcs/ectester/standalone/ECTesterStandalone.java @@ -325,7 +325,7 @@ public class ECTesterStandalone { ECPublicKey pubkey = (ECPublicKey) other.getPublic(); long elapsed = -System.nanoTime(); - if (spec != null) { + if (spec instanceof ECParameterSpec) { ka.init(privkey, spec); } else { ka.init(privkey); diff --git a/src/cz/crcs/ectester/standalone/consts/SignatureIdent.java b/src/cz/crcs/ectester/standalone/consts/SignatureIdent.java index dea8abe..93b7f99 100644 --- a/src/cz/crcs/ectester/standalone/consts/SignatureIdent.java +++ b/src/cz/crcs/ectester/standalone/consts/SignatureIdent.java @@ -52,7 +52,7 @@ public class SignatureIdent extends Ident { ALL.add(new SignatureIdent("ECGOST3410-2012-512", "GOST-3410-2012-512")); ALL.add(new SignatureIdent("GOST3411-2012-512withECGOST3410-2012-512", "GOST3411-2012-512/ECGOST3410-2012-5120", "1.2.643.7.1.1.3.3")); ALL.add(new SignatureIdent("SM3withSM2")); - // ECDDSA + // ECDDSA (rfc6979?) ALL.add(new SignatureIdent("ECDDSA", "DETECDSA", "ECDETDSA")); ALL.add(new SignatureIdent("SHA1withECDDSA", "SHA1withDETECDSA")); ALL.add(new SignatureIdent("SHA224withECDDSA", "SHA224withDETECDSA")); diff --git a/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyAgreementSpi.java b/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyAgreementSpi.java index 5fca448..7b531f5 100644 --- a/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyAgreementSpi.java +++ b/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyAgreementSpi.java @@ -65,7 +65,7 @@ public abstract class NativeKeyAgreementSpi extends KeyAgreementSpi { @Override protected void engineInit(Key key, AlgorithmParameterSpec params, SecureRandom random) throws InvalidKeyException, InvalidAlgorithmParameterException { if (!(params instanceof ECParameterSpec)) { - throw new InvalidAlgorithmParameterException(); + throw new InvalidAlgorithmParameterException(params.toString()); } engineInit(key, random); this.params = params; @@ -254,6 +254,27 @@ public abstract class NativeKeyAgreementSpi extends KeyAgreementSpi { } } + public abstract static class Gcrypt extends SimpleKeyAgreementSpi { + private String type; + + public Gcrypt(String type) { + this.type = type; + } + + @Override + native byte[] generateSecret(byte[] pubkey, byte[] privkey, ECParameterSpec params); + + @Override + native SecretKey generateSecret(byte[] pubkey, byte[] privkey, ECParameterSpec params, String algorithm); + } + + public static class GcryptECDH extends Gcrypt { + public GcryptECDH() { + super("ECDH"); + } + } + + public abstract static class Mscng extends ExtendedKeyAgreementSpi { private String type; diff --git a/src/cz/crcs/ectester/standalone/libs/jni/NativeSignatureSpi.java b/src/cz/crcs/ectester/standalone/libs/jni/NativeSignatureSpi.java index 3f99771..f2b1ab9 100644 --- a/src/cz/crcs/ectester/standalone/libs/jni/NativeSignatureSpi.java +++ b/src/cz/crcs/ectester/standalone/libs/jni/NativeSignatureSpi.java @@ -349,6 +349,97 @@ public abstract class NativeSignatureSpi extends SignatureSpi { } } + public abstract static class Gcrypt extends SimpleSignatureSpi { + private String type; + + public Gcrypt(String type) { + this.type = type; + } + + @Override + native byte[] sign(byte[] data, byte[] privkey, ECParameterSpec params); + + @Override + native boolean verify(byte[] signature, byte[] data, byte[] pubkey, ECParameterSpec params); + } + + public static class GcryptECDSAwithNONE extends Gcrypt { + + public GcryptECDSAwithNONE() { + super("NONEwithECDSA"); + } + } + + public static class GcryptECDSAwithSHA1 extends Gcrypt { + + public GcryptECDSAwithSHA1() { + super("SHA1withECDSA"); + } + } + + public static class GcryptECDSAwithSHA224 extends Gcrypt { + + public GcryptECDSAwithSHA224() { + super("SHA224withECDSA"); + } + } + + public static class GcryptECDSAwithSHA256 extends Gcrypt { + + public GcryptECDSAwithSHA256() { + super("SHA256withECDSA"); + } + } + + public static class GcryptECDSAwithSHA384 extends Gcrypt { + + public GcryptECDSAwithSHA384() { + super("SHA384withECDSA"); + } + } + + public static class GcryptECDSAwithSHA512 extends Gcrypt { + + public GcryptECDSAwithSHA512() { + super("SHA512withECDSA"); + } + } + + public static class GcryptECDDSAwithSHA1 extends Gcrypt { + + public GcryptECDDSAwithSHA1() { + super("SHA1withECDDSA"); + } + } + + public static class GcryptECDDSAwithSHA224 extends Gcrypt { + + public GcryptECDDSAwithSHA224() { + super("SHA224withECDDSA"); + } + } + + public static class GcryptECDDSAwithSHA256 extends Gcrypt { + + public GcryptECDDSAwithSHA256() { + super("SHA256withECDDSA"); + } + } + + public static class GcryptECDDSAwithSHA384 extends Gcrypt { + + public GcryptECDDSAwithSHA384() { + super("SHA384withECDDSA"); + } + } + + public static class GcryptECDDSAwithSHA512 extends Gcrypt { + + public GcryptECDDSAwithSHA512() { + super("SHA512withECDDSA"); + } + } + public abstract static class Mscng extends ExtendedSignatureSpi { private String type; diff --git a/src/cz/crcs/ectester/standalone/libs/jni/c_utils.c b/src/cz/crcs/ectester/standalone/libs/jni/c_utils.c index 49cab44..c36d3c9 100644 --- a/src/cz/crcs/ectester/standalone/libs/jni/c_utils.c +++ b/src/cz/crcs/ectester/standalone/libs/jni/c_utils.c @@ -75,7 +75,7 @@ void throw_new_var(JNIEnv *env, const char *class, const char *format, ...) { char buffer[2048]; va_list args; va_start(args, format); - int res = vsnprintf(buffer, 2048, format, args); + vsnprintf(buffer, 2048, format, args); va_end(args); throw_new(env, class, buffer); } @@ -105,4 +105,103 @@ jint get_kdf_bits(JNIEnv *env, jstring algorithm) { } (*env)->ReleaseStringUTFChars(env, algorithm, algo_data); return result; +} + +jbyteArray asn1_der_encode(JNIEnv *env, const jbyte *r, size_t r_len, const jbyte *s, size_t s_len) { + jbyte r_length = (jbyte) r_len + (r[0] & 0x80 ? 1 : 0); + jbyte s_length = (jbyte) s_len + (s[0] & 0x80 ? 1 : 0); + + // R and S are < 128 bytes, so 1 byte tag + 1 byte len + len bytes value + size_t seq_value_len = 2 + r_length + 2 + s_length; + size_t whole_len = seq_value_len; + + // The SEQUENCE length might be >= 128, so more bytes of length + size_t seq_len_len = 0; + if (seq_value_len >= 128) { + size_t s = seq_value_len; + while ((s = s >> 8)) { + seq_len_len++; + } + } + // seq_len_len bytes for length and one for length of length + whole_len += seq_len_len + 1; + + // 1 byte tag for SEQUENCE + whole_len += 1; + + jbyteArray result = (jbyteArray) (*env)->NewByteArray(env, whole_len); + jbyte *data = (*env)->GetByteArrayElements(env, result, NULL); + size_t i = 0; + data[i++] = 0x30; // SEQUENCE + if (seq_value_len < 128) { + data[i++] = (jbyte) seq_value_len; + } else { + data[i++] = (jbyte) (seq_len_len | (1 << 7)); + for (size_t j = 0; j < seq_len_len; ++j) { + data[i++] = (jbyte) (seq_value_len & (0xff << (seq_len_len - j))); + } + } + data[i++] = 0x02; //INTEGER + data[i++] = r_length; + if (r[0] & 0x80) { + data[i++] = 0; + } + memcpy(data + i, r, r_len); + i += r_len; + data[i++] = 0x02; //INTEGER + data[i++] = s_length; + if (s[0] & 0x80) { + data[i++] = 0; + } + memcpy(data + i, s, s_len); + i += s_len; + (*env)->ReleaseByteArrayElements(env, result, data, 0); + + return result; +} + +bool asn1_der_decode(JNIEnv *env, jbyteArray sig, jbyte **r_data, size_t *r_len, jbyte **s_data, size_t *s_len) { + size_t sig_len = (*env)->GetArrayLength(env, sig); + jbyte *data = (*env)->GetByteArrayElements(env, sig, NULL); + size_t i = 0; + if (data[i++] != 0x30) {//SEQUENCE + (*env)->ReleaseByteArrayElements(env, sig, data, JNI_ABORT); + return false; + } + size_t seq_value_len = 0; + if (!(data[i] & 0x80)) { + seq_value_len = data[i++]; + } else { + size_t seq_len_len = data[i++] & 0x7f; + while (seq_len_len > 0) { + seq_value_len |= (data[i++] << (seq_len_len - 1)); + seq_len_len--; + } + } + + if (data[i++] != 0x02) {//INTEGER + (*env)->ReleaseByteArrayElements(env, sig, data, JNI_ABORT); + return false; + } + size_t r_length = data[i++]; + jbyte *r_out = malloc(r_length); + memcpy(r_out, data + i, r_length); + i += r_length; + + if (data[i++] != 0x02) {//INTEGER + free(r_out); + (*env)->ReleaseByteArrayElements(env, sig, data, JNI_ABORT); + return false; + } + size_t s_length = data[i++]; + jbyte *s_out = malloc(s_length); + memcpy(s_out, data + i, s_length); + i += s_length; + + *r_len = r_length; + *r_data = r_out; + *s_len = s_length; + *s_data = s_out; + (*env)->ReleaseByteArrayElements(env, sig, data, JNI_ABORT); + return true; } \ No newline at end of file diff --git a/src/cz/crcs/ectester/standalone/libs/jni/c_utils.h b/src/cz/crcs/ectester/standalone/libs/jni/c_utils.h index b767b61..82c3538 100644 --- a/src/cz/crcs/ectester/standalone/libs/jni/c_utils.h +++ b/src/cz/crcs/ectester/standalone/libs/jni/c_utils.h @@ -1,6 +1,7 @@ #pragma once #include "native.h" +#include /** * Classes that are accessed alot are cached here, manually. @@ -38,6 +39,16 @@ void throw_new_var(JNIEnv *env, const char *class, const char *format, ...); */ jint get_kdf_bits(JNIEnv *env, jstring algorithm); +/** + * DER encode the r and s values. + */ +jbyteArray asn1_der_encode(JNIEnv *env, const jbyte *r, size_t r_len, const jbyte *s, size_t s_len); + +/** + * DER decode a signature into r and s values. + */ +bool asn1_der_decode(JNIEnv *env, jbyteArray sig, jbyte **r_data, size_t *r_len, jbyte **s_data, size_t *s_len); + /** * Some useful defines to init the provider. */ diff --git a/src/cz/crcs/ectester/standalone/libs/jni/gcrypt.c b/src/cz/crcs/ectester/standalone/libs/jni/gcrypt.c index 0705df6..0ba94c6 100644 --- a/src/cz/crcs/ectester/standalone/libs/jni/gcrypt.c +++ b/src/cz/crcs/ectester/standalone/libs/jni/gcrypt.c @@ -1,5 +1,7 @@ #include "native.h" #include +#include +#include #include #include "c_utils.h" @@ -13,7 +15,6 @@ JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_GcryptLib_create jmethodID init = (*env)->GetMethodID(env, local_provider_class, "", "(Ljava/lang/String;DLjava/lang/String;)V"); - const char *built_with = GCRYPT_VERSION; const char *running_with = gcry_check_version(GCRYPT_VERSION); if (!running_with) { return NULL; @@ -36,8 +37,18 @@ JNIEXPORT void JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeProvider_ INIT_PROVIDER(env, provider_class); ADD_KPG(env, this, "EC", "Gcrypt"); - //ADD_KA(env, self, "ECDH", "OpensslECDH"); - //ADD_SIG(env, self, "NONEwithECDSA", "OpensslECDSAwithNONE"); + ADD_KA(env, this, "ECDH", "GcryptECDH"); + ADD_SIG(env, this, "NONEwithECDSA", "GcryptECDSAwithNONE"); + ADD_SIG(env, this, "SHA1withECDSA", "GcryptECDSAwithSHA1"); + ADD_SIG(env, this, "SHA224withECDSA", "GcryptECDSAwithSHA224"); + ADD_SIG(env, this, "SHA256withECDSA", "GcryptECDSAwithSHA256"); + ADD_SIG(env, this, "SHA384withECDSA", "GcryptECDSAwithSHA384"); + ADD_SIG(env, this, "SHA512withECDSA", "GcryptECDSAwithSHA512"); + ADD_SIG(env, this, "SHA1withECDDSA", "GcryptECDDSAwithSHA1"); + ADD_SIG(env, this, "SHA224withECDDSA", "GcryptECDDSAwithSHA224"); + ADD_SIG(env, this, "SHA256withECDDSA", "GcryptECDDSAwithSHA256"); + ADD_SIG(env, this, "SHA384withECDDSA", "GcryptECDDSAwithSHA384"); + ADD_SIG(env, this, "SHA512withECDDSA", "GcryptECDDSAwithSHA512"); init_classes(env, "Gcrypt"); } @@ -82,6 +93,13 @@ static void print_sexp(gcry_sexp_t sexp) { fflush(stdout); } +static void print_chrray(unsigned char *arr, size_t len) { + for (size_t i = 0; i < len; ++i) { + printf("%02x,", ((unsigned char) arr[i] & 0xff)); + } + printf("\n"); +} + JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Gcrypt_paramsSupported(JNIEnv *env, jobject this, jobject params) { if (params == NULL) { return JNI_FALSE; @@ -105,28 +123,66 @@ JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPa } } -static jobject mpi_to_biginteger(JNIEnv *env, gcry_mpi_t mpi) { - jmethodID biginteger_init = (*env)->GetMethodID(env, biginteger_class, "", "(I[B)V"); - size_t len = 0; - gcry_mpi_print(GCRYMPI_FMT_USG, NULL, 0, &len, mpi); - jbyteArray bytes = (*env)->NewByteArray(env, len); +static gcry_mpi_t bytearray_to_mpi(JNIEnv *env, jbyteArray array) { + if (!array) { + return NULL; + } + + gcry_mpi_t result; + + size_t length = (*env)->GetArrayLength(env, array); + char data[length + 1]; + data[0] = 0; + (*env)->GetByteArrayRegion(env, array, 0, length, data + 1); + gcry_mpi_scan(&result, GCRYMPI_FMT_USG, data, length + 1, NULL); + return result; +} + +static jbyteArray mpi_to_bytearray0(JNIEnv *env, gcry_mpi_t mpi, size_t start, size_t len) { + if (!mpi) { + return NULL; + } + + size_t mpi_len = 0; + gcry_mpi_print(GCRYMPI_FMT_USG, NULL, 0, &mpi_len, mpi); + if (start >= mpi_len) { + return NULL; + } + if (start + len > mpi_len || len == 0) { + len = mpi_len - start; + } + unsigned char buff[mpi_len]; + gcry_mpi_print(GCRYMPI_FMT_USG, buff, mpi_len, NULL, mpi); + jbyteArray bytes = (*env)->NewByteArray(env, len); jbyte *data = (*env)->GetByteArrayElements(env, bytes, NULL); - gcry_mpi_print(GCRYMPI_FMT_USG, data, len, &len, mpi); + memcpy(data, buff + start, len); (*env)->ReleaseByteArrayElements(env, bytes, data, 0); + return bytes; +} + +static jbyteArray mpi_to_bytearray(JNIEnv *env, gcry_mpi_t mpi) { + return mpi_to_bytearray0(env, mpi, 0, 0); +} + +static jobject mpi_to_biginteger(JNIEnv *env, gcry_mpi_t mpi) { + if (!mpi) { + return NULL; + } + + jmethodID biginteger_init = (*env)->GetMethodID(env, biginteger_class, "", "(I[B)V"); + jbyteArray bytes = mpi_to_bytearray(env, mpi); jobject result = (*env)->NewObject(env, biginteger_class, biginteger_init, 1, bytes); return result; } static gcry_mpi_t biginteger_to_mpi(JNIEnv *env, jobject bigint) { - jmethodID to_byte_array = (*env)->GetMethodID(env, biginteger_class, "toByteArray", "()[B"); + if (!bigint) { + return NULL; + } + jmethodID to_byte_array = (*env)->GetMethodID(env, biginteger_class, "toByteArray", "()[B"); jbyteArray byte_array = (jbyteArray) (*env)->CallObjectMethod(env, bigint, to_byte_array); - jsize byte_length = (*env)->GetArrayLength(env, byte_array); - jbyte *byte_data = (*env)->GetByteArrayElements(env, byte_array, NULL); - gcry_mpi_t result; - gcry_mpi_scan(&result, GCRYMPI_FMT_USG, byte_data, byte_length, NULL); - (*env)->ReleaseByteArrayElements(env, byte_array, byte_data, JNI_ABORT); - return result; + return bytearray_to_mpi(env, byte_array); } static jint mpi_to_jint(gcry_mpi_t mpi) { @@ -144,7 +200,7 @@ static jint mpi_to_jint(gcry_mpi_t mpi) { } static jobject buff_to_ecpoint(JNIEnv *env, gcry_buffer_t buff) { - jint coord_size = (buff.size - 1) / 2; + jint coord_size = (buff.len - 1) / 2; jmethodID biginteger_init = (*env)->GetMethodID(env, biginteger_class, "", "(I[B)V"); jbyteArray x_bytes = (*env)->NewByteArray(env, coord_size); @@ -235,7 +291,7 @@ static jobject generate_from_sexp(JNIEnv *env, gcry_sexp_t gen_sexp) { 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); + jobject pubkey = (*env)->NewObject(env, pubkey_class, ec_pub_init, pub_bytes, ec_pub_param_spec); 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"); @@ -265,7 +321,6 @@ JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPai } JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Gcrypt_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)) { return NULL; } else if ((*env)->IsInstanceOf(env, params, ecgen_parameter_spec_class)) { @@ -281,4 +336,271 @@ JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPai } else { return NULL; } +} + +static gcry_sexp_t create_key(JNIEnv *env, jobject ec_param_spec, const char *key_fmt, gcry_mpi_t q, gcry_mpi_t d) { + gcry_sexp_t inner; + gcry_mpi_t p, a, b, g, n, h; + + jmethodID get_curve = (*env)->GetMethodID(env, ec_parameter_spec_class, "getCurve", "()Ljava/security/spec/EllipticCurve;"); + jobject elliptic_curve = (*env)->CallObjectMethod(env, ec_param_spec, get_curve); + + jmethodID get_field = (*env)->GetMethodID(env, elliptic_curve_class, "getField", "()Ljava/security/spec/ECField;"); + jobject field = (*env)->CallObjectMethod(env, elliptic_curve, get_field); + + jmethodID get_bits = (*env)->GetMethodID(env, fp_field_class, "getFieldSize", "()I"); + jint bits = (*env)->CallIntMethod(env, field, get_bits); + jint bytes = (bits + 7) / 8; + + jmethodID get_a = (*env)->GetMethodID(env, elliptic_curve_class, "getA", "()Ljava/math/BigInteger;"); + jobject big_a = (*env)->CallObjectMethod(env, elliptic_curve, get_a); + a = biginteger_to_mpi(env, big_a); + + jmethodID get_b = (*env)->GetMethodID(env, elliptic_curve_class, "getB", "()Ljava/math/BigInteger;"); + jobject big_b = (*env)->CallObjectMethod(env, elliptic_curve, get_b); + b = biginteger_to_mpi(env, big_b); + + jmethodID get_p = (*env)->GetMethodID(env, fp_field_class, "getP", "()Ljava/math/BigInteger;"); + jobject big_p = (*env)->CallObjectMethod(env, field, get_p); + p = biginteger_to_mpi(env, big_p); + + jmethodID get_g = (*env)->GetMethodID(env, ec_parameter_spec_class, "getGenerator", "()Ljava/security/spec/ECPoint;"); + jobject g_point = (*env)->CallObjectMethod(env, ec_param_spec, get_g); + + jmethodID get_x = (*env)->GetMethodID(env, point_class, "getAffineX", "()Ljava/math/BigInteger;"); + jobject gx = (*env)->CallObjectMethod(env, g_point, get_x); + + jmethodID get_y = (*env)->GetMethodID(env, point_class, "getAffineY", "()Ljava/math/BigInteger;"); + jobject gy = (*env)->CallObjectMethod(env, g_point, get_y); + + jmethodID to_byte_array = (*env)->GetMethodID(env, biginteger_class, "toByteArray", "()[B"); + + jbyteArray gx_bytes = (jbyteArray) (*env)->CallObjectMethod(env, gx, to_byte_array); + size_t gx_len = (*env)->GetArrayLength(env, gx_bytes); + jbyteArray gy_bytes = (jbyteArray) (*env)->CallObjectMethod(env, gy, to_byte_array); + size_t gy_len = (*env)->GetArrayLength(env, gy_bytes); + unsigned char g_data[1 + 2 * bytes]; + g_data[0] = 0x04; + jbyte *gx_data = (*env)->GetByteArrayElements(env, gx_bytes, NULL); + memcpy(g_data + 1, gx_data + (gx_len - bytes), bytes); + (*env)->ReleaseByteArrayElements(env, gx_bytes, gx_data, JNI_ABORT); + jbyte *gy_data = (*env)->GetByteArrayElements(env, gy_bytes, NULL); + memcpy(g_data + 1 + bytes, gy_data + (gy_len - bytes), bytes); + (*env)->ReleaseByteArrayElements(env, gy_bytes, gy_data, JNI_ABORT); + + gcry_mpi_scan(&g, GCRYMPI_FMT_USG, g_data, 1 + 2 * bytes, NULL); + + jmethodID get_n = (*env)->GetMethodID(env, ec_parameter_spec_class, "getOrder", "()Ljava/math/BigInteger;"); + jobject big_n = (*env)->CallObjectMethod(env, ec_param_spec, get_n); + n = biginteger_to_mpi(env, big_n); + + jmethodID get_h = (*env)->GetMethodID(env, ec_parameter_spec_class, "getCofactor", "()I"); + jint jh = (*env)->CallIntMethod(env, ec_param_spec, get_h); + h = gcry_mpi_set_ui(NULL, jh); + + if (q && d) { + gcry_sexp_build(&inner, NULL, "(ecc (flags param) (p %M) (a %M) (b %M) (g %M) (n %M) (h %M) (q %M) (d %M))", p, a, b, g, n, h, q, d, NULL); + } else if (q && !d) { + gcry_sexp_build(&inner, NULL, "(ecc (flags param) (p %M) (a %M) (b %M) (g %M) (n %M) (h %M) (q %M))", p, a, b, g, n, h, q, NULL); + } else if (!q && d) { + gcry_sexp_build(&inner, NULL, "(ecc (flags param) (p %M) (a %M) (b %M) (g %M) (n %M) (h %M) (d %M))", p, a, b, g, n, h, d, NULL); + } + gcry_sexp_t result; + gcry_sexp_build(&result, NULL, key_fmt, inner, NULL); + gcry_sexp_release(inner); + return result; +} + +static gcry_sexp_t create_pubkey(JNIEnv *env, jobject ec_param_spec, jbyteArray pubkey) { + gcry_mpi_t q = bytearray_to_mpi(env, pubkey); + gcry_sexp_t result = create_key(env, ec_param_spec, "(public-key %S)", q, NULL); + gcry_mpi_release(q); + return result; +} + +static gcry_sexp_t create_privkey(JNIEnv *env, jobject ec_param_spec, jbyteArray pubkey, jbyteArray privkey) { + gcry_mpi_t q = bytearray_to_mpi(env, pubkey); + gcry_mpi_t d = bytearray_to_mpi(env, privkey); + gcry_sexp_t result = create_key(env, ec_param_spec, "(private-key %S)", q, d); + gcry_mpi_release(q); + gcry_mpi_release(d); + return result; +} + +JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_00024Gcrypt_generateSecret___3B_3BLjava_security_spec_ECParameterSpec_2(JNIEnv *env, jobject this, jbyteArray pubkey, jbyteArray privkey, jobject params) { + jbyteArray result = NULL; + gcry_sexp_t pub = create_pubkey(env, params, pubkey); + gcry_mpi_t priv = bytearray_to_mpi(env, privkey); + + gcry_sexp_t enc_sexp; + gcry_sexp_build(&enc_sexp, NULL, "(data (flags raw) (value %M))", priv, NULL); + gcry_sexp_t res_sexp; + // TODO: figure out why ecc_encrypt_raw takes signed representation.. Nobody uses that., everybody uses unsigned reduced mod p. + gcry_error_t err = gcry_pk_encrypt(&res_sexp, enc_sexp, pub); + if (gcry_err_code(err) != GPG_ERR_NO_ERROR) { + throw_new_var(env, "java/security/GeneralSecurityException", "Error performing ECDH. Error: %ui", gcry_err_code(err)); + goto end; + } + + gcry_mpi_t derived; + err = gcry_sexp_extract_param(res_sexp, NULL, "s", &derived, NULL); + + size_t derived_bytes; + gcry_mpi_print(GCRYMPI_FMT_USG, NULL, 0, &derived_bytes, derived); + size_t coord_bytes = (derived_bytes - 1) / 2; + result = mpi_to_bytearray0(env, derived, 1, coord_bytes); + + gcry_mpi_release(derived); +end: + gcry_sexp_release(enc_sexp); + gcry_sexp_release(res_sexp); + gcry_sexp_release(pub); + gcry_mpi_release(priv); + return result; +} + +JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_00024Gcrypt_generateSecret___3B_3BLjava_security_spec_ECParameterSpec_2Ljava_lang_String_2(JNIEnv *env, jobject this, jbyteArray pubkey, jbyteArray privkey, jobject params, jstring algorithm) { + throw_new(env, "java/lang/UnsupportedOperationException", "Not supported."); + return NULL; +} + +static int starts_with(const char *whole, const char *prefix) { + return !strncmp(whole, prefix, strlen(prefix)); +} + +static int get_hash_algo(const char *sig_type) { + if (starts_with(sig_type, "SHA1")) { + return GCRY_MD_SHA1; + } else if (starts_with(sig_type, "SHA224")) { + return GCRY_MD_SHA224; + } else if (starts_with(sig_type, "SHA256")) { + return GCRY_MD_SHA256; + } else if (starts_with(sig_type, "SHA384")) { + return GCRY_MD_SHA384; + } else if (starts_with(sig_type, "SHA512")) { + return GCRY_MD_SHA512; + } else { + return GCRY_MD_NONE; + } +} + +static const char *get_sig_algo(const char *sig_type) { + const char *start = strstr(sig_type, "with") + strlen("with"); + if (starts_with(start, "ECDSA")) { + return NULL; + } else if (starts_with(start, "ECDDSA")) { + return "rfc6979"; + } else { + return NULL; + } +} + +static void get_sign_data_sexp(JNIEnv *env, gcry_sexp_t *result, jobject this, jbyteArray data) { + jclass sig_class = (*env)->FindClass(env, "cz/crcs/ectester/standalone/libs/jni/NativeSignatureSpi$Gcrypt"); + jfieldID type_id = (*env)->GetFieldID(env, sig_class, "type", "Ljava/lang/String;"); + jstring type = (jstring)(*env)->GetObjectField(env, this, type_id); + const char* type_data = (*env)->GetStringUTFChars(env, type, NULL); + int hash_algo = get_hash_algo(type_data); + const char *sig_algo = get_sig_algo(type_data); + const char *with = strstr(type_data, "with"); + char hash_name[with - type_data + 1]; + memcpy(hash_name, type_data, with - type_data); + for (size_t i = 0; i < with - type_data; ++i) { + hash_name[i] = tolower(hash_name[i]); + } + hash_name[with - type_data] = 0; + (*env)->ReleaseStringUTFChars(env, type, type_data); + + if (hash_algo == GCRY_MD_NONE) { + gcry_mpi_t data_mpi = bytearray_to_mpi(env, data); + gcry_sexp_build(result, NULL, "(data (flags raw param) (value %M))", data_mpi); + gcry_mpi_release(data_mpi); + } else { + unsigned int hash_len = gcry_md_get_algo_dlen(hash_algo); + size_t data_len = (*env)->GetArrayLength(env, data); + jbyte *data_bytes = (*env)->GetByteArrayElements(env, data, NULL); + unsigned char out_hash[hash_len]; + gcry_md_hash_buffer(hash_algo, out_hash, data_bytes, data_len); + (*env)->ReleaseByteArrayElements(env, data, data_bytes, JNI_ABORT); + gcry_mpi_t hash_mpi; + gcry_mpi_scan(&hash_mpi, GCRYMPI_FMT_USG, out_hash, hash_len, NULL); + if (!sig_algo) { + gcry_sexp_build(result, NULL, "(data (flags raw param) (value %M))", hash_mpi); + } else { + gcry_sexp_build(result, NULL, "(data (flags %s param) (hash %s %M))", sig_algo, hash_name, hash_mpi); + } + gcry_mpi_release(hash_mpi); + } +} + +JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024Gcrypt_sign(JNIEnv *env, jobject this, jbyteArray data, jbyteArray privkey, jobject params) { + jbyteArray result = NULL; + gcry_sexp_t priv_sexp = create_privkey(env, params, NULL, privkey); + + gcry_sexp_t data_sexp; + get_sign_data_sexp(env, &data_sexp, this, data); + + gcry_sexp_t res_sexp; + gcry_error_t err = gcry_pk_sign(&res_sexp, data_sexp, priv_sexp); + if (gcry_err_code(err) != GPG_ERR_NO_ERROR) { + throw_new_var(env, "java/security/GeneralSecurityException", "Error performing ECDSA. Error: %ui", gcry_err_code(err)); + goto release_init; + } + + gcry_buffer_t r_buf = {0}; + gcry_buffer_t s_buf = {0}; + err = gcry_sexp_extract_param(res_sexp, "ecdsa", "&rs", &r_buf, &s_buf, NULL); + if (gcry_err_code(err) != GPG_ERR_NO_ERROR) { + throw_new_var(env, "java/security/GeneralSecurityException", "Error extracting ECDSA output. Error: %ui", gcry_err_code(err)); + goto release_res; + } + result = asn1_der_encode(env, r_buf.data, r_buf.len, s_buf.data, s_buf.len); + + gcry_free(r_buf.data); + gcry_free(s_buf.data); +release_res: + gcry_sexp_release(res_sexp); +release_init: + gcry_sexp_release(priv_sexp); + gcry_sexp_release(data_sexp); + return result; +} + +JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024Gcrypt_verify(JNIEnv *env, jobject this, jbyteArray sig, jbyteArray data, jbyteArray pubkey, jobject params) { + jboolean result = JNI_FALSE; + gcry_sexp_t pub_sexp = create_pubkey(env, params, pubkey); + + gcry_sexp_t data_sexp; + get_sign_data_sexp(env, &data_sexp, this, data); + + size_t r_len, s_len; + jbyte *r_data, *s_data; + bool decode = asn1_der_decode(env, sig, &r_data, &r_len, &s_data, &s_len); + if (!decode) { + throw_new(env, "java/security/GeneralSecurityException", "Error decoding sig."); + goto release_init; + } + + gcry_mpi_t r_mpi, s_mpi; + gcry_mpi_scan(&r_mpi, GCRYMPI_FMT_USG, r_data, r_len, NULL); + gcry_mpi_scan(&s_mpi, GCRYMPI_FMT_USG, s_data, s_len, NULL); + free(r_data); + free(s_data); + + gcry_sexp_t sig_sexp; + gcry_sexp_build(&sig_sexp, NULL, "(sig-val (ecdsa (r %M) (s %M)))", r_mpi, s_mpi); + gcry_error_t err = gcry_pk_verify(sig_sexp, data_sexp, pub_sexp); + if (gcry_err_code(err) != GPG_ERR_NO_ERROR) { + if (gcry_err_code(err) != GPG_ERR_BAD_SIGNATURE) { + throw_new(env, "java/security/GeneralSecurityException", "Error verif sig."); + goto release_init; + } + } else { + result = JNI_TRUE; + } + +release_init: + gcry_sexp_release(pub_sexp); + gcry_sexp_release(data_sexp); + return result; } \ No newline at end of file diff --git a/src/cz/crcs/ectester/standalone/libs/jni/native.h b/src/cz/crcs/ectester/standalone/libs/jni/native.h index e86a847..47031e4 100644 --- a/src/cz/crcs/ectester/standalone/libs/jni/native.h +++ b/src/cz/crcs/ectester/standalone/libs/jni/native.h @@ -1191,3 +1191,79 @@ JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPai } #endif #endif +/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeECPublicKey_Gcrypt */ + +#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPublicKey_Gcrypt +#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPublicKey_Gcrypt +#ifdef __cplusplus +extern "C" { +#endif +#ifdef __cplusplus +} +#endif +#endif +/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeECPrivateKey_Gcrypt */ + +#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPrivateKey_Gcrypt +#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPrivateKey_Gcrypt +#ifdef __cplusplus +extern "C" { +#endif +#ifdef __cplusplus +} +#endif +#endif +/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Gcrypt */ + +#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Gcrypt +#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Gcrypt +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Gcrypt + * Method: generateSecret + * Signature: ([B[BLjava/security/spec/ECParameterSpec;)[B + */ +JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_00024Gcrypt_generateSecret___3B_3BLjava_security_spec_ECParameterSpec_2 + (JNIEnv *, jobject, jbyteArray, jbyteArray, jobject); + +/* + * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Gcrypt + * Method: generateSecret + * Signature: ([B[BLjava/security/spec/ECParameterSpec;Ljava/lang/String;)Ljavax/crypto/SecretKey; + */ +JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_00024Gcrypt_generateSecret___3B_3BLjava_security_spec_ECParameterSpec_2Ljava_lang_String_2 + (JNIEnv *, jobject, jbyteArray, jbyteArray, jobject, jstring); + +#ifdef __cplusplus +} +#endif +#endif +/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Gcrypt */ + +#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Gcrypt +#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Gcrypt +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Gcrypt + * Method: sign + * Signature: ([B[BLjava/security/spec/ECParameterSpec;)[B + */ +JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024Gcrypt_sign + (JNIEnv *, jobject, jbyteArray, jbyteArray, jobject); + +/* + * Class: cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Gcrypt + * Method: verify + * Signature: ([B[B[BLjava/security/spec/ECParameterSpec;)Z + */ +JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024Gcrypt_verify + (JNIEnv *, jobject, jbyteArray, jbyteArray, jbyteArray, jobject); + +#ifdef __cplusplus +} +#endif +#endif -- cgit v1.2.3-70-g09d2 From 0f144016e44b7e2071a6934d3a1e785c97ae8729 Mon Sep 17 00:00:00 2001 From: J08nY Date: Sun, 21 Oct 2018 14:26:26 +0200 Subject: Fix gcc and clang warnings in native sources. --- .../crcs/ectester/standalone/libs/jni/boringssl.c | 25 ++++++++----------- src/cz/crcs/ectester/standalone/libs/jni/botan.cpp | 10 +++----- src/cz/crcs/ectester/standalone/libs/jni/c_utils.c | 8 ++++++- .../crcs/ectester/standalone/libs/jni/cryptopp.cpp | 10 ++++++-- src/cz/crcs/ectester/standalone/libs/jni/gcrypt.c | 10 ++++---- src/cz/crcs/ectester/standalone/libs/jni/openssl.c | 28 ++++++++++------------ .../crcs/ectester/standalone/libs/jni/tomcrypt.c | 16 ++++++------- 7 files changed, 54 insertions(+), 53 deletions(-) (limited to 'src/cz/crcs/ectester/standalone/libs') diff --git a/src/cz/crcs/ectester/standalone/libs/jni/boringssl.c b/src/cz/crcs/ectester/standalone/libs/jni/boringssl.c index 965e396..cb1ea77 100644 --- a/src/cz/crcs/ectester/standalone/libs/jni/boringssl.c +++ b/src/cz/crcs/ectester/standalone/libs/jni/boringssl.c @@ -87,7 +87,7 @@ static jobject bignum_to_biginteger(JNIEnv *env, const BIGNUM *bn) { int size = BN_num_bytes(bn); jbyteArray bytes = (*env)->NewByteArray(env, size); jbyte *data = (*env)->GetByteArrayElements(env, bytes, NULL); - BN_bn2bin(bn, data); + BN_bn2bin(bn, (unsigned char *) data); (*env)->ReleaseByteArrayElements(env, bytes, data, 0); jobject result = (*env)->NewObject(env, biginteger_class, biginteger_init, 1, bytes); return result; @@ -99,7 +99,7 @@ static BIGNUM *biginteger_to_bignum(JNIEnv *env, jobject bigint) { jbyteArray byte_array = (jbyteArray) (*env)->CallObjectMethod(env, bigint, to_byte_array); jsize byte_length = (*env)->GetArrayLength(env, byte_array); jbyte *byte_data = (*env)->GetByteArrayElements(env, byte_array, NULL); - BIGNUM *result = BN_bin2bn(byte_data, byte_length, NULL); + BIGNUM *result = BN_bin2bn((unsigned char *) byte_data, byte_length, NULL); (*env)->ReleaseByteArrayElements(env, byte_array, byte_data, JNI_ABORT); return result; } @@ -115,10 +115,6 @@ static EC_GROUP *create_curve(JNIEnv *env, jobject params) { return NULL; } - jmethodID get_bits = (*env)->GetMethodID(env, fp_field_class, "getFieldSize", "()I"); - jint bits = (*env)->CallIntMethod(env, field, get_bits); - jint bytes = (bits + 7) / 8; - jmethodID get_a = (*env)->GetMethodID(env, elliptic_curve_class, "getA", "()Ljava/math/BigInteger;"); jobject a = (*env)->CallObjectMethod(env, elliptic_curve, get_a); BIGNUM *a_bn = biginteger_to_bignum(env, a); @@ -218,7 +214,6 @@ JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPa } static jobject create_ec_param_spec(JNIEnv *env, const EC_GROUP *curve) { - int field_type = EC_METHOD_get_field_type(EC_GROUP_method_of(curve)); BIGNUM *a; BIGNUM *b; @@ -292,13 +287,13 @@ static jobject generate_from_curve(JNIEnv *env, const EC_GROUP *curve) { jbyteArray priv_bytes = (*env)->NewByteArray(env, key_bytes); jbyte *key_priv = (*env)->GetByteArrayElements(env, priv_bytes, NULL); - BN_bn2bin_padded(key_priv, key_bytes, EC_KEY_get0_private_key(key)); + BN_bn2bin_padded((unsigned char *) key_priv, key_bytes, EC_KEY_get0_private_key(key)); (*env)->ReleaseByteArrayElements(env, priv_bytes, key_priv, 0); unsigned long key_len = 2*key_bytes + 1; jbyteArray pub_bytes = (*env)->NewByteArray(env, key_len); jbyte *key_pub = (*env)->GetByteArrayElements(env, pub_bytes, NULL); - EC_POINT_point2oct(curve, EC_KEY_get0_public_key(key), POINT_CONVERSION_UNCOMPRESSED, key_pub, key_len, NULL); + EC_POINT_point2oct(curve, EC_KEY_get0_public_key(key), POINT_CONVERSION_UNCOMPRESSED, (unsigned char *) key_pub, key_len, NULL); (*env)->ReleaseByteArrayElements(env, pub_bytes, key_pub, 0); EC_KEY_free(key); @@ -307,7 +302,7 @@ static jobject generate_from_curve(JNIEnv *env, const EC_GROUP *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); + jobject pubkey = (*env)->NewObject(env, pubkey_class, ec_pub_init, pub_bytes, ec_pub_param_spec); 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"); @@ -354,7 +349,7 @@ JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPai size_t ncurves = EC_get_builtin_curves(NULL, 0); EC_builtin_curve curves[ncurves]; EC_get_builtin_curves(curves, ncurves); - EC_GROUP *curve; + EC_GROUP *curve = NULL; for (size_t i = 0; i < ncurves; ++i) { if (strcasecmp(utf_name, OBJ_nid2sn(curves[i].nid)) == 0) { curve = EC_GROUP_new_by_curve_name(curves[i].nid); @@ -381,7 +376,7 @@ EC_KEY *barray_to_pubkey(JNIEnv *env, const EC_GROUP *curve, jbyteArray pub) { jsize pub_len = (*env)->GetArrayLength(env, pub); jbyte *pub_data = (*env)->GetByteArrayElements(env, pub, NULL); EC_POINT *pub_point = EC_POINT_new(curve); - EC_POINT_oct2point(curve, pub_point, pub_data, pub_len, NULL); + EC_POINT_oct2point(curve, pub_point, (unsigned char *) pub_data, pub_len, NULL); (*env)->ReleaseByteArrayElements(env, pub, pub_data, JNI_ABORT); EC_KEY_set_public_key(result, pub_point); EC_POINT_free(pub_point); @@ -393,7 +388,7 @@ EC_KEY *barray_to_privkey(JNIEnv *env, const EC_GROUP *curve, jbyteArray priv) EC_KEY_set_group(result, curve); jsize priv_len = (*env)->GetArrayLength(env, priv); jbyte *priv_data = (*env)->GetByteArrayElements(env, priv, NULL); - BIGNUM *s = BN_bin2bn(priv_data, priv_len, NULL); + BIGNUM *s = BN_bin2bn((unsigned char *) priv_data, priv_len, NULL); (*env)->ReleaseByteArrayElements(env, priv, priv_data, JNI_ABORT); EC_KEY_set_private_key(result, s); BN_free(s); @@ -448,7 +443,7 @@ JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSig jsize data_size = (*env)->GetArrayLength(env, data); jbyte *data_data = (*env)->GetByteArrayElements(env, data, NULL); // TODO: Do more Signatures here, maybe use the EVP interface to get to the hashes easier and not hash manually? - ECDSA_SIG *signature = ECDSA_do_sign(data_data, data_size, priv); + ECDSA_SIG *signature = ECDSA_do_sign((unsigned char *) data_data, data_size, priv); (*env)->ReleaseByteArrayElements(env, data, data_data, JNI_ABORT); if (!signature) { throw_new(env, "java/security/GeneralSecurityException", "Error signing, ECDSA_do_sign."); @@ -486,7 +481,7 @@ JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSigna jsize data_size = (*env)->GetArrayLength(env, data); jbyte *data_data = (*env)->GetByteArrayElements(env, data, NULL); - int result = ECDSA_do_verify(data_data, data_size, sig_obj, pub); + int result = ECDSA_do_verify((unsigned char *) data_data, data_size, sig_obj, pub); if (result < 0) { throw_new(env, "java/security/GeneralSecurityException", "Error verifying, ECDSA_do_verify."); EC_KEY_free(pub); EC_GROUP_free(curve); ECDSA_SIG_free(sig_obj); diff --git a/src/cz/crcs/ectester/standalone/libs/jni/botan.cpp b/src/cz/crcs/ectester/standalone/libs/jni/botan.cpp index 207532d..5de9dd3 100644 --- a/src/cz/crcs/ectester/standalone/libs/jni/botan.cpp +++ b/src/cz/crcs/ectester/standalone/libs/jni/botan.cpp @@ -145,7 +145,7 @@ static Botan::BigInt bigint_from_biginteger(JNIEnv *env, jobject biginteger) { jbyteArray byte_array = (jbyteArray) env->CallObjectMethod(biginteger, to_byte_array); jsize byte_length = env->GetArrayLength(byte_array); jbyte *byte_data = env->GetByteArrayElements(byte_array, NULL); - Botan::BigInt result((unsigned uint8_t*) byte_data, byte_length); + Botan::BigInt result((unsigned char *) byte_data, byte_length); env->ReleaseByteArrayElements(byte_array, byte_data, JNI_ABORT); return result; } @@ -157,10 +157,6 @@ static Botan::EC_Group group_from_params(JNIEnv *env, jobject params) { jmethodID get_field = env->GetMethodID(elliptic_curve_class, "getField", "()Ljava/security/spec/ECField;"); jobject field = env->CallObjectMethod(elliptic_curve, get_field); - - jmethodID get_bits = env->GetMethodID(fp_field_class, "getFieldSize", "()I"); - jint bits = env->CallIntMethod(field, get_bits); - jint bytes = (bits + 7) / 8; jmethodID get_a = env->GetMethodID(elliptic_curve_class, "getA", "()Ljava/math/BigInteger;"); jobject a = env->CallObjectMethod(elliptic_curve, get_a); @@ -299,7 +295,7 @@ JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPai for (auto it = curves.begin(); it != curves.end(); ++it) { Botan::EC_Group curve_group = Botan::EC_Group(*it); size_t curve_size = curve_group.get_p_bits(); - if (curve_size == keysize) { + if (curve_size == (size_t) keysize) { //generate on this group. Even thou no default groups are present... return generate_from_group(env, self, curve_group); } @@ -349,7 +345,7 @@ jbyteArray generate_secret(JNIEnv *env, jobject self, jbyteArray pubkey, jbyteAr jsize privkey_length = env->GetArrayLength(privkey); jbyte *privkey_data = env->GetByteArrayElements(privkey, NULL); - Botan::BigInt privkey_scalar((unsigned uint8_t*) privkey_data, privkey_length); + Botan::BigInt privkey_scalar((unsigned char *) privkey_data, privkey_length); env->ReleaseByteArrayElements(privkey, privkey_data, JNI_ABORT); Botan::AutoSeeded_RNG rng; diff --git a/src/cz/crcs/ectester/standalone/libs/jni/c_utils.c b/src/cz/crcs/ectester/standalone/libs/jni/c_utils.c index c36d3c9..81d1fb8 100644 --- a/src/cz/crcs/ectester/standalone/libs/jni/c_utils.c +++ b/src/cz/crcs/ectester/standalone/libs/jni/c_utils.c @@ -198,10 +198,16 @@ bool asn1_der_decode(JNIEnv *env, jbyteArray sig, jbyte **r_data, size_t *r_len, memcpy(s_out, data + i, s_length); i += s_length; + (*env)->ReleaseByteArrayElements(env, sig, data, JNI_ABORT); + if (i != sig_len) { + free(r_out); + free(s_out); + return false; + } + *r_len = r_length; *r_data = r_out; *s_len = s_length; *s_data = s_out; - (*env)->ReleaseByteArrayElements(env, sig, data, JNI_ABORT); return true; } \ No newline at end of file diff --git a/src/cz/crcs/ectester/standalone/libs/jni/cryptopp.cpp b/src/cz/crcs/ectester/standalone/libs/jni/cryptopp.cpp index 32121c5..1e212de 100644 --- a/src/cz/crcs/ectester/standalone/libs/jni/cryptopp.cpp +++ b/src/cz/crcs/ectester/standalone/libs/jni/cryptopp.cpp @@ -89,7 +89,7 @@ JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_CryptoppLib_crea std::stringstream ss; ss << lib_name << " "; ss << info_str[0]; - for (int i = 1; i < info_str.size(); ++i) { + for (size_t i = 1; i < info_str.size(); ++i) { ss << "." << info_str[i]; } @@ -470,6 +470,8 @@ template <> jobject params_from_group(JNIEnv *env, DL_GroupParameters_ECNewIntArray(3); to_find = 3; + } else { + return NULL; } jint *ks_data = env->GetIntArrayElements(ks, NULL); for (int i = m - 1; i > 0 && found < to_find; --i) { @@ -594,6 +596,10 @@ JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKey return NULL; } } + if (!success) { + throw_new(env, "java/security/GeneralSecurityException", "Agreement was unsuccessful."); + return NULL; + } jbyteArray result = env->NewByteArray(secret->size()); jbyte *result_data = env->GetByteArrayElements(result, NULL); @@ -648,7 +654,7 @@ JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSig Integer private_key_x((byte *) privkey_data, (size_t) privkey_length); env->ReleaseByteArrayElements(privkey, privkey_data, JNI_ABORT); - jbyteArray result; + jbyteArray result = NULL; std::unique_ptr> ecp_group = fp_group_from_params(env, params); if (ecp_group == nullptr) { diff --git a/src/cz/crcs/ectester/standalone/libs/jni/gcrypt.c b/src/cz/crcs/ectester/standalone/libs/jni/gcrypt.c index 0ba94c6..1186d30 100644 --- a/src/cz/crcs/ectester/standalone/libs/jni/gcrypt.c +++ b/src/cz/crcs/ectester/standalone/libs/jni/gcrypt.c @@ -85,6 +85,7 @@ JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPa return JNI_FALSE; } +/* static void print_sexp(gcry_sexp_t sexp) { size_t len = gcry_sexp_sprint(sexp, GCRYSEXP_FMT_ADVANCED, NULL, 0); char string[len]; @@ -99,6 +100,7 @@ static void print_chrray(unsigned char *arr, size_t len) { } printf("\n"); } +*/ JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Gcrypt_paramsSupported(JNIEnv *env, jobject this, jobject params) { if (params == NULL) { @@ -131,7 +133,7 @@ static gcry_mpi_t bytearray_to_mpi(JNIEnv *env, jbyteArray array) { gcry_mpi_t result; size_t length = (*env)->GetArrayLength(env, array); - char data[length + 1]; + jbyte data[length + 1]; data[0] = 0; (*env)->GetByteArrayRegion(env, array, 0, length, data + 1); gcry_mpi_scan(&result, GCRYMPI_FMT_USG, data, length + 1, NULL); @@ -286,7 +288,7 @@ static jobject generate_from_sexp(JNIEnv *env, gcry_sexp_t gen_sexp) { gcry_mpi_print(GCRYMPI_FMT_USG, NULL, 0, &priv_len, d); jbyteArray priv_bytes = (*env)->NewByteArray(env, priv_len); jbyte *key_priv = (*env)->GetByteArrayElements(env, priv_bytes, NULL); - gcry_mpi_print(GCRYMPI_FMT_USG, key_priv, priv_len, NULL, d); + gcry_mpi_print(GCRYMPI_FMT_USG, (unsigned char *) key_priv, priv_len, NULL, d); (*env)->ReleaseByteArrayElements(env, priv_bytes, key_priv, 0); jobject ec_pub_param_spec = (*env)->NewLocalRef(env, ec_param_spec); @@ -339,7 +341,6 @@ JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPai } static gcry_sexp_t create_key(JNIEnv *env, jobject ec_param_spec, const char *key_fmt, gcry_mpi_t q, gcry_mpi_t d) { - gcry_sexp_t inner; gcry_mpi_t p, a, b, g, n, h; jmethodID get_curve = (*env)->GetMethodID(env, ec_parameter_spec_class, "getCurve", "()Ljava/security/spec/EllipticCurve;"); @@ -397,7 +398,8 @@ static gcry_sexp_t create_key(JNIEnv *env, jobject ec_param_spec, const char *ke jmethodID get_h = (*env)->GetMethodID(env, ec_parameter_spec_class, "getCofactor", "()I"); jint jh = (*env)->CallIntMethod(env, ec_param_spec, get_h); h = gcry_mpi_set_ui(NULL, jh); - + + gcry_sexp_t inner = NULL; if (q && d) { gcry_sexp_build(&inner, NULL, "(ecc (flags param) (p %M) (a %M) (b %M) (g %M) (n %M) (h %M) (q %M) (d %M))", p, a, b, g, n, h, q, d, NULL); } else if (q && !d) { diff --git a/src/cz/crcs/ectester/standalone/libs/jni/openssl.c b/src/cz/crcs/ectester/standalone/libs/jni/openssl.c index 4ea5f6c..639503a 100644 --- a/src/cz/crcs/ectester/standalone/libs/jni/openssl.c +++ b/src/cz/crcs/ectester/standalone/libs/jni/openssl.c @@ -87,7 +87,7 @@ static jobject bignum_to_biginteger(JNIEnv *env, const BIGNUM *bn) { int size = BN_num_bytes(bn); jbyteArray bytes = (*env)->NewByteArray(env, size); jbyte *data = (*env)->GetByteArrayElements(env, bytes, NULL); - BN_bn2bin(bn, data); + BN_bn2bin(bn, (unsigned char *) data); (*env)->ReleaseByteArrayElements(env, bytes, data, 0); jobject result = (*env)->NewObject(env, biginteger_class, biginteger_init, 1, bytes); return result; @@ -99,7 +99,7 @@ static BIGNUM *biginteger_to_bignum(JNIEnv *env, jobject bigint) { jbyteArray byte_array = (jbyteArray) (*env)->CallObjectMethod(env, bigint, to_byte_array); jsize byte_length = (*env)->GetArrayLength(env, byte_array); jbyte *byte_data = (*env)->GetByteArrayElements(env, byte_array, NULL); - BIGNUM *result = BN_bin2bn(byte_data, byte_length, NULL); + BIGNUM *result = BN_bin2bn((unsigned char *) byte_data, byte_length, NULL); (*env)->ReleaseByteArrayElements(env, byte_array, byte_data, JNI_ABORT); return result; } @@ -111,10 +111,6 @@ static EC_GROUP *create_curve(JNIEnv *env, jobject params) { jmethodID get_field = (*env)->GetMethodID(env, elliptic_curve_class, "getField", "()Ljava/security/spec/ECField;"); jobject field = (*env)->CallObjectMethod(env, elliptic_curve, get_field); - jmethodID get_bits = (*env)->GetMethodID(env, fp_field_class, "getFieldSize", "()I"); - jint bits = (*env)->CallIntMethod(env, field, get_bits); - jint bytes = (bits + 7) / 8; - jmethodID get_a = (*env)->GetMethodID(env, elliptic_curve_class, "getA", "()Ljava/math/BigInteger;"); jobject a = (*env)->CallObjectMethod(env, elliptic_curve, get_a); BIGNUM *a_bn = biginteger_to_bignum(env, a); @@ -285,7 +281,7 @@ static jobject create_ec_param_spec(JNIEnv *env, const EC_GROUP *curve) { if (basis_type == NID_X9_62_tpBasis) { ks = (*env)->NewIntArray(env, 1); ks_data = (*env)->GetIntArrayElements(env, ks, NULL); - if (!EC_GROUP_get_trinomial_basis(curve, &ks_data[0])) { + if (!EC_GROUP_get_trinomial_basis(curve, (unsigned int *) &ks_data[0])) { throw_new(env, "java/security/InvalidAlgorithmParameterException", "Error creating ECParameterSpec, EC_GROUP_get_trinomial_basis."); BN_free(a); BN_free(b); (*env)->ReleaseIntArrayElements(env, ks, ks_data, JNI_ABORT); @@ -294,7 +290,7 @@ static jobject create_ec_param_spec(JNIEnv *env, const EC_GROUP *curve) { } else if (basis_type == NID_X9_62_ppBasis) { ks = (*env)->NewIntArray(env, 3); ks_data = (*env)->GetIntArrayElements(env, ks, NULL); - if (!EC_GROUP_get_pentanomial_basis(curve, &ks_data[0], &ks_data[1], &ks_data[2])) { + if (!EC_GROUP_get_pentanomial_basis(curve, (unsigned int *) &ks_data[0], (unsigned int *) &ks_data[1], (unsigned int *) &ks_data[2])) { throw_new(env, "java/security/InvalidAlgorithmParameterException", "Error creating ECParameterSpec, EC_GROUP_get_pentanomial_basis."); BN_free(a); BN_free(b); (*env)->ReleaseIntArrayElements(env, ks, ks_data, JNI_ABORT); @@ -360,13 +356,13 @@ static jobject generate_from_curve(JNIEnv *env, const EC_GROUP *curve) { jbyteArray priv_bytes = (*env)->NewByteArray(env, key_bytes); jbyte *key_priv = (*env)->GetByteArrayElements(env, priv_bytes, NULL); - BN_bn2binpad(EC_KEY_get0_private_key(key), key_priv, key_bytes); + BN_bn2binpad(EC_KEY_get0_private_key(key), (unsigned char *) key_priv, key_bytes); (*env)->ReleaseByteArrayElements(env, priv_bytes, key_priv, 0); unsigned long key_len = 2*key_bytes + 1; jbyteArray pub_bytes = (*env)->NewByteArray(env, key_len); jbyte *key_pub = (*env)->GetByteArrayElements(env, pub_bytes, NULL); - EC_POINT_point2oct(curve, EC_KEY_get0_public_key(key), POINT_CONVERSION_UNCOMPRESSED, key_pub, key_len, NULL); + EC_POINT_point2oct(curve, EC_KEY_get0_public_key(key), POINT_CONVERSION_UNCOMPRESSED, (unsigned char *) key_pub, key_len, NULL); (*env)->ReleaseByteArrayElements(env, pub_bytes, key_pub, 0); EC_KEY_free(key); @@ -375,7 +371,7 @@ static jobject generate_from_curve(JNIEnv *env, const EC_GROUP *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); + jobject pubkey = (*env)->NewObject(env, pubkey_class, ec_pub_init, pub_bytes, ec_pub_param_spec); 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"); @@ -422,7 +418,7 @@ JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPai size_t ncurves = EC_get_builtin_curves(NULL, 0); EC_builtin_curve curves[ncurves]; EC_get_builtin_curves(curves, ncurves); - EC_GROUP *curve; + EC_GROUP *curve = NULL; for (size_t i = 0; i < ncurves; ++i) { if (strcasecmp(utf_name, OBJ_nid2sn(curves[i].nid)) == 0) { curve = EC_GROUP_new_by_curve_name(curves[i].nid); @@ -449,7 +445,7 @@ EC_KEY *barray_to_pubkey(JNIEnv *env, const EC_GROUP *curve, jbyteArray pub) { jsize pub_len = (*env)->GetArrayLength(env, pub); jbyte *pub_data = (*env)->GetByteArrayElements(env, pub, NULL); EC_POINT *pub_point = EC_POINT_new(curve); - EC_POINT_oct2point(curve, pub_point, pub_data, pub_len, NULL); + EC_POINT_oct2point(curve, pub_point, (unsigned char *) pub_data, pub_len, NULL); (*env)->ReleaseByteArrayElements(env, pub, pub_data, JNI_ABORT); EC_KEY_set_public_key(result, pub_point); EC_POINT_free(pub_point); @@ -461,7 +457,7 @@ EC_KEY *barray_to_privkey(JNIEnv *env, const EC_GROUP *curve, jbyteArray priv) EC_KEY_set_group(result, curve); jsize priv_len = (*env)->GetArrayLength(env, priv); jbyte *priv_data = (*env)->GetByteArrayElements(env, priv, NULL); - BIGNUM *s = BN_bin2bn(priv_data, priv_len, NULL); + BIGNUM *s = BN_bin2bn((unsigned char *) priv_data, priv_len, NULL); (*env)->ReleaseByteArrayElements(env, priv, priv_data, JNI_ABORT); EC_KEY_set_private_key(result, s); BN_free(s); @@ -516,7 +512,7 @@ JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSig jsize data_size = (*env)->GetArrayLength(env, data); jbyte *data_data = (*env)->GetByteArrayElements(env, data, NULL); // TODO: Do more Signatures here, maybe use the EVP interface to get to the hashes easier and not hash manually? - ECDSA_SIG *signature = ECDSA_do_sign(data_data, data_size, priv); + ECDSA_SIG *signature = ECDSA_do_sign((unsigned char *) data_data, data_size, priv); (*env)->ReleaseByteArrayElements(env, data, data_data, JNI_ABORT); if (!signature) { throw_new(env, "java/security/GeneralSecurityException", "Error signing, ECDSA_do_sign."); @@ -554,7 +550,7 @@ JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSigna jsize data_size = (*env)->GetArrayLength(env, data); jbyte *data_data = (*env)->GetByteArrayElements(env, data, NULL); - int result = ECDSA_do_verify(data_data, data_size, sig_obj, pub); + int result = ECDSA_do_verify((unsigned char *) data_data, data_size, sig_obj, pub); if (result < 0) { throw_new(env, "java/security/GeneralSecurityException", "Error verifying, ECDSA_do_verify."); EC_KEY_free(pub); EC_GROUP_free(curve); ECDSA_SIG_free(sig_obj); diff --git a/src/cz/crcs/ectester/standalone/libs/jni/tomcrypt.c b/src/cz/crcs/ectester/standalone/libs/jni/tomcrypt.c index fdf5663..49e997a 100644 --- a/src/cz/crcs/ectester/standalone/libs/jni/tomcrypt.c +++ b/src/cz/crcs/ectester/standalone/libs/jni/tomcrypt.c @@ -251,18 +251,18 @@ static jobject generate_from_curve(JNIEnv *env, const ltc_ecc_set_type *curve) { 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); + ecc_ansi_x963_export(&key, (unsigned char *) 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); + jobject pubkey = (*env)->NewObject(env, pubkey_class, ec_pub_init, pub_bytes, ec_pub_param_spec); jbyteArray priv_bytes = (*env)->NewByteArray(env, curve->size); jbyte *key_priv = (*env)->GetByteArrayElements(env, priv_bytes, NULL); - ltc_mp.unsigned_write(key.k, key_priv); + ltc_mp.unsigned_write(key.k, (unsigned char *) key_priv); (*env)->ReleaseByteArrayElements(env, priv_bytes, key_priv, 0); jobject ec_priv_param_spec = (*env)->NewLocalRef(env, ec_param_spec); @@ -334,7 +334,7 @@ static jboolean privkey_from_bytes(JNIEnv *env, jbyteArray privkey, const ltc_ec out->idx = -1; out->dp = curve; ltc_mp.init(&out->k); - ltc_mp.unsigned_read(out->k, priv_data, (unsigned long) curve->size); + ltc_mp.unsigned_read(out->k, (unsigned char *) priv_data, (unsigned long) curve->size); (*env)->ReleaseByteArrayElements(env, privkey, priv_data, JNI_ABORT); return JNI_TRUE; @@ -355,8 +355,8 @@ static jboolean pubkey_from_bytes(JNIEnv *env, jbyteArray pubkey, const ltc_ecc_ 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); + ltc_mp.unsigned_read(out->pubkey.x, (unsigned char *) pub_data + 1, (unsigned long) curve->size); + ltc_mp.unsigned_read(out->pubkey.y, (unsigned char *) pub_data + 1 + curve->size, (unsigned long) curve->size); (*env)->ReleaseByteArrayElements(env, pubkey, pub_data, JNI_ABORT); @@ -417,7 +417,7 @@ JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSig 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) { + if ((err = ecc_sign_hash((unsigned char *) 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(curve); (*env)->ReleaseByteArrayElements(env, data, data_data, JNI_ABORT); @@ -452,7 +452,7 @@ JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSigna int err; int result; - if ((err = ecc_verify_hash(sig_data, sig_size, data_data, data_size, &result, &pub)) != CRYPT_OK) { + if ((err = ecc_verify_hash((unsigned char *) sig_data, sig_size, (unsigned char *) data_data, data_size, &result, &pub)) != CRYPT_OK) { throw_new(env, "java/security/GeneralSecurityException", error_to_string(err)); free_curve(curve); (*env)->ReleaseByteArrayElements(env, data, data_data, JNI_ABORT); -- cgit v1.2.3-70-g09d2 From c241bf27a9afc5ac8cb69072f3d732ae1dbf413c Mon Sep 17 00:00:00 2001 From: J08nY Date: Mon, 22 Oct 2018 00:00:42 +0200 Subject: Efficiently instantiate prngs in shims. --- build-standalone.xml | 3 +- nbproject/reader/project.properties | 4 +-- nbproject/standalone/project.properties | 4 +-- src/cz/crcs/ectester/standalone/libs/jni/botan.cpp | 39 ++++++++++------------ .../crcs/ectester/standalone/libs/jni/cryptopp.cpp | 6 ++-- 5 files changed, 25 insertions(+), 31 deletions(-) (limited to 'src/cz/crcs/ectester/standalone/libs') diff --git a/build-standalone.xml b/build-standalone.xml index 62b7813..9382a8f 100644 --- a/build-standalone.xml +++ b/build-standalone.xml @@ -118,7 +118,8 @@ - + + diff --git a/nbproject/reader/project.properties b/nbproject/reader/project.properties index 8e11520..c00c309 100644 --- a/nbproject/reader/project.properties +++ b/nbproject/reader/project.properties @@ -6,7 +6,7 @@ annotation.processing.source.output=${build.generated.sources.dir}/ap-source-out application.title=ECTesterReader application.vendor=xsvenda build.classes.dir=${build.dir}/classes -build.classes.excludes=**/*.java,**/*.form,**/*.c,**/*.cpp,**/*.hpp,**/*.h,**/*.a,**/*.o,**/Makefile +build.classes.excludes=**/*.java,**/*.form,**/*.c,**/*.cpp,**/*.hpp,**/*.h,**/*.a,**/*.o,**/*.so,**/Makefile,**/Makefile.bat # This directory is removed when the project is cleaned: build.dir=build build.generated.dir=${build.dir}/generated @@ -22,7 +22,7 @@ debug.classpath=\ debug.test.classpath=\ ${run.test.classpath} # Files in build.classes.dir which should be excluded from distribution jar -dist.archive.excludes= +dist.archive.excludes=**/*.java,**/*.form,**/*.c,**/*.cpp,**/*.hpp,**/*.h,**/*.a,**/*.o,**/*.so,**/Makefile,**/Makefile.bat # This directory is removed when the project is cleaned: dist.dir=dist dist.jar=${dist.dir}/ECTesterReader.jar diff --git a/nbproject/standalone/project.properties b/nbproject/standalone/project.properties index 7ad08a1..6b6d440 100644 --- a/nbproject/standalone/project.properties +++ b/nbproject/standalone/project.properties @@ -6,7 +6,7 @@ annotation.processing.source.output=${build.generated.sources.dir}/ap-source-out application.title=ECTesterStandalone application.vendor=xsvenda build.classes.dir=${build.dir}/classes -build.classes.excludes=**/*.java,**/*.form,**/*.c,**/*.cpp,**/*.hpp,**/*.h,**/*.a,**/*.o,**/Makefile +build.classes.excludes=**/*.java,**/*.form,**/*.c,**/*.cpp,**/*.hpp,**/*.h,**/*.a,**/*.o,**/Makefile,**/Makefile.bat # This directory is removed when the project is cleaned: build.dir=build build.generated.dir=${build.dir}/generated @@ -22,7 +22,7 @@ debug.classpath=\ debug.test.classpath=\ ${run.test.classpath} # Files in build.classes.dir which should be excluded from distribution jar -dist.archive.excludes=**/*.java,**/*.form,**/*.c,**/*.cpp,**/*.hpp,**/*.h,**/*.a,**/*.o,**/Makefile +dist.archive.excludes=**/*.java,**/*.form,**/*.c,**/*.cpp,**/*.hpp,**/*.h,**/*.a,**/*.o,**/Makefile,**/Makefile.bat # This directory is removed when the project is cleaned: dist.dir=dist dist.jar=${dist.dir}/ECTesterStandalone.jar diff --git a/src/cz/crcs/ectester/standalone/libs/jni/botan.cpp b/src/cz/crcs/ectester/standalone/libs/jni/botan.cpp index 5de9dd3..b7940df 100644 --- a/src/cz/crcs/ectester/standalone/libs/jni/botan.cpp +++ b/src/cz/crcs/ectester/standalone/libs/jni/botan.cpp @@ -19,6 +19,7 @@ #include "cpp_utils.hpp" static jclass provider_class; +static Botan::AutoSeeded_RNG rng; JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_BotanLib_createProvider(JNIEnv *env, jobject self) { /* Create the custom provider. */ @@ -234,8 +235,6 @@ static jobject params_from_group(JNIEnv *env, Botan::EC_Group group) { } static jobject generate_from_group(JNIEnv* env, jobject self, Botan::EC_Group group) { - Botan::AutoSeeded_RNG rng; - jclass botan_kpg_class = env->FindClass("cz/crcs/ectester/standalone/libs/jni/NativeKeyPairGeneratorSpi$Botan"); jfieldID type_id = env->GetFieldID(botan_kpg_class, "type", "Ljava/lang/String;"); jstring type = (jstring) env->GetObjectField(self, type_id); @@ -348,8 +347,6 @@ jbyteArray generate_secret(JNIEnv *env, jobject self, jbyteArray pubkey, jbyteAr Botan::BigInt privkey_scalar((unsigned char *) privkey_data, privkey_length); env->ReleaseByteArrayElements(privkey, privkey_data, JNI_ABORT); - Botan::AutoSeeded_RNG rng; - Botan::ECDH_PrivateKey skey(rng, curve_group, privkey_scalar); jsize pubkey_length = env->GetArrayLength(pubkey); @@ -415,8 +412,6 @@ JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSig Botan::BigInt privkey_scalar((uint8_t*) privkey_bytes, privkey_length); env->ReleaseByteArrayElements(privkey, privkey_bytes, JNI_ABORT); - Botan::AutoSeeded_RNG rng; - std::unique_ptr skey; if (type_str.find("ECDSA") != std::string::npos) { skey = std::make_unique(rng, curve_group, privkey_scalar); @@ -426,22 +421,22 @@ JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSig skey = std::make_unique(rng, curve_group, privkey_scalar); } - std::string kdf; + std::string emsa; if (type_str.find("NONE") != std::string::npos) { - kdf = "Raw"; + emsa = "Raw"; } else if (type_str.find("SHA1") != std::string::npos) { - kdf = "EMSA1(SHA-1)"; + emsa = "EMSA1(SHA-1)"; } else if (type_str.find("SHA224") != std::string::npos) { - kdf = "EMSA1(SHA-224)"; + emsa = "EMSA1(SHA-224)"; } else if (type_str.find("SHA256") != std::string::npos) { - kdf = "EMSA1(SHA-256)"; + emsa = "EMSA1(SHA-256)"; } else if (type_str.find("SHA384") != std::string::npos) { - kdf = "EMSA1(SHA-384)"; + emsa = "EMSA1(SHA-384)"; } else if (type_str.find("SHA512") != std::string::npos) { - kdf = "EMSA1(SHA-512)"; + emsa = "EMSA1(SHA-512)"; } - Botan::PK_Signer signer(*skey, rng, kdf, Botan::DER_SEQUENCE); + Botan::PK_Signer signer(*skey, rng, emsa, Botan::DER_SEQUENCE); jsize data_length = env->GetArrayLength(data); jbyte *data_bytes = env->GetByteArrayElements(data, NULL); @@ -487,22 +482,22 @@ JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSigna pkey = std::make_unique(curve_group, public_point); } - std::string kdf; + std::string emsa; if (type_str.find("NONE") != std::string::npos) { - kdf = "Raw"; + emsa = "Raw"; } else if (type_str.find("SHA1") != std::string::npos) { - kdf = "EMSA1(SHA-1)"; + emsa = "EMSA1(SHA-1)"; } else if (type_str.find("SHA224") != std::string::npos) { - kdf = "EMSA1(SHA-224)"; + emsa = "EMSA1(SHA-224)"; } else if (type_str.find("SHA256") != std::string::npos) { - kdf = "EMSA1(SHA-256)"; + emsa = "EMSA1(SHA-256)"; } else if (type_str.find("SHA384") != std::string::npos) { - kdf = "EMSA1(SHA-384)"; + emsa = "EMSA1(SHA-384)"; } else if (type_str.find("SHA512") != std::string::npos) { - kdf = "EMSA1(SHA-512)"; + emsa = "EMSA1(SHA-512)"; } - Botan::PK_Verifier verifier(*pkey, kdf, Botan::DER_SEQUENCE); + Botan::PK_Verifier verifier(*pkey, emsa, Botan::DER_SEQUENCE); jsize data_length = env->GetArrayLength(data); jsize sig_length = env->GetArrayLength(signature); diff --git a/src/cz/crcs/ectester/standalone/libs/jni/cryptopp.cpp b/src/cz/crcs/ectester/standalone/libs/jni/cryptopp.cpp index 1e212de..f14aa97 100644 --- a/src/cz/crcs/ectester/standalone/libs/jni/cryptopp.cpp +++ b/src/cz/crcs/ectester/standalone/libs/jni/cryptopp.cpp @@ -23,7 +23,6 @@ using CryptoPP::byte; #include "cryptopp/osrng.h" using CryptoPP::AutoSeededRandomPool; -using CryptoPP::AutoSeededX917RNG; #include "cryptopp/sha.h" using CryptoPP::SHA1; @@ -73,6 +72,7 @@ using CryptoPP::Integer; #include "cpp_utils.hpp" static jclass provider_class; +static AutoSeededRandomPool rng; JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_CryptoppLib_createProvider(JNIEnv *env, jobject self) { @@ -494,7 +494,6 @@ template <> jobject params_from_group(JNIEnv *env, DL_GroupParameters_EC jobject generate_from_group(JNIEnv *env, DL_GroupParameters_EC group, jobject params) { - AutoSeededRandomPool rng; typename ECDH::Domain ec_domain(group); SecByteBlock priv(ec_domain.PrivateKeyLength()), pub(ec_domain.PublicKeyLength()); @@ -616,7 +615,6 @@ JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgr template jbyteArray sign_message(JNIEnv *env, DL_GroupParameters_EC group, jbyteArray data, const Integer & private_key_x) { - AutoSeededRandomPool prng; typename ECDSA::PrivateKey pkey; pkey.Initialize(group, private_key_x); @@ -626,7 +624,7 @@ jbyteArray sign_message(JNIEnv *env, DL_GroupParameters_EC group, jbyteArray jsize data_length = env->GetArrayLength(data); jbyte *data_bytes = env->GetByteArrayElements(data, NULL); - size_t len = signer.SignMessage(prng, (byte *)data_bytes, data_length, (byte *)signature.c_str()); + size_t len = signer.SignMessage(rng, (byte *)data_bytes, data_length, (byte *)signature.c_str()); env->ReleaseByteArrayElements(data, data_bytes, JNI_ABORT); signature.resize(len); -- cgit v1.2.3-70-g09d2 From 7c3a97023703180ec6af60c27738d6d1294a0d17 Mon Sep 17 00:00:00 2001 From: J08nY Date: Tue, 30 Oct 2018 23:47:01 +0100 Subject: Fix gcrypt ecdh and ecdsa. --- src/cz/crcs/ectester/standalone/libs/jni/gcrypt.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/cz/crcs/ectester/standalone/libs') diff --git a/src/cz/crcs/ectester/standalone/libs/jni/gcrypt.c b/src/cz/crcs/ectester/standalone/libs/jni/gcrypt.c index 1186d30..9590d0a 100644 --- a/src/cz/crcs/ectester/standalone/libs/jni/gcrypt.c +++ b/src/cz/crcs/ectester/standalone/libs/jni/gcrypt.c @@ -136,7 +136,7 @@ static gcry_mpi_t bytearray_to_mpi(JNIEnv *env, jbyteArray array) { jbyte data[length + 1]; data[0] = 0; (*env)->GetByteArrayRegion(env, array, 0, length, data + 1); - gcry_mpi_scan(&result, GCRYMPI_FMT_USG, data, length + 1, NULL); + gcry_mpi_scan(&result, GCRYMPI_FMT_STD, data, length + 1, NULL); return result; } @@ -401,11 +401,11 @@ static gcry_sexp_t create_key(JNIEnv *env, jobject ec_param_spec, const char *ke gcry_sexp_t inner = NULL; if (q && d) { - gcry_sexp_build(&inner, NULL, "(ecc (flags param) (p %M) (a %M) (b %M) (g %M) (n %M) (h %M) (q %M) (d %M))", p, a, b, g, n, h, q, d, NULL); + gcry_sexp_build(&inner, NULL, "(ecc (flags param) (p %m) (a %m) (b %m) (g %m) (n %m) (h %m) (q %M) (d %M))", p, a, b, g, n, h, q, d, NULL); } else if (q && !d) { - gcry_sexp_build(&inner, NULL, "(ecc (flags param) (p %M) (a %M) (b %M) (g %M) (n %M) (h %M) (q %M))", p, a, b, g, n, h, q, NULL); + gcry_sexp_build(&inner, NULL, "(ecc (flags param) (p %m) (a %m) (b %m) (g %m) (n %m) (h %m) (q %m))", p, a, b, g, n, h, q, NULL); } else if (!q && d) { - gcry_sexp_build(&inner, NULL, "(ecc (flags param) (p %M) (a %M) (b %M) (g %M) (n %M) (h %M) (d %M))", p, a, b, g, n, h, d, NULL); + gcry_sexp_build(&inner, NULL, "(ecc (flags param) (p %m) (a %m) (b %m) (g %m) (n %m) (h %m) (d %m))", p, a, b, g, n, h, d, NULL); } gcry_sexp_t result; gcry_sexp_build(&result, NULL, key_fmt, inner, NULL); -- cgit v1.2.3-70-g09d2 From f59aaf972a83330206e8b0d2e1819f45da38f74e Mon Sep 17 00:00:00 2001 From: J08nY Date: Sun, 11 Nov 2018 17:51:53 +0100 Subject: Add WolfCrypt provider to testing. --- README.md | 1 + docs/LIBS.md | 2 ++ lib/wolfcrypt-jni.jar | Bin 0 -> 83453 bytes nbproject/standalone/manifest.mf | 2 +- nbproject/standalone/project.properties | 1 + .../crcs/ectester/standalone/ECTesterStandalone.java | 13 ++++++++++++- .../crcs/ectester/standalone/libs/WolfCryptLib.java | 18 ++++++++++++++++++ 7 files changed, 35 insertions(+), 2 deletions(-) create mode 100644 lib/wolfcrypt-jni.jar create mode 100644 src/cz/crcs/ectester/standalone/libs/WolfCryptLib.java (limited to 'src/cz/crcs/ectester/standalone/libs') diff --git a/README.md b/README.md index d70ae9b..d23922d 100644 --- a/README.md +++ b/README.md @@ -270,6 +270,7 @@ Currently supported libraries include: - [Sun EC](https://docs.oracle.com/javase/7/docs/technotes/guides/security/SunProviders.html#SunEC) - [OpenSSL](https://www.openssl.org/) - [BoringSSL](https://boringssl.googlesource.com/boringssl) + - [wolfSSL](https://www.wolfssl.com/) - [Crypto++](https://cryptopp.com/) - [libtomcrypt](http://www.libtom.net/LibTomCrypt/) - [libgcrypt](https://www.gnupg.org/related_software/libgcrypt/) diff --git a/docs/LIBS.md b/docs/LIBS.md index faab84d..d41f98a 100644 --- a/docs/LIBS.md +++ b/docs/LIBS.md @@ -55,6 +55,8 @@ Libraries that ECTester can test. - Uses Lopez-Dahab (Montgomery) ladder, XZ coordinates (ec2_mont.c): Fast multiplication on elliptic curves over GF(2^m) without precomputation (Algorithm 2P) - Contains an implementation of IEEE P1363 algorithm A.10.3 using affine coordinates (ec2_aff.c) - Has some custom arithmetic for some of the NIST primes. + - [WolfCrypt](https://www.wolfssl.com) + - C + Java - [OpenSSL](https://www.openssl.org/) - C - For prime field curves: diff --git a/lib/wolfcrypt-jni.jar b/lib/wolfcrypt-jni.jar new file mode 100644 index 0000000..890ae14 Binary files /dev/null and b/lib/wolfcrypt-jni.jar differ diff --git a/nbproject/standalone/manifest.mf b/nbproject/standalone/manifest.mf index 5e8f5d9..ad7aacb 100644 --- a/nbproject/standalone/manifest.mf +++ b/nbproject/standalone/manifest.mf @@ -1,4 +1,4 @@ Manifest-Version: 1.0 -Class-Path: lib/bcprov-jdk15on-1.58.jar lib/jcardsim-3.0.4-SNAPSHOT.jar lib/commons-cli-1.4.jar lib/snakeyaml-1.19.jar +Class-Path: lib/bcprov-jdk15on-1.58.jar lib/wolfcrypt-jni.jar lib/jcardsim-3.0.4-SNAPSHOT.jar lib/commons-cli-1.4.jar lib/snakeyaml-1.19.jar Main-Class: cz.crcs.ectester.standalone.ECTesterStandalone diff --git a/nbproject/standalone/project.properties b/nbproject/standalone/project.properties index 6b6d440..29ad3cc 100644 --- a/nbproject/standalone/project.properties +++ b/nbproject/standalone/project.properties @@ -34,6 +34,7 @@ includes=**/common/**,**/standalone/**,**/data/**,**/applet/* jar.compress=true javac.classpath=\ lib/bcprov-jdk15on-1.58.jar:\ + lib/wolfcrypt-jni.jar:\ lib/jcardsim-3.0.4-SNAPSHOT.jar:\ lib/commons-cli-1.4.jar:\ lib/snakeyaml-1.19.jar diff --git a/src/cz/crcs/ectester/standalone/ECTesterStandalone.java b/src/cz/crcs/ectester/standalone/ECTesterStandalone.java index 7480215..b6f5478 100644 --- a/src/cz/crcs/ectester/standalone/ECTesterStandalone.java +++ b/src/cz/crcs/ectester/standalone/ECTesterStandalone.java @@ -49,6 +49,7 @@ import javax.xml.parsers.ParserConfigurationException; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; +import java.lang.reflect.Field; import java.nio.file.Files; import java.security.*; import java.security.interfaces.ECPrivateKey; @@ -66,7 +67,17 @@ import java.util.stream.Collectors; * @version v0.3.0 */ public class ECTesterStandalone { - private ProviderECLibrary[] libs = new ProviderECLibrary[]{new SunECLib(), new BouncyCastleLib(), new TomcryptLib(), new BotanLib(), new CryptoppLib(), new OpensslLib(), new BoringsslLib(), new GcryptLib(), new MscngLib()}; + private ProviderECLibrary[] libs = new ProviderECLibrary[]{ + new SunECLib(), + new BouncyCastleLib(), + new TomcryptLib(), + new BotanLib(), + new CryptoppLib(), + new OpensslLib(), + new BoringsslLib(), + new GcryptLib(), + new MscngLib(), + new WolfCryptLib()}; private Config cfg; private Options opts = new Options(); diff --git a/src/cz/crcs/ectester/standalone/libs/WolfCryptLib.java b/src/cz/crcs/ectester/standalone/libs/WolfCryptLib.java new file mode 100644 index 0000000..b58eb91 --- /dev/null +++ b/src/cz/crcs/ectester/standalone/libs/WolfCryptLib.java @@ -0,0 +1,18 @@ +package cz.crcs.ectester.standalone.libs; + +import com.wolfssl.provider.jce.WolfCryptProvider; + +import java.util.HashSet; +import java.util.Set; + +public class WolfCryptLib extends ProviderECLibrary { + + public WolfCryptLib() { + super(new WolfCryptProvider()); + } + + @Override + public Set getCurves() { + return new HashSet<>(); + } +} -- cgit v1.2.3-70-g09d2 From 977bc58d83195e804769f837bd206c3467354ffe Mon Sep 17 00:00:00 2001 From: J08nY Date: Fri, 23 Nov 2018 15:25:22 +0100 Subject: Improve native lib timing. --- .../ectester/standalone/ECTesterStandalone.java | 4 + .../ectester/standalone/libs/BoringsslLib.java | 9 ++ src/cz/crcs/ectester/standalone/libs/BotanLib.java | 9 ++ .../crcs/ectester/standalone/libs/CryptoppLib.java | 9 ++ .../crcs/ectester/standalone/libs/GcryptLib.java | 9 ++ src/cz/crcs/ectester/standalone/libs/MscngLib.java | 9 ++ .../ectester/standalone/libs/NativeECLibrary.java | 9 ++ .../crcs/ectester/standalone/libs/OpensslLib.java | 9 ++ .../standalone/libs/ProviderECLibrary.java | 12 ++ .../crcs/ectester/standalone/libs/TomcryptLib.java | 10 ++ src/cz/crcs/ectester/standalone/libs/jni/Makefile | 15 +- .../crcs/ectester/standalone/libs/jni/boringssl.c | 35 ++++- src/cz/crcs/ectester/standalone/libs/jni/botan.cpp | 21 +++ .../crcs/ectester/standalone/libs/jni/c_timing.c | 57 +++++++ .../crcs/ectester/standalone/libs/jni/c_timing.h | 38 +++++ .../crcs/ectester/standalone/libs/jni/cryptopp.cpp | 23 +++ src/cz/crcs/ectester/standalone/libs/jni/gcrypt.c | 27 ++++ src/cz/crcs/ectester/standalone/libs/jni/mscng.c | 12 ++ src/cz/crcs/ectester/standalone/libs/jni/native.h | 168 +++++++++++++++++++++ src/cz/crcs/ectester/standalone/libs/jni/openssl.c | 36 ++++- .../crcs/ectester/standalone/libs/jni/tomcrypt.c | 45 ++++-- util/plot_dh.py | 76 +++++----- util/plot_gen.py | 43 +----- 23 files changed, 593 insertions(+), 92 deletions(-) create mode 100644 src/cz/crcs/ectester/standalone/libs/jni/c_timing.c create mode 100644 src/cz/crcs/ectester/standalone/libs/jni/c_timing.h (limited to 'src/cz/crcs/ectester/standalone/libs') diff --git a/src/cz/crcs/ectester/standalone/ECTesterStandalone.java b/src/cz/crcs/ectester/standalone/ECTesterStandalone.java index 46c60e0..037e8b2 100644 --- a/src/cz/crcs/ectester/standalone/ECTesterStandalone.java +++ b/src/cz/crcs/ectester/standalone/ECTesterStandalone.java @@ -241,6 +241,7 @@ public class ECTesterStandalone { for (ProviderECLibrary lib : libs) { if (lib.isInitialized() && (cfg.selected == null || lib == cfg.selected)) { System.out.println("\t- " + Colors.bold(lib.name())); + System.out.println(Colors.bold("\t\t- Supports native timing: ") + lib.supportsNativeTiming()); Set kpgs = lib.getKPGs(); if (!kpgs.isEmpty()) { System.out.println(Colors.bold("\t\t- KeyPairGenerators: ") + String.join(", ", kpgs.stream().map(KeyPairGeneratorIdent::getName).collect(Collectors.toList()))); @@ -555,6 +556,9 @@ public class ECTesterStandalone { long elapsed = -System.nanoTime(); KeyPair kp = kpg.genKeyPair(); elapsed += System.nanoTime(); + if (lib.supportsNativeTiming()) { + elapsed = lib.getLastNativeTiming(); + } ECPublicKey publicKey = (ECPublicKey) kp.getPublic(); ECPrivateKey privateKey = (ECPrivateKey) kp.getPrivate(); diff --git a/src/cz/crcs/ectester/standalone/libs/BoringsslLib.java b/src/cz/crcs/ectester/standalone/libs/BoringsslLib.java index 60ca5d9..35a48a8 100644 --- a/src/cz/crcs/ectester/standalone/libs/BoringsslLib.java +++ b/src/cz/crcs/ectester/standalone/libs/BoringsslLib.java @@ -11,6 +11,15 @@ public class BoringsslLib extends NativeECLibrary { super("boringssl_provider", "lib_boringssl.so"); } + @Override + public native boolean supportsNativeTiming(); + + @Override + public native long getNativeTimingResolution(); + + @Override + public native long getLastNativeTiming(); + @Override native Provider createProvider(); diff --git a/src/cz/crcs/ectester/standalone/libs/BotanLib.java b/src/cz/crcs/ectester/standalone/libs/BotanLib.java index cd28791..34fb178 100644 --- a/src/cz/crcs/ectester/standalone/libs/BotanLib.java +++ b/src/cz/crcs/ectester/standalone/libs/BotanLib.java @@ -12,6 +12,15 @@ public class BotanLib extends NativeECLibrary { super("botan_provider", "botan-2"); } + @Override + public native boolean supportsNativeTiming(); + + @Override + public native long getNativeTimingResolution(); + + @Override + public native long getLastNativeTiming(); + @Override native Provider createProvider(); diff --git a/src/cz/crcs/ectester/standalone/libs/CryptoppLib.java b/src/cz/crcs/ectester/standalone/libs/CryptoppLib.java index 5112d7d..5153df5 100644 --- a/src/cz/crcs/ectester/standalone/libs/CryptoppLib.java +++ b/src/cz/crcs/ectester/standalone/libs/CryptoppLib.java @@ -12,6 +12,15 @@ public class CryptoppLib extends NativeECLibrary { super("cryptopp_provider", "cryptopp"); } + @Override + public native boolean supportsNativeTiming(); + + @Override + public native long getNativeTimingResolution(); + + @Override + public native long getLastNativeTiming(); + @Override native Provider createProvider(); diff --git a/src/cz/crcs/ectester/standalone/libs/GcryptLib.java b/src/cz/crcs/ectester/standalone/libs/GcryptLib.java index a0a7fc8..ef20f97 100644 --- a/src/cz/crcs/ectester/standalone/libs/GcryptLib.java +++ b/src/cz/crcs/ectester/standalone/libs/GcryptLib.java @@ -12,6 +12,15 @@ public class GcryptLib extends NativeECLibrary { super("gcrypt_provider", "gcrypt", "gpg-error"); } + @Override + public native boolean supportsNativeTiming(); + + @Override + public native long getNativeTimingResolution(); + + @Override + public native long getLastNativeTiming(); + @Override native Provider createProvider(); diff --git a/src/cz/crcs/ectester/standalone/libs/MscngLib.java b/src/cz/crcs/ectester/standalone/libs/MscngLib.java index 527a65b..354199a 100644 --- a/src/cz/crcs/ectester/standalone/libs/MscngLib.java +++ b/src/cz/crcs/ectester/standalone/libs/MscngLib.java @@ -12,6 +12,15 @@ public class MscngLib extends NativeECLibrary { super("mscng_provider", "bcrypt"); } + @Override + public native boolean supportsNativeTiming(); + + @Override + public native long getNativeTimingResolution(); + + @Override + public native long getLastNativeTiming(); + @Override native Provider createProvider(); diff --git a/src/cz/crcs/ectester/standalone/libs/NativeECLibrary.java b/src/cz/crcs/ectester/standalone/libs/NativeECLibrary.java index ff23fd9..7870377 100644 --- a/src/cz/crcs/ectester/standalone/libs/NativeECLibrary.java +++ b/src/cz/crcs/ectester/standalone/libs/NativeECLibrary.java @@ -130,5 +130,14 @@ public abstract class NativeECLibrary extends ProviderECLibrary { return true; } + @Override + public abstract boolean supportsNativeTiming(); + + @Override + public abstract long getNativeTimingResolution(); + + @Override + public abstract long getLastNativeTiming(); + abstract Provider createProvider(); } diff --git a/src/cz/crcs/ectester/standalone/libs/OpensslLib.java b/src/cz/crcs/ectester/standalone/libs/OpensslLib.java index e558336..4f44a2a 100644 --- a/src/cz/crcs/ectester/standalone/libs/OpensslLib.java +++ b/src/cz/crcs/ectester/standalone/libs/OpensslLib.java @@ -11,6 +11,15 @@ public class OpensslLib extends NativeECLibrary { super("openssl_provider", "crypto"); } + @Override + public native boolean supportsNativeTiming(); + + @Override + public native long getNativeTimingResolution(); + + @Override + public native long getLastNativeTiming(); + @Override native Provider createProvider(); diff --git a/src/cz/crcs/ectester/standalone/libs/ProviderECLibrary.java b/src/cz/crcs/ectester/standalone/libs/ProviderECLibrary.java index 9108eaf..83a9dc9 100644 --- a/src/cz/crcs/ectester/standalone/libs/ProviderECLibrary.java +++ b/src/cz/crcs/ectester/standalone/libs/ProviderECLibrary.java @@ -62,6 +62,18 @@ public abstract class ProviderECLibrary implements ECLibrary { return results; } + public boolean supportsNativeTiming() { + return false; + } + + public long getNativeTimingResolution() { + return 0; + } + + public long getLastNativeTiming() { + return 0; + } + @Override public Set getKAs() { return getIdents("KeyAgreement", KeyAgreementIdent::get); diff --git a/src/cz/crcs/ectester/standalone/libs/TomcryptLib.java b/src/cz/crcs/ectester/standalone/libs/TomcryptLib.java index 78db00e..6ac74c9 100644 --- a/src/cz/crcs/ectester/standalone/libs/TomcryptLib.java +++ b/src/cz/crcs/ectester/standalone/libs/TomcryptLib.java @@ -12,6 +12,16 @@ public class TomcryptLib extends NativeECLibrary { super("tomcrypt_provider", "tommath", "tomcrypt"); } + @Override + public native boolean supportsNativeTiming(); + + @Override + public native long getNativeTimingResolution(); + + @Override + public native long getLastNativeTiming(); + + @Override native Provider createProvider(); diff --git a/src/cz/crcs/ectester/standalone/libs/jni/Makefile b/src/cz/crcs/ectester/standalone/libs/jni/Makefile index 2232e3d..c8ab47b 100644 --- a/src/cz/crcs/ectester/standalone/libs/jni/Makefile +++ b/src/cz/crcs/ectester/standalone/libs/jni/Makefile @@ -64,12 +64,15 @@ all: tomcrypt_provider.so botan_provider.so cryptopp_provider.so openssl_provide c_utils.o: c_utils.c $(CC) $(CFLAGS) -c $< +c_timing.o: c_timing.c + $(CC) $(CFLAGS) -c $< + cpp_utils.o: cpp_utils.cpp $(CXX) $(CXXFLAGS) -c $< # OpenSSL shim -openssl_provider.so: openssl.o c_utils.o +openssl_provider.so: openssl.o c_utils.o c_timing.o $(CC) $(LFLAGS) -o $@ $^ -L. $(shell pkg-config --libs openssl) openssl.o: openssl.c @@ -77,7 +80,7 @@ openssl.o: openssl.c # BoringSSL shim -boringssl_provider.so: boringssl.o c_utils.o +boringssl_provider.so: boringssl.o c_utils.o c_timing.o $(CC) $(LFLAGS) -o $@ $^ -L. ../../../../../../../ext/boringssl/build/crypto/libcrypto.so cp ../../../../../../../ext/boringssl/build/crypto/libcrypto.so lib_boringssl.so @@ -86,7 +89,7 @@ boringssl.o: boringssl.c # libgcrypt shim -gcrypt_provider.so: gcrypt.o c_utils.o +gcrypt_provider.so: gcrypt.o c_utils.o c_timing.o $(CC) $(LFLAGS) -o $@ $^ -L. $(shell libgcrypt-config --libs) gcrypt.o: gcrypt.c @@ -94,7 +97,7 @@ gcrypt.o: gcrypt.c # Libtomcrypt shim -tomcrypt_provider.so: tomcrypt.o c_utils.o +tomcrypt_provider.so: tomcrypt.o c_utils.o c_timing.o $(CC) $(LFLAGS) -o $@ $^ -L. -ltommath $(shell pkg-config --libs libtomcrypt) tomcrypt.o: tomcrypt.c @@ -102,7 +105,7 @@ tomcrypt.o: tomcrypt.c # Botan-2 shim -botan_provider.so: botan.o cpp_utils.o +botan_provider.so: botan.o cpp_utils.o c_timing.o $(CXX) $(LFLAGS) -o $@ $^ -L. $(shell pkg-config --libs botan-2) botan.o: botan.cpp @@ -110,7 +113,7 @@ botan.o: botan.cpp # Crypto++ shim -cryptopp_provider.so: cryptopp.o cpp_utils.o +cryptopp_provider.so: cryptopp.o cpp_utils.o c_timing.o $(CXX) $(LFLAGS) -o $@ $^ -L. $(shell pkg-config --libs libcrypto++) cryptopp.o: cryptopp.cpp diff --git a/src/cz/crcs/ectester/standalone/libs/jni/boringssl.c b/src/cz/crcs/ectester/standalone/libs/jni/boringssl.c index cb1ea77..0484d28 100644 --- a/src/cz/crcs/ectester/standalone/libs/jni/boringssl.c +++ b/src/cz/crcs/ectester/standalone/libs/jni/boringssl.c @@ -13,6 +13,7 @@ #include #include "c_utils.h" +#include "c_timing.h" static jclass provider_class; @@ -279,7 +280,12 @@ static jobject generate_from_curve(JNIEnv *env, const EC_GROUP *curve) { EC_KEY *key = EC_KEY_new(); EC_KEY_set_group(key, curve); - if (!EC_KEY_generate_key(key)) { + + native_timing_start(); + int err = EC_KEY_generate_key(key); + native_timing_stop(); + + if (!err) { throw_new(env, "java/security/GeneralSecurityException", "Error generating key, EC_KEY_generate_key."); EC_KEY_free(key); return NULL; @@ -412,7 +418,12 @@ JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKey // probably using the ECDH_KDF_X9_62 by wrapping it and dynamically choosing the EVP_MD. from the type string. jbyteArray result = (*env)->NewByteArray(env, secret_len); jbyte *result_data = (*env)->GetByteArrayElements(env, result, NULL); - if (ECDH_compute_key(result_data, secret_len, EC_KEY_get0_public_key(pub), priv, NULL) <= 0) { + + native_timing_start(); + int err = ECDH_compute_key(result_data, secret_len, EC_KEY_get0_public_key(pub), priv, NULL); + native_timing_stop(); + + if (err <= 0) { throw_new(env, "java/security/GeneralSecurityException", "Error computing ECDH, ECDH_compute_key."); EC_KEY_free(pub); EC_KEY_free(priv); EC_GROUP_free(curve); (*env)->ReleaseByteArrayElements(env, result, result_data, JNI_ABORT); @@ -443,7 +454,11 @@ JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSig jsize data_size = (*env)->GetArrayLength(env, data); jbyte *data_data = (*env)->GetByteArrayElements(env, data, NULL); // TODO: Do more Signatures here, maybe use the EVP interface to get to the hashes easier and not hash manually? + + native_timing_start(); ECDSA_SIG *signature = ECDSA_do_sign((unsigned char *) data_data, data_size, priv); + native_timing_stop(); + (*env)->ReleaseByteArrayElements(env, data, data_data, JNI_ABORT); if (!signature) { throw_new(env, "java/security/GeneralSecurityException", "Error signing, ECDSA_do_sign."); @@ -481,7 +496,11 @@ JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSigna jsize data_size = (*env)->GetArrayLength(env, data); jbyte *data_data = (*env)->GetByteArrayElements(env, data, NULL); + + native_timing_start(); int result = ECDSA_do_verify((unsigned char *) data_data, data_size, sig_obj, pub); + native_timing_stop(); + if (result < 0) { throw_new(env, "java/security/GeneralSecurityException", "Error verifying, ECDSA_do_verify."); EC_KEY_free(pub); EC_GROUP_free(curve); ECDSA_SIG_free(sig_obj); @@ -495,3 +514,15 @@ JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSigna EC_GROUP_free(curve); return (result == 1) ? JNI_TRUE : JNI_FALSE; } + +JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_BoringsslLib_supportsNativeTiming(JNIEnv *env, jobject this) { + return native_timing_supported(); +} + +JNIEXPORT jlong JNICALL Java_cz_crcs_ectester_standalone_libs_BoringsslLib_getNativeTimingResolution(JNIEnv *env, jobject this) { + return native_timing_resolution(); +} + +JNIEXPORT jlong JNICALL Java_cz_crcs_ectester_standalone_libs_BoringsslLib_getLastNativeTiming(JNIEnv *env, jobject this) { + return native_timing_last(); +} \ No newline at end of file diff --git a/src/cz/crcs/ectester/standalone/libs/jni/botan.cpp b/src/cz/crcs/ectester/standalone/libs/jni/botan.cpp index b7940df..813b9f8 100644 --- a/src/cz/crcs/ectester/standalone/libs/jni/botan.cpp +++ b/src/cz/crcs/ectester/standalone/libs/jni/botan.cpp @@ -17,6 +17,7 @@ #include #include #include "cpp_utils.hpp" +#include "c_timing.h" static jclass provider_class; static Botan::AutoSeeded_RNG rng; @@ -244,6 +245,7 @@ static jobject generate_from_group(JNIEnv* env, jobject self, Botan::EC_Group gr std::unique_ptr skey; try { + native_timing_start(); if (type_str == "ECDH") { skey = std::make_unique(rng, group); } else if (type_str == "ECDSA") { @@ -253,6 +255,7 @@ static jobject generate_from_group(JNIEnv* env, jobject self, Botan::EC_Group gr } else if (type_str == "ECGDSA") { skey = std::make_unique(rng, group); } + native_timing_stop(); } catch (Botan::Exception & ex) { throw_new(env, "java/security/GeneralSecurityException", ex.what()); return NULL; @@ -371,7 +374,9 @@ jbyteArray generate_secret(JNIEnv *env, jobject self, jbyteArray pubkey, jbyteAr std::vector derived; try { + native_timing_start(); derived = Botan::unlock(ka.derive_key(key_len, pkey.public_value()).bits_of()); + native_timing_stop(); } catch (Botan::Exception & ex) { throw_new(env, "java/security/GeneralSecurityException", ex.what()); return NULL; @@ -442,7 +447,9 @@ JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSig jbyte *data_bytes = env->GetByteArrayElements(data, NULL); std::vector sig; try { + native_timing_start(); sig = signer.sign_message((uint8_t*) data_bytes, data_length, rng); + native_timing_stop(); } catch (Botan::Exception & ex) { throw_new(env, "java/security/GeneralSecurityException", ex.what()); env->ReleaseByteArrayElements(data, data_bytes, JNI_ABORT); @@ -506,7 +513,9 @@ JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSigna bool result; try { + native_timing_start(); result = verifier.verify_message((uint8_t*)data_bytes, data_length, (uint8_t*)sig_bytes, sig_length); + native_timing_stop(); } catch (Botan::Exception & ex) { throw_new(env, "java/security/GeneralSecurityException", ex.what()); env->ReleaseByteArrayElements(data, data_bytes, JNI_ABORT); @@ -519,4 +528,16 @@ JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSigna return JNI_TRUE; } return JNI_FALSE; +} + +JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_BotanLib_supportsNativeTiming(JNIEnv *env, jobject self) { + return native_timing_supported(); +} + +JNIEXPORT jlong JNICALL Java_cz_crcs_ectester_standalone_libs_BotanLib_getNativeTimingResolution(JNIEnv *env, jobject self) { + return native_timing_resolution(); +} + +JNIEXPORT jlong JNICALL Java_cz_crcs_ectester_standalone_libs_BotanLib_getLastNativeTiming(JNIEnv *env, jobject self) { + return native_timing_last(); } \ No newline at end of file diff --git a/src/cz/crcs/ectester/standalone/libs/jni/c_timing.c b/src/cz/crcs/ectester/standalone/libs/jni/c_timing.c new file mode 100644 index 0000000..be46398 --- /dev/null +++ b/src/cz/crcs/ectester/standalone/libs/jni/c_timing.c @@ -0,0 +1,57 @@ +#include "c_timing.h" +#include + +#if _POSIX_TIMERS > 0 + +struct timespec start = {0}; +struct timespec end = {0}; + +jboolean native_timing_supported() { + return JNI_TRUE; +} + +jlong native_timing_resolution() { + struct timespec timeval; + clock_getres(CLOCK_MONOTONIC, &timeval); + return timeval.tv_nsec; +} + + +void native_timing_start() { + clock_gettime(CLOCK_MONOTONIC, &start); +} + + +void native_timing_stop() { + clock_gettime(CLOCK_MONOTONIC, &end); +} + + +jlong native_timing_last() { + jlong res = (end.tv_sec - start.tv_sec) * 1000000000 + (end.tv_nsec - start.tv_nsec); + if (res < 0) { + return 0; + } else { + return res; + } +} + +#else + +jboolean native_timing_supported() { + return JNI_FALSE; +} + +jlong native_timing_resolution() { + return 0; +} + +void native_timing_start() {} + +void native_timing_stop() {} + +jlong native_timing_last() { + return 0; +} + +#endif \ No newline at end of file diff --git a/src/cz/crcs/ectester/standalone/libs/jni/c_timing.h b/src/cz/crcs/ectester/standalone/libs/jni/c_timing.h new file mode 100644 index 0000000..bce2a19 --- /dev/null +++ b/src/cz/crcs/ectester/standalone/libs/jni/c_timing.h @@ -0,0 +1,38 @@ +#pragma once + +#include +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + +/** + * + */ +jboolean native_timing_supported(); + +/** + * + */ +jlong native_timing_resolution(); + +/** + * + */ +void native_timing_start(); + +/** + * + */ +void native_timing_stop(); + +/** + * + */ +jlong native_timing_last(); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/src/cz/crcs/ectester/standalone/libs/jni/cryptopp.cpp b/src/cz/crcs/ectester/standalone/libs/jni/cryptopp.cpp index f14aa97..089724e 100644 --- a/src/cz/crcs/ectester/standalone/libs/jni/cryptopp.cpp +++ b/src/cz/crcs/ectester/standalone/libs/jni/cryptopp.cpp @@ -70,6 +70,7 @@ using CryptoPP::Integer; #include "cpp_utils.hpp" +#include "c_timing.h" static jclass provider_class; static AutoSeededRandomPool rng; @@ -498,7 +499,9 @@ template jobject generate_from_group(JNIEnv *env, DL_GroupParameters_ SecByteBlock priv(ec_domain.PrivateKeyLength()), pub(ec_domain.PublicKeyLength()); try { + native_timing_start(); ec_domain.GenerateKeyPair(rng, priv, pub); + native_timing_stop(); } catch (Exception & ex) { throw_new(env, "java/security/GeneralSecurityException", ex.what()); return NULL; @@ -579,7 +582,9 @@ JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKey try { secret = std::make_unique(dh_agreement.AgreedValueLength()); + native_timing_start(); success = dh_agreement.Agree(*secret, private_key, public_key); + native_timing_stop(); } catch (Exception & ex) { throw_new(env, "java/security/GeneralSecurityException", ex.what()); return NULL; @@ -589,7 +594,9 @@ JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKey try { secret = std::make_unique(dh_agreement.AgreedValueLength()); + native_timing_start(); success = dh_agreement.Agree(*secret, private_key, public_key); + native_timing_stop(); } catch (Exception & ex) { throw_new(env, "java/security/GeneralSecurityException", ex.what()); return NULL; @@ -624,7 +631,9 @@ jbyteArray sign_message(JNIEnv *env, DL_GroupParameters_EC group, jbyteArray jsize data_length = env->GetArrayLength(data); jbyte *data_bytes = env->GetByteArrayElements(data, NULL); + native_timing_start(); size_t len = signer.SignMessage(rng, (byte *)data_bytes, data_length, (byte *)signature.c_str()); + native_timing_stop(); env->ReleaseByteArrayElements(data, data_bytes, JNI_ABORT); signature.resize(len); @@ -709,7 +718,9 @@ jboolean verify_message(JNIEnv *env, DL_GroupParameters_EC group, jbyteArray jsize data_length = env->GetArrayLength(data); jbyte *data_bytes = env->GetByteArrayElements(data, NULL); + native_timing_start(); bool result = verifier.VerifyMessage((byte *)data_bytes, data_length, sig, sig_len); + native_timing_stop(); env->ReleaseByteArrayElements(data, data_bytes, JNI_ABORT); return result; @@ -754,3 +765,15 @@ JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSigna // unreachable return JNI_FALSE; } + +JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_CryptoppLib_supportsNativeTiming(JNIEnv *env, jobject self) { + return native_timing_supported(); +} + +JNIEXPORT jlong JNICALL Java_cz_crcs_ectester_standalone_libs_CryptoppLib_getNativeTimingResolution(JNIEnv *env, jobject self) { + return native_timing_resolution(); +} + +JNIEXPORT jlong JNICALL Java_cz_crcs_ectester_standalone_libs_CryptoppLib_getLastNativeTiming(JNIEnv *env, jobject self) { + return native_timing_last(); +} \ No newline at end of file diff --git a/src/cz/crcs/ectester/standalone/libs/jni/gcrypt.c b/src/cz/crcs/ectester/standalone/libs/jni/gcrypt.c index 9590d0a..359d0f4 100644 --- a/src/cz/crcs/ectester/standalone/libs/jni/gcrypt.c +++ b/src/cz/crcs/ectester/standalone/libs/jni/gcrypt.c @@ -4,6 +4,7 @@ #include #include #include "c_utils.h" +#include "c_timing.h" static jclass provider_class; @@ -262,7 +263,11 @@ end: static jobject generate_from_sexp(JNIEnv *env, gcry_sexp_t gen_sexp) { jobject result = NULL; gcry_sexp_t key_sexp; + + native_timing_start(); gcry_error_t err = gcry_pk_genkey(&key_sexp, gen_sexp); + native_timing_stop(); + if (gcry_err_code(err) != GPG_ERR_NO_ERROR) { throw_new_var(env, "java/security/GeneralSecurityException", "Error generating key. Error: %ui", gcry_err_code(err)); goto release_sexp; @@ -438,7 +443,11 @@ JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKey gcry_sexp_build(&enc_sexp, NULL, "(data (flags raw) (value %M))", priv, NULL); gcry_sexp_t res_sexp; // TODO: figure out why ecc_encrypt_raw takes signed representation.. Nobody uses that., everybody uses unsigned reduced mod p. + + native_timing_start(); gcry_error_t err = gcry_pk_encrypt(&res_sexp, enc_sexp, pub); + native_timing_stop(); + if (gcry_err_code(err) != GPG_ERR_NO_ERROR) { throw_new_var(env, "java/security/GeneralSecurityException", "Error performing ECDH. Error: %ui", gcry_err_code(err)); goto end; @@ -543,7 +552,9 @@ JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSig get_sign_data_sexp(env, &data_sexp, this, data); gcry_sexp_t res_sexp; + native_timing_start(); gcry_error_t err = gcry_pk_sign(&res_sexp, data_sexp, priv_sexp); + native_timing_stop(); if (gcry_err_code(err) != GPG_ERR_NO_ERROR) { throw_new_var(env, "java/security/GeneralSecurityException", "Error performing ECDSA. Error: %ui", gcry_err_code(err)); goto release_init; @@ -591,7 +602,11 @@ JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSigna gcry_sexp_t sig_sexp; gcry_sexp_build(&sig_sexp, NULL, "(sig-val (ecdsa (r %M) (s %M)))", r_mpi, s_mpi); + + native_timing_start(); gcry_error_t err = gcry_pk_verify(sig_sexp, data_sexp, pub_sexp); + native_timing_stop(); + if (gcry_err_code(err) != GPG_ERR_NO_ERROR) { if (gcry_err_code(err) != GPG_ERR_BAD_SIGNATURE) { throw_new(env, "java/security/GeneralSecurityException", "Error verif sig."); @@ -605,4 +620,16 @@ release_init: gcry_sexp_release(pub_sexp); gcry_sexp_release(data_sexp); return result; +} + +JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_GcryptLib_supportsNativeTiming(JNIEnv *env, jobject this) { + return native_timing_supported(); +} + +JNIEXPORT jlong JNICALL Java_cz_crcs_ectester_standalone_libs_GcryptLib_getNativeTimingResolution(JNIEnv *env, jobject this) { + return native_timing_resolution(); +} + +JNIEXPORT jlong JNICALL Java_cz_crcs_ectester_standalone_libs_GcryptLib_getLastNativeTiming(JNIEnv *env, jobject this) { + return native_timing_last(); } \ No newline at end of file diff --git a/src/cz/crcs/ectester/standalone/libs/jni/mscng.c b/src/cz/crcs/ectester/standalone/libs/jni/mscng.c index 5820afd..568e924 100644 --- a/src/cz/crcs/ectester/standalone/libs/jni/mscng.c +++ b/src/cz/crcs/ectester/standalone/libs/jni/mscng.c @@ -1211,4 +1211,16 @@ JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSigna throw_new_var(env, "java/security/GeneralSecurityException", "Error 0x%x returned by BCryptVerifySignature\n", status); return JNI_FALSE; } +} + +JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_MscngLib_supportsNativeTiming(JNIEnv *env, jobject self) { + return JNI_FALSE; +} + +JNIEXPORT jlong JNICALL Java_cz_crcs_ectester_standalone_libs_MscngLib_getNativeTimingResolution(JNIEnv *env, jobject self) { + return 0; +} + +JNIEXPORT jlong JNICALL Java_cz_crcs_ectester_standalone_libs_MscngLib_getLastNativeTiming(JNIEnv *env, jobject self) { + return 0; } \ No newline at end of file diff --git a/src/cz/crcs/ectester/standalone/libs/jni/native.h b/src/cz/crcs/ectester/standalone/libs/jni/native.h index 47031e4..e410204 100644 --- a/src/cz/crcs/ectester/standalone/libs/jni/native.h +++ b/src/cz/crcs/ectester/standalone/libs/jni/native.h @@ -7,6 +7,30 @@ #ifdef __cplusplus extern "C" { #endif +/* + * Class: cz_crcs_ectester_standalone_libs_TomcryptLib + * Method: supportsNativeTiming + * Signature: ()Z + */ +JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_TomcryptLib_supportsNativeTiming + (JNIEnv *, jobject); + +/* + * Class: cz_crcs_ectester_standalone_libs_TomcryptLib + * Method: getNativeTimingResolution + * Signature: ()J + */ +JNIEXPORT jlong JNICALL Java_cz_crcs_ectester_standalone_libs_TomcryptLib_getNativeTimingResolution + (JNIEnv *, jobject); + +/* + * Class: cz_crcs_ectester_standalone_libs_TomcryptLib + * Method: getLastNativeTiming + * Signature: ()J + */ +JNIEXPORT jlong JNICALL Java_cz_crcs_ectester_standalone_libs_TomcryptLib_getLastNativeTiming + (JNIEnv *, jobject); + /* * Class: cz_crcs_ectester_standalone_libs_TomcryptLib * Method: createProvider @@ -188,6 +212,30 @@ JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSigna #ifdef __cplusplus extern "C" { #endif +/* + * Class: cz_crcs_ectester_standalone_libs_BotanLib + * Method: supportsNativeTiming + * Signature: ()Z + */ +JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_BotanLib_supportsNativeTiming + (JNIEnv *, jobject); + +/* + * Class: cz_crcs_ectester_standalone_libs_BotanLib + * Method: getNativeTimingResolution + * Signature: ()J + */ +JNIEXPORT jlong JNICALL Java_cz_crcs_ectester_standalone_libs_BotanLib_getNativeTimingResolution + (JNIEnv *, jobject); + +/* + * Class: cz_crcs_ectester_standalone_libs_BotanLib + * Method: getLastNativeTiming + * Signature: ()J + */ +JNIEXPORT jlong JNICALL Java_cz_crcs_ectester_standalone_libs_BotanLib_getLastNativeTiming + (JNIEnv *, jobject); + /* * Class: cz_crcs_ectester_standalone_libs_BotanLib * Method: createProvider @@ -369,6 +417,30 @@ JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSigna #ifdef __cplusplus extern "C" { #endif +/* + * Class: cz_crcs_ectester_standalone_libs_CryptoppLib + * Method: supportsNativeTiming + * Signature: ()Z + */ +JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_CryptoppLib_supportsNativeTiming + (JNIEnv *, jobject); + +/* + * Class: cz_crcs_ectester_standalone_libs_CryptoppLib + * Method: getNativeTimingResolution + * Signature: ()J + */ +JNIEXPORT jlong JNICALL Java_cz_crcs_ectester_standalone_libs_CryptoppLib_getNativeTimingResolution + (JNIEnv *, jobject); + +/* + * Class: cz_crcs_ectester_standalone_libs_CryptoppLib + * Method: getLastNativeTiming + * Signature: ()J + */ +JNIEXPORT jlong JNICALL Java_cz_crcs_ectester_standalone_libs_CryptoppLib_getLastNativeTiming + (JNIEnv *, jobject); + /* * Class: cz_crcs_ectester_standalone_libs_CryptoppLib * Method: createProvider @@ -550,6 +622,30 @@ JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSigna #ifdef __cplusplus extern "C" { #endif +/* + * Class: cz_crcs_ectester_standalone_libs_OpensslLib + * Method: supportsNativeTiming + * Signature: ()Z + */ +JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_OpensslLib_supportsNativeTiming + (JNIEnv *, jobject); + +/* + * Class: cz_crcs_ectester_standalone_libs_OpensslLib + * Method: getNativeTimingResolution + * Signature: ()J + */ +JNIEXPORT jlong JNICALL Java_cz_crcs_ectester_standalone_libs_OpensslLib_getNativeTimingResolution + (JNIEnv *, jobject); + +/* + * Class: cz_crcs_ectester_standalone_libs_OpensslLib + * Method: getLastNativeTiming + * Signature: ()J + */ +JNIEXPORT jlong JNICALL Java_cz_crcs_ectester_standalone_libs_OpensslLib_getLastNativeTiming + (JNIEnv *, jobject); + /* * Class: cz_crcs_ectester_standalone_libs_OpensslLib * Method: createProvider @@ -731,6 +827,30 @@ JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSigna #ifdef __cplusplus extern "C" { #endif +/* + * Class: cz_crcs_ectester_standalone_libs_MscngLib + * Method: supportsNativeTiming + * Signature: ()Z + */ +JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_MscngLib_supportsNativeTiming + (JNIEnv *, jobject); + +/* + * Class: cz_crcs_ectester_standalone_libs_MscngLib + * Method: getNativeTimingResolution + * Signature: ()J + */ +JNIEXPORT jlong JNICALL Java_cz_crcs_ectester_standalone_libs_MscngLib_getNativeTimingResolution + (JNIEnv *, jobject); + +/* + * Class: cz_crcs_ectester_standalone_libs_MscngLib + * Method: getLastNativeTiming + * Signature: ()J + */ +JNIEXPORT jlong JNICALL Java_cz_crcs_ectester_standalone_libs_MscngLib_getLastNativeTiming + (JNIEnv *, jobject); + /* * Class: cz_crcs_ectester_standalone_libs_MscngLib * Method: createProvider @@ -912,6 +1032,30 @@ JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSigna #ifdef __cplusplus extern "C" { #endif +/* + * Class: cz_crcs_ectester_standalone_libs_BoringsslLib + * Method: supportsNativeTiming + * Signature: ()Z + */ +JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_BoringsslLib_supportsNativeTiming + (JNIEnv *, jobject); + +/* + * Class: cz_crcs_ectester_standalone_libs_BoringsslLib + * Method: getNativeTimingResolution + * Signature: ()J + */ +JNIEXPORT jlong JNICALL Java_cz_crcs_ectester_standalone_libs_BoringsslLib_getNativeTimingResolution + (JNIEnv *, jobject); + +/* + * Class: cz_crcs_ectester_standalone_libs_BoringsslLib + * Method: getLastNativeTiming + * Signature: ()J + */ +JNIEXPORT jlong JNICALL Java_cz_crcs_ectester_standalone_libs_BoringsslLib_getLastNativeTiming + (JNIEnv *, jobject); + /* * Class: cz_crcs_ectester_standalone_libs_BoringsslLib * Method: createProvider @@ -1093,6 +1237,30 @@ JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSigna #ifdef __cplusplus extern "C" { #endif +/* + * Class: cz_crcs_ectester_standalone_libs_GcryptLib + * Method: supportsNativeTiming + * Signature: ()Z + */ +JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_GcryptLib_supportsNativeTiming + (JNIEnv *, jobject); + +/* + * Class: cz_crcs_ectester_standalone_libs_GcryptLib + * Method: getNativeTimingResolution + * Signature: ()J + */ +JNIEXPORT jlong JNICALL Java_cz_crcs_ectester_standalone_libs_GcryptLib_getNativeTimingResolution + (JNIEnv *, jobject); + +/* + * Class: cz_crcs_ectester_standalone_libs_GcryptLib + * Method: getLastNativeTiming + * Signature: ()J + */ +JNIEXPORT jlong JNICALL Java_cz_crcs_ectester_standalone_libs_GcryptLib_getLastNativeTiming + (JNIEnv *, jobject); + /* * Class: cz_crcs_ectester_standalone_libs_GcryptLib * Method: createProvider diff --git a/src/cz/crcs/ectester/standalone/libs/jni/openssl.c b/src/cz/crcs/ectester/standalone/libs/jni/openssl.c index 639503a..a63c2fb 100644 --- a/src/cz/crcs/ectester/standalone/libs/jni/openssl.c +++ b/src/cz/crcs/ectester/standalone/libs/jni/openssl.c @@ -12,6 +12,8 @@ #include #include "c_utils.h" +#include "c_timing.h" + static jclass provider_class; @@ -348,7 +350,12 @@ static jobject generate_from_curve(JNIEnv *env, const EC_GROUP *curve) { EC_KEY *key = EC_KEY_new(); EC_KEY_set_group(key, curve); - if (!EC_KEY_generate_key(key)) { + + native_timing_start(); + int result = EC_KEY_generate_key(key); + native_timing_stop(); + + if (!result) { throw_new(env, "java/security/GeneralSecurityException", "Error generating key, EC_KEY_generate_key."); EC_KEY_free(key); return NULL; @@ -481,7 +488,12 @@ JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKey // probably using the ECDH_KDF_X9_62 by wrapping it and dynamically choosing the EVP_MD. from the type string. jbyteArray result = (*env)->NewByteArray(env, secret_len); jbyte *result_data = (*env)->GetByteArrayElements(env, result, NULL); - if (ECDH_compute_key(result_data, secret_len, EC_KEY_get0_public_key(pub), priv, NULL) <= 0) { + + native_timing_start(); + int err = ECDH_compute_key(result_data, secret_len, EC_KEY_get0_public_key(pub), priv, NULL); + native_timing_stop(); + + if (err <= 0) { throw_new(env, "java/security/GeneralSecurityException", "Error computing ECDH, ECDH_compute_key."); EC_KEY_free(pub); EC_KEY_free(priv); EC_GROUP_free(curve); (*env)->ReleaseByteArrayElements(env, result, result_data, JNI_ABORT); @@ -512,7 +524,11 @@ JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSig jsize data_size = (*env)->GetArrayLength(env, data); jbyte *data_data = (*env)->GetByteArrayElements(env, data, NULL); // TODO: Do more Signatures here, maybe use the EVP interface to get to the hashes easier and not hash manually? + + native_timing_start(); ECDSA_SIG *signature = ECDSA_do_sign((unsigned char *) data_data, data_size, priv); + native_timing_stop(); + (*env)->ReleaseByteArrayElements(env, data, data_data, JNI_ABORT); if (!signature) { throw_new(env, "java/security/GeneralSecurityException", "Error signing, ECDSA_do_sign."); @@ -550,7 +566,11 @@ JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSigna jsize data_size = (*env)->GetArrayLength(env, data); jbyte *data_data = (*env)->GetByteArrayElements(env, data, NULL); + + native_timing_start(); int result = ECDSA_do_verify((unsigned char *) data_data, data_size, sig_obj, pub); + native_timing_stop(); + if (result < 0) { throw_new(env, "java/security/GeneralSecurityException", "Error verifying, ECDSA_do_verify."); EC_KEY_free(pub); EC_GROUP_free(curve); ECDSA_SIG_free(sig_obj); @@ -564,3 +584,15 @@ JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSigna EC_GROUP_free(curve); return (result == 1) ? JNI_TRUE : JNI_FALSE; } + +JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_OpensslLib_supportsNativeTiming(JNIEnv *env, jobject this) { + return native_timing_supported(); +} + +JNIEXPORT jlong JNICALL Java_cz_crcs_ectester_standalone_libs_OpensslLib_getNativeTimingResolution(JNIEnv *env, jobject this) { + return native_timing_resolution(); +} + +JNIEXPORT jlong JNICALL Java_cz_crcs_ectester_standalone_libs_OpensslLib_getLastNativeTiming(JNIEnv *env, jobject this) { + return native_timing_last(); +} \ No newline at end of file diff --git a/src/cz/crcs/ectester/standalone/libs/jni/tomcrypt.c b/src/cz/crcs/ectester/standalone/libs/jni/tomcrypt.c index 49e997a..471190e 100644 --- a/src/cz/crcs/ectester/standalone/libs/jni/tomcrypt.c +++ b/src/cz/crcs/ectester/standalone/libs/jni/tomcrypt.c @@ -3,6 +3,7 @@ #include #include #include "c_utils.h" +#include "c_timing.h" static prng_state ltc_prng; static jclass provider_class; @@ -20,7 +21,6 @@ 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; @@ -243,8 +243,12 @@ static void free_curve(ltc_ecc_set_type *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) { + + native_timing_start(); + int err = ecc_make_key_ex(<c_prng, find_prng("yarrow"), &key, curve); + native_timing_stop(); + + if (err != CRYPT_OK) { throw_new(env, "java/security/GeneralSecurityException", error_to_string(err)); return NULL; } @@ -380,8 +384,12 @@ JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKey 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) { + + native_timing_start(); + int err = ecc_shared_secret(&priv, &pub, result, &output_len); + native_timing_stop(); + + if (err != CRYPT_OK) { throw_new(env, "java/security/GeneralSecurityException", error_to_string(err)); free_curve(curve); return NULL; @@ -416,8 +424,12 @@ JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSig unsigned char result[curve->size*4]; unsigned long output_len = curve->size*4; - int err; - if ((err = ecc_sign_hash((unsigned char *) data_data, data_size, result, &output_len, <c_prng, find_prng("yarrow"), &priv)) != CRYPT_OK) { + + native_timing_start(); + int err = ecc_sign_hash((unsigned char *) data_data, data_size, result, &output_len, <c_prng, find_prng("yarrow"), &priv); + native_timing_stop(); + + if (err != CRYPT_OK) { throw_new(env, "java/security/GeneralSecurityException", error_to_string(err)); free_curve(curve); (*env)->ReleaseByteArrayElements(env, data, data_data, JNI_ABORT); @@ -450,9 +462,12 @@ JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSigna jsize sig_size = (*env)->GetArrayLength(env, signature); jbyte *sig_data = (*env)->GetByteArrayElements(env, signature, NULL); - int err; int result; - if ((err = ecc_verify_hash((unsigned char *) sig_data, sig_size, (unsigned char *) data_data, data_size, &result, &pub)) != CRYPT_OK) { + native_timing_start(); + int err = ecc_verify_hash((unsigned char *) sig_data, sig_size, (unsigned char *) data_data, data_size, &result, &pub); + native_timing_stop(); + + if (err != CRYPT_OK) { throw_new(env, "java/security/GeneralSecurityException", error_to_string(err)); free_curve(curve); (*env)->ReleaseByteArrayElements(env, data, data_data, JNI_ABORT); @@ -464,4 +479,16 @@ JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSigna (*env)->ReleaseByteArrayElements(env, signature, sig_data, JNI_ABORT); free_curve(curve); return result; +} + +JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_TomcryptLib_supportsNativeTiming(JNIEnv *env, jobject this) { + return native_timing_supported(); +} + +JNIEXPORT jlong JNICALL Java_cz_crcs_ectester_standalone_libs_TomcryptLib_getNativeTimingResolution(JNIEnv *env, jobject this) { + return native_timing_resolution(); +} + +JNIEXPORT jlong JNICALL Java_cz_crcs_ectester_standalone_libs_TomcryptLib_getLastNativeTiming(JNIEnv *env, jobject this) { + return native_timing_last(); } \ No newline at end of file diff --git a/util/plot_dh.py b/util/plot_dh.py index 468e73a..60e20ae 100755 --- a/util/plot_dh.py +++ b/util/plot_dh.py @@ -18,10 +18,17 @@ import argparse from copy import deepcopy from operator import itemgetter +from utils import hw, moving_average, plot_hist + if __name__ == "__main__": parser = argparse.ArgumentParser(description="Plot ECTester ECDH timing.") parser.add_argument("-o", "--output", dest="output", type=argparse.FileType("wb"), help="Write image to [file], do not display.", metavar="file") - parser.add_argument("--skip-first", dest="skip_first", action="store_true", help="Skip first entry, as it's usually a large outlier.") + parser.add_argument("--priv", dest="priv", action="store_true", help="Show private key MSB heatmap plot.") + parser.add_argument("--hist", dest="hist", action="store_true", help="Show time histogram.") + parser.add_argument("--hw-hist", dest="hw_hist", action="store_true", help="Show Hamming weight heatmap (private key Hamming weight and time).") + parser.add_argument("--avg", dest="avg", action="store_true", help="Show moving average of time.") + parser.add_argument("--log", dest="log", action="store_true", help="Use logarithmic scale.") + parser.add_argument("--skip-first", dest="skip_first", nargs="?", const=1, type=int, help="Skip first entry, as it's usually a large outlier.") parser.add_argument("-t", "--title", dest="title", nargs="?", default="", type=str, help="What title to give the figure.") parser.add_argument("file", type=str, help="The file to plot(csv).") @@ -34,18 +41,17 @@ if __name__ == "__main__": hx = lambda x: int(x, 16) data = np.genfromtxt(opts.file, delimiter=";", skip_header=1, converters={2: hx, 3: hx, 4: hx}, dtype=np.dtype([("index","u4"), ("time","u4"), ("pub", "O"), ("priv", "O"), ("secret","O")])) if opts.skip_first: - data = data[1:] + data = data[opts.skip_first:] + time_data = data["time"] if "nano" in header_names[1]: unit = r"$\mu s$" - time_data = map(lambda x: x[1]//1000, data) + time_data = np.array(list(map(lambda x: x//1000, time_data))) else: unit = r"ms" - time_data = map(itemgetter(1), data) - time_data = list(time_data) - priv_data = list(map(itemgetter(2), data)) - pub_data = list(map(itemgetter(3), data)) - secret_data = list(map(itemgetter(4), data)) + priv_data = data["priv"] + pub_data = data["pub"] + secret_data = data["secret"] plt.style.use("ggplot") fig = plt.figure() @@ -58,43 +64,37 @@ if __name__ == "__main__": layout_kwargs["rect"] = [0, 0.02, 1, 0.98] fig.tight_layout(**layout_kwargs) - axe_hist = fig.add_subplot(2,1,1) time_max = max(time_data) - time_avg = np.average(time_data) - time_median = np.median(time_data) - axe_hist.hist(time_data, bins=time_max//3, log=True) - axe_hist.axvline(x=time_avg, alpha=0.7, linestyle="dotted", color="red", label="avg = {}".format(time_avg)) - axe_hist.axvline(x=time_median, alpha=0.7, linestyle="dotted", color="green", label="median = {}".format(time_median)) - axe_hist.set_ylabel("count\n(log)") - axe_hist.set_xlabel("time ({})".format(unit)) - axe_hist.xaxis.set_major_locator(ticker.MaxNLocator()) - axe_hist.legend(loc="best") + time_min = min(time_data) + bit_size = len(bin(max(priv_data))) - 2 - priv_bit_bins = {} - for i in range(len(data)): - skey = priv_data[i] - time = time_data[i] - skey_hw = 0 - while skey: - skey_hw += 1 - skey &= skey - 1 - if skey_hw in priv_bit_bins: - priv_bit_bins[skey_hw].append(time) - else: - priv_bit_bins[skey_hw] = [time] - priv_bit_x = [] - priv_bit_y = [] - for k,v in priv_bit_bins.items(): - priv_bit_x.extend([k] * len(v)) - priv_bit_y.extend(v) - - axe_priv_hist = fig.add_subplot(2,1,2) - h, xe, ye = np.histogram2d(priv_bit_x, priv_bit_y, bins=[max(priv_bit_bins) - min(priv_bit_bins), (time_max - min(time_data))//5]) cmap = deepcopy(plt.cm.plasma) cmap.set_bad("black") + + norm = colors.Normalize() + if opts.log: + norm = colors.LogNorm() + + axe_private = fig.add_subplot(3,1,1) + priv_msb = np.array(list(map(lambda x: x >> (bit_size - 8), priv_data)), dtype=np.dtype("u1")) + heatmap, xedges, yedges = np.histogram2d(priv_msb, time_data, bins=[128, time_max - time_min]) + extent = [xedges[0], xedges[-1], yedges[0], yedges[-1]] + axe_private.imshow(heatmap.T, extent=extent, aspect="auto", cmap=cmap, origin="low", interpolation="nearest", norm=norm) + axe_private.set_xlabel("private key MSB value") + axe_private.set_ylabel("ECDH time ({})".format(unit)) + + axe_hist = fig.add_subplot(3,1,2) + plot_hist(axe_hist, time_data, "ECDH time ({})".format(unit), opts.log) + axe_hist.legend(loc="best") + + axe_priv_hist = fig.add_subplot(3,1,3) + priv_hw = np.array(list(map(hw, priv_data)), dtype=np.dtype("u2")) + h, xe, ye = np.histogram2d(priv_hw, time_data, bins=[max(priv_hw) - min(priv_hw), time_max - time_min]) im = axe_priv_hist.imshow(h.T, origin="low", cmap=cmap, aspect="auto", extent=[xe[0], xe[-1], ye[0], ye[-1]], norm=colors.LogNorm()) + axe_priv_hist.axvline(x=bit_size//2, alpha=0.7, linestyle="dotted", color="white", label=str(bit_size//2) + " bits") axe_priv_hist.set_xlabel("private key Hamming weight") axe_priv_hist.set_ylabel("time ({})".format(unit)) + axe_priv_hist.legend(loc="best") fig.colorbar(im, ax=axe_priv_hist) fig.text(0.01, 0.02, "Data size: {}".format(len(time_data)), size="small") diff --git a/util/plot_gen.py b/util/plot_gen.py index c07fc91..9d4863f 100755 --- a/util/plot_gen.py +++ b/util/plot_gen.py @@ -17,17 +17,7 @@ from matplotlib import ticker, colors from copy import deepcopy import argparse -def hw(i): - res = 0 - while i: - res += 1 - i &= i - 1 - return res - -def moving_average(a, n) : - ret = np.cumsum(a, dtype=float) - ret[n:] = ret[n:] - ret[:-n] - return ret[n - 1:] / n +from utils import hw, moving_average, plot_hist if __name__ == "__main__": parser = argparse.ArgumentParser(description="Plot results of ECTester key generation timing.") @@ -85,7 +75,6 @@ if __name__ == "__main__": pub_data = data["pub"] priv_data = data["priv"] - gen_unit = "ms" if header_names[1].endswith("[nano]"): gen_unit = r"$\mu s$" @@ -121,39 +110,23 @@ if __name__ == "__main__": if plots[0]: axe_private = fig.add_subplot(n_plots, 1, plot_i) priv_msb = np.array(list(map(lambda x: x >> (bit_size - 8), priv_data)), dtype=np.dtype("u1")) - heatmap, xedges, yedges = np.histogram2d(priv_msb, gen_time_data, bins=[256, max_gen_time - min_gen_time]) - extent = [xedges[0], xedges[-1], yedges[0], yedges[-1]] + max_msb = max(priv_msb) + min_msb = min(priv_msb) + heatmap, xedges, yedges = np.histogram2d(priv_msb, gen_time_data, bins=[max_msb - min_msb, max_gen_time - min_gen_time]) + extent = [min_msb, max_msb, yedges[0], yedges[-1]] axe_private.imshow(heatmap.T, extent=extent, aspect="auto", cmap=cmap, origin="low", interpolation="nearest", norm=norm) - axe_private.set_xlabel("private key MSB value\n(big endian)") + axe_private.set_xlabel("private key MSB value") axe_private.set_ylabel("keygen time ({})".format(gen_unit)) plot_i += 1 if plots[1]: axe_hist = fig.add_subplot(n_plots, 1, plot_i) - time_avg = np.average(gen_time_data) - time_median = np.median(gen_time_data) - axe_hist.hist(gen_time_data, bins=max_gen_time - min_gen_time, log=opts.log) - axe_hist.axvline(x=time_avg, alpha=0.7, linestyle="dotted", color="blue", label="avg = {}".format(time_avg)) - axe_hist.axvline(x=time_median, alpha=0.7, linestyle="dotted", color="green", label="median = {}".format(time_median)) - axe_hist.set_ylabel("count" + ("\n(log)" if opts.log else "")) - axe_hist.set_xlabel("keygen time ({})".format(gen_unit)) - axe_hist.xaxis.set_major_locator(ticker.MaxNLocator()) - axe_hist.legend(loc="best") + plot_hist(axe_hist, gen_time_data, "keygen time ({})".format(gen_unit), opts.log) plot_i += 1 if plots[2]: axe_hist = fig.add_subplot(n_plots, 1, plot_i) - time_max = max(export_time_data) - time_min = min(export_time_data) - time_avg = np.average(export_time_data) - time_median = np.median(export_time_data) - axe_hist.hist(export_time_data, bins=time_max - time_min, log=opts.log) - axe_hist.axvline(x=time_avg, alpha=0.7, linestyle="dotted", color="blue", label="avg = {}".format(time_avg)) - axe_hist.axvline(x=time_median, alpha=0.7, linestyle="dotted", color="green", label="median = {}".format(time_median)) - axe_hist.set_ylabel("count" + ("\n(log)" if opts.log else "")) - axe_hist.set_xlabel("export time ({})".format(export_unit)) - axe_hist.xaxis.set_major_locator(ticker.MaxNLocator()) - axe_hist.legend(loc="best") + plot_hist(axe_hist, export_time_data, "export time ({})".format(export_unit), opts.log) plot_i += 1 if plots[3]: -- cgit v1.2.3-70-g09d2