From 46b290eb6d24cd0d337d54421c8e10c9acbd6a6f Mon Sep 17 00:00:00 2001 From: J08nY Date: Mon, 5 Aug 2024 15:43:22 +0200 Subject: Add support for deterministic PRNG to OpenSSL. --- .../ectester/standalone/ECTesterStandalone.java | 42 ++++- .../crcs/ectester/standalone/libs/OpensslLib.java | 6 + .../standalone/libs/ProviderECLibrary.java | 15 +- .../cz/crcs/ectester/standalone/libs/jni/native.h | 183 +-------------------- .../cz/crcs/ectester/standalone/libs/jni/openssl.c | 53 ++++++ 5 files changed, 120 insertions(+), 179 deletions(-) (limited to 'standalone/src') diff --git a/standalone/src/main/java/cz/crcs/ectester/standalone/ECTesterStandalone.java b/standalone/src/main/java/cz/crcs/ectester/standalone/ECTesterStandalone.java index 4f76639..7967bcb 100644 --- a/standalone/src/main/java/cz/crcs/ectester/standalone/ECTesterStandalone.java +++ b/standalone/src/main/java/cz/crcs/ectester/standalone/ECTesterStandalone.java @@ -191,7 +191,8 @@ public class ECTesterStandalone { Option output = Option.builder("o").longOpt("output").desc("Output into file . The file can be prefixed by the format (one of text,yml,xml), such as: xml:.").hasArgs().argName("output_file").optionalArg(false).numberOfArgs(1).build(); Option outputRaw = Option.builder("o").longOpt("output").desc("Output CSV into file .").hasArgs().argName("output_file").optionalArg(false).numberOfArgs(1).build(); Option quiet = Option.builder("q").longOpt("quiet").desc("Do not output to stdout.").build(); - Option timeSource = Option.builder("ts").longOpt("time-source").desc("Use a given native timing source: {rdtsc, monotonic, monotonic-raw, cputime-process, cputime-thread, perfcount}").hasArgs().argName("source").optionalArg(false).numberOfArgs(1).build(); + Option timeSource = Option.builder("ts").longOpt("time-source").desc("Use a given native timing source: {rdtsc, monotonic, monotonic-raw, cputime-process, cputime-thread}").hasArgs().argName("source").optionalArg(false).numberOfArgs(1).build(); + Option prngSeed = Option.builder("ps").longOpt("prng-seed").desc("Use a deterministic PRNG with the given seed (hexadecimal).").hasArgs().argName("seed").optionalArg(false).numberOfArgs(1).build(); Options testOpts = new Options(); testOpts.addOption(bits); @@ -199,6 +200,7 @@ public class ECTesterStandalone { testOpts.addOption(curveName); testOpts.addOption(output); testOpts.addOption(quiet); + testOpts.addOption(prngSeed); testOpts.addOption(Option.builder("gt").longOpt("kpg-type").desc("Set the KeyPairGenerator object [type].").hasArg().argName("type").optionalArg(false).build()); testOpts.addOption(Option.builder("kt").longOpt("ka-type").desc("Set the KeyAgreement object [type].").hasArg().argName("type").optionalArg(false).build()); testOpts.addOption(Option.builder("st").longOpt("sig-type").desc("Set the Signature object [type].").hasArg().argName("type").optionalArg(false).build()); @@ -215,6 +217,7 @@ public class ECTesterStandalone { ecdhOpts.addOption(curveName); ecdhOpts.addOption(outputRaw); ecdhOpts.addOption(timeSource); + ecdhOpts.addOption(prngSeed); ecdhOpts.addOption(Option.builder("t").longOpt("type").desc("Set KeyAgreement object [type].").hasArg().argName("type").optionalArg(false).build()); ecdhOpts.addOption(Option.builder().longOpt("key-type").desc("Set the key [algorithm] for which the key should be derived in KeyAgreements with KDF. Default is \"AES\".").hasArg().argName("algorithm").optionalArg(false).build()); ecdhOpts.addOption(Option.builder("n").longOpt("amount").hasArg().argName("amount").optionalArg(false).desc("Do ECDH [amount] times.").build()); @@ -231,6 +234,7 @@ public class ECTesterStandalone { ecdsaOpts.addOption(curveName); ecdsaOpts.addOption(outputRaw); ecdsaOpts.addOption(timeSource); + ecdsaOpts.addOption(prngSeed); ecdsaOpts.addOptionGroup(privateKey); ecdsaOpts.addOptionGroup(publicKey); ecdsaOpts.addOption(Option.builder().longOpt("fixed").desc("Perform all ECDSA with fixed keypair.").build()); @@ -246,6 +250,7 @@ public class ECTesterStandalone { generateOpts.addOption(curveName); generateOpts.addOption(outputRaw); generateOpts.addOption(timeSource); + generateOpts.addOption(prngSeed); generateOpts.addOption(Option.builder("n").longOpt("amount").hasArg().argName("amount").optionalArg(false).desc("Generate [amount] of EC keys.").build()); generateOpts.addOption(Option.builder("t").longOpt("type").hasArg().argName("type").optionalArg(false).desc("Set KeyPairGenerator object [type].").build()); ParserOptions generate = new ParserOptions(new DefaultParser(), generateOpts, "Generate EC keypairs."); @@ -307,6 +312,7 @@ public class ECTesterStandalone { System.out.println(Colors.bold("\t\t- Fullname: ") + lib.getProvider().getName()); System.out.println(Colors.bold("\t\t- Version: ") + lib.getProvider().getVersionStr()); System.out.println(Colors.bold("\t\t- Supports native timing: ") + lib.getNativeTimingSupport().toString()); + System.out.println(Colors.bold("\t\t- Supports deterministic PRNG: ") + lib.supportsDeterministicPRNG()); Set kpgs = lib.getKPGs(); if (!kpgs.isEmpty()) { System.out.println(Colors.bold("\t\t- KeyPairGenerators: ") + kpgs.stream().map(KeyPairGeneratorIdent::getName).sorted().collect(Collectors.joining(", "))); @@ -430,6 +436,12 @@ public class ECTesterStandalone { kpg.initialize(spec); } + if (cli.hasOption("ecdh.prng-seed")) { + String seedString = cli.getOptionValue("ecdh.prng-seed"); + byte[] seed = ByteUtil.hexToBytes(seedString, true); + lib.setupDeterministicPRNG(seed); + } + if (cli.hasOption("ecdh.time-source")) { if (!lib.setNativeTimingType(cli.getOptionValue("ecdh.time-source"))) { System.err.println("Couldn't set native time source."); @@ -586,6 +598,12 @@ public class ECTesterStandalone { kpg.initialize(new ECGenParameterSpec(curveName)); } + if (cli.hasOption("ecdsa.prng-seed")) { + String seedString = cli.getOptionValue("ecdsa.prng-seed"); + byte[] seed = ByteUtil.hexToBytes(seedString, true); + lib.setupDeterministicPRNG(seed); + } + if (cli.hasOption("ecdsa.time-source")) { if (!lib.setNativeTimingType(cli.getOptionValue("ecdsa.time-source"))) { System.err.println("Couldn't set native time source."); @@ -722,6 +740,12 @@ public class ECTesterStandalone { kpg.initialize(new ECGenParameterSpec(curveName)); } + if (cli.hasOption("generate.prng-seed")) { + String seedString = cli.getOptionValue("generate.prng-seed"); + byte[] seed = ByteUtil.hexToBytes(seedString, true); + lib.setupDeterministicPRNG(seed); + } + if (cli.hasOption("generate.time-source")) { if (!lib.setNativeTimingType(cli.getOptionValue("generate.time-source"))) { System.err.println("Couldn't set native time source."); @@ -818,6 +842,13 @@ public class ECTesterStandalone { testTo = -1; } + ProviderECLibrary lib = cfg.selected; + if (cli.hasOption("test.prng-seed")) { + String seedString = cli.getOptionValue("test.prng-seed"); + byte[] seed = ByteUtil.hexToBytes(seedString, true); + lib.setupDeterministicPRNG(seed); + } + switch (testSuite) { case "test-vectors": suite = new StandaloneTestVectorSuite(writer, cfg, cli); @@ -997,6 +1028,15 @@ public class ECTesterStandalone { } } + if (cli.isNext("generate") || cli.isNext("ecdh") || cli.isNext("ecdsa") || cli.isNext("test")) { + if (cli.hasOption(next + ".prng-seed")) { + if (!selected.supportsDeterministicPRNG()) { + System.err.printf("Deterministic PRNG is not supported by library %s.%n", selected.name()); + return false; + } + } + } + return true; } } diff --git a/standalone/src/main/java/cz/crcs/ectester/standalone/libs/OpensslLib.java b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/OpensslLib.java index 61f00a4..13490f9 100644 --- a/standalone/src/main/java/cz/crcs/ectester/standalone/libs/OpensslLib.java +++ b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/OpensslLib.java @@ -16,4 +16,10 @@ public class OpensslLib extends NativeECLibrary { @Override public native Set getCurves(); + + @Override + public native boolean supportsDeterministicPRNG(); + + @Override + public native void setupDeterministicPRNG(byte[] seed); } diff --git a/standalone/src/main/java/cz/crcs/ectester/standalone/libs/ProviderECLibrary.java b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/ProviderECLibrary.java index d9d6749..936120f 100644 --- a/standalone/src/main/java/cz/crcs/ectester/standalone/libs/ProviderECLibrary.java +++ b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/ProviderECLibrary.java @@ -69,21 +69,28 @@ public abstract class ProviderECLibrary implements ECLibrary { } public boolean setNativeTimingType(String type) { - return false; + return false; } public long getNativeTimingResolution() { return 0; } - public String getNativeTimingUnit() { - return null; - } + public String getNativeTimingUnit() { + return null; + } public long getLastNativeTiming() { return 0; } + public boolean supportsDeterministicPRNG() { + return false; + } + + public void setupDeterministicPRNG(byte[] seed) { + } + @Override public Set getKAs() { return getIdents("KeyAgreement", KeyAgreementIdent::get); diff --git a/standalone/src/main/resources/cz/crcs/ectester/standalone/libs/jni/native.h b/standalone/src/main/resources/cz/crcs/ectester/standalone/libs/jni/native.h index 60c59b1..89f4b63 100644 --- a/standalone/src/main/resources/cz/crcs/ectester/standalone/libs/jni/native.h +++ b/standalone/src/main/resources/cz/crcs/ectester/standalone/libs/jni/native.h @@ -617,186 +617,21 @@ JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_OpensslLib_creat JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_OpensslLib_getCurves (JNIEnv *, jobject); -#ifdef __cplusplus -} -#endif -#endif -/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeProvider_Openssl */ - -#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeProvider_Openssl -#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeProvider_Openssl -#ifdef __cplusplus -extern "C" { -#endif -#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Openssl_serialVersionUID -#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Openssl_serialVersionUID 1421746759512286392LL -#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Openssl_MAX_ARRAY_SIZE -#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Openssl_MAX_ARRAY_SIZE 2147483639L -#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Openssl_KEYS -#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Openssl_KEYS 0L -#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Openssl_VALUES -#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Openssl_VALUES 1L -#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Openssl_ENTRIES -#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Openssl_ENTRIES 2L -#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Openssl_serialVersionUID -#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Openssl_serialVersionUID 4112578634029874840LL -#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Openssl_serialVersionUID -#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Openssl_serialVersionUID -4298000515446427739LL -/* - * Class: cz_crcs_ectester_standalone_libs_jni_NativeProvider_Openssl - * Method: setup - * Signature: ()V - */ -JNIEXPORT void JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeProvider_00024Openssl_setup - (JNIEnv *, jobject); - -#ifdef __cplusplus -} -#endif -#endif -/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Openssl */ - -#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Openssl -#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Openssl -#ifdef __cplusplus -extern "C" { -#endif -#undef cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Openssl_DEFAULT_KEYSIZE -#define cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Openssl_DEFAULT_KEYSIZE 256L /* - * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Openssl - * Method: keysizeSupported - * Signature: (I)Z - */ -JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Openssl_keysizeSupported - (JNIEnv *, jobject, jint); - -/* - * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Openssl - * Method: paramsSupported - * Signature: (Ljava/security/spec/AlgorithmParameterSpec;)Z - */ -JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Openssl_paramsSupported - (JNIEnv *, jobject, jobject); - -/* - * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Openssl - * Method: generate - * Signature: (ILjava/security/SecureRandom;)Ljava/security/KeyPair; - */ -JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Openssl_generate__ILjava_security_SecureRandom_2 - (JNIEnv *, jobject, jint, jobject); - -/* - * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Openssl - * Method: generate - * Signature: (Ljava/security/spec/AlgorithmParameterSpec;Ljava/security/SecureRandom;)Ljava/security/KeyPair; - */ -JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Openssl_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_Openssl */ - -#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPublicKey_Openssl -#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPublicKey_Openssl -#ifdef __cplusplus -extern "C" { -#endif -#ifdef __cplusplus -} -#endif -#endif -/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeECPrivateKey_Openssl */ - -#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPrivateKey_Openssl -#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPrivateKey_Openssl -#ifdef __cplusplus -extern "C" { -#endif -#ifdef __cplusplus -} -#endif -#endif -/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Openssl */ - -#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Openssl -#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Openssl -#ifdef __cplusplus -extern "C" { -#endif -/* - * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Openssl - * Method: generateSecret - * Signature: ([B[BLjava/security/spec/ECParameterSpec;)[B - */ -JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_00024Openssl_generateSecret___3B_3BLjava_security_spec_ECParameterSpec_2 - (JNIEnv *, jobject, jbyteArray, jbyteArray, jobject); - -/* - * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Openssl - * 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_00024Openssl_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_Openssl */ - -#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Openssl -#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Openssl -#ifdef __cplusplus -extern "C" { -#endif -/* - * Class: cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Openssl - * Method: sign - * Signature: ([B[BLjava/security/spec/ECParameterSpec;)[B - */ -JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024Openssl_sign - (JNIEnv *, jobject, jbyteArray, jbyteArray, jobject); - -/* - * Class: cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Openssl - * Method: verify - * Signature: ([B[B[BLjava/security/spec/ECParameterSpec;)Z - */ -JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024Openssl_verify - (JNIEnv *, jobject, jbyteArray, jbyteArray, jbyteArray, jobject); - -#ifdef __cplusplus -} -#endif -#endif -/* Header for class cz_crcs_ectester_standalone_libs_MscngLib */ - -#ifndef _Included_cz_crcs_ectester_standalone_libs_MscngLib -#define _Included_cz_crcs_ectester_standalone_libs_MscngLib -#ifdef __cplusplus -extern "C" { -#endif -/* - * Class: cz_crcs_ectester_standalone_libs_MscngLib - * Method: createProvider - * Signature: ()Ljava/security/Provider; + * Class: cz_crcs_ectester_standalone_libs_OpensslLib + * Method: supportsDeterministicPRNG + * Signature: ()Z */ -JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_MscngLib_createProvider +JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_OpensslLib_supportsDeterministicPRNG (JNIEnv *, jobject); /* - * Class: cz_crcs_ectester_standalone_libs_MscngLib - * Method: getCurves - * Signature: ()Ljava/util/Set; + * Class: cz_crcs_ectester_standalone_libs_OpensslLib + * Method: setupDeterministicPRNG + * Signature: ([B)V */ -JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_MscngLib_getCurves - (JNIEnv *, jobject); +JNIEXPORT void JNICALL Java_cz_crcs_ectester_standalone_libs_OpensslLib_setupDeterministicPRNG + (JNIEnv *, jobject, jbyteArray); #ifdef __cplusplus } diff --git a/standalone/src/main/resources/cz/crcs/ectester/standalone/libs/jni/openssl.c b/standalone/src/main/resources/cz/crcs/ectester/standalone/libs/jni/openssl.c index 59eb0db..d791646 100644 --- a/standalone/src/main/resources/cz/crcs/ectester/standalone/libs/jni/openssl.c +++ b/standalone/src/main/resources/cz/crcs/ectester/standalone/libs/jni/openssl.c @@ -14,6 +14,7 @@ #include #include #include +#include @@ -69,6 +70,58 @@ JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_OpensslLib_getCu return result; } +JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_OpensslLib_supportsDeterministicPRNG(JNIEnv *env, jobject self) { + return JNI_TRUE; +} + +static int stdlib_rand_seed(const void *buf, int num) +{ + unsigned int s = 0; + for (int i = 0; i < num && i < sizeof(unsigned int); ++i) { + s |= ((unsigned char*)buf)[i] << 8*i; + } + srand(s); + return 1; +} + +// Fill the buffer with random bytes. For each byte in the buffer, we generate +// a random number and clamp it to the range of a byte, 0-255. +static int stdlib_rand_bytes(unsigned char *buf, int num) +{ + for (int index = 0; index < num; ++index) + { + buf[index] = rand() % 256; + } + return 1; +} + +static void stdlib_rand_cleanup() {} +static int stdlib_rand_add(const void *buf, int num, double add_entropy) +{ + return 1; +} +static int stdlib_rand_status() +{ + return 1; +} + +RAND_METHOD stdlib_rand_meth = { stdlib_rand_seed, + stdlib_rand_bytes, + stdlib_rand_cleanup, + stdlib_rand_add, + stdlib_rand_bytes, + stdlib_rand_status +}; + +JNIEXPORT void JNICALL Java_cz_crcs_ectester_standalone_libs_OpensslLib_setupDeterministicPRNG(JNIEnv *env, jobject self, jbyteArray seed) { + printf("Enabling rand method.\n"); + RAND_set_rand_method(&stdlib_rand_meth); + jbyte *seed_data = (*env)->GetByteArrayElements(env, seed, NULL); + jsize seed_length = (*env)->GetArrayLength(env, seed); + RAND_seed(seed_data, seed_length); + (*env)->ReleaseByteArrayElements(env, seed, seed_data, JNI_ABORT); +} + JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Openssl_keysizeSupported(JNIEnv *env, jobject self, jint keysize) { size_t ncurves = EC_get_builtin_curves(NULL, 0); EC_builtin_curve curves[ncurves]; -- cgit v1.2.3-70-g09d2