diff --git a/tests/bench-slope.c b/tests/bench-slope.c index 2a203a07..9a0faefa 100644 --- a/tests/bench-slope.c +++ b/tests/bench-slope.c @@ -1,3487 +1,3487 @@ /* bench-slope.c - for libgcrypt * Copyright (C) 2013 Jussi Kivilinna * * This file is part of Libgcrypt. * * Libgcrypt is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser general Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * Libgcrypt is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this program; if not, see . */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #ifdef _WIN32 #include #endif #ifdef _GCRYPT_IN_LIBGCRYPT # include "../src/gcrypt-int.h" # include "../compat/libcompat.h" #else # include #endif #ifndef STR #define STR(v) #v #define STR2(v) STR(v) #endif #define PGM "bench-slope" #include "t-common.h" static int verbose; static int csv_mode; static int unaligned_mode; static int num_measurement_repetitions; /* CPU Ghz value provided by user, allows constructing cycles/byte and other results. */ static double cpu_ghz = -1; /* Attempt to autodetect CPU Ghz. */ static int auto_ghz; /* Whether we are running as part of the regression test suite. */ static int in_regression_test; /* The name of the currently printed section. */ static char *current_section_name; /* The name of the currently printed algorithm. */ static char *current_algo_name; /* The name of the currently printed mode. */ static char *current_mode_name; /* Currently used CPU Ghz (either user input or auto-detected. */ static double bench_ghz; /* Current accuracy of auto-detected CPU Ghz. */ static double bench_ghz_diff; static int in_fips_mode; /*************************************** Default parameters for measurements. */ /* Start at small buffer size, to get reasonable timer calibration for fast * implementations (AES-NI etc). Sixteen selected to support the largest block * size of current set cipher blocks. */ #define BUF_START_SIZE 16 /* From ~0 to ~4kbytes give comparable results with results from academia * (SUPERCOP). */ #define BUF_END_SIZE (BUF_START_SIZE + 4096) /* With 128 byte steps, we get (4096)/64 = 64 data points. */ #define BUF_STEP_SIZE 64 /* Number of repeated measurements at each data point. The median of these * measurements is selected as data point further analysis. */ #define NUM_MEASUREMENT_REPETITIONS 64 /* Target accuracy for auto-detected CPU Ghz. */ #define AUTO_GHZ_TARGET_DIFF (5e-5) /**************************************************** High-resolution timers. */ /* This benchmarking module needs needs high resolution timer. */ #undef NO_GET_NSEC_TIME #if defined(_WIN32) struct nsec_time { LARGE_INTEGER perf_count; }; static void get_nsec_time (struct nsec_time *t) { BOOL ok; ok = QueryPerformanceCounter (&t->perf_count); assert (ok); } static double get_time_nsec_diff (struct nsec_time *start, struct nsec_time *end) { static double nsecs_per_count = 0.0; double nsecs; if (nsecs_per_count == 0.0) { LARGE_INTEGER perf_freq; BOOL ok; /* Get counts per second. */ ok = QueryPerformanceFrequency (&perf_freq); assert (ok); nsecs_per_count = 1.0 / perf_freq.QuadPart; nsecs_per_count *= 1000000.0 * 1000.0; /* sec => nsec */ assert (nsecs_per_count > 0.0); } nsecs = end->perf_count.QuadPart - start->perf_count.QuadPart; /* counts */ nsecs *= nsecs_per_count; /* counts * (nsecs / count) => nsecs */ return nsecs; } #elif defined(HAVE_CLOCK_GETTIME) struct nsec_time { struct timespec ts; }; static void get_nsec_time (struct nsec_time *t) { int err; err = clock_gettime (CLOCK_REALTIME, &t->ts); assert (err == 0); } static double get_time_nsec_diff (struct nsec_time *start, struct nsec_time *end) { double nsecs; nsecs = end->ts.tv_sec - start->ts.tv_sec; nsecs *= 1000000.0 * 1000.0; /* sec => nsec */ /* This way we don't have to care if tv_nsec unsigned or signed. */ if (end->ts.tv_nsec >= start->ts.tv_nsec) nsecs += end->ts.tv_nsec - start->ts.tv_nsec; else nsecs -= start->ts.tv_nsec - end->ts.tv_nsec; return nsecs; } #elif defined(HAVE_GETTIMEOFDAY) struct nsec_time { struct timeval tv; }; static void get_nsec_time (struct nsec_time *t) { int err; err = gettimeofday (&t->tv, NULL); assert (err == 0); } static double get_time_nsec_diff (struct nsec_time *start, struct nsec_time *end) { double nsecs; nsecs = end->tv.tv_sec - start->tv.tv_sec; nsecs *= 1000000; /* sec => µsec */ /* This way we don't have to care if tv_usec unsigned or signed. */ if (end->tv.tv_usec >= start->tv.tv_usec) nsecs += end->tv.tv_usec - start->tv.tv_usec; else nsecs -= start->tv.tv_usec - end->tv.tv_usec; nsecs *= 1000; /* µsec => nsec */ return nsecs; } #else #define NO_GET_NSEC_TIME 1 #endif /* If no high resolution timer found, provide dummy bench-slope. */ #ifdef NO_GET_NSEC_TIME int main (void) { /* No nsec timer => SKIP test. */ return 77; } #else /* !NO_GET_NSEC_TIME */ /********************************************** Slope benchmarking framework. */ struct bench_obj { const struct bench_ops *ops; unsigned int num_measure_repetitions; unsigned int min_bufsize; unsigned int max_bufsize; unsigned int step_size; void *priv; void *hd; }; typedef int (*const bench_initialize_t) (struct bench_obj * obj); typedef void (*const bench_finalize_t) (struct bench_obj * obj); typedef void (*const bench_do_run_t) (struct bench_obj * obj, void *buffer, size_t buflen); struct bench_ops { bench_initialize_t initialize; bench_finalize_t finalize; bench_do_run_t do_run; }; static double safe_div (double x, double y) { union { double d; char buf[sizeof(double)]; } u_neg_zero, u_y; if (y != 0) return x / y; u_neg_zero.d = -0.0; u_y.d = y; if (memcmp(u_neg_zero.buf, u_y.buf, sizeof(double)) == 0) return -DBL_MAX; return DBL_MAX; } static double get_slope (double (*const get_x) (unsigned int idx, void *priv), void *get_x_priv, double y_points[], unsigned int npoints, double *overhead) { double sumx, sumy, sumx2, sumy2, sumxy; unsigned int i; double b, a; sumx = sumy = sumx2 = sumy2 = sumxy = 0; if (npoints <= 1) { /* No slope with zero or one point. */ return 0; } for (i = 0; i < npoints; i++) { double x, y; x = get_x (i, get_x_priv); /* bytes */ y = y_points[i]; /* nsecs */ sumx += x; sumy += y; sumx2 += x * x; /*sumy2 += y * y;*/ sumxy += x * y; } b = safe_div(npoints * sumxy - sumx * sumy, npoints * sumx2 - sumx * sumx); if (overhead) { a = safe_div(sumy - b * sumx, npoints); *overhead = a; /* nsecs */ } return b; /* nsecs per byte */ } double get_bench_obj_point_x (unsigned int idx, void *priv) { struct bench_obj *obj = priv; return (double) (obj->min_bufsize + (idx * obj->step_size)); } unsigned int get_num_measurements (struct bench_obj *obj) { unsigned int buf_range = obj->max_bufsize - obj->min_bufsize; unsigned int num = buf_range / obj->step_size + 1; while (obj->min_bufsize + (num * obj->step_size) > obj->max_bufsize) num--; return num + 1; } static int double_cmp (const void *_a, const void *_b) { const double *a, *b; a = _a; b = _b; if (*a > *b) return 1; if (*a < *b) return -1; return 0; } double do_bench_obj_measurement (struct bench_obj *obj, void *buffer, size_t buflen, double *measurement_raw, unsigned int loop_iterations) { const unsigned int num_repetitions = obj->num_measure_repetitions; const bench_do_run_t do_run = obj->ops->do_run; struct nsec_time start, end; unsigned int rep, loop; double res; if (num_repetitions < 1 || loop_iterations < 1) return 0.0; for (rep = 0; rep < num_repetitions; rep++) { get_nsec_time (&start); for (loop = 0; loop < loop_iterations; loop++) do_run (obj, buffer, buflen); get_nsec_time (&end); measurement_raw[rep] = get_time_nsec_diff (&start, &end); } /* Return median of repeated measurements. */ qsort (measurement_raw, num_repetitions, sizeof (measurement_raw[0]), double_cmp); if (num_repetitions % 2 == 1) return measurement_raw[num_repetitions / 2]; res = measurement_raw[num_repetitions / 2] + measurement_raw[num_repetitions / 2 - 1]; return res / 2; } unsigned int adjust_loop_iterations_to_timer_accuracy (struct bench_obj *obj, void *buffer, double *measurement_raw) { const double increase_thres = 3.0; double tmp, nsecs; unsigned int loop_iterations; unsigned int test_bufsize; test_bufsize = obj->min_bufsize; if (test_bufsize == 0) test_bufsize += obj->step_size; loop_iterations = 0; do { /* Increase loop iterations until we get other results than zero. */ nsecs = do_bench_obj_measurement (obj, buffer, test_bufsize, measurement_raw, ++loop_iterations); } while (nsecs < 1.0 - 0.1); do { /* Increase loop iterations until we get reasonable increase for elapsed time. */ tmp = do_bench_obj_measurement (obj, buffer, test_bufsize, measurement_raw, ++loop_iterations); } while (tmp < nsecs * (increase_thres - 0.1)); return loop_iterations; } /* Benchmark and return linear regression slope in nanoseconds per byte. */ double slope_benchmark (struct bench_obj *obj) { unsigned int num_measurements; double *measurements = NULL; double *measurement_raw = NULL; double slope, overhead; unsigned int loop_iterations, midx, i; unsigned char *real_buffer = NULL; unsigned char *buffer; size_t cur_bufsize; int err; err = obj->ops->initialize (obj); if (err < 0) return -1; num_measurements = get_num_measurements (obj); measurements = calloc (num_measurements, sizeof (*measurements)); if (!measurements) goto err_free; measurement_raw = calloc (obj->num_measure_repetitions, sizeof (*measurement_raw)); if (!measurement_raw) goto err_free; if (num_measurements < 1 || obj->num_measure_repetitions < 1 || obj->max_bufsize < 1 || obj->min_bufsize > obj->max_bufsize) goto err_free; real_buffer = malloc (obj->max_bufsize + 128 + unaligned_mode); if (!real_buffer) goto err_free; /* Get aligned buffer */ buffer = real_buffer; buffer += 128 - ((uintptr_t)real_buffer & (128 - 1)); if (unaligned_mode) buffer += unaligned_mode; /* Make buffer unaligned */ for (i = 0; i < obj->max_bufsize; i++) buffer[i] = 0x55 ^ (-i); /* Adjust number of loop iterations up to timer accuracy. */ loop_iterations = adjust_loop_iterations_to_timer_accuracy (obj, buffer, measurement_raw); /* Perform measurements */ for (midx = 0, cur_bufsize = obj->min_bufsize; cur_bufsize <= obj->max_bufsize; cur_bufsize += obj->step_size, midx++) { measurements[midx] = do_bench_obj_measurement (obj, buffer, cur_bufsize, measurement_raw, loop_iterations); measurements[midx] /= loop_iterations; } assert (midx == num_measurements); slope = get_slope (&get_bench_obj_point_x, obj, measurements, num_measurements, &overhead); free (measurement_raw); free (measurements); free (real_buffer); obj->ops->finalize (obj); return slope; err_free: if (measurement_raw) free (measurement_raw); if (measurements) free (measurements); if (real_buffer) free (real_buffer); obj->ops->finalize (obj); return -1; } /********************************************* CPU frequency auto-detection. */ static int auto_ghz_init (struct bench_obj *obj) { obj->min_bufsize = 16; obj->max_bufsize = 64 + obj->min_bufsize; obj->step_size = 8; obj->num_measure_repetitions = 16; return 0; } static void auto_ghz_free (struct bench_obj *obj) { (void)obj; } static void auto_ghz_bench (struct bench_obj *obj, void *buf, size_t buflen) { (void)obj; (void)buf; buflen *= 1024; /* Turbo frequency detection benchmark. Without CPU turbo-boost, this * function will give cycles/iteration result 1024.0 on high-end CPUs. * With turbo, result will be less and can be used detect turbo-clock. */ #ifdef HAVE_GCC_ASM_VOLATILE_MEMORY /* Auto-ghz operation takes two CPU cycles to perform. Memory barriers * are used to prevent compiler from optimizing this loop away. */ #define AUTO_GHZ_OPERATION \ asm volatile ("":"+r"(buflen)::"memory"); \ buflen ^= 1; \ asm volatile ("":"+r"(buflen)::"memory"); \ buflen -= 2 #else /* TODO: Needs alternative way of preventing compiler optimizations. * Mix of XOR and subtraction appears to do the trick for now. */ #define AUTO_GHZ_OPERATION \ buflen ^= 1; \ buflen -= 2 #endif #define AUTO_GHZ_OPERATION_2 \ AUTO_GHZ_OPERATION; \ AUTO_GHZ_OPERATION #define AUTO_GHZ_OPERATION_4 \ AUTO_GHZ_OPERATION_2; \ AUTO_GHZ_OPERATION_2 #define AUTO_GHZ_OPERATION_8 \ AUTO_GHZ_OPERATION_4; \ AUTO_GHZ_OPERATION_4 #define AUTO_GHZ_OPERATION_16 \ AUTO_GHZ_OPERATION_8; \ AUTO_GHZ_OPERATION_8 #define AUTO_GHZ_OPERATION_32 \ AUTO_GHZ_OPERATION_16; \ AUTO_GHZ_OPERATION_16 #define AUTO_GHZ_OPERATION_64 \ AUTO_GHZ_OPERATION_32; \ AUTO_GHZ_OPERATION_32 #define AUTO_GHZ_OPERATION_128 \ AUTO_GHZ_OPERATION_64; \ AUTO_GHZ_OPERATION_64 do { /* 1024 auto-ghz operations per loop, total 2048 instructions. */ AUTO_GHZ_OPERATION_128; AUTO_GHZ_OPERATION_128; AUTO_GHZ_OPERATION_128; AUTO_GHZ_OPERATION_128; AUTO_GHZ_OPERATION_128; AUTO_GHZ_OPERATION_128; AUTO_GHZ_OPERATION_128; AUTO_GHZ_OPERATION_128; } while (buflen); } static struct bench_ops auto_ghz_detect_ops = { &auto_ghz_init, &auto_ghz_free, &auto_ghz_bench }; double get_auto_ghz (void) { struct bench_obj obj = { 0 }; double nsecs_per_iteration; double cycles_per_iteration; obj.ops = &auto_ghz_detect_ops; nsecs_per_iteration = slope_benchmark (&obj); cycles_per_iteration = nsecs_per_iteration * cpu_ghz; /* Adjust CPU Ghz so that cycles per iteration would give '1024.0'. */ return safe_div(cpu_ghz * 1024, cycles_per_iteration); } double do_slope_benchmark (struct bench_obj *obj) { unsigned int try_count = 0; double ret; if (!auto_ghz) { /* Perform measurement without autodetection of CPU frequency. */ do { ret = slope_benchmark (obj); } while (ret <= 0 && try_count++ <= 4); bench_ghz = cpu_ghz; bench_ghz_diff = 0; } else { double target_diff = AUTO_GHZ_TARGET_DIFF; double cpu_auto_ghz_before; double cpu_auto_ghz_after; double nsecs_per_iteration; double diff; /* Perform measurement with CPU frequency autodetection. */ do { /* Repeat measurement until CPU turbo frequency has stabilized. */ if ((++try_count % 4) == 0) { /* Too much frequency instability on the system, relax target * accuracy. */ target_diff *= 2; } cpu_auto_ghz_before = get_auto_ghz (); nsecs_per_iteration = slope_benchmark (obj); cpu_auto_ghz_after = get_auto_ghz (); diff = 1.0 - safe_div(cpu_auto_ghz_before, cpu_auto_ghz_after); diff = diff < 0 ? -diff : diff; } while ((nsecs_per_iteration <= 0 || diff > target_diff) && try_count < 1000); ret = nsecs_per_iteration; bench_ghz = (cpu_auto_ghz_before + cpu_auto_ghz_after) / 2; bench_ghz_diff = diff; } return ret; } /********************************************************** Printing results. */ static void double_to_str (char *out, size_t outlen, double value) { const char *fmt; if (value < 1.0) fmt = "%.3f"; else if (value < 100.0) fmt = "%.2f"; else if (value < 1000.0) fmt = "%.1f"; else fmt = "%.0f"; snprintf (out, outlen, fmt, value); } static void bench_print_result_csv (double nsecs_per_byte) { double cycles_per_byte, mbytes_per_sec; char nsecpbyte_buf[16]; char mbpsec_buf[16]; char cpbyte_buf[16]; char mhz_buf[16]; char mhz_diff_buf[32]; strcpy (mhz_diff_buf, ""); *cpbyte_buf = 0; *mhz_buf = 0; double_to_str (nsecpbyte_buf, sizeof (nsecpbyte_buf), nsecs_per_byte); /* If user didn't provide CPU speed, we cannot show cycles/byte results. */ if (bench_ghz > 0.0) { cycles_per_byte = nsecs_per_byte * bench_ghz; double_to_str (cpbyte_buf, sizeof (cpbyte_buf), cycles_per_byte); double_to_str (mhz_buf, sizeof (mhz_buf), bench_ghz * 1000); if (auto_ghz && bench_ghz_diff * 1000 >= 1) { snprintf(mhz_diff_buf, sizeof(mhz_diff_buf), ",%.0f,Mhz-diff", bench_ghz_diff * 1000); } } mbytes_per_sec = safe_div(1000.0 * 1000.0 * 1000.0, nsecs_per_byte * 1024 * 1024); double_to_str (mbpsec_buf, sizeof (mbpsec_buf), mbytes_per_sec); /* We print two empty fields to allow for future enhancements. */ if (auto_ghz) { printf ("%s,%s,%s,,,%s,ns/B,%s,MiB/s,%s,c/B,%s,Mhz%s\n", current_section_name, current_algo_name? current_algo_name : "", current_mode_name? current_mode_name : "", nsecpbyte_buf, mbpsec_buf, cpbyte_buf, mhz_buf, mhz_diff_buf); } else { printf ("%s,%s,%s,,,%s,ns/B,%s,MiB/s,%s,c/B\n", current_section_name, current_algo_name? current_algo_name : "", current_mode_name? current_mode_name : "", nsecpbyte_buf, mbpsec_buf, cpbyte_buf); } } static void bench_print_result_std (double nsecs_per_byte) { double cycles_per_byte, mbytes_per_sec; char nsecpbyte_buf[16]; char mbpsec_buf[16]; char cpbyte_buf[16]; char mhz_buf[16]; char mhz_diff_buf[32]; strcpy (mhz_diff_buf, ""); double_to_str (nsecpbyte_buf, sizeof (nsecpbyte_buf), nsecs_per_byte); /* If user didn't provide CPU speed, we cannot show cycles/byte results. */ if (bench_ghz > 0.0) { cycles_per_byte = nsecs_per_byte * bench_ghz; double_to_str (cpbyte_buf, sizeof (cpbyte_buf), cycles_per_byte); double_to_str (mhz_buf, sizeof (mhz_buf), bench_ghz * 1000); if (auto_ghz && bench_ghz_diff * 1000 >= 0.5) { snprintf(mhz_diff_buf, sizeof(mhz_diff_buf), "±%.0f", bench_ghz_diff * 1000); } } else { strcpy (cpbyte_buf, "-"); strcpy (mhz_buf, "-"); } mbytes_per_sec = safe_div(1000.0 * 1000.0 * 1000.0, nsecs_per_byte * 1024 * 1024); double_to_str (mbpsec_buf, sizeof (mbpsec_buf), mbytes_per_sec); if (auto_ghz) { printf ("%9s ns/B %9s MiB/s %9s c/B %9s%s\n", nsecpbyte_buf, mbpsec_buf, cpbyte_buf, mhz_buf, mhz_diff_buf); } else { printf ("%9s ns/B %9s MiB/s %9s c/B\n", nsecpbyte_buf, mbpsec_buf, cpbyte_buf); } } static void bench_print_result (double nsecs_per_byte) { if (csv_mode) bench_print_result_csv (nsecs_per_byte); else bench_print_result_std (nsecs_per_byte); } static void bench_print_result_nsec_per_iteration (double nsecs_per_iteration) { double cycles_per_iteration; char nsecpiter_buf[16]; char cpiter_buf[16]; char mhz_buf[16]; strcpy(cpiter_buf, csv_mode ? "" : "-"); strcpy(mhz_buf, csv_mode ? "" : "-"); double_to_str (nsecpiter_buf, sizeof (nsecpiter_buf), nsecs_per_iteration); /* If user didn't provide CPU speed, we cannot show cycles/iter results. */ if (bench_ghz > 0.0) { cycles_per_iteration = nsecs_per_iteration * bench_ghz; double_to_str (cpiter_buf, sizeof (cpiter_buf), cycles_per_iteration); double_to_str (mhz_buf, sizeof (mhz_buf), bench_ghz * 1000); } if (csv_mode) { if (auto_ghz) printf ("%s,%s,%s,,,,,,,,,%s,ns/iter,%s,c/iter,%s,Mhz\n", current_section_name, current_algo_name ? current_algo_name : "", current_mode_name ? current_mode_name : "", nsecpiter_buf, cpiter_buf, mhz_buf); else printf ("%s,%s,%s,,,,,,,,,%s,ns/iter,%s,c/iter\n", current_section_name, current_algo_name ? current_algo_name : "", current_mode_name ? current_mode_name : "", nsecpiter_buf, cpiter_buf); } else { if (auto_ghz) printf ("%14s %13s %9s\n", nsecpiter_buf, cpiter_buf, mhz_buf); else printf ("%14s %13s\n", nsecpiter_buf, cpiter_buf); } } static void bench_print_section (const char *section_name, const char *print_name) { if (csv_mode) { gcry_free (current_section_name); current_section_name = gcry_xstrdup (section_name); } else printf ("%s:\n", print_name); } static void bench_print_header (int algo_width, const char *algo_name) { if (csv_mode) { gcry_free (current_algo_name); current_algo_name = gcry_xstrdup (algo_name); } else { if (algo_width < 0) printf (" %-*s | ", -algo_width, algo_name); else printf (" %-*s | ", algo_width, algo_name); if (auto_ghz) printf ("%14s %15s %13s %9s\n", "nanosecs/byte", "mebibytes/sec", "cycles/byte", "auto Mhz"); else printf ("%14s %15s %13s\n", "nanosecs/byte", "mebibytes/sec", "cycles/byte"); } } static void bench_print_header_nsec_per_iteration (int algo_width, const char *algo_name) { if (csv_mode) { gcry_free (current_algo_name); current_algo_name = gcry_xstrdup (algo_name); } else { if (algo_width < 0) printf (" %-*s | ", -algo_width, algo_name); else printf (" %-*s | ", algo_width, algo_name); if (auto_ghz) printf ("%14s %13s %9s\n", "nanosecs/iter", "cycles/iter", "auto Mhz"); else printf ("%14s %13s\n", "nanosecs/iter", "cycles/iter"); } } static void bench_print_algo (int algo_width, const char *algo_name) { if (csv_mode) { gcry_free (current_algo_name); current_algo_name = gcry_xstrdup (algo_name); } else { if (algo_width < 0) printf (" %-*s | ", -algo_width, algo_name); else printf (" %-*s | ", algo_width, algo_name); } } static void bench_print_mode (int width, const char *mode_name) { if (csv_mode) { gcry_free (current_mode_name); current_mode_name = gcry_xstrdup (mode_name); } else { if (width < 0) printf (" %-*s | ", -width, mode_name); else printf (" %*s | ", width, mode_name); fflush (stdout); } } static void bench_print_footer (int algo_width) { if (!csv_mode) printf (" %-*s =\n", algo_width, ""); } /********************************************************* Cipher benchmarks. */ struct bench_cipher_mode { int mode; const char *name; struct bench_ops *ops; int algo; }; static void bench_set_cipher_key (gcry_cipher_hd_t hd, int keylen) { char *key; int err, i; key = malloc (keylen); if (!key) { fprintf (stderr, PGM ": couldn't allocate %d bytes\n", keylen); gcry_cipher_close (hd); exit (1); } for (i = 0; i < keylen; i++) key[i] = 0x33 ^ (11 - i); err = gcry_cipher_setkey (hd, key, keylen); free (key); if (err) { fprintf (stderr, PGM ": gcry_cipher_setkey failed: %s\n", gpg_strerror (err)); gcry_cipher_close (hd); exit (1); } } static int bench_encrypt_init (struct bench_obj *obj) { struct bench_cipher_mode *mode = obj->priv; gcry_cipher_hd_t hd; int err, keylen; obj->min_bufsize = BUF_START_SIZE; obj->max_bufsize = BUF_END_SIZE; obj->step_size = BUF_STEP_SIZE; obj->num_measure_repetitions = num_measurement_repetitions; err = gcry_cipher_open (&hd, mode->algo, mode->mode, 0); if (err) { fprintf (stderr, PGM ": error opening cipher `%s'\n", gcry_cipher_algo_name (mode->algo)); exit (1); } keylen = gcry_cipher_get_algo_keylen (mode->algo); if (mode->mode == GCRY_CIPHER_MODE_SIV) { keylen *= 2; } if (keylen) { bench_set_cipher_key (hd, keylen); } else { fprintf (stderr, PGM ": failed to get key length for algorithm `%s'\n", gcry_cipher_algo_name (mode->algo)); gcry_cipher_close (hd); exit (1); } obj->hd = hd; return 0; } static void bench_encrypt_free (struct bench_obj *obj) { gcry_cipher_hd_t hd = obj->hd; gcry_cipher_close (hd); } static void bench_encrypt_do_bench (struct bench_obj *obj, void *buf, size_t buflen) { gcry_cipher_hd_t hd = obj->hd; int err; err = gcry_cipher_reset (hd); if (!err) err = gcry_cipher_encrypt (hd, buf, buflen, buf, buflen); if (err) { fprintf (stderr, PGM ": gcry_cipher_encrypt failed: %s\n", gpg_strerror (err)); gcry_cipher_close (hd); exit (1); } } static void bench_decrypt_do_bench (struct bench_obj *obj, void *buf, size_t buflen) { gcry_cipher_hd_t hd = obj->hd; int err; err = gcry_cipher_reset (hd); if (!err) err = gcry_cipher_decrypt (hd, buf, buflen, buf, buflen); if (err) { fprintf (stderr, PGM ": gcry_cipher_encrypt failed: %s\n", gpg_strerror (err)); gcry_cipher_close (hd); exit (1); } } static struct bench_ops encrypt_ops = { &bench_encrypt_init, &bench_encrypt_free, &bench_encrypt_do_bench }; static struct bench_ops decrypt_ops = { &bench_encrypt_init, &bench_encrypt_free, &bench_decrypt_do_bench }; static int bench_xts_encrypt_init (struct bench_obj *obj) { struct bench_cipher_mode *mode = obj->priv; gcry_cipher_hd_t hd; int err, keylen; obj->min_bufsize = BUF_START_SIZE; obj->max_bufsize = BUF_END_SIZE; obj->step_size = BUF_STEP_SIZE; obj->num_measure_repetitions = num_measurement_repetitions; err = gcry_cipher_open (&hd, mode->algo, mode->mode, 0); if (err) { fprintf (stderr, PGM ": error opening cipher `%s'\n", gcry_cipher_algo_name (mode->algo)); exit (1); } /* Double key-length for XTS. */ keylen = gcry_cipher_get_algo_keylen (mode->algo) * 2; if (keylen) { bench_set_cipher_key (hd, keylen); } else { fprintf (stderr, PGM ": failed to get key length for algorithm `%s'\n", gcry_cipher_algo_name (mode->algo)); gcry_cipher_close (hd); exit (1); } obj->hd = hd; return 0; } static struct bench_ops xts_encrypt_ops = { &bench_xts_encrypt_init, &bench_encrypt_free, &bench_encrypt_do_bench }; static struct bench_ops xts_decrypt_ops = { &bench_xts_encrypt_init, &bench_encrypt_free, &bench_decrypt_do_bench }; static void bench_ccm_encrypt_do_bench (struct bench_obj *obj, void *buf, size_t buflen) { gcry_cipher_hd_t hd = obj->hd; int err; char tag[8]; char nonce[11] = { 0x80, 0x01, }; u64 params[3]; gcry_cipher_setiv (hd, nonce, sizeof (nonce)); /* Set CCM lengths */ params[0] = buflen; params[1] = 0; /*aadlen */ params[2] = sizeof (tag); err = gcry_cipher_ctl (hd, GCRYCTL_SET_CCM_LENGTHS, params, sizeof (params)); if (err) { fprintf (stderr, PGM ": gcry_cipher_ctl failed: %s\n", gpg_strerror (err)); gcry_cipher_close (hd); exit (1); } err = gcry_cipher_encrypt (hd, buf, buflen, buf, buflen); if (err) { fprintf (stderr, PGM ": gcry_cipher_encrypt failed: %s\n", gpg_strerror (err)); gcry_cipher_close (hd); exit (1); } err = gcry_cipher_gettag (hd, tag, sizeof (tag)); if (err) { fprintf (stderr, PGM ": gcry_cipher_gettag failed: %s\n", gpg_strerror (err)); gcry_cipher_close (hd); exit (1); } } static void bench_ccm_decrypt_do_bench (struct bench_obj *obj, void *buf, size_t buflen) { gcry_cipher_hd_t hd = obj->hd; int err; char tag[8] = { 0, }; char nonce[11] = { 0x80, 0x01, }; u64 params[3]; gcry_cipher_setiv (hd, nonce, sizeof (nonce)); /* Set CCM lengths */ params[0] = buflen; params[1] = 0; /*aadlen */ params[2] = sizeof (tag); err = gcry_cipher_ctl (hd, GCRYCTL_SET_CCM_LENGTHS, params, sizeof (params)); if (err) { fprintf (stderr, PGM ": gcry_cipher_ctl failed: %s\n", gpg_strerror (err)); gcry_cipher_close (hd); exit (1); } err = gcry_cipher_decrypt (hd, buf, buflen, buf, buflen); if (err) { fprintf (stderr, PGM ": gcry_cipher_encrypt failed: %s\n", gpg_strerror (err)); gcry_cipher_close (hd); exit (1); } err = gcry_cipher_checktag (hd, tag, sizeof (tag)); if (gpg_err_code (err) == GPG_ERR_CHECKSUM) err = gpg_error (GPG_ERR_NO_ERROR); if (err) { fprintf (stderr, PGM ": gcry_cipher_gettag failed: %s\n", gpg_strerror (err)); gcry_cipher_close (hd); exit (1); } } static void bench_ccm_authenticate_do_bench (struct bench_obj *obj, void *buf, size_t buflen) { gcry_cipher_hd_t hd = obj->hd; int err; char tag[8] = { 0, }; char nonce[11] = { 0x80, 0x01, }; u64 params[3]; char data = 0xff; gcry_cipher_setiv (hd, nonce, sizeof (nonce)); /* Set CCM lengths */ params[0] = sizeof (data); /*datalen */ params[1] = buflen; /*aadlen */ params[2] = sizeof (tag); err = gcry_cipher_ctl (hd, GCRYCTL_SET_CCM_LENGTHS, params, sizeof (params)); if (err) { fprintf (stderr, PGM ": gcry_cipher_ctl failed: %s\n", gpg_strerror (err)); gcry_cipher_close (hd); exit (1); } err = gcry_cipher_authenticate (hd, buf, buflen); if (err) { fprintf (stderr, PGM ": gcry_cipher_authenticate failed: %s\n", gpg_strerror (err)); gcry_cipher_close (hd); exit (1); } err = gcry_cipher_encrypt (hd, &data, sizeof (data), &data, sizeof (data)); if (err) { fprintf (stderr, PGM ": gcry_cipher_encrypt failed: %s\n", gpg_strerror (err)); gcry_cipher_close (hd); exit (1); } err = gcry_cipher_gettag (hd, tag, sizeof (tag)); if (err) { fprintf (stderr, PGM ": gcry_cipher_gettag failed: %s\n", gpg_strerror (err)); gcry_cipher_close (hd); exit (1); } } static struct bench_ops ccm_encrypt_ops = { &bench_encrypt_init, &bench_encrypt_free, &bench_ccm_encrypt_do_bench }; static struct bench_ops ccm_decrypt_ops = { &bench_encrypt_init, &bench_encrypt_free, &bench_ccm_decrypt_do_bench }; static struct bench_ops ccm_authenticate_ops = { &bench_encrypt_init, &bench_encrypt_free, &bench_ccm_authenticate_do_bench }; static void bench_aead_encrypt_do_bench (struct bench_obj *obj, void *buf, size_t buflen, const char *nonce, size_t noncelen) { gcry_cipher_hd_t hd = obj->hd; int err; char tag[16]; gcry_cipher_reset (hd); gcry_cipher_setiv (hd, nonce, noncelen); gcry_cipher_final (hd); err = gcry_cipher_encrypt (hd, buf, buflen, buf, buflen); if (err) { fprintf (stderr, PGM ": gcry_cipher_encrypt failed: %s\n", gpg_strerror (err)); gcry_cipher_close (hd); exit (1); } err = gcry_cipher_gettag (hd, tag, sizeof (tag)); if (err) { fprintf (stderr, PGM ": gcry_cipher_gettag failed: %s\n", gpg_strerror (err)); gcry_cipher_close (hd); exit (1); } } static void bench_aead_decrypt_do_bench (struct bench_obj *obj, void *buf, size_t buflen, const char *nonce, size_t noncelen) { gcry_cipher_hd_t hd = obj->hd; int err; char tag[16] = { 0, }; gcry_cipher_reset (hd); gcry_cipher_set_decryption_tag (hd, tag, 16); gcry_cipher_setiv (hd, nonce, noncelen); gcry_cipher_final (hd); err = gcry_cipher_decrypt (hd, buf, buflen, buf, buflen); if (gpg_err_code (err) == GPG_ERR_CHECKSUM) err = gpg_error (GPG_ERR_NO_ERROR); if (err) { fprintf (stderr, PGM ": gcry_cipher_decrypt failed: %s\n", gpg_strerror (err)); gcry_cipher_close (hd); exit (1); } err = gcry_cipher_checktag (hd, tag, sizeof (tag)); if (gpg_err_code (err) == GPG_ERR_CHECKSUM) err = gpg_error (GPG_ERR_NO_ERROR); if (err) { fprintf (stderr, PGM ": gcry_cipher_gettag failed: %s\n", gpg_strerror (err)); gcry_cipher_close (hd); exit (1); } } static void bench_aead_authenticate_do_bench (struct bench_obj *obj, void *buf, size_t buflen, const char *nonce, size_t noncelen) { gcry_cipher_hd_t hd = obj->hd; int err; char tag[16] = { 0, }; char data = 0xff; gcry_cipher_reset (hd); if (noncelen > 0) { err = gcry_cipher_setiv (hd, nonce, noncelen); if (err) { fprintf (stderr, PGM ": gcry_cipher_setiv failed: %s\n", gpg_strerror (err)); gcry_cipher_close (hd); exit (1); } } err = gcry_cipher_authenticate (hd, buf, buflen); if (err) { fprintf (stderr, PGM ": gcry_cipher_authenticate failed: %s\n", gpg_strerror (err)); gcry_cipher_close (hd); exit (1); } gcry_cipher_final (hd); err = gcry_cipher_encrypt (hd, &data, sizeof (data), &data, sizeof (data)); if (err) { fprintf (stderr, PGM ": gcry_cipher_encrypt failed: %s\n", gpg_strerror (err)); gcry_cipher_close (hd); exit (1); } err = gcry_cipher_gettag (hd, tag, sizeof (tag)); if (err) { fprintf (stderr, PGM ": gcry_cipher_gettag failed: %s\n", gpg_strerror (err)); gcry_cipher_close (hd); exit (1); } } static void bench_gcm_encrypt_do_bench (struct bench_obj *obj, void *buf, size_t buflen) { char nonce[12] = { 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad, 0xde, 0xca, 0xf8, 0x88 }; bench_aead_encrypt_do_bench (obj, buf, buflen, nonce, sizeof(nonce)); } static void bench_gcm_decrypt_do_bench (struct bench_obj *obj, void *buf, size_t buflen) { char nonce[12] = { 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad, 0xde, 0xca, 0xf8, 0x88 }; bench_aead_decrypt_do_bench (obj, buf, buflen, nonce, sizeof(nonce)); } static void bench_gcm_authenticate_do_bench (struct bench_obj *obj, void *buf, size_t buflen) { char nonce[12] = { 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad, 0xde, 0xca, 0xf8, 0x88 }; bench_aead_authenticate_do_bench (obj, buf, buflen, nonce, sizeof(nonce)); } static struct bench_ops gcm_encrypt_ops = { &bench_encrypt_init, &bench_encrypt_free, &bench_gcm_encrypt_do_bench }; static struct bench_ops gcm_decrypt_ops = { &bench_encrypt_init, &bench_encrypt_free, &bench_gcm_decrypt_do_bench }; static struct bench_ops gcm_authenticate_ops = { &bench_encrypt_init, &bench_encrypt_free, &bench_gcm_authenticate_do_bench }; static void bench_ocb_encrypt_do_bench (struct bench_obj *obj, void *buf, size_t buflen) { char nonce[15] = { 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad, 0xde, 0xca, 0xf8, 0x88, 0x00, 0x00, 0x01 }; bench_aead_encrypt_do_bench (obj, buf, buflen, nonce, sizeof(nonce)); } static void bench_ocb_decrypt_do_bench (struct bench_obj *obj, void *buf, size_t buflen) { char nonce[15] = { 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad, 0xde, 0xca, 0xf8, 0x88, 0x00, 0x00, 0x01 }; bench_aead_decrypt_do_bench (obj, buf, buflen, nonce, sizeof(nonce)); } static void bench_ocb_authenticate_do_bench (struct bench_obj *obj, void *buf, size_t buflen) { char nonce[15] = { 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad, 0xde, 0xca, 0xf8, 0x88, 0x00, 0x00, 0x01 }; bench_aead_authenticate_do_bench (obj, buf, buflen, nonce, sizeof(nonce)); } static struct bench_ops ocb_encrypt_ops = { &bench_encrypt_init, &bench_encrypt_free, &bench_ocb_encrypt_do_bench }; static struct bench_ops ocb_decrypt_ops = { &bench_encrypt_init, &bench_encrypt_free, &bench_ocb_decrypt_do_bench }; static struct bench_ops ocb_authenticate_ops = { &bench_encrypt_init, &bench_encrypt_free, &bench_ocb_authenticate_do_bench }; static void bench_siv_encrypt_do_bench (struct bench_obj *obj, void *buf, size_t buflen) { bench_aead_encrypt_do_bench (obj, buf, buflen, NULL, 0); } static void bench_siv_decrypt_do_bench (struct bench_obj *obj, void *buf, size_t buflen) { bench_aead_decrypt_do_bench (obj, buf, buflen, NULL, 0); } static void bench_siv_authenticate_do_bench (struct bench_obj *obj, void *buf, size_t buflen) { bench_aead_authenticate_do_bench (obj, buf, buflen, NULL, 0); } static struct bench_ops siv_encrypt_ops = { &bench_encrypt_init, &bench_encrypt_free, &bench_siv_encrypt_do_bench }; static struct bench_ops siv_decrypt_ops = { &bench_encrypt_init, &bench_encrypt_free, &bench_siv_decrypt_do_bench }; static struct bench_ops siv_authenticate_ops = { &bench_encrypt_init, &bench_encrypt_free, &bench_siv_authenticate_do_bench }; static void bench_gcm_siv_encrypt_do_bench (struct bench_obj *obj, void *buf, size_t buflen) { char nonce[12] = { 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad, 0xde, 0xca, 0xf8, 0x88 }; bench_aead_encrypt_do_bench (obj, buf, buflen, nonce, sizeof(nonce)); } static void bench_gcm_siv_decrypt_do_bench (struct bench_obj *obj, void *buf, size_t buflen) { char nonce[12] = { 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad, 0xde, 0xca, 0xf8, 0x88 }; bench_aead_decrypt_do_bench (obj, buf, buflen, nonce, sizeof(nonce)); } static void bench_gcm_siv_authenticate_do_bench (struct bench_obj *obj, void *buf, size_t buflen) { char nonce[12] = { 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad, 0xde, 0xca, 0xf8, 0x88 }; bench_aead_authenticate_do_bench (obj, buf, buflen, nonce, sizeof(nonce)); } static struct bench_ops gcm_siv_encrypt_ops = { &bench_encrypt_init, &bench_encrypt_free, &bench_gcm_siv_encrypt_do_bench }; static struct bench_ops gcm_siv_decrypt_ops = { &bench_encrypt_init, &bench_encrypt_free, &bench_gcm_siv_decrypt_do_bench }; static struct bench_ops gcm_siv_authenticate_ops = { &bench_encrypt_init, &bench_encrypt_free, &bench_gcm_siv_authenticate_do_bench }; static void bench_eax_encrypt_do_bench (struct bench_obj *obj, void *buf, size_t buflen) { char nonce[16] = { 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad, 0xde, 0xca, 0xf8, 0x88, 0x00, 0x00, 0x01, 0x00 }; bench_aead_encrypt_do_bench (obj, buf, buflen, nonce, sizeof(nonce)); } static void bench_eax_decrypt_do_bench (struct bench_obj *obj, void *buf, size_t buflen) { char nonce[16] = { 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad, 0xde, 0xca, 0xf8, 0x88, 0x00, 0x00, 0x01, 0x00 }; bench_aead_decrypt_do_bench (obj, buf, buflen, nonce, sizeof(nonce)); } static void bench_eax_authenticate_do_bench (struct bench_obj *obj, void *buf, size_t buflen) { char nonce[16] = { 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad, 0xde, 0xca, 0xf8, 0x88, 0x00, 0x00, 0x01, 0x00 }; bench_aead_authenticate_do_bench (obj, buf, buflen, nonce, sizeof(nonce)); } static struct bench_ops eax_encrypt_ops = { &bench_encrypt_init, &bench_encrypt_free, &bench_eax_encrypt_do_bench }; static struct bench_ops eax_decrypt_ops = { &bench_encrypt_init, &bench_encrypt_free, &bench_eax_decrypt_do_bench }; static struct bench_ops eax_authenticate_ops = { &bench_encrypt_init, &bench_encrypt_free, &bench_eax_authenticate_do_bench }; static void bench_poly1305_encrypt_do_bench (struct bench_obj *obj, void *buf, size_t buflen) { char nonce[8] = { 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad }; bench_aead_encrypt_do_bench (obj, buf, buflen, nonce, sizeof(nonce)); } static void bench_poly1305_decrypt_do_bench (struct bench_obj *obj, void *buf, size_t buflen) { char nonce[8] = { 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad }; bench_aead_decrypt_do_bench (obj, buf, buflen, nonce, sizeof(nonce)); } static void bench_poly1305_authenticate_do_bench (struct bench_obj *obj, void *buf, size_t buflen) { char nonce[8] = { 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad }; bench_aead_authenticate_do_bench (obj, buf, buflen, nonce, sizeof(nonce)); } static struct bench_ops poly1305_encrypt_ops = { &bench_encrypt_init, &bench_encrypt_free, &bench_poly1305_encrypt_do_bench }; static struct bench_ops poly1305_decrypt_ops = { &bench_encrypt_init, &bench_encrypt_free, &bench_poly1305_decrypt_do_bench }; static struct bench_ops poly1305_authenticate_ops = { &bench_encrypt_init, &bench_encrypt_free, &bench_poly1305_authenticate_do_bench }; static struct bench_cipher_mode cipher_modes[] = { {GCRY_CIPHER_MODE_ECB, "ECB enc", &encrypt_ops}, {GCRY_CIPHER_MODE_ECB, "ECB dec", &decrypt_ops}, {GCRY_CIPHER_MODE_CBC, "CBC enc", &encrypt_ops}, {GCRY_CIPHER_MODE_CBC, "CBC dec", &decrypt_ops}, {GCRY_CIPHER_MODE_CFB, "CFB enc", &encrypt_ops}, {GCRY_CIPHER_MODE_CFB, "CFB dec", &decrypt_ops}, {GCRY_CIPHER_MODE_OFB, "OFB enc", &encrypt_ops}, {GCRY_CIPHER_MODE_OFB, "OFB dec", &decrypt_ops}, {GCRY_CIPHER_MODE_CTR, "CTR enc", &encrypt_ops}, {GCRY_CIPHER_MODE_CTR, "CTR dec", &decrypt_ops}, {GCRY_CIPHER_MODE_XTS, "XTS enc", &xts_encrypt_ops}, {GCRY_CIPHER_MODE_XTS, "XTS dec", &xts_decrypt_ops}, {GCRY_CIPHER_MODE_CCM, "CCM enc", &ccm_encrypt_ops}, {GCRY_CIPHER_MODE_CCM, "CCM dec", &ccm_decrypt_ops}, {GCRY_CIPHER_MODE_CCM, "CCM auth", &ccm_authenticate_ops}, {GCRY_CIPHER_MODE_EAX, "EAX enc", &eax_encrypt_ops}, {GCRY_CIPHER_MODE_EAX, "EAX dec", &eax_decrypt_ops}, {GCRY_CIPHER_MODE_EAX, "EAX auth", &eax_authenticate_ops}, {GCRY_CIPHER_MODE_GCM, "GCM enc", &gcm_encrypt_ops}, {GCRY_CIPHER_MODE_GCM, "GCM dec", &gcm_decrypt_ops}, {GCRY_CIPHER_MODE_GCM, "GCM auth", &gcm_authenticate_ops}, {GCRY_CIPHER_MODE_OCB, "OCB enc", &ocb_encrypt_ops}, {GCRY_CIPHER_MODE_OCB, "OCB dec", &ocb_decrypt_ops}, {GCRY_CIPHER_MODE_OCB, "OCB auth", &ocb_authenticate_ops}, {GCRY_CIPHER_MODE_SIV, "SIV enc", &siv_encrypt_ops}, {GCRY_CIPHER_MODE_SIV, "SIV dec", &siv_decrypt_ops}, {GCRY_CIPHER_MODE_SIV, "SIV auth", &siv_authenticate_ops}, {GCRY_CIPHER_MODE_GCM_SIV, "GCM-SIV enc", &gcm_siv_encrypt_ops}, {GCRY_CIPHER_MODE_GCM_SIV, "GCM-SIV dec", &gcm_siv_decrypt_ops}, {GCRY_CIPHER_MODE_GCM_SIV, "GCM-SIV auth", &gcm_siv_authenticate_ops}, {GCRY_CIPHER_MODE_POLY1305, "POLY1305 enc", &poly1305_encrypt_ops}, {GCRY_CIPHER_MODE_POLY1305, "POLY1305 dec", &poly1305_decrypt_ops}, {GCRY_CIPHER_MODE_POLY1305, "POLY1305 auth", &poly1305_authenticate_ops}, {0}, }; static void cipher_bench_one (int algo, struct bench_cipher_mode *pmode) { struct bench_cipher_mode mode = *pmode; struct bench_obj obj = { 0 }; double result; unsigned int blklen; unsigned int keylen; mode.algo = algo; /* Check if this mode is ok */ blklen = gcry_cipher_get_algo_blklen (algo); if (!blklen) return; keylen = gcry_cipher_get_algo_keylen (algo); if (!keylen) return; /* Stream cipher? Only test with "ECB" and POLY1305. */ if (blklen == 1 && (mode.mode != GCRY_CIPHER_MODE_ECB && mode.mode != GCRY_CIPHER_MODE_POLY1305)) return; if (blklen == 1 && mode.mode == GCRY_CIPHER_MODE_ECB) { mode.mode = GCRY_CIPHER_MODE_STREAM; mode.name = mode.ops == &encrypt_ops ? "STREAM enc" : "STREAM dec"; } /* Poly1305 has restriction for cipher algorithm */ if (mode.mode == GCRY_CIPHER_MODE_POLY1305 && algo != GCRY_CIPHER_CHACHA20) return; /* CCM has restrictions for block-size */ if (mode.mode == GCRY_CIPHER_MODE_CCM && blklen != GCRY_CCM_BLOCK_LEN) return; /* GCM has restrictions for block-size; not allowed in FIPS mode */ if (mode.mode == GCRY_CIPHER_MODE_GCM && (in_fips_mode || blklen != GCRY_GCM_BLOCK_LEN)) return; /* XTS has restrictions for block-size */ if (mode.mode == GCRY_CIPHER_MODE_XTS && blklen != GCRY_XTS_BLOCK_LEN) return; /* SIV has restrictions for block-size */ if (mode.mode == GCRY_CIPHER_MODE_SIV && blklen != GCRY_SIV_BLOCK_LEN) return; /* GCM-SIV has restrictions for block-size */ if (mode.mode == GCRY_CIPHER_MODE_GCM_SIV && blklen != GCRY_SIV_BLOCK_LEN) return; /* GCM-SIV has restrictions for key length */ if (mode.mode == GCRY_CIPHER_MODE_GCM_SIV && !(keylen == 16 || keylen == 32)) return; /* Our OCB implementation has restrictions for block-size. */ if (mode.mode == GCRY_CIPHER_MODE_OCB && blklen != GCRY_OCB_BLOCK_LEN) return; bench_print_mode (14, mode.name); obj.ops = mode.ops; obj.priv = &mode; result = do_slope_benchmark (&obj); bench_print_result (result); } static void _cipher_bench (int algo) { const char *algoname; int i; algoname = gcry_cipher_algo_name (algo); bench_print_header (14, algoname); for (i = 0; cipher_modes[i].mode; i++) cipher_bench_one (algo, &cipher_modes[i]); bench_print_footer (14); } void cipher_bench (char **argv, int argc) { int i, algo; bench_print_section ("cipher", "Cipher"); if (argv && argc) { for (i = 0; i < argc; i++) { algo = gcry_cipher_map_name (argv[i]); if (algo) _cipher_bench (algo); } } else { for (i = 1; i < 400; i++) if (!gcry_cipher_test_algo (i)) _cipher_bench (i); } } /*********************************************************** Hash benchmarks. */ struct bench_hash_mode { const char *name; struct bench_ops *ops; int algo; }; static int bench_hash_init (struct bench_obj *obj) { struct bench_hash_mode *mode = obj->priv; gcry_md_hd_t hd; int err; obj->min_bufsize = BUF_START_SIZE; obj->max_bufsize = BUF_END_SIZE; obj->step_size = BUF_STEP_SIZE; obj->num_measure_repetitions = num_measurement_repetitions; err = gcry_md_open (&hd, mode->algo, 0); if (err) { fprintf (stderr, PGM ": error opening hash `%s'\n", gcry_md_algo_name (mode->algo)); exit (1); } obj->hd = hd; return 0; } static void bench_hash_free (struct bench_obj *obj) { gcry_md_hd_t hd = obj->hd; gcry_md_close (hd); } static void bench_hash_do_bench (struct bench_obj *obj, void *buf, size_t buflen) { gcry_md_hd_t hd = obj->hd; gcry_md_reset (hd); gcry_md_write (hd, buf, buflen); gcry_md_final (hd); } static struct bench_ops hash_ops = { &bench_hash_init, &bench_hash_free, &bench_hash_do_bench }; static struct bench_hash_mode hash_modes[] = { {"", &hash_ops}, {0}, }; static void hash_bench_one (int algo, struct bench_hash_mode *pmode) { struct bench_hash_mode mode = *pmode; struct bench_obj obj = { 0 }; double result; mode.algo = algo; if (mode.name[0] == '\0') bench_print_algo (-14, gcry_md_algo_name (algo)); else bench_print_algo (14, mode.name); obj.ops = mode.ops; obj.priv = &mode; result = do_slope_benchmark (&obj); bench_print_result (result); } static void _hash_bench (int algo) { int i; for (i = 0; hash_modes[i].name; i++) hash_bench_one (algo, &hash_modes[i]); } void hash_bench (char **argv, int argc) { int i, algo; bench_print_section ("hash", "Hash"); bench_print_header (14, ""); if (argv && argc) { for (i = 0; i < argc; i++) { algo = gcry_md_map_name (argv[i]); if (algo) _hash_bench (algo); } } else { for (i = 1; i < 400; i++) if (!gcry_md_test_algo (i)) _hash_bench (i); } bench_print_footer (14); } /************************************************************ MAC benchmarks. */ struct bench_mac_mode { const char *name; struct bench_ops *ops; int algo; }; static int bench_mac_init (struct bench_obj *obj) { struct bench_mac_mode *mode = obj->priv; gcry_mac_hd_t hd; int err; unsigned int keylen; void *key; obj->min_bufsize = BUF_START_SIZE; obj->max_bufsize = BUF_END_SIZE; obj->step_size = BUF_STEP_SIZE; obj->num_measure_repetitions = num_measurement_repetitions; keylen = gcry_mac_get_algo_keylen (mode->algo); if (keylen == 0) keylen = 32; key = malloc (keylen); if (!key) { fprintf (stderr, PGM ": couldn't allocate %d bytes\n", keylen); exit (1); } memset(key, 42, keylen); err = gcry_mac_open (&hd, mode->algo, 0, NULL); if (err) { fprintf (stderr, PGM ": error opening mac `%s'\n", gcry_mac_algo_name (mode->algo)); free (key); exit (1); } err = gcry_mac_setkey (hd, key, keylen); if (err) { fprintf (stderr, PGM ": error setting key for mac `%s'\n", gcry_mac_algo_name (mode->algo)); free (key); exit (1); } switch (mode->algo) { default: break; case GCRY_MAC_POLY1305_AES: case GCRY_MAC_POLY1305_CAMELLIA: case GCRY_MAC_POLY1305_TWOFISH: case GCRY_MAC_POLY1305_SERPENT: case GCRY_MAC_POLY1305_SEED: case GCRY_MAC_POLY1305_SM4: case GCRY_MAC_POLY1305_ARIA: gcry_mac_setiv (hd, key, 16); break; } obj->hd = hd; free (key); return 0; } static void bench_mac_free (struct bench_obj *obj) { gcry_mac_hd_t hd = obj->hd; gcry_mac_close (hd); } static void bench_mac_do_bench (struct bench_obj *obj, void *buf, size_t buflen) { gcry_mac_hd_t hd = obj->hd; size_t bs; char b; gcry_mac_reset (hd); gcry_mac_write (hd, buf, buflen); bs = sizeof(b); gcry_mac_read (hd, &b, &bs); } static struct bench_ops mac_ops = { &bench_mac_init, &bench_mac_free, &bench_mac_do_bench }; static struct bench_mac_mode mac_modes[] = { {"", &mac_ops}, {0}, }; static void mac_bench_one (int algo, struct bench_mac_mode *pmode) { struct bench_mac_mode mode = *pmode; struct bench_obj obj = { 0 }; double result; mode.algo = algo; if (mode.name[0] == '\0') bench_print_algo (-18, gcry_mac_algo_name (algo)); else bench_print_algo (18, mode.name); obj.ops = mode.ops; obj.priv = &mode; result = do_slope_benchmark (&obj); bench_print_result (result); } static void _mac_bench (int algo) { int i; for (i = 0; mac_modes[i].name; i++) mac_bench_one (algo, &mac_modes[i]); } void mac_bench (char **argv, int argc) { int i, algo; bench_print_section ("mac", "MAC"); bench_print_header (18, ""); if (argv && argc) { for (i = 0; i < argc; i++) { algo = gcry_mac_map_name (argv[i]); if (algo) _mac_bench (algo); } } else { for (i = 1; i < 600; i++) if (!gcry_mac_test_algo (i)) _mac_bench (i); } bench_print_footer (18); } /************************************************************ KDF benchmarks. */ struct bench_kdf_mode { struct bench_ops *ops; int algo; int subalgo; }; static int bench_kdf_init (struct bench_obj *obj) { struct bench_kdf_mode *mode = obj->priv; if (mode->algo == GCRY_KDF_PBKDF2) { obj->min_bufsize = 2; obj->max_bufsize = 2 * 32; obj->step_size = 2; } obj->num_measure_repetitions = num_measurement_repetitions; return 0; } static void bench_kdf_free (struct bench_obj *obj) { (void)obj; } static void bench_kdf_do_bench (struct bench_obj *obj, void *buf, size_t buflen) { struct bench_kdf_mode *mode = obj->priv; char keybuf[16]; (void)buf; if (mode->algo == GCRY_KDF_PBKDF2) { gcry_kdf_derive("qwerty", 6, mode->algo, mode->subalgo, "01234567", 8, buflen, sizeof(keybuf), keybuf); } } static struct bench_ops kdf_ops = { &bench_kdf_init, &bench_kdf_free, &bench_kdf_do_bench }; static void kdf_bench_one (int algo, int subalgo) { struct bench_kdf_mode mode = { &kdf_ops }; struct bench_obj obj = { 0 }; double nsecs_per_iteration; char algo_name[32]; mode.algo = algo; mode.subalgo = subalgo; switch (subalgo) { case GCRY_MD_CRC32: case GCRY_MD_CRC32_RFC1510: case GCRY_MD_CRC24_RFC2440: case GCRY_MD_MD4: /* Skip CRC32s. */ return; } if (gcry_md_get_algo_dlen (subalgo) == 0) { /* Skip XOFs */ return; } *algo_name = 0; if (algo == GCRY_KDF_PBKDF2) { snprintf (algo_name, sizeof(algo_name), "PBKDF2-HMAC-%s", gcry_md_algo_name (subalgo)); } bench_print_algo (-24, algo_name); obj.ops = mode.ops; obj.priv = &mode; nsecs_per_iteration = do_slope_benchmark (&obj); bench_print_result_nsec_per_iteration (nsecs_per_iteration); } void kdf_bench (char **argv, int argc) { char algo_name[32]; int i, j; bench_print_section ("kdf", "KDF"); bench_print_header_nsec_per_iteration (24, ""); if (argv && argc) { for (i = 0; i < argc; i++) { for (j = 1; j < 400; j++) { if (gcry_md_test_algo (j)) continue; snprintf (algo_name, sizeof(algo_name), "PBKDF2-HMAC-%s", gcry_md_algo_name (j)); if (!strcmp(argv[i], algo_name)) kdf_bench_one (GCRY_KDF_PBKDF2, j); } } } else { for (i = 1; i < 400; i++) if (!gcry_md_test_algo (i)) kdf_bench_one (GCRY_KDF_PBKDF2, i); } bench_print_footer (24); } /************************************************************ ECC benchmarks. */ #if USE_ECC enum bench_ecc_algo { ECC_ALGO_ED25519 = 0, ECC_ALGO_ED448, ECC_ALGO_X25519, ECC_ALGO_X448, ECC_ALGO_NIST_P192, ECC_ALGO_NIST_P224, ECC_ALGO_NIST_P256, ECC_ALGO_NIST_P384, ECC_ALGO_NIST_P521, ECC_ALGO_SECP256K1, ECC_ALGO_BRAINP256R1, __MAX_ECC_ALGO }; enum bench_ecc_operation { ECC_OPER_MULT = 0, ECC_OPER_KEYGEN, ECC_OPER_SIGN, ECC_OPER_VERIFY, __MAX_ECC_OPER }; struct bench_ecc_oper { enum bench_ecc_operation oper; const char *name; struct bench_ops *ops; enum bench_ecc_algo algo; }; struct bench_ecc_mult_hd { gcry_ctx_t ec; gcry_mpi_t k, x, y; gcry_mpi_point_t G, Q; }; struct bench_ecc_hd { gcry_sexp_t key_spec; gcry_sexp_t data; gcry_sexp_t pub_key; gcry_sexp_t sec_key; gcry_sexp_t sig; }; static int ecc_algo_fips_allowed (int algo) { switch (algo) { case ECC_ALGO_NIST_P224: case ECC_ALGO_NIST_P256: case ECC_ALGO_NIST_P384: case ECC_ALGO_NIST_P521: - return 1; - case ECC_ALGO_SECP256K1: - case ECC_ALGO_BRAINP256R1: case ECC_ALGO_ED25519: case ECC_ALGO_ED448: + return 1; + case ECC_ALGO_SECP256K1: + case ECC_ALGO_BRAINP256R1: case ECC_ALGO_X25519: case ECC_ALGO_X448: case ECC_ALGO_NIST_P192: default: - return 0; + return 0; } } static const char * ecc_algo_name (int algo) { switch (algo) { case ECC_ALGO_ED25519: return "Ed25519"; case ECC_ALGO_ED448: return "Ed448"; case ECC_ALGO_X25519: return "X25519"; case ECC_ALGO_X448: return "X448"; case ECC_ALGO_NIST_P192: return "NIST-P192"; case ECC_ALGO_NIST_P224: return "NIST-P224"; case ECC_ALGO_NIST_P256: return "NIST-P256"; case ECC_ALGO_NIST_P384: return "NIST-P384"; case ECC_ALGO_NIST_P521: return "NIST-P521"; case ECC_ALGO_SECP256K1: return "secp256k1"; case ECC_ALGO_BRAINP256R1: return "brainpoolP256r1"; default: return NULL; } } static const char * ecc_algo_curve (int algo) { switch (algo) { case ECC_ALGO_ED25519: return "Ed25519"; case ECC_ALGO_ED448: return "Ed448"; case ECC_ALGO_X25519: return "Curve25519"; case ECC_ALGO_X448: return "X448"; case ECC_ALGO_NIST_P192: return "NIST P-192"; case ECC_ALGO_NIST_P224: return "NIST P-224"; case ECC_ALGO_NIST_P256: return "NIST P-256"; case ECC_ALGO_NIST_P384: return "NIST P-384"; case ECC_ALGO_NIST_P521: return "NIST P-521"; case ECC_ALGO_SECP256K1: return "secp256k1"; case ECC_ALGO_BRAINP256R1: return "brainpoolP256r1"; default: return NULL; } } static int ecc_nbits (int algo) { switch (algo) { case ECC_ALGO_ED25519: return 255; case ECC_ALGO_ED448: return 448; case ECC_ALGO_X25519: return 255; case ECC_ALGO_X448: return 448; case ECC_ALGO_NIST_P192: return 192; case ECC_ALGO_NIST_P224: return 224; case ECC_ALGO_NIST_P256: return 256; case ECC_ALGO_NIST_P384: return 384; case ECC_ALGO_NIST_P521: return 521; case ECC_ALGO_SECP256K1: return 256; case ECC_ALGO_BRAINP256R1: return 256; default: return 0; } } static int ecc_map_name (const char *name) { int i; for (i = 0; i < __MAX_ECC_ALGO; i++) { if (strcmp(ecc_algo_name(i), name) == 0) { return i; } } return -1; } static int bench_ecc_mult_init (struct bench_obj *obj) { struct bench_ecc_oper *oper = obj->priv; struct bench_ecc_mult_hd *hd; int p_size = ecc_nbits (oper->algo); gpg_error_t err; gcry_mpi_t p; obj->min_bufsize = 1; obj->max_bufsize = 4; obj->step_size = 1; obj->num_measure_repetitions = num_measurement_repetitions / obj->max_bufsize; while (obj->num_measure_repetitions == 0) { if (obj->max_bufsize == 2) { obj->num_measure_repetitions = 2; } else { obj->max_bufsize--; obj->num_measure_repetitions = num_measurement_repetitions / obj->max_bufsize; } } hd = calloc (1, sizeof(*hd)); if (!hd) return -1; err = gcry_mpi_ec_new (&hd->ec, NULL, ecc_algo_curve(oper->algo)); if (err) { fprintf (stderr, PGM ": gcry_mpi_ec_new failed: %s\n", gpg_strerror (err)); exit (1); } hd->G = gcry_mpi_ec_get_point ("g", hd->ec, 1); hd->Q = gcry_mpi_point_new (0); hd->x = gcry_mpi_new (0); hd->y = gcry_mpi_new (0); hd->k = gcry_mpi_new (p_size); gcry_mpi_randomize (hd->k, p_size, GCRY_WEAK_RANDOM); p = gcry_mpi_ec_get_mpi ("p", hd->ec, 1); gcry_mpi_mod (hd->k, hd->k, p); gcry_mpi_release (p); obj->hd = hd; return 0; } static void bench_ecc_mult_free (struct bench_obj *obj) { struct bench_ecc_mult_hd *hd = obj->hd; gcry_mpi_release (hd->k); gcry_mpi_release (hd->y); gcry_mpi_release (hd->x); gcry_mpi_point_release (hd->Q); gcry_mpi_point_release (hd->G); gcry_ctx_release (hd->ec); free (hd); obj->hd = NULL; } static void bench_ecc_mult_do_bench (struct bench_obj *obj, void *buf, size_t num_iter) { struct bench_ecc_oper *oper = obj->priv; struct bench_ecc_mult_hd *hd = obj->hd; gcry_mpi_t y; size_t i; (void)buf; if (oper->algo == ECC_ALGO_X25519 || oper->algo == ECC_ALGO_X448) { y = NULL; } else { y = hd->y; } for (i = 0; i < num_iter; i++) { gcry_mpi_ec_mul (hd->Q, hd->k, hd->G, hd->ec); if (gcry_mpi_ec_get_affine (hd->x, y, hd->Q, hd->ec)) { fprintf (stderr, PGM ": gcry_mpi_ec_get_affine failed\n"); exit (1); } } } static int bench_ecc_init (struct bench_obj *obj) { struct bench_ecc_oper *oper = obj->priv; struct bench_ecc_hd *hd; int p_size = ecc_nbits (oper->algo); gpg_error_t err; gcry_mpi_t x; obj->min_bufsize = 1; obj->max_bufsize = 4; obj->step_size = 1; obj->num_measure_repetitions = num_measurement_repetitions / obj->max_bufsize; while (obj->num_measure_repetitions == 0) { if (obj->max_bufsize == 2) { obj->num_measure_repetitions = 2; } else { obj->max_bufsize--; obj->num_measure_repetitions = num_measurement_repetitions / obj->max_bufsize; } } hd = calloc (1, sizeof(*hd)); if (!hd) return -1; x = gcry_mpi_new (p_size); gcry_mpi_randomize (x, p_size, GCRY_WEAK_RANDOM); switch (oper->algo) { default: gcry_mpi_release (x); free (hd); return -1; case ECC_ALGO_ED25519: err = gcry_sexp_build (&hd->key_spec, NULL, "(genkey (ecdsa (curve \"Ed25519\")" "(flags eddsa)))"); if (err) break; err = gcry_sexp_build (&hd->data, NULL, "(data (flags eddsa)(hash-algo sha512)" " (value %m))", x); break; case ECC_ALGO_ED448: err = gcry_sexp_build (&hd->key_spec, NULL, "(genkey (ecdsa (curve \"Ed448\")" "(flags eddsa)))"); if (err) break; err = gcry_sexp_build (&hd->data, NULL, "(data (flags eddsa)(hash-algo shake256)" " (value %m))", x); break; case ECC_ALGO_NIST_P192: case ECC_ALGO_NIST_P224: case ECC_ALGO_NIST_P256: case ECC_ALGO_NIST_P384: case ECC_ALGO_NIST_P521: err = gcry_sexp_build (&hd->key_spec, NULL, "(genkey (ECDSA (nbits %d)))", p_size); if (err) break; err = gcry_sexp_build (&hd->data, NULL, "(data (flags raw) (value %m))", x); break; case ECC_ALGO_BRAINP256R1: err = gcry_sexp_build (&hd->key_spec, NULL, "(genkey (ECDSA (curve brainpoolP256r1)))"); if (err) break; err = gcry_sexp_build (&hd->data, NULL, "(data (flags raw) (value %m))", x); break; } gcry_mpi_release (x); if (err) { fprintf (stderr, PGM ": gcry_sexp_build failed: %s\n", gpg_strerror (err)); exit (1); } obj->hd = hd; return 0; } static void bench_ecc_free (struct bench_obj *obj) { struct bench_ecc_hd *hd = obj->hd; gcry_sexp_release (hd->sig); gcry_sexp_release (hd->pub_key); gcry_sexp_release (hd->sec_key); gcry_sexp_release (hd->data); gcry_sexp_release (hd->key_spec); free (hd); obj->hd = NULL; } static void bench_ecc_keygen (struct bench_ecc_hd *hd) { gcry_sexp_t key_pair; gpg_error_t err; err = gcry_pk_genkey (&key_pair, hd->key_spec); if (err) { fprintf (stderr, PGM ": gcry_pk_genkey failed: %s\n", gpg_strerror (err)); exit (1); } hd->pub_key = gcry_sexp_find_token (key_pair, "public-key", 0); if (!hd->pub_key) { fprintf (stderr, PGM ": public part missing in key\n"); exit (1); } hd->sec_key = gcry_sexp_find_token (key_pair, "private-key", 0); if (!hd->sec_key) { fprintf (stderr, PGM ": private part missing in key\n"); exit (1); } gcry_sexp_release (key_pair); } static void bench_ecc_keygen_do_bench (struct bench_obj *obj, void *buf, size_t num_iter) { struct bench_ecc_hd *hd = obj->hd; size_t i; (void)buf; for (i = 0; i < num_iter; i++) { bench_ecc_keygen (hd); gcry_sexp_release (hd->pub_key); gcry_sexp_release (hd->sec_key); } hd->pub_key = NULL; hd->sec_key = NULL; } static void bench_ecc_sign_do_bench (struct bench_obj *obj, void *buf, size_t num_iter) { struct bench_ecc_hd *hd = obj->hd; gpg_error_t err; size_t i; (void)buf; bench_ecc_keygen (hd); for (i = 0; i < num_iter; i++) { err = gcry_pk_sign (&hd->sig, hd->data, hd->sec_key); if (err) { fprintf (stderr, PGM ": gcry_pk_sign failed: %s\n", gpg_strerror (err)); exit (1); } gcry_sexp_release (hd->sig); } gcry_sexp_release (hd->pub_key); gcry_sexp_release (hd->sec_key); hd->sig = NULL; hd->pub_key = NULL; hd->sec_key = NULL; } static void bench_ecc_verify_do_bench (struct bench_obj *obj, void *buf, size_t num_iter) { struct bench_ecc_hd *hd = obj->hd; gpg_error_t err; int i; (void)buf; bench_ecc_keygen (hd); err = gcry_pk_sign (&hd->sig, hd->data, hd->sec_key); if (err) { fprintf (stderr, PGM ": gcry_pk_sign failed: %s\n", gpg_strerror (err)); exit (1); } for (i = 0; i < num_iter; i++) { err = gcry_pk_verify (hd->sig, hd->data, hd->pub_key); if (err) { fprintf (stderr, PGM ": gcry_pk_verify failed: %s\n", gpg_strerror (err)); exit (1); } } gcry_sexp_release (hd->sig); gcry_sexp_release (hd->pub_key); gcry_sexp_release (hd->sec_key); hd->sig = NULL; hd->pub_key = NULL; hd->sec_key = NULL; } static struct bench_ops ecc_mult_ops = { &bench_ecc_mult_init, &bench_ecc_mult_free, &bench_ecc_mult_do_bench }; static struct bench_ops ecc_keygen_ops = { &bench_ecc_init, &bench_ecc_free, &bench_ecc_keygen_do_bench }; static struct bench_ops ecc_sign_ops = { &bench_ecc_init, &bench_ecc_free, &bench_ecc_sign_do_bench }; static struct bench_ops ecc_verify_ops = { &bench_ecc_init, &bench_ecc_free, &bench_ecc_verify_do_bench }; static struct bench_ecc_oper ecc_operations[] = { { ECC_OPER_MULT, "mult", &ecc_mult_ops }, { ECC_OPER_KEYGEN, "keygen", &ecc_keygen_ops }, { ECC_OPER_SIGN, "sign", &ecc_sign_ops }, { ECC_OPER_VERIFY, "verify", &ecc_verify_ops }, { 0, NULL, NULL } }; static void cipher_ecc_one (enum bench_ecc_algo algo, struct bench_ecc_oper *poper) { struct bench_ecc_oper oper = *poper; struct bench_obj obj = { 0 }; double result; if ((algo == ECC_ALGO_X25519 || algo == ECC_ALGO_X448 || algo == ECC_ALGO_SECP256K1) && oper.oper != ECC_OPER_MULT) return; oper.algo = algo; bench_print_mode (14, oper.name); obj.ops = oper.ops; obj.priv = &oper; result = do_slope_benchmark (&obj); bench_print_result_nsec_per_iteration (result); } static void _ecc_bench (int algo) { const char *algo_name; int i; /* Skip not allowed mechanisms */ if (in_fips_mode && !ecc_algo_fips_allowed (algo)) return; algo_name = ecc_algo_name (algo); bench_print_header_nsec_per_iteration (14, algo_name); for (i = 0; ecc_operations[i].name; i++) cipher_ecc_one (algo, &ecc_operations[i]); bench_print_footer (14); } #endif void ecc_bench (char **argv, int argc) { #if USE_ECC int i, algo; bench_print_section ("ecc", "ECC"); if (argv && argc) { for (i = 0; i < argc; i++) { algo = ecc_map_name (argv[i]); if (algo >= 0) _ecc_bench (algo); } } else { for (i = 0; i < __MAX_ECC_ALGO; i++) _ecc_bench (i); } #else (void)argv; (void)argc; #endif } /************************************************************ MPI benchmarks. */ #define MPI_START_SIZE 64 #define MPI_END_SIZE 1024 #define MPI_STEP_SIZE 8 #define MPI_NUM_STEPS (((MPI_END_SIZE - MPI_START_SIZE) / MPI_STEP_SIZE) + 1) enum bench_mpi_test { MPI_TEST_ADD = 0, MPI_TEST_SUB, MPI_TEST_RSHIFT3, MPI_TEST_LSHIFT3, MPI_TEST_RSHIFT65, MPI_TEST_LSHIFT65, MPI_TEST_MUL4, MPI_TEST_MUL8, MPI_TEST_MUL16, MPI_TEST_MUL32, MPI_TEST_DIV4, MPI_TEST_DIV8, MPI_TEST_DIV16, MPI_TEST_DIV32, MPI_TEST_MOD4, MPI_TEST_MOD8, MPI_TEST_MOD16, MPI_TEST_MOD32, __MAX_MPI_TEST }; static const char * const mpi_test_names[] = { "add", "sub", "rshift3", "lshift3", "rshift65", "lshift65", "mul4", "mul8", "mul16", "mul32", "div4", "div8", "div16", "div32", "mod4", "mod8", "mod16", "mod32", NULL, }; struct bench_mpi_mode { const char *name; struct bench_ops *ops; enum bench_mpi_test test_id; }; struct bench_mpi_hd { gcry_mpi_t bytes[MPI_NUM_STEPS + 1]; gcry_mpi_t y; }; static int bench_mpi_init (struct bench_obj *obj) { struct bench_mpi_mode *mode = obj->priv; struct bench_mpi_hd *hd; int y_bytes; int i, j; (void)mode; obj->min_bufsize = MPI_START_SIZE; obj->max_bufsize = MPI_END_SIZE; obj->step_size = MPI_STEP_SIZE; obj->num_measure_repetitions = num_measurement_repetitions; hd = calloc (1, sizeof(*hd)); if (!hd) return -1; /* Generate input MPIs for benchmark. */ for (i = MPI_START_SIZE, j = 0; j < DIM(hd->bytes); i += MPI_STEP_SIZE, j++) { hd->bytes[j] = gcry_mpi_new (i * 8); gcry_mpi_randomize (hd->bytes[j], i * 8, GCRY_WEAK_RANDOM); gcry_mpi_set_bit (hd->bytes[j], i * 8 - 1); } switch (mode->test_id) { case MPI_TEST_MUL4: case MPI_TEST_DIV4: case MPI_TEST_MOD4: y_bytes = 4; break; case MPI_TEST_MUL8: case MPI_TEST_DIV8: case MPI_TEST_MOD8: y_bytes = 8; break; case MPI_TEST_MUL16: case MPI_TEST_DIV16: case MPI_TEST_MOD16: y_bytes = 16; break; case MPI_TEST_MUL32: case MPI_TEST_DIV32: case MPI_TEST_MOD32: y_bytes = 32; break; default: y_bytes = 0; break; } hd->y = gcry_mpi_new (y_bytes * 8); if (y_bytes) { gcry_mpi_randomize (hd->y, y_bytes * 8, GCRY_WEAK_RANDOM); gcry_mpi_set_bit (hd->y, y_bytes * 8 - 1); } obj->hd = hd; return 0; } static void bench_mpi_free (struct bench_obj *obj) { struct bench_mpi_hd *hd = obj->hd; int i; gcry_mpi_release (hd->y); for (i = DIM(hd->bytes) - 1; i >= 0; i--) gcry_mpi_release (hd->bytes[i]); free(hd); } static void bench_mpi_do_bench (struct bench_obj *obj, void *buf, size_t buflen) { struct bench_mpi_hd *hd = obj->hd; struct bench_mpi_mode *mode = obj->priv; int bytes_idx = (buflen - MPI_START_SIZE) / MPI_STEP_SIZE; gcry_mpi_t x; (void)buf; x = gcry_mpi_new (2 * (MPI_END_SIZE + 1) * 8); switch (mode->test_id) { case MPI_TEST_ADD: gcry_mpi_add (x, hd->bytes[bytes_idx], hd->bytes[bytes_idx]); break; case MPI_TEST_SUB: gcry_mpi_sub (x, hd->bytes[bytes_idx + 1], hd->bytes[bytes_idx]); break; case MPI_TEST_RSHIFT3: gcry_mpi_rshift (x, hd->bytes[bytes_idx], 3); break; case MPI_TEST_LSHIFT3: gcry_mpi_lshift (x, hd->bytes[bytes_idx], 3); break; case MPI_TEST_RSHIFT65: gcry_mpi_rshift (x, hd->bytes[bytes_idx], 65); break; case MPI_TEST_LSHIFT65: gcry_mpi_lshift (x, hd->bytes[bytes_idx], 65); break; case MPI_TEST_MUL4: case MPI_TEST_MUL8: case MPI_TEST_MUL16: case MPI_TEST_MUL32: gcry_mpi_mul (x, hd->bytes[bytes_idx], hd->y); break; case MPI_TEST_DIV4: case MPI_TEST_DIV8: case MPI_TEST_DIV16: case MPI_TEST_DIV32: gcry_mpi_div (x, NULL, hd->bytes[bytes_idx], hd->y, 0); break; case MPI_TEST_MOD4: case MPI_TEST_MOD8: case MPI_TEST_MOD16: case MPI_TEST_MOD32: gcry_mpi_mod (x, hd->bytes[bytes_idx], hd->y); break; default: break; } gcry_mpi_release (x); } static struct bench_ops mpi_ops = { &bench_mpi_init, &bench_mpi_free, &bench_mpi_do_bench }; static struct bench_mpi_mode mpi_modes[] = { {"", &mpi_ops}, {0}, }; static void mpi_bench_one (int test_id, struct bench_mpi_mode *pmode) { struct bench_mpi_mode mode = *pmode; struct bench_obj obj = { 0 }; double result; mode.test_id = test_id; if (mode.name[0] == '\0') bench_print_algo (-18, mpi_test_names[test_id]); else bench_print_algo (18, mode.name); obj.ops = mode.ops; obj.priv = &mode; result = do_slope_benchmark (&obj); bench_print_result (result); } static void _mpi_bench (int test_id) { int i; for (i = 0; mpi_modes[i].name; i++) mpi_bench_one (test_id, &mpi_modes[i]); } static int mpi_match_test(const char *name) { int i; for (i = 0; i < __MAX_MPI_TEST; i++) if (strcmp(name, mpi_test_names[i]) == 0) return i; return -1; } void mpi_bench (char **argv, int argc) { int i, test_id; bench_print_section ("mpi", "MPI"); bench_print_header (18, ""); if (argv && argc) { for (i = 0; i < argc; i++) { test_id = mpi_match_test (argv[i]); if (test_id >= 0) _mpi_bench (test_id); } } else { for (i = 0; i < __MAX_MPI_TEST; i++) _mpi_bench (i); } bench_print_footer (18); } /************************************************************** Main program. */ void print_help (void) { static const char *help_lines[] = { "usage: bench-slope [options] [hash|mac|cipher|kdf|ecc|mpi [algonames]]", "", " options:", " --cpu-mhz Set CPU speed for calculating cycles", " per bytes results. Set as \"auto\"", " for auto-detection of CPU speed.", " --disable-hwf Disable hardware acceleration feature(s)", " for benchmarking.", " --repetitions Use N repetitions (default " STR2(NUM_MEASUREMENT_REPETITIONS) ")", " --unaligned Use unaligned input buffers.", " --csv Use CSV output format", NULL }; const char **line; for (line = help_lines; *line; line++) fprintf (stdout, "%s\n", *line); } /* Warm up CPU. */ static void warm_up_cpu (void) { struct nsec_time start, end; if (in_regression_test) return; get_nsec_time (&start); do { get_nsec_time (&end); } while (get_time_nsec_diff (&start, &end) < 1000.0 * 1000.0 * 1000.0); } int main (int argc, char **argv) { int last_argc = -1; if (argc) { argc--; argv++; } /* We skip this test if we are running under the test suite (no args and srcdir defined) and GCRYPT_NO_BENCHMARKS is set. */ if (!argc && getenv ("srcdir") && getenv ("GCRYPT_NO_BENCHMARKS")) exit (77); if (getenv ("GCRYPT_IN_REGRESSION_TEST")) { in_regression_test = 1; num_measurement_repetitions = 2; } else num_measurement_repetitions = NUM_MEASUREMENT_REPETITIONS; while (argc && last_argc != argc) { last_argc = argc; if (!strcmp (*argv, "--")) { argc--; argv++; break; } else if (!strcmp (*argv, "--help")) { print_help (); exit (0); } else if (!strcmp (*argv, "--verbose")) { verbose++; argc--; argv++; } else if (!strcmp (*argv, "--debug")) { verbose += 2; debug++; argc--; argv++; } else if (!strcmp (*argv, "--csv")) { csv_mode = 1; argc--; argv++; } else if (!strcmp (*argv, "--unaligned")) { unaligned_mode = 1; argc--; argv++; } else if (!strcmp (*argv, "--disable-hwf")) { argc--; argv++; if (argc) { if (gcry_control (GCRYCTL_DISABLE_HWF, *argv, NULL)) fprintf (stderr, PGM ": unknown hardware feature `%s' - option ignored\n", *argv); argc--; argv++; } } else if (!strcmp (*argv, "--cpu-mhz")) { argc--; argv++; if (argc) { if (!strcmp (*argv, "auto")) { auto_ghz = 1; } else { cpu_ghz = atof (*argv); cpu_ghz /= 1000; /* Mhz => Ghz */ } argc--; argv++; } } else if (!strcmp (*argv, "--repetitions")) { argc--; argv++; if (argc) { num_measurement_repetitions = atof (*argv); if (num_measurement_repetitions < 2) { fprintf (stderr, PGM ": value for --repetitions too small - using %d\n", NUM_MEASUREMENT_REPETITIONS); num_measurement_repetitions = NUM_MEASUREMENT_REPETITIONS; } argc--; argv++; } } } xgcry_control ((GCRYCTL_SET_VERBOSITY, (int) verbose)); if (!gcry_check_version (GCRYPT_VERSION)) { fprintf (stderr, PGM ": version mismatch; pgm=%s, library=%s\n", GCRYPT_VERSION, gcry_check_version (NULL)); exit (1); } if (debug) xgcry_control ((GCRYCTL_SET_DEBUG_FLAGS, 1u, 0)); xgcry_control ((GCRYCTL_DISABLE_SECMEM, 0)); xgcry_control ((GCRYCTL_INITIALIZATION_FINISHED, 0)); xgcry_control ((GCRYCTL_ENABLE_QUICK_RANDOM, 0)); if (gcry_fips_mode_active ()) in_fips_mode = 1; if (in_regression_test) fputs ("Note: " PGM " running in quick regression test mode.\n", stdout); if (!argc) { warm_up_cpu (); hash_bench (NULL, 0); mac_bench (NULL, 0); cipher_bench (NULL, 0); kdf_bench (NULL, 0); ecc_bench (NULL, 0); mpi_bench (NULL, 0); } else if (!strcmp (*argv, "hash")) { argc--; argv++; warm_up_cpu (); hash_bench ((argc == 0) ? NULL : argv, argc); } else if (!strcmp (*argv, "mac")) { argc--; argv++; warm_up_cpu (); mac_bench ((argc == 0) ? NULL : argv, argc); } else if (!strcmp (*argv, "cipher")) { argc--; argv++; warm_up_cpu (); cipher_bench ((argc == 0) ? NULL : argv, argc); } else if (!strcmp (*argv, "kdf")) { argc--; argv++; warm_up_cpu (); kdf_bench ((argc == 0) ? NULL : argv, argc); } else if (!strcmp (*argv, "ecc")) { argc--; argv++; warm_up_cpu (); ecc_bench ((argc == 0) ? NULL : argv, argc); } else if (!strcmp (*argv, "mpi")) { argc--; argv++; warm_up_cpu (); mpi_bench ((argc == 0) ? NULL : argv, argc); } else { fprintf (stderr, PGM ": unknown argument: %s\n", *argv); print_help (); } return 0; } #endif /* !NO_GET_NSEC_TIME */ diff --git a/tests/benchmark.c b/tests/benchmark.c index cf8182a6..3a3abadd 100644 --- a/tests/benchmark.c +++ b/tests/benchmark.c @@ -1,2087 +1,2086 @@ /* benchmark.c - for libgcrypt * Copyright (C) 2002, 2004, 2005, 2006, 2008 Free Software Foundation, Inc. * * This file is part of Libgcrypt. * * Libgcrypt is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser general Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * Libgcrypt is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this program; if not, see . */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #ifdef _GCRYPT_IN_LIBGCRYPT # include "../src/gcrypt-int.h" # include "../compat/libcompat.h" #else # include #endif #include "stopwatch.h" #define PGM "benchmark" #include "t-common.h" /* Do encryption tests with large buffers (100 KiB). */ static int large_buffers; /* Do encryption tests with huge buffers (256 MiB). */ static int huge_buffers; /* Number of cipher repetitions. */ static int cipher_repetitions; /* Number of hash repetitions. */ static int hash_repetitions; /* Number of hash repetitions. */ static int mac_repetitions; /* Alignment of the buffers. */ static int buffer_alignment; /* Whether to include the keysetup in the cipher timings. */ static int cipher_with_keysetup; /* Whether fips mode was active at startup. */ static int in_fips_mode; /* Whether we are running as part of the regression test suite. */ static int in_regression_test; /* Whether --progress is in use. */ static int with_progress; /* Runtime flag to switch to a different progress output. */ static int single_char_progress; #if USE_DSA static const char sample_private_dsa_key_1024[] = "(private-key\n" " (dsa\n" " (p #00A126202D592214C5A8F6016E2C3F4256052ACB1CB17D88E64B1293FAF08F5E4685" "03E6F68366B326A56284370EB2103E92D8346A163E44A08FDC422AC8E9E44268557A" "853539A6AF39353A59CE5E78FD98B57D0F3E3A7EBC8A256AC9A775BA59689F3004BF" "C3035730C4C0C51626C5D7F5852637EC589BB29DAB46C161572E4B#)\n" " (q #00DEB5A296421887179ECA1762884DE2AF8185AFC5#)\n" " (g #3958B34AE7747194ECBD312F8FEE8CBE3918E94DF9FD11E2912E56318F33BDC38622" "B18DDFF393074BCA8BAACF50DF27AEE529F3E8AEECE55C398DAB3A5E04C2EA142312" "FACA2FE7F0A88884F8DAC3979EE67598F9A383B2A2325F035C796F352A5C3CDF2CB3" "85AD24EC52A6E55247E1BB37D260F79E617D2A4446415B6AD79A#)\n" " (y #519E9FE9AB0545A6724E74603B7B04E48DC1437E0284A11EA605A7BA8AB1CF354FD4" "ECC93880AC293391C69B558AD84E7AAFA88F11D028CF3A378F241D6B056A90C588F6" "66F68D27262B4DA84657D15057D371BCEC1F6504032507D5B881E45FC93A1B973155" "D91C57219D090C3ACD75E7C2B9F1176A208AC03D6C12AC28A271#)\n" " (x #4186F8A58C5DF46C5BCFC7006BEEBF05E93C0CA7#)\n" "))\n"; static const char sample_public_dsa_key_1024[] = "(public-key\n" " (dsa\n" " (p #00A126202D592214C5A8F6016E2C3F4256052ACB1CB17D88E64B1293FAF08F5E4685" "03E6F68366B326A56284370EB2103E92D8346A163E44A08FDC422AC8E9E44268557A" "853539A6AF39353A59CE5E78FD98B57D0F3E3A7EBC8A256AC9A775BA59689F3004BF" "C3035730C4C0C51626C5D7F5852637EC589BB29DAB46C161572E4B#)\n" " (q #00DEB5A296421887179ECA1762884DE2AF8185AFC5#)\n" " (g #3958B34AE7747194ECBD312F8FEE8CBE3918E94DF9FD11E2912E56318F33BDC38622" "B18DDFF393074BCA8BAACF50DF27AEE529F3E8AEECE55C398DAB3A5E04C2EA142312" "FACA2FE7F0A88884F8DAC3979EE67598F9A383B2A2325F035C796F352A5C3CDF2CB3" "85AD24EC52A6E55247E1BB37D260F79E617D2A4446415B6AD79A#)\n" " (y #519E9FE9AB0545A6724E74603B7B04E48DC1437E0284A11EA605A7BA8AB1CF354FD4" "ECC93880AC293391C69B558AD84E7AAFA88F11D028CF3A378F241D6B056A90C588F6" "66F68D27262B4DA84657D15057D371BCEC1F6504032507D5B881E45FC93A1B973155" "D91C57219D090C3ACD75E7C2B9F1176A208AC03D6C12AC28A271#)\n" "))\n"; static const char sample_private_dsa_key_2048[] = "(private-key\n" " (dsa\n" " (p #00B54636673962B64F7DC23C71ACEF6E7331796F607560B194DFCC0CA370E858A365" "A413152FB6EB8C664BD171AC316FE5B381CD084D07377571599880A068EF1382D85C" "308B4E9DEAC12D66DE5C4A826EBEB5ED94A62E7301E18927E890589A2F230272A150" "C118BC3DC2965AE0D05BE4F65C6137B2BA7EDABB192C3070D202C10AA3F534574970" "71454DB8A73DDB6511A5BA98EF1450FD90DE5BAAFC9FD3AC22EBEA612DD075BB7405" "D56866D125E33982C046808F7CEBA8E5C0B9F19A6FE451461660A1CBA9EF68891179" "0256A573D3B8F35A5C7A0C6C31F2DB90E25A26845252AD9E485EF2D339E7B5890CD4" "2F9C9F315ED409171EC35CA04CC06B275577B3#)\n" " (q #00DA67989167FDAC4AE3DF9247A716859A30C0CF9C5A6DBA01EABA3481#)\n" " (g #48E35DA584A089D05142AA63603FDB00D131B07A0781E2D5A8F9614D2B33D3E40A78" "98A9E10CDBB612CF093F95A3E10D09566726F2C12823836B2D9CD974BB695665F3B3" "5D219A9724B87F380BD5207EDA0AE38C79E8F18122C3F76E4CEB0ABED3250914987F" "B30D4B9E19C04C28A5D4F45560AF586F6A1B41751EAD90AE7F044F4E2A4A50C1F508" "4FC202463F478F678B9A19392F0D2961C5391C546EF365368BB46410C9C1CEE96E9F" "0C953570C2ED06328B11C90E86E57CAA7FA5ABAA278E22A4C8C08E16EE59F484EC44" "2CF55535BAA2C6BEA8833A555372BEFE1E665D3C7DAEF58061D5136331EF4EB61BC3" "6EE4425A553AF8885FEA15A88135BE133520#)\n" " (y #66E0D1A69D663466F8FEF2B7C0878DAC93C36A2FB2C05E0306A53B926021D4B92A1C" "2FA6860061E88E78CBBBA49B0E12700F07DBF86F72CEB2927EDAC0C7E3969C3A47BB" "4E0AE93D8BB3313E93CC7A72DFEEE442EFBC81B3B2AEC9D8DCBE21220FB760201D79" "328C41C773866587A44B6954767D022A88072900E964089D9B17133603056C985C4F" "8A0B648F297F8D2C3CB43E4371DC6002B5B12CCC085BDB2CFC5074A0587566187EE3" "E11A2A459BD94726248BB8D6CC62938E11E284C2C183576FBB51749EB238C4360923" "79C08CE1C8CD77EB57404CE9B4744395ACF721487450BADE3220576F2F816248B0A7" "14A264330AECCB24DE2A1107847B23490897#)\n" " (x #477BD14676E22563C5ABA68025CEBA2A48D485F5B2D4AD4C0EBBD6D0#)\n" "))\n"; static const char sample_public_dsa_key_2048[] = "(public-key\n" " (dsa\n" " (p #00B54636673962B64F7DC23C71ACEF6E7331796F607560B194DFCC0CA370E858A365" "A413152FB6EB8C664BD171AC316FE5B381CD084D07377571599880A068EF1382D85C" "308B4E9DEAC12D66DE5C4A826EBEB5ED94A62E7301E18927E890589A2F230272A150" "C118BC3DC2965AE0D05BE4F65C6137B2BA7EDABB192C3070D202C10AA3F534574970" "71454DB8A73DDB6511A5BA98EF1450FD90DE5BAAFC9FD3AC22EBEA612DD075BB7405" "D56866D125E33982C046808F7CEBA8E5C0B9F19A6FE451461660A1CBA9EF68891179" "0256A573D3B8F35A5C7A0C6C31F2DB90E25A26845252AD9E485EF2D339E7B5890CD4" "2F9C9F315ED409171EC35CA04CC06B275577B3#)\n" " (q #00DA67989167FDAC4AE3DF9247A716859A30C0CF9C5A6DBA01EABA3481#)\n" " (g #48E35DA584A089D05142AA63603FDB00D131B07A0781E2D5A8F9614D2B33D3E40A78" "98A9E10CDBB612CF093F95A3E10D09566726F2C12823836B2D9CD974BB695665F3B3" "5D219A9724B87F380BD5207EDA0AE38C79E8F18122C3F76E4CEB0ABED3250914987F" "B30D4B9E19C04C28A5D4F45560AF586F6A1B41751EAD90AE7F044F4E2A4A50C1F508" "4FC202463F478F678B9A19392F0D2961C5391C546EF365368BB46410C9C1CEE96E9F" "0C953570C2ED06328B11C90E86E57CAA7FA5ABAA278E22A4C8C08E16EE59F484EC44" "2CF55535BAA2C6BEA8833A555372BEFE1E665D3C7DAEF58061D5136331EF4EB61BC3" "6EE4425A553AF8885FEA15A88135BE133520#)\n" " (y #66E0D1A69D663466F8FEF2B7C0878DAC93C36A2FB2C05E0306A53B926021D4B92A1C" "2FA6860061E88E78CBBBA49B0E12700F07DBF86F72CEB2927EDAC0C7E3969C3A47BB" "4E0AE93D8BB3313E93CC7A72DFEEE442EFBC81B3B2AEC9D8DCBE21220FB760201D79" "328C41C773866587A44B6954767D022A88072900E964089D9B17133603056C985C4F" "8A0B648F297F8D2C3CB43E4371DC6002B5B12CCC085BDB2CFC5074A0587566187EE3" "E11A2A459BD94726248BB8D6CC62938E11E284C2C183576FBB51749EB238C4360923" "79C08CE1C8CD77EB57404CE9B4744395ACF721487450BADE3220576F2F816248B0A7" "14A264330AECCB24DE2A1107847B23490897#)\n" "))\n"; static const char sample_private_dsa_key_3072[] = "(private-key\n" " (dsa\n" " (p #00BA73E148AEA5E8B64878AF5BE712B8302B9671C5F3EEB7722A9D0D9868D048C938" "877C91C335C7819292E69C7D34264F1578E32EC2DA8408DF75D0EB76E0D3030B84B5" "62D8EF93AB53BAB6B8A5DE464F5CA87AEA43BDCF0FB0B7815AA3114CFC84FD916A83" "B3D5FD78390189332232E9D037D215313FD002FF46C048B66703F87FAE092AAA0988" "AC745336EBE672A01DEDBD52395783579B67CF3AE1D6F1602CCCB12154FA0E00AE46" "0D9B289CF709194625BCB919B11038DEFC50ADBBA20C3F320078E4E9529B4F6848E2" "AB5E6278DB961FE226F2EEBD201E071C48C5BEF98B4D9BEE42C1C7102D893EBF8902" "D7A91266340AFD6CE1D09E52282FFF5B97EAFA3886A3FCF84FF76D1E06538D0D8E60" "B3332145785E07D29A5965382DE3470D1D888447FA9C00A2373378FC3FA7B9F7D17E" "95A6A5AE1397BE46D976EF2C96E89913AC4A09351CA661BF6F67E30407DA846946C7" "62D9BAA6B77825097D3E7B886456BB32E3E74516BF3FD93D71B257AA8F723E01CE33" "8015353D3778B02B892AF7#)\n" " (q #00BFF3F3CC18FA018A5B8155A8695E1E4939660D5E4759322C39D50F3B93E5F68B#)\n" " (g #6CCFD8219F5FCE8EF2BEF3262929787140847E38674B1EF8DB20255E212CB6330EC4" "DFE8A26AB7ECC5760DEB9BBF59A2B2821D510F1868172222867558B8D204E889C474" "7CA30FBF9D8CF41AE5D5BD845174641101593849FF333E6C93A6550931B2B9D56B98" "9CAB01729D9D736FA6D24A74D2DDE1E9E648D141473E443DD6BBF0B3CAB64F9FE4FC" "134B2EB57437789F75C744DF1FA67FA8A64603E5441BC7ECE29E00BDF262BDC81E8C" "7330A18A412DE38E7546D342B89A0AF675A89E6BEF00540EB107A2FE74EA402B0D89" "F5C02918DEEEAF8B8737AC866B09B50810AB8D8668834A1B9E1E53866E2B0A926FAB" "120A0CDE5B3715FFFE6ACD1AB73588DCC1EC4CE9392FE57F8D1D35811200CB07A0E6" "374E2C4B0AEB7E3D077B8545C0E438DCC0F1AE81E186930E99EBC5B91B77E92803E0" "21602887851A4FFDB3A7896AC655A0901218C121C5CBB0931E7D5EAC243F37711B5F" "D5A62B1B38A83F03D8F6703D8B98DF367FC8A76990335F62173A5391836F0F2413EC" "4997AF9EB55C6660B01A#)\n" " (y #2320B22434C5DB832B4EC267CC52E78DD5CCFA911E8F0804E7E7F32B186B2D4167AE" "4AA6869822E76400492D6A193B0535322C72B0B7AA4A87E33044FDC84BE24C64A053" "A37655EE9EABDCDC1FDF63F3F1C677CEB41595DF7DEFE9178D85A3D621B4E4775492" "8C0A58D2458D06F9562E4DE2FE6129A64063A99E88E54485B97484A28188C4D33F15" "DDC903B6CEA0135E3E3D27B4EA39319696305CE93D7BA7BE00367DBE3AAF43491E71" "CBF254744A5567F5D70090D6139E0C990239627B3A1C5B20B6F9F6374B8D8D8A8997" "437265BE1E3B4810D4B09254400DE287A0DFFBAEF339E48D422B1D41A37E642BC026" "73314701C8FA9792845C129351A87A945A03E6C895860E51D6FB8B7340A94D1A8A7B" "FA85AC83B4B14E73AB86CB96C236C8BFB0978B61B2367A7FE4F7891070F56C78D5DD" "F5576BFE5BE4F333A4E2664E79528B3294907AADD63F4F2E7AA8147B928D8CD69765" "3DB98C4297CB678046ED55C0DBE60BF7142C594603E4D705DC3D17270F9F086EC561" "2703D518D8D49FF0EBE6#)\n" " (x #00A9FFFC88E67D6F7B810E291C050BAFEA7FC4A75E8D2F16CFED3416FD77607232#)\n" "))\n"; static const char sample_public_dsa_key_3072[] = "(public-key\n" " (dsa\n" " (p #00BA73E148AEA5E8B64878AF5BE712B8302B9671C5F3EEB7722A9D0D9868D048C938" "877C91C335C7819292E69C7D34264F1578E32EC2DA8408DF75D0EB76E0D3030B84B5" "62D8EF93AB53BAB6B8A5DE464F5CA87AEA43BDCF0FB0B7815AA3114CFC84FD916A83" "B3D5FD78390189332232E9D037D215313FD002FF46C048B66703F87FAE092AAA0988" "AC745336EBE672A01DEDBD52395783579B67CF3AE1D6F1602CCCB12154FA0E00AE46" "0D9B289CF709194625BCB919B11038DEFC50ADBBA20C3F320078E4E9529B4F6848E2" "AB5E6278DB961FE226F2EEBD201E071C48C5BEF98B4D9BEE42C1C7102D893EBF8902" "D7A91266340AFD6CE1D09E52282FFF5B97EAFA3886A3FCF84FF76D1E06538D0D8E60" "B3332145785E07D29A5965382DE3470D1D888447FA9C00A2373378FC3FA7B9F7D17E" "95A6A5AE1397BE46D976EF2C96E89913AC4A09351CA661BF6F67E30407DA846946C7" "62D9BAA6B77825097D3E7B886456BB32E3E74516BF3FD93D71B257AA8F723E01CE33" "8015353D3778B02B892AF7#)\n" " (q #00BFF3F3CC18FA018A5B8155A8695E1E4939660D5E4759322C39D50F3B93E5F68B#)\n" " (g #6CCFD8219F5FCE8EF2BEF3262929787140847E38674B1EF8DB20255E212CB6330EC4" "DFE8A26AB7ECC5760DEB9BBF59A2B2821D510F1868172222867558B8D204E889C474" "7CA30FBF9D8CF41AE5D5BD845174641101593849FF333E6C93A6550931B2B9D56B98" "9CAB01729D9D736FA6D24A74D2DDE1E9E648D141473E443DD6BBF0B3CAB64F9FE4FC" "134B2EB57437789F75C744DF1FA67FA8A64603E5441BC7ECE29E00BDF262BDC81E8C" "7330A18A412DE38E7546D342B89A0AF675A89E6BEF00540EB107A2FE74EA402B0D89" "F5C02918DEEEAF8B8737AC866B09B50810AB8D8668834A1B9E1E53866E2B0A926FAB" "120A0CDE5B3715FFFE6ACD1AB73588DCC1EC4CE9392FE57F8D1D35811200CB07A0E6" "374E2C4B0AEB7E3D077B8545C0E438DCC0F1AE81E186930E99EBC5B91B77E92803E0" "21602887851A4FFDB3A7896AC655A0901218C121C5CBB0931E7D5EAC243F37711B5F" "D5A62B1B38A83F03D8F6703D8B98DF367FC8A76990335F62173A5391836F0F2413EC" "4997AF9EB55C6660B01A#)\n" " (y #2320B22434C5DB832B4EC267CC52E78DD5CCFA911E8F0804E7E7F32B186B2D4167AE" "4AA6869822E76400492D6A193B0535322C72B0B7AA4A87E33044FDC84BE24C64A053" "A37655EE9EABDCDC1FDF63F3F1C677CEB41595DF7DEFE9178D85A3D621B4E4775492" "8C0A58D2458D06F9562E4DE2FE6129A64063A99E88E54485B97484A28188C4D33F15" "DDC903B6CEA0135E3E3D27B4EA39319696305CE93D7BA7BE00367DBE3AAF43491E71" "CBF254744A5567F5D70090D6139E0C990239627B3A1C5B20B6F9F6374B8D8D8A8997" "437265BE1E3B4810D4B09254400DE287A0DFFBAEF339E48D422B1D41A37E642BC026" "73314701C8FA9792845C129351A87A945A03E6C895860E51D6FB8B7340A94D1A8A7B" "FA85AC83B4B14E73AB86CB96C236C8BFB0978B61B2367A7FE4F7891070F56C78D5DD" "F5576BFE5BE4F333A4E2664E79528B3294907AADD63F4F2E7AA8147B928D8CD69765" "3DB98C4297CB678046ED55C0DBE60BF7142C594603E4D705DC3D17270F9F086EC561" "2703D518D8D49FF0EBE6#)\n" "))\n"; #endif /* USE_DSA */ #if USE_ELGAMAL static const char sample_public_elg_key_1024[] = "(public-key" " (elg" " (p #00F7CC7C08AF096B620C545C9353B1140D698FF8BE2D97A3515C17C7F8DABCDB8FB6" "64A46416C90C530C18DF5ABB6C1DDE3AE2FA9DDC9CE40DF644CDE2E759F6DE43F31A" "EEEBC136A460B3E4B0A8F99326A335145B19F4C81B13804894B7D2A30F78A8A7D7F4" "52B83836FDB0DE90BE327FB5E5318757BEF5FE0FC3A5461CBEA0D3#)" " (g #06#)" " (y #36B38FB63E3340A0DD8A0468E9FAA512A32DA010BF7110201D0A3DF1B8FEA0E16F3C" "80374584E554804B96EAA8C270FE531F75D0DBD81BA65640EDB1F76D46C27D2925B7" "3EC3B295CDAEEF242904A84D74FB2879425F82D4C5B59BB49A992F85D574168DED85" "D227600BBEF7AF0B8F0DEB785528370E4C4B3E4D65C536122A5A#)" " ))"; static const char sample_private_elg_key_1024[] = "(private-key" " (elg" " (p #00F7CC7C08AF096B620C545C9353B1140D698FF8BE2D97A3515C17C7F8DABCDB8FB6" "64A46416C90C530C18DF5ABB6C1DDE3AE2FA9DDC9CE40DF644CDE2E759F6DE43F31A" "EEEBC136A460B3E4B0A8F99326A335145B19F4C81B13804894B7D2A30F78A8A7D7F4" "52B83836FDB0DE90BE327FB5E5318757BEF5FE0FC3A5461CBEA0D3#)" " (g #06#)" " (y #36B38FB63E3340A0DD8A0468E9FAA512A32DA010BF7110201D0A3DF1B8FEA0E16F3C" "80374584E554804B96EAA8C270FE531F75D0DBD81BA65640EDB1F76D46C27D2925B7" "3EC3B295CDAEEF242904A84D74FB2879425F82D4C5B59BB49A992F85D574168DED85" "D227600BBEF7AF0B8F0DEB785528370E4C4B3E4D65C536122A5A#)" " (x #03656C6186FCD27D4A4B1F5010DC0D2AE7833B501E423FCD51DE5EB6D80DACFE#)" " ))"; static const char sample_public_elg_key_2048[] = "(public-key" " (elg" " (p #00BE5A2BB4E562D7B644E3D01321CB818DBA27295C339FC2C47EAE9823225EE1E7B6" "38C5DE300E931080E09CC89A18C9D180C16559FEF0D89D6A09534BB86489CCCEE30D" "C18E007A8726BB99F2B2D90D2694597757B120CD2435C0098AD1B74C20004C25BA97" "73EAA4FBEC594EE17F8B25867EEB0F9F857C751116ADED68ADA2A1E9F9F4F40D18F0" "EC1221CA6A746FC5F4CDA2B8B5D0AB83834564ACF6FDBB1AB01D4BFBD1E2C0108FF5" "5FB3190C6D6DA4D95EA683EFA44935CFBC0BF5C6118ACC3768AEA9A98D06024841B8" "D07C234289D22A5E3948F199C397AA991C59A55BEA0C01E91902E039116946FEA135" "768011AF6B622C5AF366EF0196FC4EAEAA8127#)" " (g #07#)" " (y #5AFF87BC23D8B97AA62897A5C1CDFFA86C59F39EDBD6012B6F333CE23D872009B8C8" "D1E220E18CFCADFE0AA16346BA2EA132472FFEC746D11C6E758896052313BB501210" "2389C683A25A3464E9B35A192BAE0A3BB99C973126F7560D968C4A754901DC967354" "D61A90ACD56D90DCC4337AFB71FAE3FD18C60EB0D6DD173877DF5DB5199C4931FE4E" "5046F814422580E1162798406FC6554781142DBB7922D4B5B37A111F23761636090F" "6212681E133365191CF15753AE737F17943ED4B7506DE0A85C3B6D63227F9D65ADF8" "2C3DF0676C8F43B5B1C07D9AD4E6D0C812401D7DA7B9484DBA8CD3B73B19A95EB237" "D493E092AEA2371AA904009C8960B0969D12#)" " ))"; static const char sample_private_elg_key_2048[] = "(private-key" " (elg" " (p #00BE5A2BB4E562D7B644E3D01321CB818DBA27295C339FC2C47EAE9823225EE1E7B6" "38C5DE300E931080E09CC89A18C9D180C16559FEF0D89D6A09534BB86489CCCEE30D" "C18E007A8726BB99F2B2D90D2694597757B120CD2435C0098AD1B74C20004C25BA97" "73EAA4FBEC594EE17F8B25867EEB0F9F857C751116ADED68ADA2A1E9F9F4F40D18F0" "EC1221CA6A746FC5F4CDA2B8B5D0AB83834564ACF6FDBB1AB01D4BFBD1E2C0108FF5" "5FB3190C6D6DA4D95EA683EFA44935CFBC0BF5C6118ACC3768AEA9A98D06024841B8" "D07C234289D22A5E3948F199C397AA991C59A55BEA0C01E91902E039116946FEA135" "768011AF6B622C5AF366EF0196FC4EAEAA8127#)" " (g #07#)" " (y #5AFF87BC23D8B97AA62897A5C1CDFFA86C59F39EDBD6012B6F333CE23D872009B8C8" "D1E220E18CFCADFE0AA16346BA2EA132472FFEC746D11C6E758896052313BB501210" "2389C683A25A3464E9B35A192BAE0A3BB99C973126F7560D968C4A754901DC967354" "D61A90ACD56D90DCC4337AFB71FAE3FD18C60EB0D6DD173877DF5DB5199C4931FE4E" "5046F814422580E1162798406FC6554781142DBB7922D4B5B37A111F23761636090F" "6212681E133365191CF15753AE737F17943ED4B7506DE0A85C3B6D63227F9D65ADF8" "2C3DF0676C8F43B5B1C07D9AD4E6D0C812401D7DA7B9484DBA8CD3B73B19A95EB237" "D493E092AEA2371AA904009C8960B0969D12#)" " (x #0628C3903972C55BDC1BC4223075616D3F3BA57D55532DDB40CB14CF72070E0D28BF" "D0402B9088D25ED8FC#)" " ))"; static const char sample_public_elg_key_3072[] = "(public-key" " (elg" " (p #008EAA3497AFE3706E1A57FFA52E68C64C500731B58EBAFEB51C4A20AB15BA57FA72" "BA1510A4703D5AA6F05DB67E4A776F92AD08800577DC686D00B793167A5D79C997E0" "5B9A9E5974B4B68B4D71ED8EC37F2F45235D901997D72915643F058E712AA18275A2" "C6F9F7C2B9B7CD1E814D215F12A840800B546AEF2A2E6C077CDD1A322738FFD36DB2" "FA5420B5848EED870BC1A6CF55040AE8D2A5945F11AE2BCBE107B41A59EFDBD3B05C" "F4C876C02C9AEAE22CD4C86806A415302936E4C1E5AA59DBBCCD2F83C20941A29888" "A70ADB94D3B8A6489C46BF2C5219CD9FD2341EA21D4E68A4ECC468FD09D215FE96D4" "7AEA12FD22B2456D2CC13672FC7E9772A365C68668157C51E46966B6A1831C429BA0" "D513519713C49C13C5FC7C14BE0A117627B204C4478D0A93C6B57929E448C9B65BF2" "390E04BC5940320C0262FC1A221E7C796493432239A6F12BC62C5CF32E8ADBC1730C" "84C6E6E6BD95AF62835941F3F344AF46BFE5A8F629D5FA699FE37EF8B8C6A2484E42" "D226206FDF7D1FB93A5457#)" " (g #0B#)" " (y #18E734FF645AE169079AEAFC78772371089AD3088627ECF77034AFBDF33ADF594AAF" "3288F6979E0DB59CE3D2F0FEE031DFF187F1E4549D3C79668794CB19C14481ECDE2D" "D50861AB674F87A011D50D35F28E424D0D2353850899C2CDD0CC8FDBFC5A0CA395F0" "E605D46CBDD140DBEF426EBD638C9ADD83C195C45CE84ED2D2B21B87800C783A4F79" "12226FEFBDA01C66B254534A51765AF09687275AA80C5DFBA143A6262E47C547D7E2" "289413F8C5C56AED3FA7E5DF5526958E2294FE318AF590C0E720029C202563E6E686" "9EC810F39A859262FB6047C1D418CAA9047A00BDB127B44B69CF6BC8E6B3709B4C23" "79783C5F8457EFE23EDA6FF00D1DDCC29268FC4A6C18577BE2B7004089CBB824027A" "A53C86B51DB054CC83B4F50C8923E2E9431F0A77D741237226CC68591083A2E40171" "5C7B74100BB74003E2264F8B44A0B0BC5404C44218ABE65C04AA573877506CE4F48C" "9E3F8AD1CD8DD9F285DD015C2FC5DEBCFA5779AD87F0BBC62E9EC6246021AB450DB9" "4DDDEFAFD2C7C66E235D#)" " ))"; static const char sample_private_elg_key_3072[] = "(private-key" " (elg" " (p #008EAA3497AFE3706E1A57FFA52E68C64C500731B58EBAFEB51C4A20AB15BA57FA72" "BA1510A4703D5AA6F05DB67E4A776F92AD08800577DC686D00B793167A5D79C997E0" "5B9A9E5974B4B68B4D71ED8EC37F2F45235D901997D72915643F058E712AA18275A2" "C6F9F7C2B9B7CD1E814D215F12A840800B546AEF2A2E6C077CDD1A322738FFD36DB2" "FA5420B5848EED870BC1A6CF55040AE8D2A5945F11AE2BCBE107B41A59EFDBD3B05C" "F4C876C02C9AEAE22CD4C86806A415302936E4C1E5AA59DBBCCD2F83C20941A29888" "A70ADB94D3B8A6489C46BF2C5219CD9FD2341EA21D4E68A4ECC468FD09D215FE96D4" "7AEA12FD22B2456D2CC13672FC7E9772A365C68668157C51E46966B6A1831C429BA0" "D513519713C49C13C5FC7C14BE0A117627B204C4478D0A93C6B57929E448C9B65BF2" "390E04BC5940320C0262FC1A221E7C796493432239A6F12BC62C5CF32E8ADBC1730C" "84C6E6E6BD95AF62835941F3F344AF46BFE5A8F629D5FA699FE37EF8B8C6A2484E42" "D226206FDF7D1FB93A5457#)" " (g #0B#)" " (y #18E734FF645AE169079AEAFC78772371089AD3088627ECF77034AFBDF33ADF594AAF" "3288F6979E0DB59CE3D2F0FEE031DFF187F1E4549D3C79668794CB19C14481ECDE2D" "D50861AB674F87A011D50D35F28E424D0D2353850899C2CDD0CC8FDBFC5A0CA395F0" "E605D46CBDD140DBEF426EBD638C9ADD83C195C45CE84ED2D2B21B87800C783A4F79" "12226FEFBDA01C66B254534A51765AF09687275AA80C5DFBA143A6262E47C547D7E2" "289413F8C5C56AED3FA7E5DF5526958E2294FE318AF590C0E720029C202563E6E686" "9EC810F39A859262FB6047C1D418CAA9047A00BDB127B44B69CF6BC8E6B3709B4C23" "79783C5F8457EFE23EDA6FF00D1DDCC29268FC4A6C18577BE2B7004089CBB824027A" "A53C86B51DB054CC83B4F50C8923E2E9431F0A77D741237226CC68591083A2E40171" "5C7B74100BB74003E2264F8B44A0B0BC5404C44218ABE65C04AA573877506CE4F48C" "9E3F8AD1CD8DD9F285DD015C2FC5DEBCFA5779AD87F0BBC62E9EC6246021AB450DB9" "4DDDEFAFD2C7C66E235D#)" " (x #03A73F0389E470AAC831B039F8AA0C4EBD3A47DD083E32EEA08E4911236CD597C272" "9823D47A51C8535DA52FE6DAB3E8D1C20D#)" " ))"; #endif /* USE_ELGAMAL */ #define BUG() do {fprintf ( stderr, "Ooops at %s:%d\n", __FILE__ , __LINE__ );\ exit(2);} while(0) static void show_sexp (const char *prefix, gcry_sexp_t a) { char *buf; size_t size; fputs (prefix, stderr); size = gcry_sexp_sprint (a, GCRYSEXP_FMT_ADVANCED, NULL, 0); buf = malloc (size); if (!buf) die ("out of core\n"); gcry_sexp_sprint (a, GCRYSEXP_FMT_ADVANCED, buf, size); fprintf (stderr, "%.*s", (int)size, buf); } static void progress_cb (void *cb_data, const char *what, int printchar, int current, int total) { (void)cb_data; if (single_char_progress) { fputc (printchar, stdout); fflush (stderr); } else { fprintf (stderr, PGM ": progress (%s %c %d %d)\n", what, printchar, current, total); fflush (stderr); } } static void random_bench (int very_strong) { char buf[128]; int i; printf ("%-10s", "random"); if (!very_strong) { start_timer (); for (i=0; i < 100; i++) gcry_randomize (buf, sizeof buf, GCRY_STRONG_RANDOM); stop_timer (); printf (" %s", elapsed_time (1)); } start_timer (); for (i=0; i < 100; i++) gcry_randomize (buf, 8, very_strong? GCRY_VERY_STRONG_RANDOM:GCRY_STRONG_RANDOM); stop_timer (); printf (" %s", elapsed_time (1)); putchar ('\n'); if (verbose) xgcry_control ((GCRYCTL_DUMP_RANDOM_STATS)); } static void md_bench ( const char *algoname ) { int algo; gcry_md_hd_t hd; int i, j, repcount; char buf_base[1000+15]; size_t bufsize = 1000; char *buf; char *largebuf_base; char *largebuf; char digest[512/8]; gcry_error_t err = GPG_ERR_NO_ERROR; if (!algoname) { for (i=1; i < 400; i++) if (in_fips_mode && i == GCRY_MD_MD5) ; /* Don't use MD5 in fips mode. */ else if ( !gcry_md_test_algo (i) ) md_bench (gcry_md_algo_name (i)); return; } buf = buf_base + ((16 - ((size_t)buf_base & 0x0f)) % buffer_alignment); algo = gcry_md_map_name (algoname); if (!algo) { fprintf (stderr, PGM ": invalid hash algorithm `%s'\n", algoname); exit (1); } err = gcry_md_open (&hd, algo, 0); if (err) { fprintf (stderr, PGM ": error opening hash algorithm `%s'\n", algoname); exit (1); } for (i=0; i < bufsize; i++) buf[i] = i; printf ("%-12s", gcry_md_algo_name (algo)); start_timer (); for (repcount=0; repcount < hash_repetitions; repcount++) for (i=0; i < 1000; i++) gcry_md_write (hd, buf, bufsize); gcry_md_final (hd); stop_timer (); printf (" %s", elapsed_time (1)); fflush (stdout); gcry_md_reset (hd); start_timer (); for (repcount=0; repcount < hash_repetitions; repcount++) for (i=0; i < 10000; i++) gcry_md_write (hd, buf, bufsize/10); gcry_md_final (hd); stop_timer (); printf (" %s", elapsed_time (1)); fflush (stdout); gcry_md_reset (hd); start_timer (); for (repcount=0; repcount < hash_repetitions; repcount++) for (i=0; i < 1000000; i++) gcry_md_write (hd, buf, 1); gcry_md_final (hd); stop_timer (); printf (" %s", elapsed_time (1)); fflush (stdout); start_timer (); for (repcount=0; repcount < hash_repetitions; repcount++) for (i=0; i < 1000; i++) for (j=0; j < bufsize; j++) gcry_md_putc (hd, buf[j]); gcry_md_final (hd); stop_timer (); printf (" %s", elapsed_time (1)); fflush (stdout); gcry_md_close (hd); /* Now 100 hash operations on 10000 bytes using the fast function. We initialize the buffer so that all memory pages are committed and we have repeatable values. */ if (gcry_md_get_algo_dlen (algo) > sizeof digest) die ("digest buffer too short\n"); if (gcry_md_get_algo_dlen (algo)) { largebuf_base = malloc (10000+15); if (!largebuf_base) die ("out of core\n"); largebuf = (largebuf_base + ((16 - ((size_t)largebuf_base & 0x0f)) % buffer_alignment)); for (i=0; i < 10000; i++) largebuf[i] = i; start_timer (); for (repcount=0; repcount < hash_repetitions; repcount++) for (i=0; i < 100; i++) gcry_md_hash_buffer (algo, digest, largebuf, 10000); stop_timer (); printf (" %s", elapsed_time (1)); free (largebuf_base); } putchar ('\n'); fflush (stdout); } static void mac_bench ( const char *algoname ) { int algo; gcry_mac_hd_t hd; int step, pos, j, i, repcount; char buf_base[1000+15]; size_t bufsize = 1000; char *buf; char mac[3][512]; char key[512]; unsigned int maclen, keylen; size_t macoutlen; gcry_error_t err = GPG_ERR_NO_ERROR; if (!algoname) { for (i=1; i < 600; i++) if (in_fips_mode && i == GCRY_MAC_HMAC_MD5) ; /* Don't use MD5 in fips mode. */ else if ( !gcry_mac_test_algo (i) ) mac_bench (gcry_mac_algo_name (i)); return; } buf = buf_base + ((16 - ((size_t)buf_base & 0x0f)) % buffer_alignment); algo = gcry_mac_map_name (algoname); if (!algo) { fprintf (stderr, PGM ": invalid MAC algorithm `%s'\n", algoname); exit (1); } maclen = gcry_mac_get_algo_maclen (algo); if (maclen > sizeof(mac)) maclen = sizeof(mac); keylen = gcry_mac_get_algo_keylen (algo); if (keylen == 0) keylen = 32; if (keylen > sizeof(key)) keylen = sizeof(key); for (i=0; i < keylen; i++) key[i] = (keylen - i) ^ 0x54; err = gcry_mac_open (&hd, algo, 0, NULL); if (err) { fprintf (stderr, PGM ": error opening mac algorithm `%s': %s\n", algoname, gpg_strerror (err)); exit (1); } err = gcry_mac_setkey (hd, key, keylen); if (err) { fprintf (stderr, PGM ": error setting key for mac algorithm `%s': %s\n", algoname, gpg_strerror (err)); exit (1); } for (i=0; i < bufsize; i++) buf[i] = i; if (algo >= GCRY_MAC_POLY1305_AES && algo <= GCRY_MAC_POLY1305_ARIA) { static const char iv[16] = { 1, 2, 3, 4, }; err = gcry_mac_setiv(hd, iv, sizeof(iv)); if (err) { fprintf (stderr, PGM ": error setting nonce for mac algorithm `%s': %s\n", algoname, gpg_strerror (err)); exit (1); } } printf ("%-20s", gcry_mac_algo_name (algo)); start_timer (); for (repcount=0; repcount < mac_repetitions; repcount++) for (i=0; i < 1000; i++) gcry_mac_write (hd, buf, bufsize); macoutlen = maclen; gcry_mac_read (hd, mac[0], &macoutlen); stop_timer (); printf (" %s", elapsed_time (1)); fflush (stdout); gcry_mac_reset (hd); start_timer (); for (repcount=0; repcount < mac_repetitions; repcount++) for (i=0; i < 1000; i++) for (step=bufsize/10, pos=0, j=0; j < 10; j++, pos+=step) gcry_mac_write (hd, &buf[pos], step); macoutlen = maclen; gcry_mac_read (hd, mac[1], &macoutlen); stop_timer (); printf (" %s", elapsed_time (1)); fflush (stdout); gcry_mac_reset (hd); start_timer (); for (repcount=0; repcount < mac_repetitions; repcount++) for (i=0; i < 1000; i++) for (step=bufsize/100, pos=0, j=0; j < 100; j++, pos+=step) gcry_mac_write (hd, &buf[pos], step); macoutlen = maclen; gcry_mac_read (hd, mac[2], &macoutlen); stop_timer (); printf (" %s", elapsed_time (1)); fflush (stdout); gcry_mac_close (hd); for (i=1; i < 3; i++) { if (memcmp(mac[i-1], mac[i], maclen)) { fprintf (stderr, PGM ": mac mismatch with algorithm `%s'\n", algoname); exit(1); } } putchar ('\n'); fflush (stdout); } static void ccm_aead_init(gcry_cipher_hd_t hd, size_t buflen, int authlen) { const char _L[4]; char nonce[15 - sizeof(_L)]; u64 params[3]; gcry_error_t err = GPG_ERR_NO_ERROR; (void)_L; memset (nonce, 0x33, sizeof(nonce)); err = gcry_cipher_setiv (hd, nonce, sizeof(nonce)); if (err) { fprintf (stderr, "gcry_cipher_setiv failed: %s\n", gpg_strerror (err)); gcry_cipher_close (hd); exit (1); } params[0] = buflen; /* encryptedlen */ params[1] = 0; /* aadlen */ params[2] = authlen; /* authtaglen */ err = gcry_cipher_ctl (hd, GCRYCTL_SET_CCM_LENGTHS, params, sizeof(params)); if (err) { fprintf (stderr, "gcry_cipher_setiv failed: %s\n", gpg_strerror (err)); gcry_cipher_close (hd); exit (1); } } static gcry_error_t cipher_encrypt (gcry_cipher_hd_t h, char *out, size_t outsize, const char *in, size_t inlen, size_t max_inlen) { gcry_error_t ret; while (inlen) { size_t currlen = inlen; if (currlen > max_inlen) currlen = max_inlen; ret = gcry_cipher_encrypt(h, out, outsize, in, currlen); if (ret) return ret; out += currlen; in += currlen; outsize -= currlen; inlen -= currlen; } return 0; } static gcry_error_t cipher_decrypt (gcry_cipher_hd_t h, char *out, size_t outsize, const char *in, size_t inlen, size_t max_inlen) { gcry_error_t ret; while (inlen) { size_t currlen = inlen; if (currlen > max_inlen) currlen = max_inlen; ret = gcry_cipher_decrypt(h, out, outsize, in, currlen); if (ret) return ret; out += currlen; in += currlen; outsize -= currlen; inlen -= currlen; } return 0; } static void cipher_bench ( const char *algoname ) { static int header_printed; int algo; gcry_cipher_hd_t hd; int i; int keylen, blklen; char key[128]; char *outbuf, *buf; char *raw_outbuf, *raw_buf; size_t allocated_buflen, buflen; int repetitions; static const struct { int mode; const char *name; int blocked; unsigned int max_inlen; void (* const aead_init)(gcry_cipher_hd_t hd, size_t buflen, int authlen); int req_blocksize; int authlen; int noncelen; int doublekey; } modes[] = { { GCRY_CIPHER_MODE_ECB, " ECB/Stream", 1, 0xffffffffU }, { GCRY_CIPHER_MODE_CBC, " CBC/Poly1305", 1, 0xffffffffU }, { GCRY_CIPHER_MODE_CFB, " CFB", 0, 0xffffffffU }, { GCRY_CIPHER_MODE_OFB, " OFB", 0, 0xffffffffU }, { GCRY_CIPHER_MODE_CTR, " CTR", 0, 0xffffffffU }, { GCRY_CIPHER_MODE_XTS, " XTS", 0, 16 << 20, NULL, GCRY_XTS_BLOCK_LEN, 0, 0, 1 }, { GCRY_CIPHER_MODE_CCM, " CCM", 0, 0xffffffffU, ccm_aead_init, GCRY_CCM_BLOCK_LEN, 8, }, { GCRY_CIPHER_MODE_GCM, " GCM", 0, 0xffffffffU, NULL, GCRY_GCM_BLOCK_LEN, GCRY_GCM_BLOCK_LEN }, { GCRY_CIPHER_MODE_OCB, " OCB", 1, 0xffffffffU, NULL, 16, 16, 15 }, { GCRY_CIPHER_MODE_EAX, " EAX", 0, 0xffffffffU, NULL, 0, 8, 8 }, { GCRY_CIPHER_MODE_STREAM, "", 0, 0xffffffffU }, { GCRY_CIPHER_MODE_POLY1305, "", 0, 0xffffffffU, NULL, 1, 16, 12 }, {0} }; int modeidx; gcry_error_t err = GPG_ERR_NO_ERROR; if (!algoname) { for (i=1; i < 400; i++) if ( !gcry_cipher_test_algo (i) ) cipher_bench (gcry_cipher_algo_name (i)); return; } if (huge_buffers) { allocated_buflen = 256 * 1024 * 1024; repetitions = 4; } else if (large_buffers) { allocated_buflen = 1024 * 100; repetitions = 10; } else { allocated_buflen = 1024; repetitions = 1000; } repetitions *= cipher_repetitions; raw_buf = gcry_xcalloc (allocated_buflen+15, 1); buf = (raw_buf + ((16 - ((size_t)raw_buf & 0x0f)) % buffer_alignment)); outbuf = raw_outbuf = gcry_xmalloc (allocated_buflen+15); outbuf = (raw_outbuf + ((16 - ((size_t)raw_outbuf & 0x0f)) % buffer_alignment)); if (!header_printed) { if (cipher_repetitions != 1) printf ("Running each test %d times.\n", cipher_repetitions); printf ("%-12s", ""); for (modeidx=0; modes[modeidx].mode; modeidx++) if (*modes[modeidx].name) printf (" %-15s", modes[modeidx].name ); putchar ('\n'); printf ("%-12s", ""); for (modeidx=0; modes[modeidx].mode; modeidx++) if (*modes[modeidx].name) printf (" ---------------" ); putchar ('\n'); header_printed = 1; } algo = gcry_cipher_map_name (algoname); if (!algo) { fprintf (stderr, PGM ": invalid cipher algorithm `%s'\n", algoname); exit (1); } keylen = gcry_cipher_get_algo_keylen (algo); if (!keylen) { fprintf (stderr, PGM ": failed to get key length for algorithm `%s'\n", algoname); exit (1); } if ( keylen * 2 > sizeof key ) { fprintf (stderr, PGM ": algo %d, keylength problem (%d)\n", algo, keylen ); exit (1); } for (i=0; i < keylen * 2; i++) key[i] = i + (clock () & 0xff); blklen = gcry_cipher_get_algo_blklen (algo); if (!blklen) { fprintf (stderr, PGM ": failed to get block length for algorithm `%s'\n", algoname); exit (1); } printf ("%-12s", gcry_cipher_algo_name (algo)); fflush (stdout); for (modeidx=0; modes[modeidx].mode; modeidx++) { size_t modekeylen = keylen * (!!modes[modeidx].doublekey + 1); int is_stream = modes[modeidx].mode == GCRY_CIPHER_MODE_STREAM || modes[modeidx].mode == GCRY_CIPHER_MODE_POLY1305; if ((blklen > 1 && is_stream) || (blklen == 1 && !is_stream)) continue; if (modes[modeidx].mode == GCRY_CIPHER_MODE_POLY1305 && algo != GCRY_CIPHER_CHACHA20) continue; /* GCM is not available in FIPS mode */ if (in_fips_mode && modes[modeidx].mode == GCRY_CIPHER_MODE_GCM) continue; if (modes[modeidx].req_blocksize > 0 && blklen != modes[modeidx].req_blocksize) { printf (" %7s %7s", "-", "-" ); continue; } for (i=0; i < sizeof buf; i++) buf[i] = i; err = gcry_cipher_open (&hd, algo, modes[modeidx].mode, 0); if (err) { fprintf (stderr, PGM ": error opening cipher `%s'\n", algoname); exit (1); } if (!cipher_with_keysetup) { err = gcry_cipher_setkey (hd, key, modekeylen); if (err) { fprintf (stderr, "gcry_cipher_setkey failed: %s\n", gpg_strerror (err)); gcry_cipher_close (hd); exit (1); } } buflen = allocated_buflen; if (modes[modeidx].blocked) buflen = (buflen / blklen) * blklen; start_timer (); for (i=err=0; !err && i < repetitions; i++) { if (cipher_with_keysetup) { err = gcry_cipher_setkey (hd, key, modekeylen); if (err) { fprintf (stderr, "gcry_cipher_setkey failed: %s\n", gpg_strerror (err)); gcry_cipher_close (hd); exit (1); } } if (modes[modeidx].noncelen) { char nonce[100]; size_t noncelen; noncelen = modes[modeidx].noncelen; if (noncelen > sizeof nonce) noncelen = sizeof nonce; memset (nonce, 42, noncelen); err = gcry_cipher_setiv (hd, nonce, noncelen); if (err) { fprintf (stderr, "gcry_cipher_setiv failed: %s\n", gpg_strerror (err)); gcry_cipher_close (hd); exit (1); } } if (modes[modeidx].aead_init) { (*modes[modeidx].aead_init) (hd, buflen, modes[modeidx].authlen); gcry_cipher_final (hd); err = cipher_encrypt (hd, outbuf, buflen, buf, buflen, modes[modeidx].max_inlen); if (err) break; err = gcry_cipher_gettag (hd, outbuf, modes[modeidx].authlen); } else { err = cipher_encrypt (hd, outbuf, buflen, buf, buflen, modes[modeidx].max_inlen); } } stop_timer (); printf (" %s", elapsed_time (1)); fflush (stdout); gcry_cipher_close (hd); if (err) { fprintf (stderr, "gcry_cipher_encrypt failed: %s\n", gpg_strerror (err) ); exit (1); } err = gcry_cipher_open (&hd, algo, modes[modeidx].mode, 0); if (err) { fprintf (stderr, PGM ": error opening cipher `%s'/n", algoname); exit (1); } if (!cipher_with_keysetup) { err = gcry_cipher_setkey (hd, key, modekeylen); if (err) { fprintf (stderr, "gcry_cipher_setkey failed: %s\n", gpg_strerror (err)); gcry_cipher_close (hd); exit (1); } } start_timer (); for (i=err=0; !err && i < repetitions; i++) { if (cipher_with_keysetup) { err = gcry_cipher_setkey (hd, key, modekeylen); if (err) { fprintf (stderr, "gcry_cipher_setkey failed: %s\n", gpg_strerror (err)); gcry_cipher_close (hd); exit (1); } } if (modes[modeidx].noncelen) { char nonce[100]; size_t noncelen; noncelen = modes[modeidx].noncelen; if (noncelen > sizeof nonce) noncelen = sizeof nonce; memset (nonce, 42, noncelen); err = gcry_cipher_setiv (hd, nonce, noncelen); if (err) { fprintf (stderr, "gcry_cipher_setiv failed: %s\n", gpg_strerror (err)); gcry_cipher_close (hd); exit (1); } } if (modes[modeidx].aead_init) { (*modes[modeidx].aead_init) (hd, buflen, modes[modeidx].authlen); gcry_cipher_final (hd); err = cipher_decrypt (hd, outbuf, buflen, buf, buflen, modes[modeidx].max_inlen); if (err) break; err = gcry_cipher_checktag (hd, outbuf, modes[modeidx].authlen); if (gpg_err_code (err) == GPG_ERR_CHECKSUM) err = 0; } else { gcry_cipher_final (hd); err = cipher_decrypt (hd, outbuf, buflen, buf, buflen, modes[modeidx].max_inlen); } } stop_timer (); printf (" %s", elapsed_time (1)); fflush (stdout); gcry_cipher_close (hd); if (err) { fprintf (stderr, "gcry_cipher_decrypt failed: %s\n", gpg_strerror (err) ); exit (1); } } putchar ('\n'); gcry_free (raw_buf); gcry_free (raw_outbuf); } static void rsa_bench (int iterations, int print_header, int no_blinding) { #if USE_RSA gpg_error_t err; int p_sizes[] = { 1024, 2048, 3072, 4096 }; int testno; if (print_header) printf ("Algorithm generate %4d*priv %4d*public\n" "------------------------------------------------\n", iterations, iterations ); for (testno=0; testno < DIM (p_sizes); testno++) { gcry_sexp_t key_spec, key_pair, pub_key, sec_key; gcry_mpi_t x; gcry_sexp_t data; gcry_sexp_t sig = NULL; int count; unsigned nbits = p_sizes[testno]; printf ("RSA %3d bit ", nbits); fflush (stdout); if (in_fips_mode && nbits < 2048) { puts ("[skipped in fips mode]"); continue; } err = gcry_sexp_build (&key_spec, NULL, gcry_fips_mode_active () ? "(genkey (RSA (nbits %d)))" : "(genkey (RSA (nbits %d)(transient-key)))", nbits); if (err) die ("creating S-expression failed: %s\n", gcry_strerror (err)); start_timer (); err = gcry_pk_genkey (&key_pair, key_spec); if (err) die ("creating %d bit RSA key failed: %s\n", nbits, gcry_strerror (err)); pub_key = gcry_sexp_find_token (key_pair, "public-key", 0); if (! pub_key) die ("public part missing in key\n"); sec_key = gcry_sexp_find_token (key_pair, "private-key", 0); if (! sec_key) die ("private part missing in key\n"); gcry_sexp_release (key_pair); gcry_sexp_release (key_spec); stop_timer (); printf (" %s", elapsed_time (1)); fflush (stdout); x = gcry_mpi_new (nbits); gcry_mpi_randomize (x, nbits-8, GCRY_WEAK_RANDOM); err = gcry_sexp_build (&data, NULL, "(data (flags raw) (value %m))", x); gcry_mpi_release (x); if (err) die ("converting data failed: %s\n", gcry_strerror (err)); start_timer (); for (count=0; count < iterations; count++) { gcry_sexp_release (sig); err = gcry_pk_sign (&sig, data, sec_key); if (err) die ("signing failed (%d): %s\n", count, gpg_strerror (err)); } stop_timer (); printf (" %s", elapsed_time (1)); fflush (stdout); start_timer (); for (count=0; count < iterations; count++) { err = gcry_pk_verify (sig, data, pub_key); if (err) { putchar ('\n'); show_sexp ("seckey:\n", sec_key); show_sexp ("data:\n", data); show_sexp ("sig:\n", sig); die ("verify failed (%d): %s\n", count, gpg_strerror (err)); } } stop_timer (); printf (" %s", elapsed_time (1)); if (no_blinding) { fflush (stdout); x = gcry_mpi_new (nbits); gcry_mpi_randomize (x, nbits-8, GCRY_WEAK_RANDOM); err = gcry_sexp_build (&data, NULL, "(data (flags no-blinding) (value %m))", x); gcry_mpi_release (x); if (err) die ("converting data failed: %s\n", gcry_strerror (err)); start_timer (); for (count=0; count < iterations; count++) { gcry_sexp_release (sig); err = gcry_pk_sign (&sig, data, sec_key); if (err) die ("signing failed (%d): %s\n", count, gpg_strerror (err)); } stop_timer (); printf (" %s", elapsed_time (1)); fflush (stdout); } putchar ('\n'); fflush (stdout); gcry_sexp_release (sig); gcry_sexp_release (data); gcry_sexp_release (sec_key); gcry_sexp_release (pub_key); } #else /* USE_RSA */ (void) iterations; (void) print_header; (void) no_blinding; #endif /* USE_RSA */ } static void elg_bench (int iterations, int print_header) { #ifdef USE_ELGAMAL gpg_error_t err; gcry_sexp_t pub_key[3], sec_key[3]; int p_sizes[3] = { 1024, 2048, 3072 }; gcry_sexp_t data = NULL; gcry_sexp_t enc = NULL; gcry_sexp_t plain = NULL; int i, j; err = gcry_sexp_sscan (pub_key+0, NULL, sample_public_elg_key_1024, strlen (sample_public_elg_key_1024)); if (!err) err = gcry_sexp_sscan (sec_key+0, NULL, sample_private_elg_key_1024, strlen (sample_private_elg_key_1024)); if (!err) err = gcry_sexp_sscan (pub_key+1, NULL, sample_public_elg_key_2048, strlen (sample_public_elg_key_2048)); if (!err) err = gcry_sexp_sscan (sec_key+1, NULL, sample_private_elg_key_2048, strlen (sample_private_elg_key_2048)); if (!err) err = gcry_sexp_sscan (pub_key+2, NULL, sample_public_elg_key_3072, strlen (sample_public_elg_key_3072)); if (!err) err = gcry_sexp_sscan (sec_key+2, NULL, sample_private_elg_key_3072, strlen (sample_private_elg_key_3072)); if (err) { fprintf (stderr, PGM ": converting sample keys failed: %s\n", gcry_strerror (err)); exit (1); } if (print_header) printf ("Algorithm generate %4d*priv %4d*public\n" "------------------------------------------------\n", iterations, iterations ); for (i=0; i < DIM (p_sizes); i++) { char timerbuf1[100]; { gcry_mpi_t x = gcry_mpi_new (p_sizes[i]); gcry_mpi_randomize (x, p_sizes[i] - 16, GCRY_WEAK_RANDOM); err = gcry_sexp_build (&data, NULL, "(data (flags raw) (value %m))", x); gcry_mpi_release (x); } if (err) { fprintf (stderr, PGM ": converting data failed: %s\n", gcry_strerror (err)); exit (1); } printf ("ELG %d bit -", p_sizes[i]); fflush (stdout); if (in_fips_mode) { puts ("[skipped in fips mode]"); goto next; } start_timer (); for (j=0; j < iterations; j++) { gcry_sexp_release (enc); err = gcry_pk_encrypt (&enc, data, pub_key[i]); if (err) { putchar ('\n'); fprintf (stderr, PGM ": encrypt failed: %s\n", gpg_strerror (err)); exit (1); } } stop_timer (); snprintf (timerbuf1, sizeof timerbuf1, " %s", elapsed_time (1)); fflush (stdout); start_timer (); for (j=0; j < iterations; j++) { gcry_sexp_release (plain); err = gcry_pk_decrypt (&plain, enc, sec_key[i]); if (err) { putchar ('\n'); fprintf (stderr, PGM ": decrypt failed: %s\n", gpg_strerror (err)); exit (1); } } stop_timer (); printf (" %s %s\n", elapsed_time (1), timerbuf1); fflush (stdout); next: gcry_sexp_release (plain); plain = NULL; gcry_sexp_release (enc); enc = NULL; gcry_sexp_release (data); data = NULL; } for (i=0; i < DIM (p_sizes); i++) { gcry_sexp_release (sec_key[i]); gcry_sexp_release (pub_key[i]); } #else /* USE_ELGAMAL */ (void) iterations; (void) print_header; #endif /* USE_ELGAMAL */ } static void dsa_bench (int iterations, int print_header) { #ifdef USE_DSA gpg_error_t err; gcry_sexp_t pub_key[3], sec_key[3]; int p_sizes[3] = { 1024, 2048, 3072 }; int q_sizes[3] = { 160, 224, 256 }; gcry_sexp_t data; gcry_sexp_t sig = NULL; int i, j; err = gcry_sexp_sscan (pub_key+0, NULL, sample_public_dsa_key_1024, strlen (sample_public_dsa_key_1024)); if (!err) err = gcry_sexp_sscan (sec_key+0, NULL, sample_private_dsa_key_1024, strlen (sample_private_dsa_key_1024)); if (!err) err = gcry_sexp_sscan (pub_key+1, NULL, sample_public_dsa_key_2048, strlen (sample_public_dsa_key_2048)); if (!err) err = gcry_sexp_sscan (sec_key+1, NULL, sample_private_dsa_key_2048, strlen (sample_private_dsa_key_2048)); if (!err) err = gcry_sexp_sscan (pub_key+2, NULL, sample_public_dsa_key_3072, strlen (sample_public_dsa_key_3072)); if (!err) err = gcry_sexp_sscan (sec_key+2, NULL, sample_private_dsa_key_3072, strlen (sample_private_dsa_key_3072)); if (err) { fprintf (stderr, PGM ": converting sample keys failed: %s\n", gcry_strerror (err)); exit (1); } if (print_header) printf ("Algorithm generate %4d*priv %4d*public\n" "------------------------------------------------\n", iterations, iterations ); for (i=0; i < DIM (q_sizes); i++) { gcry_mpi_t x; x = gcry_mpi_new (q_sizes[i]); gcry_mpi_randomize (x, q_sizes[i], GCRY_WEAK_RANDOM); err = gcry_sexp_build (&data, NULL, "(data (flags raw) (value %m))", x); gcry_mpi_release (x); if (err) { fprintf (stderr, PGM ": converting data failed: %s\n", gcry_strerror (err)); exit (1); } printf ("DSA %d/%d -", p_sizes[i], q_sizes[i]); fflush (stdout); if (in_fips_mode) { puts ("[skipped in fips mode]"); goto next; } start_timer (); for (j=0; j < iterations; j++) { gcry_sexp_release (sig); err = gcry_pk_sign (&sig, data, sec_key[i]); if (err) { putchar ('\n'); fprintf (stderr, PGM ": signing failed: %s\n", gpg_strerror (err)); exit (1); } } stop_timer (); printf (" %s", elapsed_time (1)); fflush (stdout); start_timer (); for (j=0; j < iterations; j++) { err = gcry_pk_verify (sig, data, pub_key[i]); if (err) { putchar ('\n'); fprintf (stderr, PGM ": verify failed: %s\n", gpg_strerror (err)); exit (1); } } stop_timer (); printf (" %s\n", elapsed_time (1)); fflush (stdout); next: gcry_sexp_release (sig); gcry_sexp_release (data); sig = NULL; } for (i=0; i < DIM (q_sizes); i++) { gcry_sexp_release (sec_key[i]); gcry_sexp_release (pub_key[i]); } #else (void) iterations; (void) print_header; #endif /* USE_DSA */ } static void ecc_bench (int iterations, int print_header) { #if USE_ECC gpg_error_t err; const char *p_sizes[] = { "192", "224", "256", "384", "521", "Ed25519", "Ed448", "gost256", "gost512" }; int testno; if (print_header) printf ("Algorithm generate %4d*priv %4d*public\n" "------------------------------------------------\n", iterations, iterations ); for (testno=0; testno < DIM (p_sizes); testno++) { gcry_sexp_t key_spec, key_pair, pub_key, sec_key; gcry_mpi_t x; gcry_sexp_t data; gcry_sexp_t sig = NULL; int count; int p_size; int is_ed25519; int is_ed448; int is_gost; is_ed25519 = !strcmp (p_sizes[testno], "Ed25519"); is_ed448 = !strcmp (p_sizes[testno], "Ed448"); is_gost = !strncmp (p_sizes[testno], "gost", 4); - /* Only P-{224,256,384,521} are allowed in fips mode */ + /* Only P-{224,256,384,521} and EdDSA curves are allowed in fips mode */ if (gcry_fips_mode_active() - && (is_ed25519 || is_ed448 || is_gost - || !strcmp (p_sizes[testno], "192"))) + && (is_gost || !strcmp (p_sizes[testno], "192"))) continue; if (is_ed25519) { p_size = 256; printf ("EdDSA Ed25519 "); fflush (stdout); } else if (is_ed448) { p_size = 448; printf ("EdDSA Ed448 "); fflush (stdout); } else if (is_gost) { p_size = atoi (p_sizes[testno] + 4); printf ("GOST %3d bit ", p_size); fflush (stdout); } else { p_size = atoi (p_sizes[testno]); printf ("ECDSA %3d bit ", p_size); } fflush (stdout); if (is_ed25519) err = gcry_sexp_build (&key_spec, NULL, "(genkey (ecdsa (curve \"Ed25519\")" "(flags eddsa)))"); else if (is_ed448) err = gcry_sexp_build (&key_spec, NULL, "(genkey (ecdsa (curve \"Ed448\")" "(flags eddsa)))"); else if (is_gost) err = gcry_sexp_build (&key_spec, NULL, "(genkey (ecdsa (curve %s)))", p_size == 256 ? "GOST2001-test" : "GOST2012-512-test"); else err = gcry_sexp_build (&key_spec, NULL, "(genkey (ECDSA (nbits %d)))", p_size); if (err) die ("creating S-expression failed: %s\n", gcry_strerror (err)); start_timer (); err = gcry_pk_genkey (&key_pair, key_spec); if (err) die ("creating %d bit ECC key failed: %s\n", p_size, gcry_strerror (err)); if (verbose > 2) show_sexp ("ECC key:\n", key_pair); pub_key = gcry_sexp_find_token (key_pair, "public-key", 0); if (! pub_key) die ("public part missing in key\n"); sec_key = gcry_sexp_find_token (key_pair, "private-key", 0); if (! sec_key) die ("private part missing in key\n"); gcry_sexp_release (key_pair); gcry_sexp_release (key_spec); stop_timer (); printf (" %s", elapsed_time (1)); fflush (stdout); x = gcry_mpi_new (p_size); gcry_mpi_randomize (x, p_size, GCRY_WEAK_RANDOM); if (is_ed25519) err = gcry_sexp_build (&data, NULL, "(data (flags eddsa)(hash-algo sha512)" " (value %m))", x); else if (is_ed448) err = gcry_sexp_build (&data, NULL, "(data (flags eddsa)(hash-algo shake256)" " (value %m))", x); else if (is_gost) err = gcry_sexp_build (&data, NULL, "(data (flags gost) (value %m))", x); else err = gcry_sexp_build (&data, NULL, "(data (flags raw) (value %m))", x); gcry_mpi_release (x); if (err) die ("converting data failed: %s\n", gcry_strerror (err)); start_timer (); for (count=0; count < iterations; count++) { gcry_sexp_release (sig); err = gcry_pk_sign (&sig, data, sec_key); if (err) { if (verbose) { putc ('\n', stderr); show_sexp ("signing key:\n", sec_key); show_sexp ("signed data:\n", data); } die ("signing failed: %s\n", gpg_strerror (err)); } } stop_timer (); printf (" %s", elapsed_time (1)); fflush (stdout); start_timer (); for (count=0; count < iterations; count++) { err = gcry_pk_verify (sig, data, pub_key); if (err) { putchar ('\n'); show_sexp ("seckey:\n", sec_key); show_sexp ("data:\n", data); show_sexp ("sig:\n", sig); die ("verify failed: %s\n", gpg_strerror (err)); } } stop_timer (); printf (" %s\n", elapsed_time (1)); fflush (stdout); gcry_sexp_release (sig); gcry_sexp_release (data); gcry_sexp_release (sec_key); gcry_sexp_release (pub_key); } #else (void) iterations; (void) print_header; #endif /*USE_ECC*/ } static void do_powm ( const char *n_str, const char *e_str, const char *m_str) { gcry_mpi_t e, n, msg, cip; gcry_error_t err; int i; err = gcry_mpi_scan (&n, GCRYMPI_FMT_HEX, n_str, 0, 0); if (err) BUG (); err = gcry_mpi_scan (&e, GCRYMPI_FMT_HEX, e_str, 0, 0); if (err) BUG (); err = gcry_mpi_scan (&msg, GCRYMPI_FMT_HEX, m_str, 0, 0); if (err) BUG (); cip = gcry_mpi_new (0); start_timer (); for (i=0; i < 1000; i++) gcry_mpi_powm (cip, msg, e, n); stop_timer (); printf (" %s", elapsed_time (1)); fflush (stdout); /* { */ /* char *buf; */ /* if (gcry_mpi_aprint (GCRYMPI_FMT_HEX, (void**)&buf, NULL, cip)) */ /* BUG (); */ /* printf ("result: %s\n", buf); */ /* gcry_free (buf); */ /* } */ gcry_mpi_release (cip); gcry_mpi_release (msg); gcry_mpi_release (n); gcry_mpi_release (e); } static void mpi_bench (void) { printf ("%-10s", "powm"); fflush (stdout); do_powm ( "20A94417D4D5EF2B2DA99165C7DC87DADB3979B72961AF90D09D59BA24CB9A10166FDCCC9C659F2B9626EC23F3FA425F564A072BA941B03FA81767CC289E4", "29", "B870187A323F1ECD5B8A0B4249507335A1C4CE8394F38FD76B08C78A42C58F6EA136ACF90DFE8603697B1694A3D81114D6117AC1811979C51C4DD013D52F8" ); do_powm ( "20A94417D4D5EF2B2DA99165C7DC87DADB3979B72961AF90D09D59BA24CB9A10166FDCCC9C659F2B9626EC23F3FA425F564A072BA941B03FA81767CC289E41071F0246879A442658FBD18C1771571E7073EEEB2160BA0CBFB3404D627069A6CFBD53867AD2D9D40231648000787B5C84176B4336144644AE71A403CA40716", "29", "B870187A323F1ECD5B8A0B4249507335A1C4CE8394F38FD76B08C78A42C58F6EA136ACF90DFE8603697B1694A3D81114D6117AC1811979C51C4DD013D52F8FC4EE4BB446B83E48ABED7DB81CBF5E81DE4759E8D68AC985846D999F96B0D8A80E5C69D272C766AB8A23B40D50A4FA889FBC2BD2624222D8EB297F4BAEF8593847" ); do_powm ( "20A94417D4D5EF2B2DA99165C7DC87DADB3979B72961AF90D09D59BA24CB9A10166FDCCC9C659F2B9626EC23F3FA425F564A072BA941B03FA81767CC289E41071F0246879A442658FBD18C1771571E7073EEEB2160BA0CBFB3404D627069A6CFBD53867AD2D9D40231648000787B5C84176B4336144644AE71A403CA4071620A94417D4D5EF2B2DA99165C7DC87DADB3979B72961AF90D09D59BA24CB9A10166FDCCC9C659F2B9626EC23F3FA425F564A072BA941B03FA81767CC289E41071F0246879A442658FBD18C1771571E7073EEEB2160BA0CBFB3404D627069A6CFBD53867AD2D9D40231648000787B5C84176B4336144644AE71A403CA40716", "29", "B870187A323F1ECD5B8A0B4249507335A1C4CE8394F38FD76B08C78A42C58F6EA136ACF90DFE8603697B1694A3D81114D6117AC1811979C51C4DD013D52F8FC4EE4BB446B83E48ABED7DB81CBF5E81DE4759E8D68AC985846D999F96B0D8A80E5C69D272C766AB8A23B40D50A4FA889FBC2BD2624222D8EB297F4BAEF8593847B870187A323F1ECD5B8A0B4249507335A1C4CE8394F38FD76B08C78A42C58F6EA136ACF90DFE8603697B1694A3D81114D6117AC1811979C51C4DD013D52F8FC4EE4BB446B83E48ABED7DB81CBF5E81DE4759E8D68AC985846D999F96B0D8A80E5C69D272C766AB8A23B40D50A4FA889FBC2BD2624222D8EB297F4BAEF8593847" ); putchar ('\n'); } static void prime_bench (void) { gpg_error_t err; int i; gcry_mpi_t prime; int old_prog = single_char_progress; single_char_progress = 1; if (!with_progress) printf ("%-10s", "prime"); fflush (stdout); start_timer (); for (i=0; i < 10; i++) { if (with_progress) fputs ("primegen ", stdout); err = gcry_prime_generate (&prime, 1024, 0, NULL, NULL, NULL, GCRY_WEAK_RANDOM, GCRY_PRIME_FLAG_SECRET); if (with_progress) { fputc ('\n', stdout); fflush (stdout); } if (err) { fprintf (stderr, PGM ": error creating prime: %s\n", gpg_strerror (err)); exit (1); } gcry_mpi_release (prime); } stop_timer (); if (with_progress) printf ("%-10s", "prime"); printf (" %s\n", elapsed_time (1)); fflush (stdout); single_char_progress = old_prog; } int main( int argc, char **argv ) { int last_argc = -1; int no_blinding = 0; int use_secmem = 0; int pk_count = 100; buffer_alignment = 1; if (argc) { argc--; argv++; } /* We skip this test if we are running under the test suite (no args and srcdir defined) and GCRYPT_NO_BENCHMARKS is set. */ if (!argc && getenv ("srcdir") && getenv ("GCRYPT_NO_BENCHMARKS")) exit (77); if (getenv ("GCRYPT_IN_REGRESSION_TEST")) { in_regression_test = 1; pk_count = 10; } while (argc && last_argc != argc ) { last_argc = argc; if (!strcmp (*argv, "--")) { argc--; argv++; break; } else if (!strcmp (*argv, "--help")) { fputs ("usage: benchmark " "[md|mac|cipher|random|mpi|rsa|dsa|ecc|prime [algonames]]\n", stdout); exit (0); } else if (!strcmp (*argv, "--verbose")) { verbose++; argc--; argv++; } else if (!strcmp (*argv, "--debug")) { verbose += 2; debug++; argc--; argv++; } else if (!strcmp (*argv, "--use-secmem")) { use_secmem = 1; argc--; argv++; } else if (!strcmp (*argv, "--prefer-standard-rng")) { /* This is anyway the default, but we may want to use it for debugging. */ xgcry_control ((GCRYCTL_SET_PREFERRED_RNG_TYPE, GCRY_RNG_TYPE_STANDARD)); argc--; argv++; } else if (!strcmp (*argv, "--prefer-fips-rng")) { xgcry_control ((GCRYCTL_SET_PREFERRED_RNG_TYPE, GCRY_RNG_TYPE_FIPS)); argc--; argv++; } else if (!strcmp (*argv, "--prefer-system-rng")) { xgcry_control ((GCRYCTL_SET_PREFERRED_RNG_TYPE, GCRY_RNG_TYPE_SYSTEM)); argc--; argv++; } else if (!strcmp (*argv, "--no-blinding")) { no_blinding = 1; argc--; argv++; } else if (!strcmp (*argv, "--large-buffers")) { large_buffers = 1; argc--; argv++; } else if (!strcmp (*argv, "--huge-buffers")) { huge_buffers = 1; argc--; argv++; } else if (!strcmp (*argv, "--cipher-repetitions")) { argc--; argv++; if (argc) { cipher_repetitions = atoi(*argv); argc--; argv++; } } else if (!strcmp (*argv, "--cipher-with-keysetup")) { cipher_with_keysetup = 1; argc--; argv++; } else if (!strcmp (*argv, "--hash-repetitions")) { argc--; argv++; if (argc) { hash_repetitions = atoi(*argv); argc--; argv++; } } else if (!strcmp (*argv, "--mac-repetitions")) { argc--; argv++; if (argc) { mac_repetitions = atoi(*argv); argc--; argv++; } } else if (!strcmp (*argv, "--pk-count")) { argc--; argv++; if (argc) { pk_count = atoi(*argv); argc--; argv++; } } else if (!strcmp (*argv, "--alignment")) { argc--; argv++; if (argc) { buffer_alignment = atoi(*argv); argc--; argv++; } } else if (!strcmp (*argv, "--disable-hwf")) { argc--; argv++; if (argc) { if (gcry_control (GCRYCTL_DISABLE_HWF, *argv, NULL)) fprintf (stderr, PGM ": unknown hardware feature `%s'" " - option ignored\n", *argv); argc--; argv++; } } else if (!strcmp (*argv, "--fips")) { argc--; argv++; /* This command needs to be called before gcry_check_version. */ xgcry_control ((GCRYCTL_FORCE_FIPS_MODE, 0)); } else if (!strcmp (*argv, "--progress")) { argc--; argv++; with_progress = 1; } } if (buffer_alignment < 1 || buffer_alignment > 16) die ("value for --alignment must be in the range 1 to 16\n"); xgcry_control ((GCRYCTL_SET_VERBOSITY, (int)verbose)); if (!gcry_check_version (GCRYPT_VERSION)) { fprintf (stderr, PGM ": version mismatch; pgm=%s, library=%s\n", GCRYPT_VERSION, gcry_check_version (NULL)); exit (1); } if (debug) xgcry_control ((GCRYCTL_SET_DEBUG_FLAGS, 1u , 0)); if (gcry_fips_mode_active ()) in_fips_mode = 1; else if (!use_secmem) xgcry_control ((GCRYCTL_DISABLE_SECMEM, 0)); if (with_progress) gcry_set_progress_handler (progress_cb, NULL); xgcry_control ((GCRYCTL_INITIALIZATION_FINISHED, 0)); if (cipher_repetitions < 1) cipher_repetitions = 1; if (hash_repetitions < 1) hash_repetitions = 1; if (mac_repetitions < 1) mac_repetitions = 1; if (in_regression_test) fputs ("Note: " PGM " running in quick regression test mode.\n", stdout); if ( !argc ) { xgcry_control ((GCRYCTL_ENABLE_QUICK_RANDOM, 0)); md_bench (NULL); putchar ('\n'); mac_bench (NULL); putchar ('\n'); cipher_bench (NULL); putchar ('\n'); rsa_bench (pk_count, 1, no_blinding); elg_bench (pk_count, 0); dsa_bench (pk_count, 0); ecc_bench (pk_count, 0); putchar ('\n'); mpi_bench (); putchar ('\n'); random_bench (0); } else if ( !strcmp (*argv, "random") || !strcmp (*argv, "strongrandom")) { if (argc == 1) random_bench ((**argv == 's')); else if (argc == 2) { xgcry_control ((GCRYCTL_SET_RANDOM_SEED_FILE, argv[1])); random_bench ((**argv == 's')); xgcry_control ((GCRYCTL_UPDATE_RANDOM_SEED_FILE)); } else fputs ("usage: benchmark [strong]random [seedfile]\n", stdout); } else if ( !strcmp (*argv, "md")) { if (argc == 1) md_bench (NULL); else for (argc--, argv++; argc; argc--, argv++) md_bench ( *argv ); } else if ( !strcmp (*argv, "mac")) { if (argc == 1) mac_bench (NULL); else for (argc--, argv++; argc; argc--, argv++) mac_bench ( *argv ); } else if ( !strcmp (*argv, "cipher")) { if (argc == 1) cipher_bench (NULL); else for (argc--, argv++; argc; argc--, argv++) cipher_bench ( *argv ); } else if ( !strcmp (*argv, "mpi")) { mpi_bench (); } else if ( !strcmp (*argv, "pubkey")) { xgcry_control ((GCRYCTL_ENABLE_QUICK_RANDOM, 0)); rsa_bench (pk_count, 1, no_blinding); elg_bench (pk_count, 0); dsa_bench (pk_count, 0); ecc_bench (pk_count, 0); } else if ( !strcmp (*argv, "rsa")) { xgcry_control ((GCRYCTL_ENABLE_QUICK_RANDOM, 0)); rsa_bench (pk_count, 1, no_blinding); } else if ( !strcmp (*argv, "elg")) { xgcry_control ((GCRYCTL_ENABLE_QUICK_RANDOM, 0)); elg_bench (pk_count, 1); } else if ( !strcmp (*argv, "dsa")) { xgcry_control ((GCRYCTL_ENABLE_QUICK_RANDOM, 0)); dsa_bench (pk_count, 1); } else if ( !strcmp (*argv, "ecc")) { xgcry_control ((GCRYCTL_ENABLE_QUICK_RANDOM, 0)); ecc_bench (pk_count, 1); } else if ( !strcmp (*argv, "prime")) { xgcry_control ((GCRYCTL_ENABLE_QUICK_RANDOM, 0)); prime_bench (); } else { fprintf (stderr, PGM ": bad arguments\n"); return 1; } if (in_fips_mode && !gcry_fips_mode_active ()) fprintf (stderr, PGM ": FIPS mode is not anymore active\n"); return 0; } diff --git a/tests/curves.c b/tests/curves.c index 27d43a74..3cd74422 100644 --- a/tests/curves.c +++ b/tests/curves.c @@ -1,353 +1,353 @@ /* curves.c - ECC curves regression tests * Copyright (C) 2011 Free Software Foundation, Inc. * * This file is part of Libgcrypt. * * Libgcrypt is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * Libgcrypt is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this program; if not, see . * SPDX-License-Identifier: LGPL-2.1-or-later */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include "../src/gcrypt-int.h" #define PGM "curves" #include "t-common.h" /* Number of curves defined in ../cipher/ecc-curves.c */ #define N_CURVES 27 /* A real world sample public key. */ static char const sample_key_1[] = "(public-key\n" " (ecdsa\n" " (p #00FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF#)\n" " (a #00FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC#)\n" " (b #5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B#)\n" " (g #046B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296" "4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5#)\n" " (n #00FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551#)\n" " (h #000000000000000000000000000000000000000000000000000000000000000001#)\n" " (q #0442B927242237639A36CE9221B340DB1A9AB76DF2FE3E171277F6A4023DED146EE" "86525E38CCECFF3FB8D152CC6334F70D23A525175C1BCBDDE6E023B2228770E#)\n" " ))"; static char const sample_key_1_curve[] = "NIST P-256"; static unsigned int sample_key_1_nbits = 256; /* A made up sample public key. */ static char const sample_key_2[] = "(public-key\n" " (ecdh\n" " (p #00e95e4a5f737059dc60dfc7ad95b3d8139515620f#)\n" " (a #340e7be2a280eb74e2be61bada745d97e8f7c300#)\n" " (b #1e589a8595423412134faa2dbdec95c8d8675e58#)\n" " (g #04bed5af16ea3f6a4f62938c4631eb5af7bdbcdbc3" "1667cb477a1a8ec338f94741669c976316da6321#)\n" " (n #00e95e4a5f737059dc60df5991d45029409e60fc09#)\n" " (h #000000000000000000000000000000000000000000000000000000000000000001#)\n" " (q #041111111111111111111111111111111111111111" "2222222222222222222222222222222222222222#)\n" " ))"; static char const sample_key_2_curve[] = "brainpoolP160r1"; static unsigned int sample_key_2_nbits = 160; static int in_fips_mode; static void list_curves (void) { int idx; const char *name; unsigned int nbits; for (idx=0; (name = gcry_pk_get_curve (NULL, idx, &nbits)); idx++) { if (verbose) printf ("%s - %u bits\n", name, nbits); } if (idx != N_CURVES) fail ("expected %d curves but got %d\n", N_CURVES, idx); if (gcry_pk_get_curve (NULL, -1, NULL)) fail ("curve iteration failed\n"); } static void check_matching (void) { gpg_error_t err; gcry_sexp_t key; const char *name; unsigned int nbits; err = gcry_sexp_new (&key, sample_key_1, 0, 1); if (err) die ("parsing s-expression string failed: %s\n", gpg_strerror (err)); name = gcry_pk_get_curve (key, 0, &nbits); if (!name) fail ("curve name not found for sample_key_1\n"); else if (strcmp (name, sample_key_1_curve)) fail ("expected curve name %s but got %s for sample_key_1\n", sample_key_1_curve, name); else if (nbits != sample_key_1_nbits) fail ("expected curve size %u but got %u for sample_key_1\n", sample_key_1_nbits, nbits); gcry_sexp_release (key); if (!in_fips_mode) { err = gcry_sexp_new (&key, sample_key_2, 0, 1); if (err) die ("parsing s-expression string failed: %s\n", gpg_strerror (err)); name = gcry_pk_get_curve (key, 0, &nbits); if (!name) fail ("curve name not found for sample_key_2\n"); else if (strcmp (name, sample_key_2_curve)) fail ("expected curve name %s but got %s for sample_key_2\n", sample_key_2_curve, name); else if (nbits != sample_key_2_nbits) fail ("expected curve size %u but got %u for sample_key_2\n", sample_key_2_nbits, nbits); gcry_sexp_release (key); } } #define TEST_ERROR_EXPECTED (1 << 0) #define TEST_NOFIPS (1 << 1) static void check_get_params (void) { static struct { int algo; const char *name; int flags; } tv[] = { - { GCRY_PK_ECC, "Ed25519", TEST_NOFIPS }, - { GCRY_PK_ECC, "1.3.6.1.4.1.11591.15.1", TEST_NOFIPS }, - { GCRY_PK_ECC, "1.3.101.112", TEST_NOFIPS }, + { GCRY_PK_ECC, "Ed25519" }, + { GCRY_PK_ECC, "1.3.6.1.4.1.11591.15.1" }, + { GCRY_PK_ECC, "1.3.101.112" }, { GCRY_PK_ECC, "Curve25519", TEST_NOFIPS }, { GCRY_PK_ECC, "1.3.6.1.4.1.3029.1.5.1", TEST_NOFIPS }, { GCRY_PK_ECC, "1.3.101.110", TEST_NOFIPS }, { GCRY_PK_ECC, "X25519", TEST_NOFIPS }, - { GCRY_PK_ECC, "Ed448", TEST_NOFIPS }, + { GCRY_PK_ECC, "Ed448" }, + { GCRY_PK_ECC, "1.3.101.113" }, { GCRY_PK_ECC, "X448", TEST_NOFIPS }, - { GCRY_PK_ECC, "1.3.101.113", TEST_NOFIPS }, { GCRY_PK_ECC, "1.3.101.111", TEST_NOFIPS }, { GCRY_PK_ECC, "NIST P-192", TEST_NOFIPS }, { GCRY_PK_ECC, "1.2.840.10045.3.1.1", TEST_NOFIPS }, { GCRY_PK_ECC, "prime192v1", TEST_NOFIPS }, { GCRY_PK_ECC, "secp192r1", TEST_NOFIPS }, { GCRY_PK_ECC, "nistp192", TEST_NOFIPS }, { GCRY_PK_ECC, "NIST P-224" }, { GCRY_PK_ECC, "secp224r1" }, { GCRY_PK_ECC, "1.3.132.0.33" }, { GCRY_PK_ECC, "nistp224" }, { GCRY_PK_ECC, "NIST P-256" }, { GCRY_PK_ECC, "1.2.840.10045.3.1.7" }, { GCRY_PK_ECC, "prime256v1" }, { GCRY_PK_ECC, "secp256r1" }, { GCRY_PK_ECC, "nistp256" }, { GCRY_PK_ECC, "NIST P-384" }, { GCRY_PK_ECC, "secp384r1" }, { GCRY_PK_ECC, "1.3.132.0.34" }, { GCRY_PK_ECC, "nistp384" }, { GCRY_PK_ECC, "NIST P-521" }, { GCRY_PK_ECC, "secp521r1" }, { GCRY_PK_ECC, "1.3.132.0.35" }, { GCRY_PK_ECC, "nistp521" }, { GCRY_PK_ECC, "brainpoolP160r1", TEST_NOFIPS }, { GCRY_PK_ECC, "1.3.36.3.3.2.8.1.1.1", TEST_NOFIPS }, { GCRY_PK_ECC, "brainpoolP192r1", TEST_NOFIPS }, { GCRY_PK_ECC, "1.3.36.3.3.2.8.1.1.3", TEST_NOFIPS }, { GCRY_PK_ECC, "brainpoolP224r1", TEST_NOFIPS }, { GCRY_PK_ECC, "1.3.36.3.3.2.8.1.1.5", TEST_NOFIPS }, { GCRY_PK_ECC, "brainpoolP256r1", TEST_NOFIPS }, { GCRY_PK_ECC, "1.3.36.3.3.2.8.1.1.7", TEST_NOFIPS }, { GCRY_PK_ECC, "brainpoolP320r1", TEST_NOFIPS }, { GCRY_PK_ECC, "1.3.36.3.3.2.8.1.1.9", TEST_NOFIPS }, { GCRY_PK_ECC, "brainpoolP384r1", TEST_NOFIPS }, { GCRY_PK_ECC, "1.3.36.3.3.2.8.1.1.11", TEST_NOFIPS }, { GCRY_PK_ECC, "brainpoolP512r1", TEST_NOFIPS }, { GCRY_PK_ECC, "1.3.36.3.3.2.8.1.1.13", TEST_NOFIPS }, { GCRY_PK_ECC, "GOST2001-test", TEST_NOFIPS }, { GCRY_PK_ECC, "1.2.643.2.2.35.0", TEST_NOFIPS }, { GCRY_PK_ECC, "GOST2001-CryptoPro-A", TEST_NOFIPS }, { GCRY_PK_ECC, "1.2.643.2.2.35.1", TEST_NOFIPS }, { GCRY_PK_ECC, "GOST2001-CryptoPro-B", TEST_NOFIPS }, { GCRY_PK_ECC, "1.2.643.2.2.35.2", TEST_NOFIPS }, { GCRY_PK_ECC, "GOST2001-CryptoPro-C", TEST_NOFIPS }, { GCRY_PK_ECC, "1.2.643.2.2.35.3", TEST_NOFIPS }, { GCRY_PK_ECC, "GOST2001-CryptoPro-A", TEST_NOFIPS }, { GCRY_PK_ECC, "GOST2001-CryptoPro-XchA", TEST_NOFIPS }, { GCRY_PK_ECC, "GOST2001-CryptoPro-C", TEST_NOFIPS }, { GCRY_PK_ECC, "GOST2001-CryptoPro-XchB", TEST_NOFIPS }, { GCRY_PK_ECC, "GOST2001-CryptoPro-A", TEST_NOFIPS }, { GCRY_PK_ECC, "1.2.643.2.2.36.0", TEST_NOFIPS }, { GCRY_PK_ECC, "GOST2001-CryptoPro-C", TEST_NOFIPS }, { GCRY_PK_ECC, "1.2.643.2.2.36.1", TEST_NOFIPS }, /* Noet that GOST2012-256-tc26-A" is only in the curve alias * list but has no parameter entry. */ { GCRY_PK_ECC, "GOST2001-CryptoPro-A", TEST_NOFIPS }, { GCRY_PK_ECC, "1.2.643.7.1.2.1.1.2", TEST_NOFIPS }, { GCRY_PK_ECC, "GOST2001-CryptoPro-A", TEST_NOFIPS }, { GCRY_PK_ECC, "GOST2012-256-tc26-B", TEST_NOFIPS }, { GCRY_PK_ECC, "GOST2001-CryptoPro-B", TEST_NOFIPS }, { GCRY_PK_ECC, "1.2.643.7.1.2.1.1.3", TEST_NOFIPS }, { GCRY_PK_ECC, "GOST2001-CryptoPro-B", TEST_NOFIPS }, { GCRY_PK_ECC, "GOST2012-256-tc26-C", TEST_NOFIPS }, { GCRY_PK_ECC, "GOST2001-CryptoPro-C", TEST_NOFIPS }, { GCRY_PK_ECC, "1.2.643.7.1.2.1.1.4", TEST_NOFIPS }, { GCRY_PK_ECC, "GOST2001-CryptoPro-C", TEST_NOFIPS }, { GCRY_PK_ECC, "GOST2012-256-tc26-D", TEST_NOFIPS }, { GCRY_PK_ECC, "GOST2012-512-test", TEST_NOFIPS }, { GCRY_PK_ECC, "GOST2012-test", TEST_NOFIPS }, { GCRY_PK_ECC, "GOST2012-512-test", TEST_NOFIPS }, { GCRY_PK_ECC, "1.2.643.7.1.2.1.2.0", TEST_NOFIPS }, { GCRY_PK_ECC, "GOST2012-512-tc26-A", TEST_NOFIPS }, { GCRY_PK_ECC, "GOST2012-tc26-A", TEST_NOFIPS }, { GCRY_PK_ECC, "GOST2012-512-tc26-B", TEST_NOFIPS }, { GCRY_PK_ECC, "GOST2012-tc26-B", TEST_NOFIPS }, { GCRY_PK_ECC, "GOST2012-512-tc26-A", TEST_NOFIPS }, { GCRY_PK_ECC, "1.2.643.7.1.2.1.2.1", TEST_NOFIPS }, { GCRY_PK_ECC, "GOST2012-512-tc26-B", TEST_NOFIPS }, { GCRY_PK_ECC, "1.2.643.7.1.2.1.2.2", TEST_NOFIPS }, { GCRY_PK_ECC, "GOST2012-512-tc26-C", TEST_NOFIPS }, { GCRY_PK_ECC, "1.2.643.7.1.2.1.2.3", TEST_NOFIPS }, { GCRY_PK_ECC, "secp256k1", TEST_NOFIPS }, { GCRY_PK_ECC, "1.3.132.0.10", TEST_NOFIPS }, { GCRY_PK_ECC, "sm2p256v1", TEST_NOFIPS }, { GCRY_PK_ECC, "1.2.156.10197.1.301", TEST_NOFIPS }, /* Check also the ECC algo mapping. */ - { GCRY_PK_ECDSA, "Ed25519", TEST_NOFIPS }, - { GCRY_PK_EDDSA, "Ed25519", TEST_NOFIPS }, - { GCRY_PK_ECDH, "Ed25519", TEST_NOFIPS }, + { GCRY_PK_ECDSA, "Ed25519" }, + { GCRY_PK_EDDSA, "Ed25519" }, + { GCRY_PK_ECDH, "Ed25519" }, { GCRY_PK_ECDSA, "Curve25519", TEST_NOFIPS }, { GCRY_PK_EDDSA, "Curve25519", TEST_NOFIPS }, { GCRY_PK_ECDH, "Curve25519", TEST_NOFIPS }, { GCRY_PK_ECC, "NoSuchCurve", TEST_ERROR_EXPECTED }, { GCRY_PK_RSA, "rsa", TEST_ERROR_EXPECTED }, { GCRY_PK_ELG, "elg", TEST_ERROR_EXPECTED }, { GCRY_PK_DSA, "dsa", TEST_ERROR_EXPECTED } }; int idx; gcry_sexp_t param; const char *name; param = gcry_pk_get_param (GCRY_PK_ECDSA, sample_key_1_curve); if (!param) fail ("error gerring parameters for `%s'\n", sample_key_1_curve); name = gcry_pk_get_curve (param, 0, NULL); if (!name) fail ("get_param: curve name not found for sample_key_1\n"); else if (strcmp (name, sample_key_1_curve)) fail ("get_param: expected curve name %s but got %s for sample_key_1\n", sample_key_1_curve, name); gcry_sexp_release (param); if (!in_fips_mode) { param = gcry_pk_get_param (GCRY_PK_ECDSA, sample_key_2_curve); if (!param) fail ("error gerring parameters for `%s'\n", sample_key_2_curve); name = gcry_pk_get_curve (param, 0, NULL); if (!name) fail ("get_param: curve name not found for sample_key_2\n"); else if (strcmp (name, sample_key_2_curve)) fail ("get_param: expected curve name %s but got %s for sample_key_2\n", sample_key_2_curve, name); gcry_sexp_release (param); } /* Some simple tests */ for (idx=0; idx < DIM (tv); idx++) { param = gcry_pk_get_param (tv[idx].algo, tv[idx].name); if (in_fips_mode && tv[idx].flags & TEST_NOFIPS) { if (param) fail ("get_param: test %d (%s) should have failed in fips mode\n", idx, tv[idx].name); } else { if (!param) { if (!(tv[idx].flags & TEST_ERROR_EXPECTED)) fail ("get_param: test %d (%s) failed\n", idx, tv[idx].name); } else { if (tv[idx].flags & TEST_ERROR_EXPECTED) fail ("get_param: test %d (%s) failed (error expected)\n", idx, tv[idx].name); } } gcry_sexp_release (param); } } int main (int argc, char **argv) { if (argc > 1 && !strcmp (argv[1], "--verbose")) verbose = 1; else if (argc > 1 && !strcmp (argv[1], "--debug")) verbose = debug = 1; if (!gcry_check_version (GCRYPT_VERSION)) die ("version mismatch\n"); xgcry_control ((GCRYCTL_DISABLE_SECMEM, 0)); xgcry_control ((GCRYCTL_INITIALIZATION_FINISHED, 0)); if (debug) xgcry_control ((GCRYCTL_SET_DEBUG_FLAGS, 1u, 0)); if (gcry_fips_mode_active ()) in_fips_mode = 1; list_curves (); check_matching (); check_get_params (); return error_count ? 1 : 0; } diff --git a/tests/keygen.c b/tests/keygen.c index 45cd0dcc..eb388374 100644 --- a/tests/keygen.c +++ b/tests/keygen.c @@ -1,807 +1,781 @@ /* keygen.c - key generation regression tests * Copyright (C) 2003, 2005, 2012 Free Software Foundation, Inc. * Copyright (C) 2013, 2015 g10 Code GmbH * * This file is part of Libgcrypt. * * Libgcrypt is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * Libgcrypt is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this program; if not, see . */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include "../src/gcrypt-int.h" #define PGM "keygen" #include "t-common.h" static int in_fips_mode; /* static void */ /* show_note (const char *format, ...) */ /* { */ /* va_list arg_ptr; */ /* if (!verbose && getenv ("srcdir")) */ /* fputs (" ", stderr); /\* To align above "PASS: ". *\/ */ /* else */ /* fprintf (stderr, "%s: ", PGM); */ /* va_start (arg_ptr, format); */ /* vfprintf (stderr, format, arg_ptr); */ /* if (*format && format[strlen(format)-1] != '\n') */ /* putc ('\n', stderr); */ /* va_end (arg_ptr); */ /* } */ static void show_sexp (const char *prefix, gcry_sexp_t a) { char *buf; size_t size; fprintf (stderr, "%s: ", PGM); if (prefix) fputs (prefix, stderr); size = gcry_sexp_sprint (a, GCRYSEXP_FMT_ADVANCED, NULL, 0); buf = xmalloc (size); gcry_sexp_sprint (a, GCRYSEXP_FMT_ADVANCED, buf, size); fprintf (stderr, "%.*s", (int)size, buf); gcry_free (buf); } #if USE_RSA static void show_mpi (const char *prefix, gcry_mpi_t a) { char *buf; void *bufaddr = &buf; gcry_error_t rc; fprintf (stderr, "%s: ", PGM); if (prefix) fputs (prefix, stderr); rc = gcry_mpi_aprint (GCRYMPI_FMT_HEX, bufaddr, NULL, a); if (rc) fprintf (stderr, "[error printing number: %s]\n", gpg_strerror (rc)); else { fprintf (stderr, "%s\n", buf); gcry_free (buf); } } static void check_generated_rsa_key (gcry_sexp_t key, unsigned long expected_e) { gcry_sexp_t skey, pkey, list; pkey = gcry_sexp_find_token (key, "public-key", 0); if (!pkey) fail ("public part missing in return value\n"); else { gcry_mpi_t e = NULL; list = gcry_sexp_find_token (pkey, "e", 0); if (!list || !(e=gcry_sexp_nth_mpi (list, 1, 0)) ) fail ("public exponent not found\n"); else if (!expected_e) { if (verbose) show_mpi ("public exponent: ", e); } else if ( gcry_mpi_cmp_ui (e, expected_e)) { show_mpi ("public exponent: ", e); fail ("public exponent is not %lu\n", expected_e); } gcry_sexp_release (list); gcry_mpi_release (e); gcry_sexp_release (pkey); } skey = gcry_sexp_find_token (key, "private-key", 0); if (!skey) fail ("private part missing in return value\n"); else { int rc = gcry_pk_testkey (skey); if (rc) fail ("gcry_pk_testkey failed: %s\n", gpg_strerror (rc)); gcry_sexp_release (skey); } } #endif /* USE_RSA */ static void check_rsa_keys (void) { #if USE_RSA gcry_sexp_t keyparm, key; int rc; if (verbose) info ("creating 2048 bit RSA key\n"); rc = gcry_sexp_new (&keyparm, "(genkey\n" " (rsa\n" " (nbits 4:2048)\n" " ))", 0, 1); if (rc) die ("error creating S-expression: %s\n", gpg_strerror (rc)); rc = gcry_pk_genkey (&key, keyparm); gcry_sexp_release (keyparm); if (rc) die ("error generating RSA key: %s\n", gpg_strerror (rc)); if (verbose) info ("creating 1024 bit RSA key\n"); rc = gcry_sexp_new (&keyparm, "(genkey\n" " (rsa\n" " (nbits 4:1024)\n" " ))", 0, 1); if (rc) die ("error creating S-expression: %s\n", gpg_strerror (rc)); gcry_sexp_release (key); rc = gcry_pk_genkey (&key, keyparm); gcry_sexp_release (keyparm); if (rc && !in_fips_mode) fail ("error generating RSA key: %s\n", gpg_strerror (rc)); else if (!rc && in_fips_mode) fail ("generating 1024 bit RSA key must not work!"); if (!rc) { if (verbose > 1) show_sexp ("1024 bit RSA key:\n", key); check_generated_rsa_key (key, 65537); } gcry_sexp_release (key); if (verbose) info ("creating 2048 bit RSA key with e=65539\n"); rc = gcry_sexp_new (&keyparm, "(genkey\n" " (rsa\n" " (nbits 4:2048)\n" " (rsa-use-e 5:65539)\n" " ))", 0, 1); if (rc) die ("error creating S-expression: %s\n", gpg_strerror (rc)); rc = gcry_pk_genkey (&key, keyparm); gcry_sexp_release (keyparm); if (rc) fail ("error generating RSA key: %s\n", gpg_strerror (rc)); if (!rc) check_generated_rsa_key (key, 65539); gcry_sexp_release (key); if (verbose) info ("creating 512 bit RSA key with e=257\n"); rc = gcry_sexp_new (&keyparm, "(genkey\n" " (rsa\n" " (nbits 3:512)\n" " (rsa-use-e 3:257)\n" " ))", 0, 1); if (rc) die ("error creating S-expression: %s\n", gpg_strerror (rc)); rc = gcry_pk_genkey (&key, keyparm); gcry_sexp_release (keyparm); if (rc && !in_fips_mode) fail ("error generating RSA key: %s\n", gpg_strerror (rc)); else if (!rc && in_fips_mode) fail ("generating 512 bit RSA key must not work!"); if (verbose && rc && in_fips_mode) info ("... correctly rejected key creation in FIPS mode (%s)\n", gpg_strerror (rc)); if (!rc) check_generated_rsa_key (key, 257); gcry_sexp_release (key); if (verbose) info ("creating 512 bit RSA key with default e\n"); rc = gcry_sexp_new (&keyparm, "(genkey\n" " (rsa\n" " (nbits 3:512)\n" " (rsa-use-e 1:0)\n" " ))", 0, 1); if (rc) die ("error creating S-expression: %s\n", gpg_strerror (rc)); rc = gcry_pk_genkey (&key, keyparm); gcry_sexp_release (keyparm); if (rc && !in_fips_mode) fail ("error generating RSA key: %s\n", gpg_strerror (rc)); else if (!rc && in_fips_mode) fail ("generating 512 bit RSA key must not work!"); if (verbose && rc && in_fips_mode) info ("... correctly rejected key creation in FIPS mode (%s)\n", gpg_strerror (rc)); if (!rc) check_generated_rsa_key (key, 0); /* We don't expect a constant exponent. */ gcry_sexp_release (key); #endif /* USE_RSA */ } static void check_elg_keys (void) { #if USE_ELGAMAL gcry_sexp_t keyparm, key; int rc; if (verbose) info ("creating 1024 bit Elgamal key\n"); rc = gcry_sexp_new (&keyparm, "(genkey\n" " (elg\n" " (nbits 4:1024)\n" " ))", 0, 1); if (rc) die ("error creating S-expression: %s\n", gpg_strerror (rc)); rc = gcry_pk_genkey (&key, keyparm); gcry_sexp_release (keyparm); if (rc && !in_fips_mode) die ("error generating Elgamal key: %s\n", gpg_strerror (rc)); else if (!rc && in_fips_mode) die ("generating Elgamal key must not work in FIPS mode."); if (verbose > 1) show_sexp ("1024 bit Elgamal key:\n", key); gcry_sexp_release (key); #endif /* USE_ELGAMAL */ } static void check_dsa_keys (void) { #if USE_DSA gcry_sexp_t keyparm, key; int rc; int i; /* Check that DSA generation works and that it can grok the qbits argument. */ if (verbose) info ("creating 5 1024 bit DSA keys\n"); for (i=0; i < 5; i++) { rc = gcry_sexp_new (&keyparm, "(genkey\n" " (dsa\n" " (nbits 4:1024)\n" " ))", 0, 1); if (rc) die ("error creating S-expression: %s\n", gpg_strerror (rc)); rc = gcry_pk_genkey (&key, keyparm); gcry_sexp_release (keyparm); if (rc && !in_fips_mode) die ("error generating DSA key: %s\n", gpg_strerror (rc)); else if (!rc && in_fips_mode) die ("generating 1024 bit DSA key must not work in FIPS mode!"); if (!i && verbose > 1) show_sexp ("1024 bit DSA key:\n", key); gcry_sexp_release (key); } if (verbose) info ("creating 1536 bit DSA key\n"); rc = gcry_sexp_new (&keyparm, "(genkey\n" " (dsa\n" " (nbits 4:1536)\n" " (qbits 3:224)\n" " ))", 0, 1); if (rc) die ("error creating S-expression: %s\n", gpg_strerror (rc)); rc = gcry_pk_genkey (&key, keyparm); gcry_sexp_release (keyparm); if (rc && !in_fips_mode) die ("error generating DSA key: %s\n", gpg_strerror (rc)); else if (!rc && in_fips_mode) die ("generating 1536 bit DSA key must not work in FIPS mode!"); if (verbose > 1) show_sexp ("1536 bit DSA key:\n", key); gcry_sexp_release (key); if (verbose) info ("creating 3072 bit DSA key\n"); rc = gcry_sexp_new (&keyparm, "(genkey\n" " (dsa\n" " (nbits 4:3072)\n" " (qbits 3:256)\n" " ))", 0, 1); if (rc) die ("error creating S-expression: %s\n", gpg_strerror (rc)); rc = gcry_pk_genkey (&key, keyparm); gcry_sexp_release (keyparm); if (rc && !in_fips_mode) die ("error generating DSA key: %s\n", gpg_strerror (rc)); else if (!rc && in_fips_mode) die ("generating DSA key must not work in FIPS mode!"); if (verbose > 1) show_sexp ("3072 bit DSA key:\n", key); gcry_sexp_release (key); if (verbose) info ("creating 2048/256 bit DSA key\n"); rc = gcry_sexp_new (&keyparm, "(genkey\n" " (dsa\n" " (nbits 4:2048)\n" " (qbits 3:256)\n" " ))", 0, 1); if (rc) die ("error creating S-expression: %s\n", gpg_strerror (rc)); rc = gcry_pk_genkey (&key, keyparm); gcry_sexp_release (keyparm); if (rc && !in_fips_mode) die ("error generating DSA key: %s\n", gpg_strerror (rc)); else if (!rc && in_fips_mode) die ("generating DSA key must not work in FIPS mode!"); if (verbose > 1) show_sexp ("2048 bit DSA key:\n", key); gcry_sexp_release (key); if (verbose) info ("creating 2048/224 bit DSA key\n"); rc = gcry_sexp_new (&keyparm, "(genkey\n" " (dsa\n" " (nbits 4:2048)\n" " (qbits 3:224)\n" " ))", 0, 1); if (rc) die ("error creating S-expression: %s\n", gpg_strerror (rc)); rc = gcry_pk_genkey (&key, keyparm); gcry_sexp_release (keyparm); if (rc && !in_fips_mode) die ("error generating DSA key: %s\n", gpg_strerror (rc)); else if (!rc && in_fips_mode) die ("generating DSA key must not work in FIPS mode!"); if (verbose > 1) show_sexp ("2048 bit DSA key:\n", key); gcry_sexp_release (key); #endif /* USE_DSA */ } #if USE_ECC static void check_generated_ecc_key (gcry_sexp_t key) { gcry_sexp_t skey, pkey; pkey = gcry_sexp_find_token (key, "public-key", 0); if (!pkey) fail ("public part missing in return value\n"); else { /* Fixme: Check more stuff. */ gcry_sexp_release (pkey); } skey = gcry_sexp_find_token (key, "private-key", 0); if (!skey) fail ("private part missing in return value\n"); else { int rc = gcry_pk_testkey (skey); if (rc) fail ("gcry_pk_testkey failed: %s\n", gpg_strerror (rc)); gcry_sexp_release (skey); } /* Finally check that gcry_pk_testkey also works on the entire S-expression. */ { int rc = gcry_pk_testkey (key); if (rc) fail ("gcry_pk_testkey failed on key pair: %s\n", gpg_strerror (rc)); } } #endif /* USE_ECC */ static void check_ecc_keys (void) { #if USE_ECC const char *curves[] = { "NIST P-521", "NIST P-384", "NIST P-256", "Ed25519", NULL }; int testno; gcry_sexp_t keyparm, key; int rc; for (testno=0; curves[testno]; testno++) { if (verbose) info ("creating ECC key using curve %s\n", curves[testno]); if (!strcmp (curves[testno], "Ed25519")) { - /* Ed25519 isn't allowed in fips mode */ - if (in_fips_mode) - continue; rc = gcry_sexp_build (&keyparm, NULL, "(genkey(ecc(curve %s)(flags param eddsa)))", curves[testno]); } else rc = gcry_sexp_build (&keyparm, NULL, "(genkey(ecc(curve %s)(flags param)))", curves[testno]); if (rc) die ("error creating S-expression: %s\n", gpg_strerror (rc)); rc = gcry_pk_genkey (&key, keyparm); gcry_sexp_release (keyparm); if (rc) die ("error generating ECC key using curve %s: %s\n", curves[testno], gpg_strerror (rc)); if (verbose > 1) show_sexp ("ECC key:\n", key); check_generated_ecc_key (key); gcry_sexp_release (key); } if (verbose) info ("creating ECC key using curve Ed25519 for ECDSA\n"); rc = gcry_sexp_build (&keyparm, NULL, "(genkey(ecc(curve Ed25519)))"); if (rc) die ("error creating S-expression: %s\n", gpg_strerror (rc)); rc = gcry_pk_genkey (&key, keyparm); gcry_sexp_release (keyparm); - if (rc && !in_fips_mode) + if (rc) die ("error generating ECC key using curve Ed25519 for ECDSA: %s\n", gpg_strerror (rc)); - else if (!rc && in_fips_mode) - fail ("generating Ed25519 key must not work!"); - - if (verbose && rc && in_fips_mode) - info ("... correctly rejected key creation in FIPS mode (%s)\n", - gpg_strerror (rc)); if (!rc) { if (verbose > 1) show_sexp ("ECC key:\n", key); check_generated_ecc_key (key); } gcry_sexp_release (key); if (verbose) info ("creating ECC key using curve Ed25519 for ECDSA (nocomp)\n"); rc = gcry_sexp_build (&keyparm, NULL, "(genkey(ecc(curve Ed25519)(flags nocomp)))"); if (rc) die ("error creating S-expression: %s\n", gpg_strerror (rc)); rc = gcry_pk_genkey (&key, keyparm); gcry_sexp_release (keyparm); - if (rc && !in_fips_mode) + if (rc) die ("error generating ECC key using curve Ed25519 for ECDSA" " (nocomp): %s\n", gpg_strerror (rc)); - else if (!rc && in_fips_mode) - fail ("generating Ed25519 key must not work in FIPS mode!"); - if (verbose && rc && in_fips_mode) - info ("... correctly rejected key creation in FIPS mode (%s)\n", - gpg_strerror (rc)); gcry_sexp_release (key); if (verbose) info ("creating ECC key using curve NIST P-384 for ECDSA\n"); /* Must be specified as nistp384 (one word), because ecc_generate * uses _gcry_sexp_nth_string which takes the first word of the name * and thus libgcrypt can't find it later in its curves table. */ rc = gcry_sexp_build (&keyparm, NULL, "(genkey(ecc(curve nistp384)))"); if (rc) die ("error creating S-expression: %s\n", gpg_strerror (rc)); rc = gcry_pk_genkey (&key, keyparm); gcry_sexp_release (keyparm); if (rc) die ("error generating ECC key using curve NIST P-384 for ECDSA: %s\n", gpg_strerror (rc)); if (verbose > 1) show_sexp ("ECC key:\n", key); check_generated_ecc_key (key); gcry_sexp_release (key); if (verbose) info ("creating ECC key using curve NIST P-384 for ECDSA (nocomp)\n"); rc = gcry_sexp_build (&keyparm, NULL, "(genkey(ecc(curve nistp384)(flags nocomp)))"); if (rc) die ("error creating S-expression: %s\n", gpg_strerror (rc)); rc = gcry_pk_genkey (&key, keyparm); gcry_sexp_release (keyparm); if (rc) die ("error generating ECC key using curve NIST P-384 for ECDSA" " (nocomp): %s\n", gpg_strerror (rc)); if (verbose > 1) show_sexp ("ECC key:\n", key); check_generated_ecc_key (key); gcry_sexp_release (key); if (verbose) info ("creating ECC key using curve Ed25519 for ECDSA (transient-key)\n"); rc = gcry_sexp_build (&keyparm, NULL, "(genkey(ecc(curve Ed25519)(flags transient-key)))"); if (rc) die ("error creating S-expression: %s\n", gpg_strerror (rc)); rc = gcry_pk_genkey (&key, keyparm); gcry_sexp_release (keyparm); - if (rc && !in_fips_mode) + if (rc) die ("error generating ECC key using curve Ed25519 for ECDSA" " (transient-key): %s\n", gpg_strerror (rc)); - else if (!rc && in_fips_mode) - fail ("generating Ed25519 key must not work in FIPS mode!"); - - if (verbose && rc && in_fips_mode) - info ("... correctly rejected key creation in FIPS mode (%s)\n", - gpg_strerror (rc)); if (!rc) { if (verbose > 1) show_sexp ("ECC key:\n", key); check_generated_ecc_key (key); } gcry_sexp_release (key); if (verbose) info ("creating ECC key using curve Ed25519 for ECDSA " "(transient-key no-keytest)\n"); rc = gcry_sexp_build (&keyparm, NULL, "(genkey(ecc(curve Ed25519)" "(flags transient-key no-keytest)))"); if (rc) die ("error creating S-expression: %s\n", gpg_strerror (rc)); rc = gcry_pk_genkey (&key, keyparm); gcry_sexp_release (keyparm); - if (rc && !in_fips_mode) + if (rc) die ("error generating ECC key using curve Ed25519 for ECDSA" " (transient-key no-keytest): %s\n", gpg_strerror (rc)); - else if (!rc && in_fips_mode) - fail ("generating Ed25519 key must not work in FIPS mode!"); - - if (verbose && rc && in_fips_mode) - info ("... correctly rejected key creation in FIPS mode (%s)\n", - gpg_strerror (rc)); if (!rc) { if (verbose > 1) show_sexp ("ECC key:\n", key); check_generated_ecc_key (key); } gcry_sexp_release (key); #endif /* USE_ECC */ } static void check_nonce (void) { char a[32], b[32]; int i,j; int oops=0; if (verbose) info ("checking gcry_create_nonce\n"); gcry_create_nonce (a, sizeof a); for (i=0; i < 10; i++) { gcry_create_nonce (b, sizeof b); if (!memcmp (a, b, sizeof a)) die ("identical nonce found\n"); } for (i=0; i < 10; i++) { gcry_create_nonce (a, sizeof a); if (!memcmp (a, b, sizeof a)) die ("identical nonce found\n"); } again: for (i=1,j=0; i < sizeof a; i++) if (a[0] == a[i]) j++; if (j+1 == sizeof (a)) { if (oops) die ("impossible nonce found\n"); oops++; gcry_create_nonce (a, sizeof a); goto again; } } static void progress_cb (void *cb_data, const char *what, int printchar, int current, int total) { (void)cb_data; (void)what; (void)current; (void)total; if (printchar == '\n') fputs ( "", stdout); else putchar (printchar); fflush (stdout); } static void usage (int mode) { fputs ("usage: " PGM " [options] [{rsa|elg|dsa|ecc|nonce}]\n" "Options:\n" " --verbose be verbose\n" " --debug flyswatter\n" " --fips run in FIPS mode\n" " --no-quick To not use the quick RNG hack\n" " --progress print progress indicators\n", mode? stderr : stdout); if (mode) exit (1); } int main (int argc, char **argv) { int last_argc = -1; int opt_fips = 0; int with_progress = 0; int no_quick = 0; if (argc) { argc--; argv++; } while (argc && last_argc != argc ) { last_argc = argc; if (!strcmp (*argv, "--")) { argc--; argv++; break; } else if (!strcmp (*argv, "--help")) { usage (0); exit (0); } else if (!strcmp (*argv, "--verbose")) { verbose++; argc--; argv++; } else if (!strcmp (*argv, "--debug")) { verbose += 2; debug++; argc--; argv++; } else if (!strcmp (*argv, "--fips")) { argc--; argv++; opt_fips = 1; } else if (!strcmp (*argv, "--progress")) { argc--; argv++; with_progress = 1; } else if (!strcmp (*argv, "--no-quick")) { argc--; argv++; no_quick = 1; } else if (!strncmp (*argv, "--", 2)) die ("unknown option '%s'", *argv); else break; } xgcry_control ((GCRYCTL_SET_VERBOSITY, (int)verbose)); if (opt_fips) xgcry_control ((GCRYCTL_FORCE_FIPS_MODE, 0)); if (!gcry_check_version (GCRYPT_VERSION)) die ("version mismatch\n"); if (!opt_fips) xgcry_control ((GCRYCTL_DISABLE_SECMEM, 0)); xgcry_control ((GCRYCTL_INITIALIZATION_FINISHED, 0)); if (debug) xgcry_control ((GCRYCTL_SET_DEBUG_FLAGS, 1u , 0)); /* No valuable keys are create, so we can speed up our RNG. */ if (!no_quick) xgcry_control ((GCRYCTL_ENABLE_QUICK_RANDOM, 0)); if (with_progress) gcry_set_progress_handler (progress_cb, NULL); if ( gcry_fips_mode_active () ) in_fips_mode = 1; if (opt_fips && !in_fips_mode) die ("failed to switch into FIPS mode\n"); if (!argc) { check_rsa_keys (); check_elg_keys (); check_dsa_keys (); check_ecc_keys (); check_nonce (); } else { for (; argc; argc--, argv++) if (!strcmp (*argv, "rsa")) check_rsa_keys (); else if (!strcmp (*argv, "elg")) check_elg_keys (); else if (!strcmp (*argv, "dsa")) check_dsa_keys (); else if (!strcmp (*argv, "ecc")) check_ecc_keys (); else if (!strcmp (*argv, "nonce")) check_nonce (); else usage (1); } return error_count? 1:0; } diff --git a/tests/keygrip.c b/tests/keygrip.c index 114b6f04..cf650350 100644 --- a/tests/keygrip.c +++ b/tests/keygrip.c @@ -1,404 +1,400 @@ /* keygrip.c - verifies that keygrips are calculated as expected * Copyright (C) 2005 Free Software Foundation, Inc. * * This file is part of Libgcrypt. * * Libgcrypt is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * Libgcrypt is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this program; if not, see . * SPDX-License-Identifier: LGPL-2.1-or-later */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #define PGM "keygrip" #include "t-common.h" static int repetitions; /* Whether fips mode was active at startup. */ static int in_fips_mode; static void print_hex (const char *text, const void *buf, size_t n) { const unsigned char *p = buf; fputs (text, stdout); for (; n; n--, p++) printf ("%02X", *p); putchar ('\n'); } static struct { int algo; const char *key; const unsigned char grip[20]; int skip_when_fips; } key_grips[] = { { GCRY_PK_RSA, "(private-key" " (rsa" " (n #00B6B509596A9ECABC939212F891E656A626BA07DA8521A9CAD4C08E640C04052FBB87F424EF1A0275A48A9299AC9DB69ABE3D0124E6C756B1F7DFB9B842D6251AEA6EE85390495CADA73D671537FCE5850A932F32BAB60AB1AC1F852C1F83C625E7A7D70CDA9EF16D5C8E47739D77DF59261ABE8454807FF441E143FBD37F8545#)" " (e #010001#)" " (d #077AD3DE284245F4806A1B82B79E616FBDE821C82D691A65665E57B5FAD3F34E67F401E7BD2E28699E89D9C496CF821945AE83AC7A1231176A196BA6027E77D85789055D50404A7A2A95B1512F91F190BBAEF730ED550D227D512F89C0CDB31AC06FA9A19503DDF6B66D0B42B9691BFD6140EC1720FFC48AE00C34796DC899E5#)" " (p #00D586C78E5F1B4BF2E7CD7A04CA091911706F19788B93E44EE20AAF462E8363E98A72253ED845CCBF2481BB351E8557C85BCFFF0DABDBFF8E26A79A0938096F27#)" " (q #00DB0CDF60F26F2A296C88D6BF9F8E5BE45C0DDD713C96CC73EBCB48B061740943F21D2A93D6E42A7211E7F02A95DCED6C390A67AD21ECF739AE8A0CA46FF2EBB3#)" " (u #33149195F16912DB20A48D020DBC3B9E3881B39D722BF79378F6340F43148A6E9FC5F53E2853B7387BA4443BA53A52FCA8173DE6E85B42F9783D4A7817D0680B#)))", "\x32\xCF\xFA\x85\xB1\x79\x1F\xBB\x26\x14\xE9\x1A\xFD\xF3\xAF\xE3\x32\x08\x2E\x25" }, { GCRY_PK_DSA, " (public-key" " (dsa" " (p #0084E4C626E16005770BD9509ABF7354492E85B8C0060EFAAAEC617F725B592FAA59DF5460575F41022776A9718CE62EDD542AB73C7720869EBDBC834D174ADCD7136827DF51E2613545A25CA573BC502A61B809000B6E35F5EB7FD6F18C35678C23EA1C3638FB9CFDBA2800EE1B62F41A4479DE824F2834666FBF8DC5B53C2617#)" " (q #00B0E6F710051002A9F425D98A677B18E0E5B038AB#)" " (g #44370CEE0FE8609994183DBFEBA7EEA97D466838BCF65EFF506E35616DA93FA4E572A2F08886B74977BC00CA8CD3DBEA7AEB7DB8CBB180E6975E0D2CA76E023E6DE9F8CCD8826EBA2F72B8516532F6001DEFFAE76AA5E59E0FA33DBA3999B4E92D1703098CDEDCC416CF008801964084CDE1980132B2B78CB4CE9C15A559528B#)" " (y #3D5DD14AFA2BF24A791E285B90232213D0E3BA74AB1109E768AED19639A322F84BB7D959E2BA92EF73DE4C7F381AA9F4053CFA3CD4527EF9043E304E5B95ED0A3A5A9D590AA641C13DB2B6E32B9B964A6A2C730DD3EA7C8E13F7A140AFF1A91CE375E9B9B960384779DC4EA180FA1F827C52288F366C0770A220F50D6D8FD6F6#)))", "\x04\xA3\x4F\xA0\x2B\x03\x94\xD7\x32\xAD\xD5\x9B\x50\xAF\xDB\x5D\x57\x22\xA6\x10" }, { GCRY_PK_DSA, "(private-key" " (dsa" " (p #0084E4C626E16005770BD9509ABF7354492E85B8C0060EFAAAEC617F725B592FAA59DF5460575F41022776A9718CE62EDD542AB73C7720869EBDBC834D174ADCD7136827DF51E2613545A25CA573BC502A61B809000B6E35F5EB7FD6F18C35678C23EA1C3638FB9CFDBA2800EE1B62F41A4479DE824F2834666FBF8DC5B53C2617#)" " (q #00B0E6F710051002A9F425D98A677B18E0E5B038AB#)" " (g #44370CEE0FE8609994183DBFEBA7EEA97D466838BCF65EFF506E35616DA93FA4E572A2F08886B74977BC00CA8CD3DBEA7AEB7DB8CBB180E6975E0D2CA76E023E6DE9F8CCD8826EBA2F72B8516532F6001DEFFAE76AA5E59E0FA33DBA3999B4E92D1703098CDEDCC416CF008801964084CDE1980132B2B78CB4CE9C15A559528B#)" " (y #3D5DD14AFA2BF24A791E285B90232213D0E3BA74AB1109E768AED19639A322F84BB7D959E2BA92EF73DE4C7F381AA9F4053CFA3CD4527EF9043E304E5B95ED0A3A5A9D590AA641C13DB2B6E32B9B964A6A2C730DD3EA7C8E13F7A140AFF1A91CE375E9B9B960384779DC4EA180FA1F827C52288F366C0770A220F50D6D8FD6F6#)" " (x #0087F9E91BFBCC1163DE71ED86D557708E32F8ADDE#)))", "\x04\xA3\x4F\xA0\x2B\x03\x94\xD7\x32\xAD\xD5\x9B\x50\xAF\xDB\x5D\x57\x22\xA6\x10" }, { GCRY_PK_ECDSA, "(public-key" " (ecdsa(flags param)" " (p #00FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF#)" " (a #00FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC#)" " (b #5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B#)" " (g #046B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C2964FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5#)" " (n #00FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551#)" " (h #000000000000000000000000000000000000000000000000000000000000000001#)" " (q #04C8A4CEC2E9A9BC8E173531A67B0840DF345C32E261ADD780E6D83D56EFADFD5DE872F8B854819B59543CE0B7F822330464FBC4E6324DADDCD9D059554F63B344#)))", "\xE6\xDF\x94\x2D\xBD\x8C\x77\x05\xA3\xDD\x41\x6E\xFC\x04\x01\xDB\x31\x0E\x99\xB6" }, { GCRY_PK_ECDSA, "(public-key" " (ecdsa(flags param)" " (p #00FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF#)" " (curve \"NIST P-256\")" " (b #5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B#)" " (g #046B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C2964FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5#)" " (n #00FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551#)" " (h #000000000000000000000000000000000000000000000000000000000000000001#)" " (q #04C8A4CEC2E9A9BC8E173531A67B0840DF345C32E261ADD780E6D83D56EFADFD5DE872F8B854819B59543CE0B7F822330464FBC4E6324DADDCD9D059554F63B344#)))", "\xE6\xDF\x94\x2D\xBD\x8C\x77\x05\xA3\xDD\x41\x6E\xFC\x04\x01\xDB\x31\x0E\x99\xB6" }, { GCRY_PK_ECDSA, "(public-key" " (ecdsa" " (p #00FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF#)" " (curve \"NIST P-256\")" " (b #5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B#)" " (g #046B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C2964FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5#)" " (n #00FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551#)" " (h #000000000000000000000000000000000000000000000000000000000000000001#)" " (q #04C8A4CEC2E9A9BC8E173531A67B0840DF345C32E261ADD780E6D83D56EFADFD5DE872F8B854819B59543CE0B7F822330464FBC4E6324DADDCD9D059554F63B344#)))", "\xE6\xDF\x94\x2D\xBD\x8C\x77\x05\xA3\xDD\x41\x6E\xFC\x04\x01\xDB\x31\x0E\x99\xB6" }, { GCRY_PK_ECDSA, "(public-key" " (ecdsa" " (curve secp256r1)" " (q #04C8A4CEC2E9A9BC8E173531A67B0840DF345C32E261ADD780E6D83D56EFADFD5DE872F8B854819B59543CE0B7F822330464FBC4E6324DADDCD9D059554F63B344#)))", "\xE6\xDF\x94\x2D\xBD\x8C\x77\x05\xA3\xDD\x41\x6E\xFC\x04\x01\xDB\x31\x0E\x99\xB6" }, { GCRY_PK_ECC, "(public-key" " (ecc" " (curve secp256r1)" " (q #04C8A4CEC2E9A9BC8E173531A67B0840DF345C32E261ADD780E6D83D56EFADFD5DE872F8B854819B59543CE0B7F822330464FBC4E6324DADDCD9D059554F63B344#)))", "\xE6\xDF\x94\x2D\xBD\x8C\x77\x05\xA3\xDD\x41\x6E\xFC\x04\x01\xDB\x31\x0E\x99\xB6" }, { GCRY_PK_ECC, "(public-key" " (ecc" " (curve brainpoolP256r1)" " (q #042ECD8679930BE2DB4AD42B8600BA3F80" /* */"2D4D539BFF2F69B83EC9B7BBAA7F3406" /* */"436DD11A1756AFE56CD93408410FCDA9" /* */"BA95024EB613BD481A14FCFEC27A448A#)))", "\x52\xBA\xD4\xB4\xA3\x2D\x32\xA1\xDD\x06" "\x5E\x99\x0B\xF1\xAB\xC1\x13\x3D\x84\xD4", 1 }, { /* Compressed form of above. */ GCRY_PK_ECC, "(public-key" " (ecc" " (curve brainpoolP256r1)" " (q #022ECD8679930BE2DB4AD42B8600BA3F80" /* */"2D4D539BFF2F69B83EC9B7BBAA7F3406#)))", "\x52\xBA\xD4\xB4\xA3\x2D\x32\xA1\xDD\x06" "\x5E\x99\x0B\xF1\xAB\xC1\x13\x3D\x84\xD4", 1 }, { GCRY_PK_ECC, "(public-key" " (ecc" " (curve brainpoolP256r1)" " (q #045B784CA008EE64AB3D85017EE0D2BE87" /* */"558762C7300E0C8E06B1F9AF7C031458" /* */"9EBBA41915313417BA54218EB0569C59" /* */"0B156C76DBCAB6E84575E6EF68CE7B87#)))", "\x99\x38\x6A\x82\x41\x96\x29\x9C\x89\x74" "\xD6\xE1\xBF\x43\xAC\x9B\x9A\x12\xE7\x3F", 1 }, { /* Compressed form of above. */ GCRY_PK_ECC, "(public-key" " (ecc" " (curve brainpoolP256r1)" " (q #035B784CA008EE64AB3D85017EE0D2BE87" /* */"558762C7300E0C8E06B1F9AF7C031458#)))", "\x99\x38\x6A\x82\x41\x96\x29\x9C\x89\x74" "\xD6\xE1\xBF\x43\xAC\x9B\x9A\x12\xE7\x3F", 1 }, { /* Ed25519 standard */ GCRY_PK_ECC, "(public-key" " (ecc" " (curve Ed25519)" " (q #04" " 1CC662926E7EFF4982B7FB8B928E61CD74CCDD85277CC57196C3AD20B611085F" " 47BD24842905C049257673B3F5249524E0A41FAA17B25B818D0F97E625F1A1D0#)" " ))", "\x0C\xCA\xB2\xFD\x48\x9A\x33\x40\x2C\xE8" - "\xE0\x4A\x1F\xB2\x45\xEA\x80\x3D\x0A\xF1", - 1 + "\xE0\x4A\x1F\xB2\x45\xEA\x80\x3D\x0A\xF1" }, { /* Ed25519+EdDSA */ GCRY_PK_ECC, "(public-key" " (ecc" " (curve Ed25519)(flags eddsa)" " (q #773E72848C1FD5F9652B29E2E7AF79571A04990E96F2016BF4E0EC1890C2B7DB#)" " ))", "\x9D\xB6\xC6\x4A\x38\x83\x0F\x49\x60\x70" - "\x17\x89\x47\x55\x20\xBE\x8C\x82\x1F\x47", - 1 + "\x17\x89\x47\x55\x20\xBE\x8C\x82\x1F\x47" }, { /* Ed25519+EdDSA (with compression prefix) */ GCRY_PK_ECC, "(public-key" " (ecc" " (curve Ed25519)(flags eddsa)" " (q #40" " 773E72848C1FD5F9652B29E2E7AF79571A04990E96F2016BF4E0EC1890C2B7DB#)" " ))", "\x9D\xB6\xC6\x4A\x38\x83\x0F\x49\x60\x70" - "\x17\x89\x47\x55\x20\xBE\x8C\x82\x1F\x47", - 1 + "\x17\x89\x47\x55\x20\xBE\x8C\x82\x1F\x47" }, { /* Ed25519+EdDSA (same but uncompressed)*/ GCRY_PK_ECC, "(public-key" " (ecc" " (curve Ed25519)(flags eddsa)" " (q #04" " 629ad237d1ed04dcd4abe1711dd699a1cf51b1584c4de7a4ef8b8a640180b26f" " 5bb7c29018ece0f46b01f2960e99041a5779afe7e2292b65f9d51f8c84723e77#)" " ))", "\x9D\xB6\xC6\x4A\x38\x83\x0F\x49\x60\x70" - "\x17\x89\x47\x55\x20\xBE\x8C\x82\x1F\x47", - 1 + "\x17\x89\x47\x55\x20\xBE\x8C\x82\x1F\x47" }, { /* Cv25519 */ GCRY_PK_ECC, "(public-key" " (ecc" " (curve Curve25519)(flags djb-tweak)" " (q #40" " 918C1733127F6BF2646FAE3D081A18AE77111C903B906310B077505EFFF12740#)" " ))", "\x0F\x89\xA5\x65\xD3\xEA\x18\x7C\xE8\x39" "\x33\x23\x98\xF5\xD4\x80\x67\x7D\xF4\x9C", 1 }, { /* Random key */ GCRY_PK_RSA, "(shadowed-private-key" " (rsa" " (n #00B493C79928398DA9D99AC0E949FE6EB62F683CB974FFFBFBC01066F5C9A89B" " D3DC48EAD7C65F36EA943C2B2C865C26C4884FF9EDFDA8C99C855B737D77EEF6" " B85DBC0CCEC0E900C1F89A6893A2A93E8B31028469B6927CEB2F08687E547C68" " 6B0A2F7E50A194FF7AB7637E03DE0912EF7F6E5F1EC37625BD1620CCC2E7A564" " 31E168CDAFBD1D9E61AE47A69A6FA03EF22F844528A710B2392F262B95A3078C" " F321DC8325F92A5691EF69F34FD0DE0B22C79D29DC87723FCADE463829E8E5F7" " D196D73D6C9C180F6A6A0DDBF7B9D8F7FA293C36163B12199EF6A1A95CAE4051" " E3069C522CC6C4A7110F663A5DAD20F66C13A1674D050088208FAE4F33B3AB51" " 03#)" " (e #00010001#)" " (shadowed t1-v1" " (#D2760001240102000005000123350000# OPENPGP.1)" ")))", "\xE5\x6E\xE6\xEE\x5A\x2F\xDC\x3E\x98\x9D" "\xFE\x49\xDA\xF5\x67\x43\xE3\x27\x28\x33" } }; static void check (void) { unsigned char buf[20]; unsigned char *ret; gcry_error_t err; gcry_sexp_t sexp; unsigned int i; int repn; for (i = 0; i < (sizeof (key_grips) / sizeof (*key_grips)); i++) { if (in_fips_mode && key_grips[i].skip_when_fips) continue; if (gcry_pk_test_algo (key_grips[i].algo)) { if (verbose) fprintf (stderr, "algo %d not available; test skipped\n", key_grips[i].algo); continue; } err = gcry_sexp_sscan (&sexp, NULL, key_grips[i].key, strlen (key_grips[i].key)); if (err) die ("scanning data %d failed: %s\n", i, gpg_strerror (err)); if (debug) info ("check(%d): s-exp='%s'\n", i, key_grips[i].key); for (repn=0; repn < repetitions; repn++) { ret = gcry_pk_get_keygrip (sexp, buf); if (!ret) die ("gcry_pk_get_keygrip failed for %d\n", i); if ( memcmp (key_grips[i].grip, buf, sizeof (buf)) ) { print_hex ("keygrip: ", buf, sizeof buf); die ("keygrip for %d does not match\n", i); } else if (debug && !repn) print_hex ("keygrip: ", buf, sizeof buf); } gcry_sexp_release (sexp); } } static void progress_handler (void *cb_data, const char *what, int printchar, int current, int total) { (void)cb_data; (void)what; (void)current; (void)total; putchar (printchar); } int main (int argc, char **argv) { int last_argc = -1; if (argc) { argc--; argv++; } while (argc && last_argc != argc ) { last_argc = argc; if (!strcmp (*argv, "--")) { argc--; argv++; break; } else if (!strcmp (*argv, "--verbose")) { verbose = 1; argc--; argv++; } else if (!strcmp (*argv, "--debug")) { verbose = 1; debug = 1; argc--; argv++; } else if (!strcmp (*argv, "--repetitions")) { argc--; argv++; if (argc) { repetitions = atoi(*argv); argc--; argv++; } } } if (repetitions < 1) repetitions = 1; if (!gcry_check_version (GCRYPT_VERSION)) die ("version mismatch\n"); gcry_set_progress_handler (progress_handler, NULL); xgcry_control ((GCRYCTL_DISABLE_SECMEM, 0)); xgcry_control ((GCRYCTL_INITIALIZATION_FINISHED, 0)); if (debug) xgcry_control ((GCRYCTL_SET_DEBUG_FLAGS, 1u, 0)); if (gcry_fips_mode_active ()) in_fips_mode = 1; check (); return 0; } diff --git a/tests/pubkey.c b/tests/pubkey.c index 2669b41a..be150e03 100644 --- a/tests/pubkey.c +++ b/tests/pubkey.c @@ -1,1381 +1,1380 @@ /* pubkey.c - Public key encryption/decryption tests * Copyright (C) 2001, 2002, 2003, 2005 Free Software Foundation, Inc. * * This file is part of Libgcrypt. * * Libgcrypt is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * Libgcrypt is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this program; if not, see . */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #define PGM "pubkey" #include "t-common.h" static int in_fips_mode; #if USE_RSA /* Sample RSA keys, taken from basic.c. */ static const char sample_private_key_1[] = "(private-key\n" " (openpgp-rsa\n" " (n #009F56231A3D82E3E7D613D59D53E9AB921BEF9F08A782AED0B6E46ADBC853EC" " 7C71C422435A3CD8FA0DB9EFD55CD3295BADC4E8E2E2B94E15AE82866AB8ADE8" " 7E469FAE76DC3577DE87F1F419C4EB41123DFAF8D16922D5EDBAD6E9076D5A1C" " 958106F0AE5E2E9193C6B49124C64C2A241C4075D4AF16299EB87A6585BAE917" " DEF27FCDD165764D069BC18D16527B29DAAB549F7BBED4A7C6A842D203ED6613" " 6E2411744E432CD26D940132F25874483DCAEECDFD95744819CBCF1EA810681C" " 42907EBCB1C7EAFBE75C87EC32C5413EA10476545D3FC7B2ADB1B66B7F200918" " 664B0E5261C2895AA28B0DE321E921B3F877172CCCAB81F43EF98002916156F6" " CB#)\n" " (e #010001#)\n" " (d #07EF82500C403899934FE993AC5A36F14FF2DF38CF1EF315F205EE4C83EDAA19" " 8890FC23DE9AA933CAFB37B6A8A8DBA675411958337287310D3FF2F1DDC0CB93" " 7E70F57F75F833C021852B631D2B9A520E4431A03C5C3FCB5742DCD841D9FB12" " 771AA1620DCEC3F1583426066ED9DC3F7028C5B59202C88FDF20396E2FA0EC4F" " 5A22D9008F3043673931BC14A5046D6327398327900867E39CC61B2D1AFE2F48" " EC8E1E3861C68D257D7425F4E6F99ABD77D61F10CA100EFC14389071831B33DD" " 69CC8EABEF860D1DC2AAA84ABEAE5DFC91BC124DAF0F4C8EF5BBEA436751DE84" " 3A8063E827A024466F44C28614F93B0732A100D4A0D86D532FE1E22C7725E401" " #)\n" " (p #00C29D438F115825779631CD665A5739367F3E128ADC29766483A46CA80897E0" " 79B32881860B8F9A6A04C2614A904F6F2578DAE13EA67CD60AE3D0AA00A1FF9B" " 441485E44B2DC3D0B60260FBFE073B5AC72FAF67964DE15C8212C389D20DB9CF" " 54AF6AEF5C4196EAA56495DD30CF709F499D5AB30CA35E086C2A1589D6283F17" " 83#)\n" " (q #00D1984135231CB243FE959C0CBEF551EDD986AD7BEDF71EDF447BE3DA27AF46" " 79C974A6FA69E4D52FE796650623DE70622862713932AA2FD9F2EC856EAEAA77" " 88B4EA6084DC81C902F014829B18EA8B2666EC41586818E0589E18876065F97E" " 8D22CE2DA53A05951EC132DCEF41E70A9C35F4ACC268FFAC2ADF54FA1DA110B9" " 19#)\n" " (u #67CF0FD7635205DD80FA814EE9E9C267C17376BF3209FB5D1BC42890D2822A04" " 479DAF4D5B6ED69D0F8D1AF94164D07F8CD52ECEFE880641FA0F41DDAB1785E4" " A37A32F997A516480B4CD4F6482B9466A1765093ED95023CA32D5EDC1E34CEE9" " AF595BC51FE43C4BF810FA225AF697FB473B83815966188A4312C048B885E3F7" " #)\n" " )\n" ")\n"; /* The same key as above but without p, q and u to test the non CRT case. */ static const char sample_private_key_1_1[] = "(private-key\n" " (openpgp-rsa\n" " (n #009F56231A3D82E3E7D613D59D53E9AB921BEF9F08A782AED0B6E46ADBC853EC" " 7C71C422435A3CD8FA0DB9EFD55CD3295BADC4E8E2E2B94E15AE82866AB8ADE8" " 7E469FAE76DC3577DE87F1F419C4EB41123DFAF8D16922D5EDBAD6E9076D5A1C" " 958106F0AE5E2E9193C6B49124C64C2A241C4075D4AF16299EB87A6585BAE917" " DEF27FCDD165764D069BC18D16527B29DAAB549F7BBED4A7C6A842D203ED6613" " 6E2411744E432CD26D940132F25874483DCAEECDFD95744819CBCF1EA810681C" " 42907EBCB1C7EAFBE75C87EC32C5413EA10476545D3FC7B2ADB1B66B7F200918" " 664B0E5261C2895AA28B0DE321E921B3F877172CCCAB81F43EF98002916156F6" " CB#)\n" " (e #010001#)\n" " (d #07EF82500C403899934FE993AC5A36F14FF2DF38CF1EF315F205EE4C83EDAA19" " 8890FC23DE9AA933CAFB37B6A8A8DBA675411958337287310D3FF2F1DDC0CB93" " 7E70F57F75F833C021852B631D2B9A520E4431A03C5C3FCB5742DCD841D9FB12" " 771AA1620DCEC3F1583426066ED9DC3F7028C5B59202C88FDF20396E2FA0EC4F" " 5A22D9008F3043673931BC14A5046D6327398327900867E39CC61B2D1AFE2F48" " EC8E1E3861C68D257D7425F4E6F99ABD77D61F10CA100EFC14389071831B33DD" " 69CC8EABEF860D1DC2AAA84ABEAE5DFC91BC124DAF0F4C8EF5BBEA436751DE84" " 3A8063E827A024466F44C28614F93B0732A100D4A0D86D532FE1E22C7725E401" " #)\n" " )\n" ")\n"; /* The same key as above but just without q to test the non CRT case. This should fail. */ static const char sample_private_key_1_2[] = "(private-key\n" " (openpgp-rsa\n" " (n #009F56231A3D82E3E7D613D59D53E9AB921BEF9F08A782AED0B6E46ADBC853EC" " 7C71C422435A3CD8FA0DB9EFD55CD3295BADC4E8E2E2B94E15AE82866AB8ADE8" " 7E469FAE76DC3577DE87F1F419C4EB41123DFAF8D16922D5EDBAD6E9076D5A1C" " 958106F0AE5E2E9193C6B49124C64C2A241C4075D4AF16299EB87A6585BAE917" " DEF27FCDD165764D069BC18D16527B29DAAB549F7BBED4A7C6A842D203ED6613" " 6E2411744E432CD26D940132F25874483DCAEECDFD95744819CBCF1EA810681C" " 42907EBCB1C7EAFBE75C87EC32C5413EA10476545D3FC7B2ADB1B66B7F200918" " 664B0E5261C2895AA28B0DE321E921B3F877172CCCAB81F43EF98002916156F6" " CB#)\n" " (e #010001#)\n" " (d #07EF82500C403899934FE993AC5A36F14FF2DF38CF1EF315F205EE4C83EDAA19" " 8890FC23DE9AA933CAFB37B6A8A8DBA675411958337287310D3FF2F1DDC0CB93" " 7E70F57F75F833C021852B631D2B9A520E4431A03C5C3FCB5742DCD841D9FB12" " 771AA1620DCEC3F1583426066ED9DC3F7028C5B59202C88FDF20396E2FA0EC4F" " 5A22D9008F3043673931BC14A5046D6327398327900867E39CC61B2D1AFE2F48" " EC8E1E3861C68D257D7425F4E6F99ABD77D61F10CA100EFC14389071831B33DD" " 69CC8EABEF860D1DC2AAA84ABEAE5DFC91BC124DAF0F4C8EF5BBEA436751DE84" " 3A8063E827A024466F44C28614F93B0732A100D4A0D86D532FE1E22C7725E401" " #)\n" " (p #00C29D438F115825779631CD665A5739367F3E128ADC29766483A46CA80897E0" " 79B32881860B8F9A6A04C2614A904F6F2578DAE13EA67CD60AE3D0AA00A1FF9B" " 441485E44B2DC3D0B60260FBFE073B5AC72FAF67964DE15C8212C389D20DB9CF" " 54AF6AEF5C4196EAA56495DD30CF709F499D5AB30CA35E086C2A1589D6283F17" " 83#)\n" " (u #67CF0FD7635205DD80FA814EE9E9C267C17376BF3209FB5D1BC42890D2822A04" " 479DAF4D5B6ED69D0F8D1AF94164D07F8CD52ECEFE880641FA0F41DDAB1785E4" " A37A32F997A516480B4CD4F6482B9466A1765093ED95023CA32D5EDC1E34CEE9" " AF595BC51FE43C4BF810FA225AF697FB473B83815966188A4312C048B885E3F7" " #)\n" " )\n" ")\n"; static const char sample_public_key_1[] = "(public-key\n" " (rsa\n" " (n #009F56231A3D82E3E7D613D59D53E9AB921BEF9F08A782AED0B6E46ADBC853EC" " 7C71C422435A3CD8FA0DB9EFD55CD3295BADC4E8E2E2B94E15AE82866AB8ADE8" " 7E469FAE76DC3577DE87F1F419C4EB41123DFAF8D16922D5EDBAD6E9076D5A1C" " 958106F0AE5E2E9193C6B49124C64C2A241C4075D4AF16299EB87A6585BAE917" " DEF27FCDD165764D069BC18D16527B29DAAB549F7BBED4A7C6A842D203ED6613" " 6E2411744E432CD26D940132F25874483DCAEECDFD95744819CBCF1EA810681C" " 42907EBCB1C7EAFBE75C87EC32C5413EA10476545D3FC7B2ADB1B66B7F200918" " 664B0E5261C2895AA28B0DE321E921B3F877172CCCAB81F43EF98002916156F6" " CB#)\n" " (e #010001#)\n" " )\n" ")\n"; #endif /* USE_RSA */ static void show_sexp (const char *prefix, gcry_sexp_t a) { char *buf; size_t size; if (prefix) fputs (prefix, stderr); size = gcry_sexp_sprint (a, GCRYSEXP_FMT_ADVANCED, NULL, 0); buf = gcry_xmalloc (size); gcry_sexp_sprint (a, GCRYSEXP_FMT_ADVANCED, buf, size); fprintf (stderr, "%.*s", (int)size, buf); gcry_free (buf); } #if USE_RSA /* from ../cipher/pubkey-util.c */ static gpg_err_code_t _gcry_pk_util_get_nbits (gcry_sexp_t list, unsigned int *r_nbits) { char buf[50]; const char *s; size_t n; *r_nbits = 0; list = gcry_sexp_find_token (list, "nbits", 0); if (!list) return 0; /* No NBITS found. */ s = gcry_sexp_nth_data (list, 1, &n); if (!s || n >= DIM (buf) - 1 ) { /* NBITS given without a cdr. */ gcry_sexp_release (list); return GPG_ERR_INV_OBJ; } memcpy (buf, s, n); buf[n] = 0; *r_nbits = (unsigned int)strtoul (buf, NULL, 0); gcry_sexp_release (list); return 0; } #endif /* USE_RSA */ /* Convert STRING consisting of hex characters into its binary representation and return it as an allocated buffer. The valid length of the buffer is returned at R_LENGTH. The string is delimited by end of string. The function returns NULL on error. */ static void * data_from_hex (const char *string, size_t *r_length) { const char *s; unsigned char *buffer; size_t length; buffer = gcry_xmalloc (strlen(string)/2+1); length = 0; for (s=string; *s; s +=2 ) { if (!hexdigitp (s) || !hexdigitp (s+1)) die ("error parsing hex string `%s'\n", string); ((unsigned char*)buffer)[length++] = xtoi_2 (s); } *r_length = length; return buffer; } static void extract_cmp_data (gcry_sexp_t sexp, const char *name, const char *expected) { gcry_sexp_t l1; const void *a; size_t alen; void *b; size_t blen; l1 = gcry_sexp_find_token (sexp, name, 0); a = gcry_sexp_nth_data (l1, 1, &alen); b = data_from_hex (expected, &blen); if (!a) fail ("parameter \"%s\" missing in key\n", name); else if ( alen != blen || memcmp (a, b, alen) ) { fail ("parameter \"%s\" does not match expected value\n", name); if (verbose) { info ("expected: %s\n", expected); show_sexp ("sexp: ", sexp); } } gcry_free (b); gcry_sexp_release (l1); } #if USE_RSA || USE_ELGAMAL static void check_keys_crypt (gcry_sexp_t pkey, gcry_sexp_t skey, gcry_sexp_t plain0, gpg_err_code_t decrypt_fail_code) { gcry_sexp_t plain1, cipher, l; gcry_mpi_t x0, x1; int rc; int have_flags; /* Extract data from plaintext. */ l = gcry_sexp_find_token (plain0, "value", 0); x0 = gcry_sexp_nth_mpi (l, 1, GCRYMPI_FMT_USG); gcry_sexp_release (l); /* Encrypt data. */ rc = gcry_pk_encrypt (&cipher, plain0, pkey); if (rc) die ("encryption failed: %s\n", gcry_strerror (rc)); l = gcry_sexp_find_token (cipher, "flags", 0); have_flags = !!l; gcry_sexp_release (l); /* Decrypt data. */ rc = gcry_pk_decrypt (&plain1, cipher, skey); gcry_sexp_release (cipher); if (rc) { if (decrypt_fail_code && gpg_err_code (rc) == decrypt_fail_code) { gcry_mpi_release (x0); return; /* This is the expected failure code. */ } die ("decryption failed: %s\n", gcry_strerror (rc)); } /* Extract decrypted data. Note that for compatibility reasons, the output of gcry_pk_decrypt depends on whether a flags lists (even if empty) occurs in its input data. Because we passed the output of encrypt directly to decrypt, such a flag value won't be there as of today. We check it anyway. */ l = gcry_sexp_find_token (plain1, "value", 0); if (l) { if (!have_flags) die ("compatibility mode of pk_decrypt broken\n"); gcry_sexp_release (plain1); x1 = gcry_sexp_nth_mpi (l, 1, GCRYMPI_FMT_USG); gcry_sexp_release (l); } else { if (have_flags) die ("compatibility mode of pk_decrypt broken\n"); x1 = gcry_sexp_nth_mpi (plain1, 0, GCRYMPI_FMT_USG); gcry_sexp_release (plain1); } /* Compare. */ if (gcry_mpi_cmp (x0, x1)) die ("data corrupted\n"); gcry_mpi_release (x0); gcry_mpi_release (x1); } static void check_keys (gcry_sexp_t pkey, gcry_sexp_t skey, unsigned int nbits_data, gpg_err_code_t decrypt_fail_code) { gcry_sexp_t plain; gcry_mpi_t x; int rc; /* Create plain text. */ x = gcry_mpi_new (nbits_data); gcry_mpi_randomize (x, nbits_data, GCRY_WEAK_RANDOM); rc = gcry_sexp_build (&plain, NULL, "(data (flags raw) (value %m))", x); if (rc) die ("converting data for encryption failed: %s\n", gcry_strerror (rc)); check_keys_crypt (pkey, skey, plain, decrypt_fail_code); gcry_sexp_release (plain); gcry_mpi_release (x); /* Create plain text. */ x = gcry_mpi_new (nbits_data); gcry_mpi_randomize (x, nbits_data, GCRY_WEAK_RANDOM); rc = gcry_sexp_build (&plain, NULL, "(data (flags raw no-blinding) (value %m))", x); gcry_mpi_release (x); if (rc) die ("converting data for encryption failed: %s\n", gcry_strerror (rc)); check_keys_crypt (pkey, skey, plain, decrypt_fail_code); gcry_sexp_release (plain); } #endif /* USE_RSA || USE_ELGAMAL */ #if USE_RSA static void get_keys_sample (gcry_sexp_t *pkey, gcry_sexp_t *skey, int secret_variant) { gcry_sexp_t pub_key, sec_key; int rc; static const char *secret; switch (secret_variant) { case 0: secret = sample_private_key_1; break; case 1: secret = sample_private_key_1_1; break; case 2: secret = sample_private_key_1_2; break; default: die ("BUG\n"); } rc = gcry_sexp_sscan (&pub_key, NULL, sample_public_key_1, strlen (sample_public_key_1)); if (!rc) rc = gcry_sexp_sscan (&sec_key, NULL, secret, strlen (secret)); if (rc) die ("converting sample keys failed: %s\n", gcry_strerror (rc)); *pkey = pub_key; *skey = sec_key; } static void get_keys_new (gcry_sexp_t *pkey, gcry_sexp_t *skey) { gcry_sexp_t key_spec, key, pub_key, sec_key; int rc; rc = gcry_sexp_new (&key_spec, "(genkey (rsa (nbits 4:2048)))", 0, 1); if (rc) die ("error creating S-expression: %s\n", gcry_strerror (rc)); rc = gcry_pk_genkey (&key, key_spec); gcry_sexp_release (key_spec); if (rc) die ("error generating RSA key: %s\n", gcry_strerror (rc)); if (verbose > 1) show_sexp ("generated RSA key:\n", key); pub_key = gcry_sexp_find_token (key, "public-key", 0); if (! pub_key) die ("public part missing in key\n"); sec_key = gcry_sexp_find_token (key, "private-key", 0); if (! sec_key) die ("private part missing in key\n"); gcry_sexp_release (key); *pkey = pub_key; *skey = sec_key; } static void get_keys_x931_new (gcry_sexp_t *pkey, gcry_sexp_t *skey) { gcry_sexp_t key_spec, key, pub_key, sec_key; int rc; rc = gcry_sexp_new (&key_spec, "(genkey (rsa (nbits 4:2048)(use-x931)))", 0, 1); if (rc) die ("error creating S-expression: %s\n", gcry_strerror (rc)); rc = gcry_pk_genkey (&key, key_spec); gcry_sexp_release (key_spec); if (rc) { if (in_fips_mode) { if (verbose) fprintf (stderr, "The X9.31 RSA keygen is not available in FIPS modee.\n"); return; } die ("error generating RSA key: %s\n", gcry_strerror (rc)); } else if (in_fips_mode) die ("generating X9.31 RSA key unexpected worked in FIPS mode\n"); if (verbose > 1) show_sexp ("generated RSA (X9.31) key:\n", key); pub_key = gcry_sexp_find_token (key, "public-key", 0); if (!pub_key) die ("public part missing in key\n"); sec_key = gcry_sexp_find_token (key, "private-key", 0); if (!sec_key) die ("private part missing in key\n"); gcry_sexp_release (key); *pkey = pub_key; *skey = sec_key; } #endif /* USE_RSA */ #if USE_ELGAMAL static void get_elg_key_new (gcry_sexp_t *pkey, gcry_sexp_t *skey, int fixed_x) { gcry_sexp_t key_spec, key, pub_key, sec_key; int rc; rc = gcry_sexp_new (&key_spec, (fixed_x ? "(genkey (elg (nbits 4:1024)(xvalue my.not-so-secret.key)))" : "(genkey (elg (nbits 3:512)))"), 0, 1); if (rc) die ("error creating S-expression: %s\n", gcry_strerror (rc)); rc = gcry_pk_genkey (&key, key_spec); gcry_sexp_release (key_spec); if (rc) { if (in_fips_mode) { if (verbose) fprintf (stderr, "The Elgamal keys are not available in FIPS modee.\n"); return; } die ("error generating Elgamal key: %s\n", gcry_strerror (rc)); } if (verbose > 1) show_sexp ("generated ELG key:\n", key); pub_key = gcry_sexp_find_token (key, "public-key", 0); if (!pub_key) die ("public part missing in key\n"); sec_key = gcry_sexp_find_token (key, "private-key", 0); if (!sec_key) die ("private part missing in key\n"); gcry_sexp_release (key); *pkey = pub_key; *skey = sec_key; } #endif /* USE_ELGAMAL */ #if USE_DSA static void get_dsa_key_new (gcry_sexp_t *pkey, gcry_sexp_t *skey, int transient_key) { gcry_sexp_t key_spec, key, pub_key, sec_key; int rc; rc = gcry_sexp_new (&key_spec, transient_key ? "(genkey (dsa (nbits 4:2048)(transient-key)))" : "(genkey (dsa (nbits 4:2048)))", 0, 1); if (rc) die ("error creating S-expression: %s\n", gcry_strerror (rc)); rc = gcry_pk_genkey (&key, key_spec); gcry_sexp_release (key_spec); if (rc) { if (in_fips_mode) { if (verbose) fprintf (stderr, "The DSA keys are not available in FIPS modee.\n"); return; } die ("error generating DSA key: %s\n", gcry_strerror (rc)); } if (verbose > 1) show_sexp ("generated DSA key:\n", key); pub_key = gcry_sexp_find_token (key, "public-key", 0); if (!pub_key) die ("public part missing in key\n"); sec_key = gcry_sexp_find_token (key, "private-key", 0); if (!sec_key) die ("private part missing in key\n"); gcry_sexp_release (key); *pkey = pub_key; *skey = sec_key; } static void get_dsa_key_fips186_new (gcry_sexp_t *pkey, gcry_sexp_t *skey) { gcry_sexp_t key_spec, key, pub_key, sec_key; int rc; rc = gcry_sexp_new (&key_spec, "(genkey (dsa (nbits 4:2048)(use-fips186)))", 0, 1); if (rc) die ("error creating S-expression: %s\n", gcry_strerror (rc)); rc = gcry_pk_genkey (&key, key_spec); gcry_sexp_release (key_spec); if (rc) { if (in_fips_mode) { if (verbose) fprintf (stderr, "The DSA keys are not available in FIPS modee.\n"); return; } die ("error generating DSA key: %s\n", gcry_strerror (rc)); } if (verbose > 1) show_sexp ("generated DSA key (fips 186):\n", key); pub_key = gcry_sexp_find_token (key, "public-key", 0); if (!pub_key) die ("public part missing in key\n"); sec_key = gcry_sexp_find_token (key, "private-key", 0); if (!sec_key) die ("private part missing in key\n"); gcry_sexp_release (key); *pkey = pub_key; *skey = sec_key; } static void get_dsa_key_with_domain_new (gcry_sexp_t *pkey, gcry_sexp_t *skey) { gcry_sexp_t key_spec, key, pub_key, sec_key; int rc; rc = gcry_sexp_new (&key_spec, "(genkey (dsa (transient-key)(domain" "(p #a8adb6c0b4cf9588012e5deff1a871d383e0e2a85b5e8e03d814fe13a059705e" "663230a377bf7323a8fa117100200bfd5adf857393b0bbd67906c081e585410e" "38480ead51684dac3a38f7b64c9eb109f19739a4517cd7d5d6291e8af20a3fbf" "17336c7bf80ee718ee087e322ee41047dabefbcc34d10b66b644ddb3160a28c0" "639563d71993a26543eadb7718f317bf5d9577a6156561b082a10029cd44012b" "18de6844509fe058ba87980792285f2750969fe89c2cd6498db3545638d5379d" "125dccf64e06c1af33a6190841d223da1513333a7c9d78462abaab31b9f96d5f" "34445ceb6309f2f6d2c8dde06441e87980d303ef9a1ff007e8be2f0be06cc15f#)" "(q #e71f8567447f42e75f5ef85ca20fe557ab0343d37ed09edc3f6e68604d6b9dfb#)" "(g #5ba24de9607b8998e66ce6c4f812a314c6935842f7ab54cd82b19fa104abfb5d" "84579a623b2574b37d22ccae9b3e415e48f5c0f9bcbdff8071d63b9bb956e547" "af3a8df99e5d3061979652ff96b765cb3ee493643544c75dbe5bb39834531952" "a0fb4b0378b3fcbb4c8b5800a5330392a2a04e700bb6ed7e0b85795ea38b1b96" "2741b3f33b9dde2f4ec1354f09e2eb78e95f037a5804b6171659f88715ce1a9b" "0cc90c27f35ef2f10ff0c7c7a2bb0154d9b8ebe76a3d764aa879af372f4240de" "8347937e5a90cec9f41ff2f26b8da9a94a225d1a913717d73f10397d2183f1ba" "3b7b45a68f1ff1893caf69a827802f7b6a48d51da6fbefb64fd9a6c5b75c4561#)" ")))", 0, 1); if (rc) die ("error creating S-expression: %s\n", gcry_strerror (rc)); rc = gcry_pk_genkey (&key, key_spec); gcry_sexp_release (key_spec); if (rc) { if (in_fips_mode) { if (verbose) fprintf (stderr, "The DSA keys are not available in FIPS modee.\n"); return; } die ("error generating DSA key: %s\n", gcry_strerror (rc)); } if (verbose > 1) show_sexp ("generated DSA key:\n", key); pub_key = gcry_sexp_find_token (key, "public-key", 0); if (!pub_key) die ("public part missing in key\n"); sec_key = gcry_sexp_find_token (key, "private-key", 0); if (!sec_key) die ("private part missing in key\n"); gcry_sexp_release (key); *pkey = pub_key; *skey = sec_key; } #if 0 static void get_dsa_key_fips186_with_domain_new (gcry_sexp_t *pkey, gcry_sexp_t *skey) { gcry_sexp_t key_spec, key, pub_key, sec_key; int rc; rc = gcry_sexp_new (&key_spec, "(genkey (dsa (transient-key)(use-fips186)(domain" "(p #d3aed1876054db831d0c1348fbb1ada72507e5fbf9a62cbd47a63aeb7859d6921" "4adeb9146a6ec3f43520f0fd8e3125dd8bbc5d87405d1ac5f82073cd762a3f8d7" "74322657c9da88a7d2f0e1a9ceb84a39cb40876179e6a76e400498de4bb9379b0" "5f5feb7b91eb8fea97ee17a955a0a8a37587a272c4719d6feb6b54ba4ab69#)" "(q #9c916d121de9a03f71fb21bc2e1c0d116f065a4f#)" "(g #8157c5f68ca40b3ded11c353327ab9b8af3e186dd2e8dade98761a0996dda99ab" "0250d3409063ad99efae48b10c6ab2bba3ea9a67b12b911a372a2bba260176fad" "b4b93247d9712aad13aa70216c55da9858f7a298deb670a403eb1e7c91b847f1e" "ccfbd14bd806fd42cf45dbb69cd6d6b43add2a78f7d16928eaa04458dea44#)" ")))", 0, 1); if (rc) die ("error creating S-expression: %s\n", gcry_strerror (rc)); rc = gcry_pk_genkey (&key, key_spec); gcry_sexp_release (key_spec); if (rc) die ("error generating DSA key: %s\n", gcry_strerror (rc)); if (verbose > 1) show_sexp ("generated DSA key:\n", key); pub_key = gcry_sexp_find_token (key, "public-key", 0); if (!pub_key) die ("public part missing in key\n"); sec_key = gcry_sexp_find_token (key, "private-key", 0); if (!sec_key) die ("private part missing in key\n"); gcry_sexp_release (key); *pkey = pub_key; *skey = sec_key; } #endif /*0*/ static void get_dsa_key_fips186_with_seed_new (gcry_sexp_t *pkey, gcry_sexp_t *skey) { gcry_sexp_t key_spec, key, pub_key, sec_key; int rc; rc = gcry_sexp_new (&key_spec, "(genkey" " (dsa" " (nbits 4:2048)" " (qbits 3:256)" " (use-fips186)" " (transient-key)" " (derive-parms" " (seed #f770a4598ff756931fc529764513b103ce57d85f4ad8c5cf297c9b4d48241c5b#))))", 0, 1); if (rc) die ("error creating S-expression: %s\n", gcry_strerror (rc)); rc = gcry_pk_genkey (&key, key_spec); gcry_sexp_release (key_spec); if (rc) { if (in_fips_mode) { if (verbose) fprintf (stderr, "The DSA keys are not available in FIPS modee.\n"); return; } die ("error generating DSA key: %s\n", gcry_strerror (rc)); } if (verbose > 1) show_sexp ("generated DSA key (fips 186 with seed):\n", key); pub_key = gcry_sexp_find_token (key, "public-key", 0); if (!pub_key) die ("public part missing in key\n"); sec_key = gcry_sexp_find_token (key, "private-key", 0); if (!sec_key) die ("private part missing in key\n"); gcry_sexp_release (key); *pkey = pub_key; *skey = sec_key; } #endif /* USE_ELGAMAL */ static void check_run (void) { gpg_error_t err; gcry_sexp_t pkey, skey; int variant; (void) err; (void) pkey; (void) skey; (void) variant; #if USE_RSA pkey = skey = NULL; for (variant=0; variant < 3; variant++) { if (verbose) fprintf (stderr, "Checking sample key (%d).\n", variant); get_keys_sample (&pkey, &skey, variant); /* Check gcry_pk_testkey which requires all elements. */ err = gcry_pk_testkey (skey); if ((variant == 0 && err) || (variant > 0 && gpg_err_code (err) != GPG_ERR_NO_OBJ)) die ("gcry_pk_testkey failed: %s\n", gpg_strerror (err)); /* Run the usual check but expect an error from variant 2. */ check_keys (pkey, skey, 800, variant == 2? GPG_ERR_NO_OBJ : 0); gcry_sexp_release (pkey); gcry_sexp_release (skey); pkey = skey = NULL; } #endif /* USE_RSA */ #if USE_RSA if (verbose) fprintf (stderr, "Checking generated RSA key.\n"); get_keys_new (&pkey, &skey); check_keys (pkey, skey, 800, 0); gcry_sexp_release (pkey); gcry_sexp_release (skey); pkey = skey = NULL; if (verbose) fprintf (stderr, "Checking generated RSA key (X9.31).\n"); get_keys_x931_new (&pkey, &skey); if (!in_fips_mode) check_keys (pkey, skey, 800, 0); gcry_sexp_release (pkey); gcry_sexp_release (skey); pkey = skey = NULL; #endif /* USE_RSA */ #if USE_ELGAMAL if (verbose) fprintf (stderr, "Checking generated Elgamal key.\n"); get_elg_key_new (&pkey, &skey, 0); if (!in_fips_mode) check_keys (pkey, skey, 400, 0); gcry_sexp_release (pkey); gcry_sexp_release (skey); pkey = skey = NULL; if (verbose) fprintf (stderr, "Checking passphrase generated Elgamal key.\n"); get_elg_key_new (&pkey, &skey, 1); if (!in_fips_mode) check_keys (pkey, skey, 800, 0); gcry_sexp_release (pkey); gcry_sexp_release (skey); pkey = skey = NULL; #endif /* USE_ELGAMAL */ #if USE_DSA if (verbose) fprintf (stderr, "Generating DSA key.\n"); get_dsa_key_new (&pkey, &skey, 0); if (!in_fips_mode) { /* Fixme: Add a check function for DSA keys. */ ; } gcry_sexp_release (pkey); gcry_sexp_release (skey); pkey = skey = NULL; if (verbose) fprintf (stderr, "Generating transient DSA key.\n"); get_dsa_key_new (&pkey, &skey, 1); if (!in_fips_mode) { /* Fixme: Add a check function for DSA keys. */ ; } gcry_sexp_release (pkey); gcry_sexp_release (skey); pkey = skey = NULL; if (verbose) fprintf (stderr, "Generating DSA key (FIPS 186).\n"); get_dsa_key_fips186_new (&pkey, &skey); if (!in_fips_mode) { /* Fixme: Add a check function for DSA keys. */ ; } gcry_sexp_release (pkey); gcry_sexp_release (skey); pkey = skey = NULL; if (verbose) fprintf (stderr, "Generating DSA key with given domain.\n"); get_dsa_key_with_domain_new (&pkey, &skey); if (!in_fips_mode) { /* Fixme: Add a check function for DSA keys. */ ; } gcry_sexp_release (pkey); gcry_sexp_release (skey); pkey = skey = NULL; /* We need new test vectors for get_dsa_key_fips186_with_domain_new. */ if (verbose) fprintf (stderr, "Generating DSA key with given domain (FIPS 186)" " - skipped.\n"); /* get_dsa_key_fips186_with_domain_new (&pkey, &skey); */ /* /\* Fixme: Add a check function for DSA keys. *\/ */ /* gcry_sexp_release (pkey); */ /* gcry_sexp_release (skey); */ if (verbose) fprintf (stderr, "Generating DSA key with given seed (FIPS 186).\n"); get_dsa_key_fips186_with_seed_new (&pkey, &skey); if (!in_fips_mode) { /* Fixme: Add a check function for DSA keys. */ ; } gcry_sexp_release (pkey); gcry_sexp_release (skey); pkey = skey = NULL; #endif /* USE_DSA */ } #ifdef USE_RSA static gcry_mpi_t key_param_from_sexp (gcry_sexp_t sexp, const char *topname, const char *name) { gcry_sexp_t l1, l2; gcry_mpi_t result; l1 = gcry_sexp_find_token (sexp, topname, 0); if (!l1) return NULL; l2 = gcry_sexp_find_token (l1, name, 0); if (!l2) { gcry_sexp_release (l1); return NULL; } result = gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG); gcry_sexp_release (l2); gcry_sexp_release (l1); return result; } static void check_x931_derived_key (int what) { static struct { const char *param; const char *expected_d; } testtable[] = { { /* First example from X9.31 (D.1.1). */ "(genkey\n" " (rsa\n" " (nbits 4:1024)\n" " (rsa-use-e 1:3)\n" " (derive-parms\n" " (Xp1 #1A1916DDB29B4EB7EB6732E128#)\n" " (Xp2 #192E8AAC41C576C822D93EA433#)\n" " (Xp #D8CD81F035EC57EFE822955149D3BFF70C53520D\n" " 769D6D76646C7A792E16EBD89FE6FC5B605A6493\n" " 39DFC925A86A4C6D150B71B9EEA02D68885F5009\n" " B98BD984#)\n" " (Xq1 #1A5CF72EE770DE50CB09ACCEA9#)\n" " (Xq2 #134E4CAA16D2350A21D775C404#)\n" " (Xq #CC1092495D867E64065DEE3E7955F2EBC7D47A2D\n" " 7C9953388F97DDDC3E1CA19C35CA659EDC2FC325\n" " 6D29C2627479C086A699A49C4C9CEE7EF7BD1B34\n" " 321DE34A#))))\n", "1CCDA20BCFFB8D517EE9666866621B11822C7950D55F4BB5BEE37989A7D173" "12E326718BE0D79546EAAE87A56623B919B1715FFBD7F16028FC4007741961" "C88C5D7B4DAAAC8D36A98C9EFBB26C8A4A0E6BC15B358E528A1AC9D0F042BE" "B93BCA16B541B33F80C933A3B769285C462ED5677BFE89DF07BED5C127FD13" "241D3C4B" }, { /* Second example from X9.31 (D.2.1). */ "(genkey\n" " (rsa\n" " (nbits 4:1536)\n" " (rsa-use-e 1:3)\n" " (derive-parms\n" " (Xp1 #18272558B61316348297EACA74#)\n" " (Xp2 #1E970E8C6C97CEF91F05B0FA80#)\n" " (Xp #F7E943C7EF2169E930DCF23FE389EF7507EE8265\n" " 0D42F4A0D3A3CEFABE367999BB30EE680B2FE064\n" " 60F707F46005F8AA7CBFCDDC4814BBE7F0F8BC09\n" " 318C8E51A48D134296E40D0BBDD282DCCBDDEE1D\n" " EC86F0B1C96EAFF5CDA70F9AEB6EE31E#)\n" " (Xq1 #11FDDA6E8128DC1629F75192BA#)\n" " (Xq2 #18AB178ECA907D72472F65E480#)\n" " (Xq #C47560011412D6E13E3E7D007B5C05DBF5FF0D0F\n" " CFF1FA2070D16C7ABA93EDFB35D8700567E5913D\n" " B734E3FBD15862EBC59FA0425DFA131E549136E8\n" " E52397A8ABE4705EC4877D4F82C4AAC651B33DA6\n" " EA14B9D5F2A263DC65626E4D6CEAC767#))))\n", "1FB56069985F18C4519694FB71055721A01F14422DC901C35B03A64D4A5BD1" "259D573305F5B056AC931B82EDB084E39A0FD1D1A86CC5B147A264F7EF4EB2" "0ED1E7FAAE5CAE4C30D5328B7F74C3CAA72C88B70DED8EDE207B8629DA2383" "B78C3CE1CA3F9F218D78C938B35763AF2A8714664CC57F5CECE2413841F5E9" "EDEC43B728E25A41BF3E1EF8D9EEE163286C9F8BF0F219D3B322C3E4B0389C" "2E8BB28DC04C47DA2BF38823731266D2CF6CC3FC181738157624EF051874D0" "BBCCB9F65C83" /* Note that this example in X9.31 gives this value for D: "7ED581A6617C6311465A53EDC4155C86807C5108B724070D6C0E9935296F44" "96755CCC17D6C15AB24C6E0BB6C2138E683F4746A1B316C51E8993DFBD3AC8" "3B479FEAB972B930C354CA2DFDD30F2A9CB222DC37B63B7881EE18A7688E0E" "DE30F38728FE7C8635E324E2CD5D8EBCAA1C51993315FD73B38904E107D7A7" "B7B10EDCA3896906FCF87BE367BB858CA1B27E2FC3C8674ECC8B0F92C0E270" "BA2ECA3701311F68AFCE208DCC499B4B3DB30FF0605CE055D893BC1461D342" "EF32E7D9720B" This is a bug in X9.31, obviously introduced by using d = e^{-1} mod (p-1)(q-1) instead of using the universal exponent as required by 4.1.3: d = e^{-1} mod lcm(p-1,q-1) The examples in X9.31 seem to be pretty buggy, see cipher/primegen.c for another bug. Not only that I had to spend 100 USD for the 66 pages of the document, it also took me several hours to figure out that the bugs are in the document and not in my code. */ }, { /* First example from NIST RSAVS (B.1.1). */ "(genkey\n" " (rsa\n" " (nbits 4:1024)\n" " (rsa-use-e 1:3)\n" " (derive-parms\n" " (Xp1 #1ed3d6368e101dab9124c92ac8#)\n" " (Xp2 #16e5457b8844967ce83cab8c11#)\n" " (Xp #b79f2c2493b4b76f329903d7555b7f5f06aaa5ea\n" " ab262da1dcda8194720672a4e02229a0c71f60ae\n" " c4f0d2ed8d49ef583ca7d5eeea907c10801c302a\n" " cab44595#)\n" " (Xq1 #1a5d9e3fa34fb479bedea412f6#)\n" " (Xq2 #1f9cca85f185341516d92e82fd#)\n" " (Xq #c8387fd38fa33ddcea6a9de1b2d55410663502db\n" " c225655a9310cceac9f4cf1bce653ec916d45788\n" " f8113c46bc0fa42bf5e8d0c41120c1612e2ea8bb\n" " 2f389eda#))))\n", "17ef7ad4fd96011b62d76dfb2261b4b3270ca8e07bc501be954f8719ef586b" "f237e8f693dd16c23e7adecc40279dc6877c62ab541df5849883a5254fccfd" "4072a657b7f4663953930346febd6bbd82f9a499038402cbf97fd5f068083a" "c81ad0335c4aab0da19cfebe060a1bac7482738efafea078e21df785e56ea0" "dc7e8feb" }, { /* Second example from NIST RSAVS (B.1.1). */ "(genkey\n" " (rsa\n" " (nbits 4:1536)\n" " (rsa-use-e 1:3)\n" " (derive-parms\n" " (Xp1 #1e64c1af460dff8842c22b64d0#)\n" " (Xp2 #1e948edcedba84039c81f2ac0c#)\n" " (Xp #c8c67df894c882045ede26a9008ab09ea0672077\n" " d7bc71d412511cd93981ddde8f91b967da404056\n" " c39f105f7f239abdaff92923859920f6299e82b9\n" " 5bd5b8c959948f4a034d81613d6235a3953b49ce\n" " 26974eb7bb1f14843841281b363b9cdb#)\n" " (Xq1 #1f3df0f017ddd05611a97b6adb#)\n" " (Xq2 #143edd7b22d828913abf24ca4d#)\n" " (Xq #f15147d0e7c04a1e3f37adde802cdc610999bf7a\n" " b0088434aaeda0c0ab3910b14d2ce56cb66bffd9\n" " 7552195fae8b061077e03920814d8b9cfb5a3958\n" " b3a82c2a7fc97e55db543948d3396289245336ec\n" " 9e3cb308cc655aebd766340da8921383#))))\n", "1f8b19f3f5f2ac9fc599f110cad403dcd9bdf5f7f00fb2790e78e820398184" "1f3fb3dd230fb223d898f45719d9b2d3525587ff2b8bcc7425e40550a5b536" "1c8e9c1d26e83fbd9c33c64029c0e878b829d55def12912b73d94fd758c461" "0f473e230c41b5e4c86e27c5a5029d82c811c88525d0269b95bd2ff272994a" "dbd80f2c2ecf69065feb8abd8b445b9c6d306b1585d7d3d7576d49842bc7e2" "8b4a2f88f4a47e71c3edd35fdf83f547ea5c2b532975c551ed5268f748b2c4" "2ccf8a84835b" } }; gpg_error_t err; gcry_sexp_t key_spec = NULL, key = NULL, pub_key = NULL, sec_key = NULL; gcry_mpi_t d_expected = NULL, d_have = NULL; if (what < 0 && what >= sizeof testtable) die ("invalid WHAT value\n"); err = gcry_sexp_new (&key_spec, testtable[what].param, 0, 1); if (err) die ("error creating S-expression [%d]: %s\n", what, gpg_strerror (err)); { unsigned nbits; err = _gcry_pk_util_get_nbits(key_spec, &nbits); if (err) die ("nbits not found\n"); if (in_fips_mode && nbits < 2048) { info("RSA key test with %d bits skipped in fips mode\n", nbits); gcry_sexp_release (key_spec); goto leave; } } err = gcry_pk_genkey (&key, key_spec); gcry_sexp_release (key_spec); if (err) { fail ("error generating RSA key [%d]: %s\n", what, gpg_strerror (err)); goto leave; } pub_key = gcry_sexp_find_token (key, "public-key", 0); if (!pub_key) die ("public part missing in key [%d]\n", what); sec_key = gcry_sexp_find_token (key, "private-key", 0); if (!sec_key) die ("private part missing in key [%d]\n", what); err = gcry_mpi_scan (&d_expected, GCRYMPI_FMT_HEX, testtable[what].expected_d, 0, NULL); if (err) die ("error converting string [%d]\n", what); if (verbose > 1) show_sexp ("generated key:\n", key); d_have = key_param_from_sexp (sec_key, "rsa", "d"); if (!d_have) die ("parameter d not found in RSA secret key [%d]\n", what); if (gcry_mpi_cmp (d_expected, d_have)) { show_sexp (NULL, sec_key); die ("parameter d does match expected value [%d]\n", what); } leave: gcry_mpi_release (d_expected); gcry_mpi_release (d_have); gcry_sexp_release (key); gcry_sexp_release (pub_key); gcry_sexp_release (sec_key); } #endif /* USE_RSA */ #if USE_ECC static void check_ecc_sample_key (void) { static const char ecc_private_key[] = "(private-key\n" " (ecdsa\n" " (curve \"NIST P-256\")\n" " (q #04D4F6A6738D9B8D3A7075C1E4EE95015FC0C9B7E4272D2BEB6644D3609FC781" "B71F9A8072F58CB66AE2F89BB12451873ABF7D91F9E1FBF96BF2F70E73AAC9A283#)\n" " (d #5A1EF0035118F19F3110FB81813D3547BCE1E5BCE77D1F744715E1D5BBE70378#)" "))"; static const char ecc_private_key_wo_q[] = "(private-key\n" " (ecdsa\n" " (curve \"NIST P-256\")\n" " (d #5A1EF0035118F19F3110FB81813D3547BCE1E5BCE77D1F744715E1D5BBE70378#)" "))"; static const char ecc_public_key[] = "(public-key\n" " (ecdsa\n" " (curve \"NIST P-256\")\n" " (q #04D4F6A6738D9B8D3A7075C1E4EE95015FC0C9B7E4272D2BEB6644D3609FC781" "B71F9A8072F58CB66AE2F89BB12451873ABF7D91F9E1FBF96BF2F70E73AAC9A283#)" "))"; static const char hash_string[] = "(data (flags raw)\n" " (value #00112233445566778899AABBCCDDEEFF" /* */ "000102030405060708090A0B0C0D0E0F#))"; static const char hash2_string[] = "(data (flags raw)\n" " (hash sha1 #00112233445566778899AABBCCDDEEFF" /* */ "000102030405060708090A0B0C0D0E0F" /* */ "000102030405060708090A0B0C0D0E0F" /* */ "00112233445566778899AABBCCDDEEFF#))"; /* hash2, but longer than curve length, so it will be truncated */ static const char hash3_string[] = "(data (flags raw)\n" " (hash sha1 #00112233445566778899AABBCCDDEEFF" /* */ "000102030405060708090A0B0C0D0E0F" /* */ "000102030405060708090A0B0C0D0E0F" /* */ "00112233445566778899AABBCCDDEEFF" /* */ "000102030405060708090A0B0C0D0E0F#))"; gpg_error_t err; gcry_sexp_t key, hash, hash2, hash3, sig, sig2; if (verbose) fprintf (stderr, "Checking sample ECC key.\n"); if ((err = gcry_sexp_new (&hash, hash_string, 0, 1))) die ("line %d: %s", __LINE__, gpg_strerror (err)); if ((err = gcry_sexp_new (&hash2, hash2_string, 0, 1))) die ("line %d: %s", __LINE__, gpg_strerror (err)); if ((err = gcry_sexp_new (&hash3, hash3_string, 0, 1))) die ("line %d: %s", __LINE__, gpg_strerror (err)); if ((err = gcry_sexp_new (&key, ecc_private_key, 0, 1))) die ("line %d: %s", __LINE__, gpg_strerror (err)); if ((err = gcry_pk_sign (&sig, hash, key))) die ("gcry_pk_sign failed: %s", gpg_strerror (err)); gcry_sexp_release (key); if ((err = gcry_sexp_new (&key, ecc_public_key, 0, 1))) die ("line %d: %s", __LINE__, gpg_strerror (err)); if ((err = gcry_pk_verify (sig, hash, key))) die ("gcry_pk_verify failed: %s", gpg_strerror (err)); /* Verify hash truncation */ gcry_sexp_release (key); if ((err = gcry_sexp_new (&key, ecc_private_key, 0, 1))) die ("line %d: %s", __LINE__, gpg_strerror (err)); if ((err = gcry_pk_sign (&sig2, hash2, key))) die ("gcry_pk_sign failed: %s", gpg_strerror (err)); gcry_sexp_release (sig); if ((err = gcry_pk_sign (&sig, hash3, key))) die ("gcry_pk_sign failed: %s", gpg_strerror (err)); gcry_sexp_release (key); if ((err = gcry_sexp_new (&key, ecc_public_key, 0, 1))) die ("line %d: %s", __LINE__, gpg_strerror (err)); if ((err = gcry_pk_verify (sig, hash2, key))) die ("gcry_pk_verify failed: %s", gpg_strerror (err)); if ((err = gcry_pk_verify (sig2, hash3, key))) die ("gcry_pk_verify failed: %s", gpg_strerror (err)); /* Now try signing without the Q parameter. */ gcry_sexp_release (key); if ((err = gcry_sexp_new (&key, ecc_private_key_wo_q, 0, 1))) die ("line %d: %s", __LINE__, gpg_strerror (err)); gcry_sexp_release (sig); if ((err = gcry_pk_sign (&sig, hash, key))) die ("gcry_pk_sign without Q failed: %s", gpg_strerror (err)); gcry_sexp_release (key); if ((err = gcry_sexp_new (&key, ecc_public_key, 0, 1))) die ("line %d: %s", __LINE__, gpg_strerror (err)); if ((err = gcry_pk_verify (sig, hash, key))) die ("gcry_pk_verify signed without Q failed: %s", gpg_strerror (err)); gcry_sexp_release (sig); gcry_sexp_release (sig2); gcry_sexp_release (key); gcry_sexp_release (hash); gcry_sexp_release (hash2); gcry_sexp_release (hash3); } static void check_ed25519ecdsa_sample_key (void) { static const char ecc_private_key[] = "(private-key\n" " (ecc\n" " (curve \"Ed25519\")\n" " (q #044C056555BE4084BB3D8D8895FDF7C2893DFE0256251923053010977D12658321" " 156D1ADDC07987713A418783658B476358D48D582DB53233D9DED3C1C2577B04#)" " (d #09A0C38E0F1699073541447C19DA12E3A07A7BFDB0C186E4AC5BCE6F23D55252#)" "))"; static const char ecc_private_key_wo_q[] = "(private-key\n" " (ecc\n" " (curve \"Ed25519\")\n" " (d #09A0C38E0F1699073541447C19DA12E3A07A7BFDB0C186E4AC5BCE6F23D55252#)" "))"; static const char ecc_public_key[] = "(public-key\n" " (ecc\n" " (curve \"Ed25519\")\n" " (q #044C056555BE4084BB3D8D8895FDF7C2893DFE0256251923053010977D12658321" " 156D1ADDC07987713A418783658B476358D48D582DB53233D9DED3C1C2577B04#)" "))"; static const char ecc_public_key_comp[] = "(public-key\n" " (ecc\n" " (curve \"Ed25519\")\n" " (q #047b57c2c1d3ded93332b52d588dd45863478b658387413a718779c0dd1a6d95#)" "))"; static const char hash_string[] = "(data (flags rfc6979)\n" " (hash sha256 #00112233445566778899AABBCCDDEEFF" /* */ "000102030405060708090A0B0C0D0E0F#))"; gpg_error_t err; gcry_sexp_t key, hash, sig; if (verbose) fprintf (stderr, "Checking sample Ed25519/ECDSA key.\n"); /* Sign. */ if ((err = gcry_sexp_new (&hash, hash_string, 0, 1))) die ("line %d: %s", __LINE__, gpg_strerror (err)); if ((err = gcry_sexp_new (&key, ecc_private_key, 0, 1))) die ("line %d: %s", __LINE__, gpg_strerror (err)); if ((err = gcry_pk_sign (&sig, hash, key))) die ("gcry_pk_sign failed: %s", gpg_strerror (err)); /* Verify. */ gcry_sexp_release (key); if ((err = gcry_sexp_new (&key, ecc_public_key, 0, 1))) die ("line %d: %s", __LINE__, gpg_strerror (err)); if ((err = gcry_pk_verify (sig, hash, key))) die ("gcry_pk_verify failed: %s", gpg_strerror (err)); /* Verify again using a compressed public key. */ gcry_sexp_release (key); if ((err = gcry_sexp_new (&key, ecc_public_key_comp, 0, 1))) die ("line %d: %s", __LINE__, gpg_strerror (err)); if ((err = gcry_pk_verify (sig, hash, key))) die ("gcry_pk_verify failed (comp): %s", gpg_strerror (err)); /* Sign without a Q parameter. */ gcry_sexp_release (key); if ((err = gcry_sexp_new (&key, ecc_private_key_wo_q, 0, 1))) die ("line %d: %s", __LINE__, gpg_strerror (err)); gcry_sexp_release (sig); if ((err = gcry_pk_sign (&sig, hash, key))) die ("gcry_pk_sign w/o Q failed: %s", gpg_strerror (err)); /* Verify. */ gcry_sexp_release (key); if ((err = gcry_sexp_new (&key, ecc_public_key, 0, 1))) die ("line %d: %s", __LINE__, gpg_strerror (err)); if ((err = gcry_pk_verify (sig, hash, key))) die ("gcry_pk_verify signed w/o Q failed: %s", gpg_strerror (err)); /* Verify again using a compressed public key. */ gcry_sexp_release (key); if ((err = gcry_sexp_new (&key, ecc_public_key_comp, 0, 1))) die ("line %d: %s", __LINE__, gpg_strerror (err)); if ((err = gcry_pk_verify (sig, hash, key))) die ("gcry_pk_verify signed w/o Q failed (comp): %s", gpg_strerror (err)); extract_cmp_data (sig, "r", ("a63123a783ef29b8276e08987daca4" "655d0179e22199bf63691fd88eb64e15")); extract_cmp_data (sig, "s", ("0d9b45c696ab90b96b08812b485df185" "623ddaf5d02fa65ca5056cb6bd0f16f1")); gcry_sexp_release (sig); gcry_sexp_release (key); gcry_sexp_release (hash); } #endif /* USE_ECC */ int main (int argc, char **argv) { int i; if (argc > 1 && !strcmp (argv[1], "--verbose")) verbose = 1; else if (argc > 1 && !strcmp (argv[1], "--debug")) { verbose = 2; debug = 1; } xgcry_control ((GCRYCTL_DISABLE_SECMEM, 0)); if (!gcry_check_version (GCRYPT_VERSION)) die ("version mismatch\n"); xgcry_control ((GCRYCTL_INITIALIZATION_FINISHED, 0)); if (debug) xgcry_control ((GCRYCTL_SET_DEBUG_FLAGS, 1u , 0)); /* No valuable keys are create, so we can speed up our RNG. */ xgcry_control ((GCRYCTL_ENABLE_QUICK_RANDOM, 0)); if (gcry_fips_mode_active ()) in_fips_mode = 1; for (i=0; i < 2; i++) check_run (); #ifdef USE_RSA for (i=0; i < 4; i++) check_x931_derived_key (i); #endif /* USE_RSA */ #ifdef USE_ECC check_ecc_sample_key (); - if (!in_fips_mode) - check_ed25519ecdsa_sample_key (); + check_ed25519ecdsa_sample_key (); #endif /* USE_ECC */ return !!error_count; } diff --git a/tests/t-ed25519.c b/tests/t-ed25519.c index 4278c302..ce828b27 100644 --- a/tests/t-ed25519.c +++ b/tests/t-ed25519.c @@ -1,512 +1,508 @@ /* t-ed25519.c - Check the Ed25519 crypto * Copyright (C) 2013 g10 Code GmbH * * This file is part of Libgcrypt. * * Libgcrypt is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * Libgcrypt is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this program; if not, see . */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include "stopwatch.h" #define PGM "t-ed25519" #include "t-common.h" #define N_TESTS 1026 static int sign_with_pk; static int no_verify; static int no_fips; static int custom_data_file; -static int in_fips_mode; static void show_note (const char *format, ...) { va_list arg_ptr; if (!verbose && getenv ("srcdir")) fputs (" ", stderr); /* To align above "PASS: ". */ else fprintf (stderr, "%s: ", PGM); va_start (arg_ptr, format); vfprintf (stderr, format, arg_ptr); if (*format && format[strlen(format)-1] != '\n') putc ('\n', stderr); va_end (arg_ptr); } static void show_sexp (const char *prefix, gcry_sexp_t a) { char *buf; size_t size; fprintf (stderr, "%s: ", PGM); if (prefix) fputs (prefix, stderr); size = gcry_sexp_sprint (a, GCRYSEXP_FMT_ADVANCED, NULL, 0); buf = xmalloc (size); gcry_sexp_sprint (a, GCRYSEXP_FMT_ADVANCED, buf, size); fprintf (stderr, "%.*s", (int)size, buf); gcry_free (buf); } /* Prepend FNAME with the srcdir environment variable's value and * return an allocated filename. */ char * prepend_srcdir (const char *fname) { static const char *srcdir; char *result; if (!srcdir && !(srcdir = getenv ("srcdir"))) srcdir = "."; result = xmalloc (strlen (srcdir) + 1 + strlen (fname) + 1); strcpy (result, srcdir); strcat (result, "/"); strcat (result, fname); return result; } /* Read next line but skip over empty and comment lines. Caller must xfree the result. */ static char * read_textline (FILE *fp, int *lineno) { char line[4096]; char *p; do { if (!fgets (line, sizeof line, fp)) { if (feof (fp)) return NULL; die ("error reading input line: %s\n", strerror (errno)); } ++*lineno; p = strchr (line, '\n'); if (!p) die ("input line %d not terminated or too long\n", *lineno); *p = 0; for (p--;p > line && my_isascii (*p) && isspace (*p); p--) *p = 0; } while (!*line || *line == '#'); /* if (debug) */ /* info ("read line: '%s'\n", line); */ return xstrdup (line); } /* Copy the data after the tag to BUFFER. BUFFER will be allocated as needed. */ static void copy_data (char **buffer, const char *line, int lineno) { const char *s; xfree (*buffer); *buffer = NULL; s = strchr (line, ':'); if (!s) { fail ("syntax error at input line %d", lineno); return; } for (s++; my_isascii (*s) && isspace (*s); s++) ; *buffer = xstrdup (s); } /* Convert STRING consisting of hex characters into its binary representation and return it as an allocated buffer. The valid length of the buffer is returned at R_LENGTH. The string is delimited by end of string. The function returns NULL on error. */ static void * hex2buffer (const char *string, size_t *r_length) { const char *s; unsigned char *buffer; size_t length; buffer = xmalloc (strlen(string)/2+1); length = 0; for (s=string; *s; s +=2 ) { if (!hexdigitp (s) || !hexdigitp (s+1)) return NULL; /* Invalid hex digits. */ ((unsigned char*)buffer)[length++] = xtoi_2 (s); } *r_length = length; return buffer; } static void hexdowncase (char *string) { char *p; for (p=string; *p; p++) if (my_isascii (*p)) *p = tolower (*p); } static void one_test (int testno, const char *sk, const char *pk, const char *msg, const char *sig) { gpg_error_t err; int i; char *p; void *buffer = NULL; void *buffer2 = NULL; size_t buflen, buflen2; gcry_ctx_t ctx = NULL; const char *data_tmpl; gcry_sexp_t s_tmp, s_tmp2; gcry_sexp_t s_sk = NULL; gcry_sexp_t s_pk = NULL; gcry_sexp_t s_sig= NULL; unsigned char *sig_r = NULL; unsigned char *sig_s = NULL; char *sig_rs_string = NULL; size_t sig_r_len, sig_s_len; if (verbose > 1) info ("Running test %d\n", testno); if (!(buffer = hex2buffer (sk, &buflen))) { fail ("error building s-exp for test %d, %s: %s", testno, "sk", "invalid hex string"); goto leave; } if (!(buffer2 = hex2buffer (pk, &buflen2))) { fail ("error building s-exp for test %d, %s: %s", testno, "pk", "invalid hex string"); goto leave; } if (sign_with_pk) err = gcry_sexp_build (&s_sk, NULL, "(private-key" " (ecc" " (curve \"Ed25519\")" " (flags eddsa)" " (q %b)" " (d %b)))", (int)buflen2, buffer2, (int)buflen, buffer); else err = gcry_sexp_build (&s_sk, NULL, "(private-key" " (ecc" " (curve \"Ed25519\")" " (flags eddsa)" " (d %b)))", (int)buflen, buffer); if (err) { fail ("error building s-exp for test %d, %s: %s", testno, "sk", gpg_strerror (err)); goto leave; } if ((err = gcry_sexp_build (&s_pk, NULL, "(public-key" " (ecc" " (curve \"Ed25519\")" " (flags eddsa)" " (q %b)))", (int)buflen2, buffer2))) { fail ("error building s-exp for test %d, %s: %s", testno, "pk", gpg_strerror (err)); goto leave; } xfree (buffer); if (!(buffer = hex2buffer (msg, &buflen))) { fail ("error building s-exp for test %d, %s: %s", testno, "msg", "invalid hex string"); goto leave; } err = gcry_pk_input_data_push (&ctx, buffer, buflen); if (err) { fail ("error setting input data for test: %s", gpg_strerror (err)); goto leave; } data_tmpl = "(data(value %b))"; err = gcry_pk_hash_sign (&s_sig, data_tmpl, s_sk, NULL, ctx); if (err) { fail ("gcry_pk_hash_sign failed: %s", gpg_strerror (err)); goto leave; } if (err) fail ("gcry_pk_sign failed for test %d: %s", testno, gpg_strerror (err)); if (debug) show_sexp ("sig=", s_sig); s_tmp2 = NULL; s_tmp = gcry_sexp_find_token (s_sig, "sig-val", 0); if (s_tmp) { s_tmp2 = s_tmp; s_tmp = gcry_sexp_find_token (s_tmp2, "eddsa", 0); if (s_tmp) { gcry_sexp_release (s_tmp2); s_tmp2 = s_tmp; s_tmp = gcry_sexp_find_token (s_tmp2, "r", 0); if (s_tmp) { sig_r = gcry_sexp_nth_buffer (s_tmp, 1, &sig_r_len); gcry_sexp_release (s_tmp); } s_tmp = gcry_sexp_find_token (s_tmp2, "s", 0); if (s_tmp) { sig_s = gcry_sexp_nth_buffer (s_tmp, 1, &sig_s_len); gcry_sexp_release (s_tmp); } } } gcry_sexp_release (s_tmp2); s_tmp2 = NULL; if (!sig_r || !sig_s) fail ("gcry_pk_sign failed for test %d: %s", testno, "r or s missing"); else { sig_rs_string = xmalloc (2*(sig_r_len + sig_s_len)+1); p = sig_rs_string; *p = 0; for (i=0; i < sig_r_len; i++, p += 2) snprintf (p, 3, "%02x", sig_r[i]); for (i=0; i < sig_s_len; i++, p += 2) snprintf (p, 3, "%02x", sig_s[i]); if (strcmp (sig_rs_string, sig)) { fail ("gcry_pk_sign failed for test %d: %s", testno, "wrong value returned"); info (" expected: '%s'", sig); info (" got: '%s'", sig_rs_string); } } if (!no_verify) if ((err = gcry_pk_hash_verify (s_sig, data_tmpl, s_pk, NULL, ctx))) fail ("gcry_pk_verify failed for test %d: %s", testno, gpg_strerror (err)); leave: gcry_ctx_release (ctx); gcry_sexp_release (s_sig); gcry_sexp_release (s_sk); gcry_sexp_release (s_pk); xfree (buffer); xfree (buffer2); xfree (sig_r); xfree (sig_s); xfree (sig_rs_string); } static void check_ed25519 (const char *fname) { FILE *fp; int lineno, ntests; char *line; int testno; char *sk, *pk, *msg, *sig; info ("Checking Ed25519.\n"); fp = fopen (fname, "r"); if (!fp) die ("error opening '%s': %s\n", fname, strerror (errno)); testno = 0; sk = pk = msg = sig = NULL; lineno = ntests = 0; while ((line = read_textline (fp, &lineno))) { if (!strncmp (line, "TST:", 4)) testno = atoi (line+4); else if (!strncmp (line, "SK:", 3)) copy_data (&sk, line, lineno); else if (!strncmp (line, "PK:", 3)) copy_data (&pk, line, lineno); else if (!strncmp (line, "MSG:", 4)) copy_data (&msg, line, lineno); else if (!strncmp (line, "SIG:", 4)) copy_data (&sig, line, lineno); else fail ("unknown tag at input line %d", lineno); xfree (line); if (testno && sk && pk && msg && sig) { hexdowncase (sig); one_test (testno, sk, pk, msg, sig); ntests++; if (!(ntests % 256)) show_note ("%d of %d tests done\n", ntests, N_TESTS); xfree (pk); pk = NULL; xfree (sk); sk = NULL; xfree (msg); msg = NULL; xfree (sig); sig = NULL; } } xfree (pk); xfree (sk); xfree (msg); xfree (sig); if (ntests != N_TESTS && !custom_data_file) fail ("did %d tests but expected %d", ntests, N_TESTS); else if ((ntests % 256)) show_note ("%d tests done\n", ntests); fclose (fp); } int main (int argc, char **argv) { int last_argc = -1; char *fname = NULL; if (argc) { argc--; argv++; } while (argc && last_argc != argc ) { last_argc = argc; if (!strcmp (*argv, "--")) { argc--; argv++; break; } else if (!strcmp (*argv, "--help")) { fputs ("usage: " PGM " [options]\n" "Options:\n" " --verbose print timings etc.\n" " --debug flyswatter\n" " --sign-with-pk also use the public key for signing\n" " --no-verify skip the verify test\n" " --data FNAME take test data from file FNAME\n", stdout); exit (0); } else if (!strcmp (*argv, "--verbose")) { verbose++; argc--; argv++; } else if (!strcmp (*argv, "--debug")) { verbose += 2; debug++; argc--; argv++; } else if (!strcmp (*argv, "--sign-with-pk")) { sign_with_pk = 1; argc--; argv++; } else if (!strcmp (*argv, "--no-verify")) { no_verify = 1; argc--; argv++; } else if (!strcmp (*argv, "--data")) { argc--; argv++; if (argc) { xfree (fname); fname = xstrdup (*argv); argc--; argv++; } } else if (!strcmp (*argv, "--no-fips")) { no_fips = 1; argc--; argv++; } else if (!strncmp (*argv, "--", 2)) die ("unknown option '%s'", *argv); } if (!fname) fname = prepend_srcdir ("t-ed25519.inp"); else custom_data_file = 1; xgcry_control ((GCRYCTL_DISABLE_SECMEM, 0)); if (!gcry_check_version (GCRYPT_VERSION)) die ("version mismatch\n"); if (debug) xgcry_control ((GCRYCTL_SET_DEBUG_FLAGS, 1u , 0)); if (no_fips) { xgcry_control ((GCRYCTL_NO_FIPS_MODE, 0)); xgcry_control ((GCRYCTL_FIPS_MODE_P, 0)); } xgcry_control ((GCRYCTL_ENABLE_QUICK_RANDOM, 0)); xgcry_control ((GCRYCTL_INITIALIZATION_FINISHED, 0)); - if (gcry_fips_mode_active ()) - in_fips_mode = 1; - start_timer (); check_ed25519 (fname); stop_timer (); xfree (fname); info ("All tests completed in %s. Errors: %d\n", elapsed_time (1), error_count); return !!error_count; } diff --git a/tests/t-ed448.c b/tests/t-ed448.c index b769f801..b68fd855 100644 --- a/tests/t-ed448.c +++ b/tests/t-ed448.c @@ -1,542 +1,529 @@ /* t-ed448.c - Check the Ed448 crypto * Copyright (C) 2020 g10 Code GmbH * * This file is part of Libgcrypt. * * Libgcrypt is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * Libgcrypt is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this program; if not, see . */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include "stopwatch.h" #define PGM "t-ed448" #include "t-common.h" #define N_TESTS 11 static int sign_with_pk; static int no_verify; static int custom_data_file; -static int in_fips_mode; static void show_note (const char *format, ...) { va_list arg_ptr; if (!verbose && getenv ("srcdir")) fputs (" ", stderr); /* To align above "PASS: ". */ else fprintf (stderr, "%s: ", PGM); va_start (arg_ptr, format); vfprintf (stderr, format, arg_ptr); if (*format && format[strlen(format)-1] != '\n') putc ('\n', stderr); va_end (arg_ptr); } static void show_sexp (const char *prefix, gcry_sexp_t a) { char *buf; size_t size; fprintf (stderr, "%s: ", PGM); if (prefix) fputs (prefix, stderr); size = gcry_sexp_sprint (a, GCRYSEXP_FMT_ADVANCED, NULL, 0); buf = xmalloc (size); gcry_sexp_sprint (a, GCRYSEXP_FMT_ADVANCED, buf, size); fprintf (stderr, "%.*s", (int)size, buf); gcry_free (buf); } /* Prepend FNAME with the srcdir environment variable's value and * return an allocated filename. */ char * prepend_srcdir (const char *fname) { static const char *srcdir; char *result; if (!srcdir && !(srcdir = getenv ("srcdir"))) srcdir = "."; result = xmalloc (strlen (srcdir) + 1 + strlen (fname) + 1); strcpy (result, srcdir); strcat (result, "/"); strcat (result, fname); return result; } /* Read next line but skip over empty and comment lines. Caller must xfree the result. */ static char * read_textline (FILE *fp, int *lineno) { char line[4096]; char *p; do { if (!fgets (line, sizeof line, fp)) { if (feof (fp)) return NULL; die ("error reading input line: %s\n", strerror (errno)); } ++*lineno; p = strchr (line, '\n'); if (!p) die ("input line %d not terminated or too long\n", *lineno); *p = 0; for (p--;p > line && my_isascii (*p) && isspace (*p); p--) *p = 0; } while (!*line || *line == '#'); /* if (debug) */ /* info ("read line: '%s'\n", line); */ return xstrdup (line); } /* Copy the data after the tag to BUFFER. BUFFER will be allocated as needed. */ static void copy_data (char **buffer, const char *line, int lineno) { const char *s; xfree (*buffer); *buffer = NULL; s = strchr (line, ':'); if (!s) { fail ("syntax error at input line %d", lineno); return; } for (s++; my_isascii (*s) && isspace (*s); s++) ; *buffer = xstrdup (s); } /* Convert STRING consisting of hex characters into its binary representation and return it as an allocated buffer. The valid length of the buffer is returned at R_LENGTH. The string is delimited by end of string. The function returns NULL on error. */ static void * hex2buffer (const char *string, size_t *r_length) { const char *s; unsigned char *buffer; size_t length; buffer = xmalloc (strlen(string)/2+1); length = 0; for (s=string; *s; s +=2 ) { if (!hexdigitp (s) || !hexdigitp (s+1)) return NULL; /* Invalid hex digits. */ ((unsigned char*)buffer)[length++] = xtoi_2 (s); } *r_length = length; return buffer; } static void hexdowncase (char *string) { char *p; for (p=string; *p; p++) if (my_isascii (*p)) *p = tolower (*p); } static void one_test (int testno, int ph, const char *sk, const char *pk, const char *msg, const char *ctx_str, const char *sig) { gpg_error_t err; int i; char *p; void *buffer = NULL; void *buffer2 = NULL; size_t buflen, buflen2; gcry_ctx_t ctx = NULL; const char *data_tmpl; gcry_sexp_t s_tmp, s_tmp2; gcry_sexp_t s_sk = NULL; gcry_sexp_t s_pk = NULL; gcry_sexp_t s_sig= NULL; unsigned char *sig_r = NULL; unsigned char *sig_s = NULL; char *sig_rs_string = NULL; size_t sig_r_len, sig_s_len; if (verbose > 1) info ("Running test %d %d\n", testno, ph); if (!(buffer = hex2buffer (sk, &buflen))) { fail ("error building s-exp for test %d, %s: %s", testno, "sk", "invalid hex string"); goto leave; } if (!(buffer2 = hex2buffer (pk, &buflen2))) { fail ("error building s-exp for test %d, %s: %s", testno, "pk", "invalid hex string"); goto leave; } if (sign_with_pk) err = gcry_sexp_build (&s_sk, NULL, "(private-key" " (ecc" " (curve \"Ed448\")" " (q %b)" " (d %b)))", (int)buflen2, buffer2, (int)buflen, buffer); else err = gcry_sexp_build (&s_sk, NULL, "(private-key" " (ecc" " (curve \"Ed448\")" " (d %b)))", (int)buflen, buffer); if (err) { fail ("error building s-exp for test %d, %s: %s", testno, "sk", gpg_strerror (err)); goto leave; } if ((err = gcry_sexp_build (&s_pk, NULL, "(public-key" " (ecc" " (curve \"Ed448\")" " (q %b)))", (int)buflen2, buffer2))) { fail ("error building s-exp for test %d, %s: %s", testno, "pk", gpg_strerror (err)); goto leave; } xfree (buffer); if (!(buffer = hex2buffer (msg, &buflen))) { fail ("error building s-exp for test %d, %s: %s", testno, "msg", "invalid hex string"); goto leave; } err = gcry_pk_input_data_push (&ctx, buffer, buflen); if (err) { fail ("error setting input data for test: %s", gpg_strerror (err)); goto leave; } if (ctx_str) { xfree (buffer2); if (!(buffer2 = hex2buffer (ctx_str, &buflen2))) { fail ("error building s-exp for test %d, %s: %s", testno, "ctx", "invalid hex string"); goto leave; } err = gcry_pk_input_data_push (&ctx, buffer2, buflen2); if (err) { fail ("error setting ctx for test: %s", gpg_strerror (err)); goto leave; } if (ph) data_tmpl = "(data(flags prehash)(label %b)(value %b))"; else data_tmpl = "(data(label %b)(value %b))"; } else { if (ph) data_tmpl = "(data(flags prehash)(value %b))"; else data_tmpl = "(data(value %b))"; } err = gcry_pk_hash_sign (&s_sig, data_tmpl, s_sk, NULL, ctx); - if (in_fips_mode) - { - if (!err) - fail ("gcry_pk_sign is not expected to work in FIPS mode for test %d", - testno); - if (verbose > 1) - info ("not executed in FIPS mode\n"); - goto leave; - } if (err) fail ("gcry_pk_sign failed for test %d: %s", testno, gpg_strerror (err)); if (debug) show_sexp ("sig=", s_sig); s_tmp2 = NULL; s_tmp = gcry_sexp_find_token (s_sig, "sig-val", 0); if (s_tmp) { s_tmp2 = s_tmp; s_tmp = gcry_sexp_find_token (s_tmp2, "eddsa", 0); if (s_tmp) { gcry_sexp_release (s_tmp2); s_tmp2 = s_tmp; s_tmp = gcry_sexp_find_token (s_tmp2, "r", 0); if (s_tmp) { sig_r = gcry_sexp_nth_buffer (s_tmp, 1, &sig_r_len); gcry_sexp_release (s_tmp); } s_tmp = gcry_sexp_find_token (s_tmp2, "s", 0); if (s_tmp) { sig_s = gcry_sexp_nth_buffer (s_tmp, 1, &sig_s_len); gcry_sexp_release (s_tmp); } } } gcry_sexp_release (s_tmp2); s_tmp2 = NULL; if (!sig_r || !sig_s) fail ("gcry_pk_sign failed for test %d: %s", testno, "r or s missing"); else { sig_rs_string = xmalloc (2*(sig_r_len + sig_s_len)+1); p = sig_rs_string; *p = 0; for (i=0; i < sig_r_len; i++, p += 2) snprintf (p, 3, "%02x", sig_r[i]); for (i=0; i < sig_s_len; i++, p += 2) snprintf (p, 3, "%02x", sig_s[i]); if (strcmp (sig_rs_string, sig)) { fail ("gcry_pk_sign failed for test %d: %s", testno, "wrong value returned"); info (" expected: '%s'", sig); info (" got: '%s'", sig_rs_string); } } if (!no_verify) if ((err = gcry_pk_hash_verify (s_sig, data_tmpl, s_pk, NULL, ctx))) fail ("gcry_pk_verify failed for test %d: %s", testno, gpg_strerror (err)); leave: gcry_ctx_release (ctx); gcry_sexp_release (s_sig); gcry_sexp_release (s_sk); gcry_sexp_release (s_pk); xfree (buffer); xfree (buffer2); xfree (sig_r); xfree (sig_s); xfree (sig_rs_string); } static void check_ed448 (const char *fname) { FILE *fp; int lineno, ntests; char *line; int testno; int ph; char *sk, *pk, *msg, *ctx, *sig; info ("Checking Ed448.\n"); fp = fopen (fname, "r"); if (!fp) die ("error opening '%s': %s\n", fname, strerror (errno)); testno = 0; ph = 0; sk = pk = msg = ctx = sig = NULL; lineno = ntests = 0; while ((line = read_textline (fp, &lineno))) { if (!strncmp (line, "TST:", 4)) testno = atoi (line+4); else if (!strncmp (line, "PH:", 3)) ph = atoi (line+3); else if (!strncmp (line, "SK:", 3)) copy_data (&sk, line, lineno); else if (!strncmp (line, "PK:", 3)) copy_data (&pk, line, lineno); else if (!strncmp (line, "MSG:", 4)) copy_data (&msg, line, lineno); else if (!strncmp (line, "CTX:", 4)) copy_data (&ctx, line, lineno); else if (!strncmp (line, "SIG:", 4)) copy_data (&sig, line, lineno); else fail ("unknown tag at input line %d", lineno); xfree (line); if (testno && sk && pk && msg && sig) { hexdowncase (sig); one_test (testno, ph, sk, pk, msg, ctx, sig); ntests++; if (!(ntests % 256)) show_note ("%d of %d tests done\n", ntests, N_TESTS); ph = 0; xfree (pk); pk = NULL; xfree (sk); sk = NULL; xfree (msg); msg = NULL; xfree (ctx); ctx = NULL; xfree (sig); sig = NULL; } } xfree (pk); xfree (sk); xfree (msg); xfree (ctx); xfree (sig); if (ntests != N_TESTS && !custom_data_file) fail ("did %d tests but expected %d", ntests, N_TESTS); else if ((ntests % 256)) show_note ("%d tests done\n", ntests); fclose (fp); } int main (int argc, char **argv) { int last_argc = -1; char *fname = NULL; if (argc) { argc--; argv++; } while (argc && last_argc != argc ) { last_argc = argc; if (!strcmp (*argv, "--")) { argc--; argv++; break; } else if (!strcmp (*argv, "--help")) { fputs ("usage: " PGM " [options]\n" "Options:\n" " --verbose print timings etc.\n" " --debug flyswatter\n" " --sign-with-pk also use the public key for signing\n" " --no-verify skip the verify test\n" " --data FNAME take test data from file FNAME\n", stdout); exit (0); } else if (!strcmp (*argv, "--verbose")) { verbose++; argc--; argv++; } else if (!strcmp (*argv, "--debug")) { verbose += 2; debug++; argc--; argv++; } else if (!strcmp (*argv, "--sign-with-pk")) { sign_with_pk = 1; argc--; argv++; } else if (!strcmp (*argv, "--no-verify")) { no_verify = 1; argc--; argv++; } else if (!strcmp (*argv, "--data")) { argc--; argv++; if (argc) { xfree (fname); fname = xstrdup (*argv); argc--; argv++; } } else if (!strncmp (*argv, "--", 2)) die ("unknown option '%s'", *argv); } if (!fname) fname = prepend_srcdir ("t-ed448.inp"); else custom_data_file = 1; xgcry_control ((GCRYCTL_DISABLE_SECMEM, 0)); if (!gcry_check_version (GCRYPT_VERSION)) die ("version mismatch\n"); if (debug) xgcry_control ((GCRYCTL_SET_DEBUG_FLAGS, 1u , 0)); xgcry_control ((GCRYCTL_ENABLE_QUICK_RANDOM, 0)); xgcry_control ((GCRYCTL_INITIALIZATION_FINISHED, 0)); - if (gcry_fips_mode_active ()) - in_fips_mode = 1; - start_timer (); check_ed448 (fname); stop_timer (); xfree (fname); info ("All tests completed in %s. Errors: %d\n", elapsed_time (1), error_count); return !!error_count; }