From 60d3b5b9ffb8c1273af0cc0338ec1c98f464f4b1 Mon Sep 17 00:00:00 2001 From: Hubert Kario Date: Sat, 18 Jan 2020 19:13:02 +0100 Subject: [PATCH] add FFDH to speed command the openssl speed command could not benchmark FFDH speed, but it could benchmark ECDH, making comparisons between the two hard this commit adds this feature fixes #9475 Signed-off-by: Hubert Kario Reviewed-by: Matt Caswell Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/10887) --- apps/speed.c | 325 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 320 insertions(+), 5 deletions(-) diff --git a/apps/speed.c b/apps/speed.c index bd05631f30..f481b6b8fd 100644 --- a/apps/speed.c +++ b/apps/speed.c @@ -16,6 +16,7 @@ #define ECDH_SECONDS 10 #define EdDSA_SECONDS 10 #define SM2_SECONDS 10 +#define FFDH_SECONDS 10 /* We need to use some deprecated APIs */ #define OPENSSL_SUPPRESS_DEPRECATED @@ -98,6 +99,9 @@ # include # include "./testrsa.h" #endif +#ifndef OPENSSL_NO_DH +# include +#endif #include #if !defined(OPENSSL_NO_DSA) && !defined(OPENSSL_NO_DEPRECATED_3_0) # include @@ -125,6 +129,7 @@ #define MAX_MISALIGNMENT 63 #define MAX_ECDH_SIZE 256 #define MISALIGN 64 +#define MAX_FFDH_SIZE 1024 typedef struct openssl_speed_sec_st { int sym; @@ -134,6 +139,7 @@ typedef struct openssl_speed_sec_st { int ecdh; int eddsa; int sm2; + int ffdh; } openssl_speed_sec_t; static volatile int run = 0; @@ -435,6 +441,22 @@ static const OPT_PAIR rsa_choices[RSA_NUM] = { static double rsa_results[RSA_NUM][2]; /* 2 ops: sign then verify */ #endif /* OPENSSL_NO_RSA */ +#ifndef OPENSSL_NO_DH +enum ff_params_t { + R_FFDH_2048, R_FFDH_3072, R_FFDH_4096, R_FFDH_6144, R_FFDH_8192, FFDH_NUM +}; + +static const OPT_PAIR ffdh_choices[FFDH_NUM] = { + {"ffdh2048", R_FFDH_2048}, + {"ffdh3072", R_FFDH_3072}, + {"ffdh4096", R_FFDH_4096}, + {"ffdh6144", R_FFDH_6144}, + {"ffdh8192", R_FFDH_8192}, +}; + +static double ffdh_results[FFDH_NUM][1]; /* 1 op: derivation */ +#endif /* OPENSSL_NO_DH */ + #ifndef OPENSSL_NO_EC enum ec_curves_t { R_EC_P160, R_EC_P192, R_EC_P224, R_EC_P256, R_EC_P384, R_EC_P521, @@ -561,6 +583,11 @@ typedef struct loopargs_st { unsigned char *secret_a; unsigned char *secret_b; size_t outlen[EC_NUM]; +#endif +#ifndef OPENSSL_NO_DH + EVP_PKEY_CTX *ffdh_ctx[FFDH_NUM]; + unsigned char *secret_ff_a; + unsigned char *secret_ff_b; #endif EVP_CIPHER_CTX *ctx; #ifndef OPENSSL_NO_DEPRECATED_3_0 @@ -1067,6 +1094,24 @@ static int RSA_verify_loop(void *args) } #endif +#ifndef OPENSSL_NO_DH +static long ffdh_c[FFDH_NUM][1]; + +static int FFDH_derive_key_loop(void *args) +{ + loopargs_t *tempargs = *(loopargs_t **) args; + EVP_PKEY_CTX *ffdh_ctx = tempargs->ffdh_ctx[testnum]; + unsigned char *derived_secret = tempargs->secret_ff_a; + size_t outlen = MAX_FFDH_SIZE; + int count; + + for (count = 0; COND(ffdh_c[testnum][0]); count++) + EVP_PKEY_derive(ffdh_ctx, derived_secret, &outlen); + + return count; +} +#endif /* OPENSSL_NO_DH */ + #if !defined(OPENSSL_NO_DSA) && !defined(OPENSSL_NO_DEPRECATED_3_0) static long dsa_c[DSA_NUM][2]; static int DSA_sign_loop(void *args) @@ -1463,7 +1508,8 @@ int speed_main(int argc, char **argv) #endif openssl_speed_sec_t seconds = { SECONDS, RSA_SECONDS, DSA_SECONDS, ECDSA_SECONDS, ECDH_SECONDS, - EdDSA_SECONDS, SM2_SECONDS }; + EdDSA_SECONDS, SM2_SECONDS, + FFDH_SECONDS }; /* What follows are the buffers and key material. */ #if !defined(OPENSSL_NO_RC5) && !defined(OPENSSL_NO_DEPRECATED_3_0) @@ -1521,6 +1567,23 @@ int speed_main(int argc, char **argv) uint8_t rsa_doit[RSA_NUM] = { 0 }; int primes = RSA_DEFAULT_PRIME_NUM; #endif +#ifndef OPENSSL_NO_DH + typedef struct ffdh_params_st { + const char *name; + unsigned int nid; + unsigned int bits; + } FFDH_PARAMS; + + static const FFDH_PARAMS ffdh_params[FFDH_NUM] = { + {"ffdh2048", NID_ffdhe2048, 2048}, + {"ffdh3072", NID_ffdhe3072, 3072}, + {"ffdh4096", NID_ffdhe4096, 4096}, + {"ffdh6144", NID_ffdhe6144, 6144}, + {"ffdh8192", NID_ffdhe8192, 8192} + }; + uint8_t ffdh_doit[FFDH_NUM] = { 0 }; + +#endif /* OPENSSL_NO_DH */ #if !defined(OPENSSL_NO_DSA) && !defined(OPENSSL_NO_DEPRECATED_3_0) static const unsigned int dsa_bits[DSA_NUM] = { 512, 1024, 2048 }; uint8_t dsa_doit[DSA_NUM] = { 0 }; @@ -1720,7 +1783,7 @@ int speed_main(int argc, char **argv) case OPT_SECONDS: seconds.sym = seconds.rsa = seconds.dsa = seconds.ecdsa = seconds.ecdh = seconds.eddsa - = seconds.sm2 = atoi(opt_arg()); + = seconds.sm2 = seconds.ffdh = atoi(opt_arg()); break; case OPT_BYTES: lengths_single = atoi(opt_arg()); @@ -1767,6 +1830,18 @@ int speed_main(int argc, char **argv) } } #endif +#ifndef OPENSSL_NO_DH + if (strncmp(algo, "ffdh", 4) == 0) { + if (algo[4] == '\0') { + memset(ffdh_doit, 1, sizeof(ffdh_doit)); + continue; + } + if (opt_found(algo, ffdh_choices, &i)) { + ffdh_doit[i] = 2; + continue; + } + } +#endif #if !defined(OPENSSL_NO_DSA) && !defined(OPENSSL_NO_DEPRECATED_3_0) if (strncmp(algo, "dsa", 3) == 0) { if (algo[3] == '\0') { @@ -1901,6 +1976,10 @@ int speed_main(int argc, char **argv) #ifndef OPENSSL_NO_EC loopargs[i].secret_a = app_malloc(MAX_ECDH_SIZE, "ECDH secret a"); loopargs[i].secret_b = app_malloc(MAX_ECDH_SIZE, "ECDH secret b"); +#endif +#ifndef OPENSSL_NO_DH + loopargs[i].secret_ff_a = app_malloc(MAX_FFDH_SIZE, "FFDH secret a"); + loopargs[i].secret_ff_b = app_malloc(MAX_FFDH_SIZE, "FFDH secret b"); #endif } @@ -1919,6 +1998,9 @@ int speed_main(int argc, char **argv) #if !defined(OPENSSL_NO_RSA) && !defined(OPENSSL_NO_DEPRECATED_3_0) memset(rsa_doit, 1, sizeof(rsa_doit)); #endif +#ifndef OPENSSL_NO_DH + memset(ffdh_doit, 1, sizeof(ffdh_doit)); +#endif #if !defined(OPENSSL_NO_DSA) && !defined(OPENSSL_NO_DEPRECATED_3_0) memset(dsa_doit, 1, sizeof(dsa_doit)); #endif @@ -2110,7 +2192,7 @@ int speed_main(int argc, char **argv) c[D_IGE_256_AES][i] = c[D_IGE_256_AES][i - 1] * l0 / l1; } -#if !defined(OPENSSL_NO_RSA) && !defined(OPENSSL_NO_DEPRECATED_3_0) +# if !defined(OPENSSL_NO_RSA) && !defined(OPENSSL_NO_DEPRECATED_3_0) rsa_c[R_RSA_512][0] = count / 2000; rsa_c[R_RSA_512][1] = count / 400; for (i = 1; i < RSA_NUM; i++) { @@ -2260,6 +2342,19 @@ int speed_main(int argc, char **argv) # endif # endif /* OPENSSL_NO_EC */ +# ifndef OPENSSL_NO_DH + ffdh_c[R_FFDH_2048][0] = count / 1000; + for (i = R_FFDH_3072; i <= R_FFDH_8192; i++) { + ffdh_c[i][0] = ffdh_c[i - 1][0] / 2; + if (ffdh_doit[i] <= 1 && ffdh_c[i][0] == 0) { + ffdh_doit[i] = 0; + } else { + if (ffdh_c[i][0] == 0) + ffdh_c[i][0] = 1; + } + } +# endif /* OPENSSL_NO_DH */ + # else /* not worth fixing */ # error "You cannot disable DES on systems without SIGALRM." @@ -3510,8 +3605,188 @@ int speed_main(int argc, char **argv) } } # endif /* OPENSSL_NO_SM2 */ - #endif /* OPENSSL_NO_EC */ + +#ifndef OPENSSL_NO_DH + for (testnum = 0; testnum < FFDH_NUM; testnum++) { + int ffdh_checks = 1; + + if (!ffdh_doit[testnum]) + continue; + + for (i = 0; i < loopargs_len; i++) { + EVP_PKEY *pkey_A = NULL; + EVP_PKEY *pkey_B = NULL; + EVP_PKEY_CTX *ffdh_ctx = NULL; + EVP_PKEY_CTX *test_ctx = NULL; + size_t secret_size; + size_t test_out; + + /* Ensure that the error queue is empty */ + if (ERR_peek_error()) { + BIO_printf(bio_err, + "WARNING: the error queue contains previous unhandled errors.\n"); + ERR_print_errors(bio_err); + } + + pkey_A = EVP_PKEY_new(); + if (!pkey_A) { + BIO_printf(bio_err, "Error while initialising EVP_PKEY (out of memory?).\n"); + ERR_print_errors(bio_err); + rsa_count = 1; + ffdh_checks = 0; + break; + } + pkey_B = EVP_PKEY_new(); + if (!pkey_B) { + BIO_printf(bio_err, "Error while initialising EVP_PKEY (out of memory?).\n"); + ERR_print_errors(bio_err); + rsa_count = 1; + ffdh_checks = 0; + break; + } + + ffdh_ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_DH, NULL); + if (!ffdh_ctx) { + BIO_printf(bio_err, "Error while allocating EVP_PKEY_CTX.\n"); + ERR_print_errors(bio_err); + rsa_count = 1; + ffdh_checks = 0; + break; + } + + if (EVP_PKEY_keygen_init(ffdh_ctx) <= 0) { + BIO_printf(bio_err, "Error while initialising EVP_PKEY_CTX.\n"); + ERR_print_errors(bio_err); + rsa_count = 1; + ffdh_checks = 0; + break; + } + if (EVP_PKEY_CTX_set_dh_nid(ffdh_ctx, ffdh_params[testnum].nid) <= 0) { + BIO_printf(bio_err, "Error setting DH key size for keygen.\n"); + ERR_print_errors(bio_err); + rsa_count = 1; + ffdh_checks = 0; + break; + } + + if (EVP_PKEY_keygen(ffdh_ctx, &pkey_A) <= 0 || + EVP_PKEY_keygen(ffdh_ctx, &pkey_B) <= 0) { + BIO_printf(bio_err, "FFDH key generation failure.\n"); + ERR_print_errors(bio_err); + rsa_count = 1; + ffdh_checks = 0; + break; + } + + EVP_PKEY_CTX_free(ffdh_ctx); + + /* check if the derivation works correctly both ways so that + * we know if future derive calls will fail, and we can skip + * error checking in benchmarked code */ + ffdh_ctx = EVP_PKEY_CTX_new(pkey_A, NULL); + if (!ffdh_ctx) { + BIO_printf(bio_err, "Error while allocating EVP_PKEY_CTX.\n"); + ERR_print_errors(bio_err); + rsa_count = 1; + ffdh_checks = 0; + break; + } + if (EVP_PKEY_derive_init(ffdh_ctx) <= 0) { + BIO_printf(bio_err, "FFDH derivation context init failure.\n"); + ERR_print_errors(bio_err); + rsa_count = 1; + ffdh_checks = 0; + break; + } + if (EVP_PKEY_derive_set_peer(ffdh_ctx, pkey_B) <= 0) { + BIO_printf(bio_err, "Assigning peer key for derivation failed.\n"); + ERR_print_errors(bio_err); + rsa_count = 1; + ffdh_checks = 0; + break; + } + if (EVP_PKEY_derive(ffdh_ctx, NULL, &secret_size) <= 0) { + BIO_printf(bio_err, "Checking size of shared secret failed.\n"); + ERR_print_errors(bio_err); + rsa_count = 1; + ffdh_checks = 0; + break; + } + if (secret_size > MAX_FFDH_SIZE) { + BIO_printf(bio_err, "Assertion failure: shared secret too large.\n"); + rsa_count = 1; + ffdh_checks = 0; + break; + } + if (EVP_PKEY_derive(ffdh_ctx, + loopargs[i].secret_ff_a, + &secret_size) <= 0) { + BIO_printf(bio_err, "Shared secret derive failure.\n"); + ERR_print_errors(bio_err); + rsa_count = 1; + ffdh_checks = 0; + break; + } + /* Now check from side B */ + test_ctx = EVP_PKEY_CTX_new(pkey_B, NULL); + if (!test_ctx) { + BIO_printf(bio_err, "Error while allocating EVP_PKEY_CTX.\n"); + ERR_print_errors(bio_err); + rsa_count = 1; + ffdh_checks = 0; + break; + } + if (!EVP_PKEY_derive_init(test_ctx) || + !EVP_PKEY_derive_set_peer(test_ctx, pkey_A) || + !EVP_PKEY_derive(test_ctx, NULL, &test_out) || + !EVP_PKEY_derive(test_ctx, loopargs[i].secret_ff_b, &test_out) || + test_out != secret_size) { + BIO_printf(bio_err, "FFDH computation failure.\n"); + rsa_count = 1; + ffdh_checks = 0; + break; + } + + /* compare the computed secrets */ + if (CRYPTO_memcmp(loopargs[i].secret_ff_a, + loopargs[i].secret_ff_b, secret_size)) { + BIO_printf(bio_err, "FFDH computations don't match.\n"); + ERR_print_errors(bio_err); + rsa_count = 1; + ffdh_checks = 0; + break; + } + + loopargs[i].ffdh_ctx[testnum] = ffdh_ctx; + + EVP_PKEY_free(pkey_A); + pkey_A = NULL; + EVP_PKEY_free(pkey_B); + pkey_B = NULL; + EVP_PKEY_CTX_free(test_ctx); + test_ctx = NULL; + } + if (ffdh_checks != 0) { + pkey_print_message("", "ffdh", ffdh_c[testnum][0], + ffdh_params[testnum].bits, seconds.ffdh); + Time_F(START); + count = + run_benchmark(async_jobs, FFDH_derive_key_loop, loopargs); + d = Time_F(STOP); + BIO_printf(bio_err, + mr ? "+R12:%ld:%d:%.2f\n" : + "%ld %u-bits FFDH ops in %.2fs\n", count, + ffdh_params[testnum].bits, d); + ffdh_results[testnum][0] = (double)count / d; + rsa_count = count; + }; + if (rsa_count <= 1) { + /* if longer than 10s, don't do any more */ + stop_it(ffdh_doit, testnum); + } + } +#endif /* OPENSSL_NO_DH */ #ifndef NO_FORK show_res: #endif @@ -3688,6 +3963,26 @@ int speed_main(int argc, char **argv) } # endif #endif /* OPENSSL_NO_EC */ +#ifndef OPENSSL_NO_DH + testnum = 1; + for (k = 0; k < FFDH_NUM; k++) { + if (!ffdh_doit[k]) + continue; + if (testnum && !mr) { + printf("%23sop op/s\n", " "); + testnum = 0; + } + if (mr) + printf("+F8:%u:%u:%f:%f\n", + k, ffdh_params[k].bits, + ffdh_results[k][0], 1.0 / ffdh_results[k][0]); + + else + printf("%4u bits ffdh %8.4fs %8.1f\n", + ffdh_params[k].bits, + 1.0 / ffdh_results[k][0], ffdh_results[k][0]); + } +#endif /* OPENSSL_NO_DH */ ret = 0; @@ -3701,6 +3996,13 @@ int speed_main(int argc, char **argv) for (k = 0; k < RSA_NUM; k++) RSA_free(loopargs[i].rsa_key[k]); #endif +#ifndef OPENSSL_NO_DH + OPENSSL_free(loopargs[i].secret_ff_a); + OPENSSL_free(loopargs[i].secret_ff_b); + for (k = 0; k < FFDH_NUM; k++) { + EVP_PKEY_CTX_free(loopargs[i].ffdh_ctx[k]); + } +#endif #if !defined(OPENSSL_NO_DSA) && !defined(OPENSSL_NO_DEPRECATED_3_0) for (k = 0; k < DSA_NUM; k++) DSA_free(loopargs[i].dsa_key[k]); @@ -3982,7 +4284,20 @@ static int do_multi(int multi, int size_num) sm2_results[k][1] += d; } # endif /* OPENSSL_NO_SM2 */ -# endif +# endif /* OPENSSL_NO_EC */ +# ifndef OPENSSL_NO_DH + else if (strncmp(buf, "+F8:", 4) == 0) { + int k; + double d; + + p = buf + 4; + k = atoi(sstrsep(&p, sep)); + sstrsep(&p, sep); + + d = atof(sstrsep(&p, sep)); + ffdh_results[k][0] += d; + } +# endif /* OPENSSL_NO_DH */ else if (strncmp(buf, "+H:", 3) == 0) { ; -- 2.25.1