From d4cfd73aea1cf2eab4ff542d13f17e40d9b154ae Mon Sep 17 00:00:00 2001 From: Andrew Dinh Date: Tue, 21 Oct 2025 14:58:41 +0200 Subject: [PATCH 1/7] Add evp_hash perftool --- source/CMakeLists.txt | 3 + source/evp_hash.c | 298 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 301 insertions(+) create mode 100644 source/evp_hash.c diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt index d861513..980d6be 100644 --- a/source/CMakeLists.txt +++ b/source/CMakeLists.txt @@ -184,3 +184,6 @@ target_link_libraries(evp_setpeer PRIVATE perf) add_executable(writeread writeread.c) target_link_libraries(writeread PRIVATE perf) + +add_executable(evp_hash evp_hash.c) +target_link_libraries(evp_hash PRIVATE perf) diff --git a/source/evp_hash.c b/source/evp_hash.c new file mode 100644 index 0000000..59ab9e2 --- /dev/null +++ b/source/evp_hash.c @@ -0,0 +1,298 @@ +/* + * Copyright 2025 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * This CLI tool computes hashes using the specified algorithm. Uses the EVP API + * by default, but this tool can also use the corresponding deprecated API's. + * Prints out the average time per hash computation. + */ + +#include +#include +#ifndef _WIN32 +# include +# include +#else +# include +# include "perflib/getopt.h" +#endif /* _WIN32 */ + +#include +#include +#include "perflib/perflib.h" + +#define RUN_TIME 5 +#define DATA_SIZE 1500 + +size_t *counts = NULL; +OSSL_TIME max_time; +int err = 0; +static int threadcount; +size_t num_calls; + +typedef enum { + SHA1_ALG = 0, + SHA224_ALG, + SHA256_ALG, + SHA384_ALG, + SHA512_ALG, +} hash_algorithm_type; + +static unsigned char data[DATA_SIZE]; +static int deprecated_api = 0; +static int update_times = 1; +static int hash_algorithm = -1; + +int hash_deprecated() +{ + int i; + SHA_CTX sha_ctx; + SHA256_CTX sha256_ctx; + SHA512_CTX sha512_ctx; + unsigned char md[EVP_MAX_MD_SIZE]; + + switch (hash_algorithm) { + case SHA1_ALG: + if (!SHA1_Init(&sha_ctx)) + return 0; + for (i = 0; i < update_times; i++) + if (!SHA1_Update(&sha_ctx, data, sizeof(data))) + return 0; + if (!SHA1_Final(md, &sha_ctx)) + return 0; + break; + case SHA224_ALG: + if (!SHA224_Init(&sha256_ctx)) + return 0; + for (i = 0; i < update_times; i++) + if (!SHA224_Update(&sha256_ctx, data, sizeof(data))) + return 0; + if (!SHA224_Final(md, &sha256_ctx)) + return 0; + break; + case SHA256_ALG: + if (!SHA256_Init(&sha256_ctx)) + return 0; + for (i = 0; i < update_times; i++) + if (!SHA256_Update(&sha256_ctx, data, sizeof(data))) + return 0; + if (!SHA256_Final(md, &sha256_ctx)) + return 0; + break; + case SHA384_ALG: + if (!SHA384_Init(&sha512_ctx)) + return 0; + for (i = 0; i < update_times; i++) + if (!SHA384_Update(&sha512_ctx, data, sizeof(data))) + return 0; + if (!SHA384_Final(md, &sha512_ctx)) + return 0; + break; + case SHA512_ALG: + if (!SHA512_Init(&sha512_ctx)) + return 0; + for (i = 0; i < update_times; i++) + if (!SHA512_Update(&sha512_ctx, data, sizeof(data))) + return 0; + if (!SHA512_Final(md, &sha512_ctx)) + return 0; + break; + default: + return 0; + } + + return 1; +} + +int hash_evp(EVP_MD_CTX *mctx, const EVP_MD *evp_md) +{ + int i; + unsigned char md[EVP_MAX_MD_SIZE]; + + if (!EVP_DigestInit(mctx, evp_md)) + return 0; + + for (i = 0; i < update_times; i++) + if (!EVP_DigestUpdate(mctx, data, sizeof(data))) + return 0; + + if (!EVP_DigestFinal(mctx, md, NULL)) + return 0; + + return 1; +} + +void do_hash(size_t num) +{ + OSSL_TIME time; + EVP_MD_CTX *mctx = NULL; + const EVP_MD *evp_md = NULL; + + counts[num] = 0; + + if (!deprecated_api) { + switch (hash_algorithm) { + case SHA1_ALG: + evp_md = EVP_sha1(); + break; + case SHA224_ALG: + evp_md = EVP_sha224(); + break; + case SHA256_ALG: + evp_md = EVP_sha256(); + break; + case SHA384_ALG: + evp_md = EVP_sha384(); + break; + case SHA512_ALG: + evp_md = EVP_sha512(); + break; + default: + err = 1; + return; + } + + if ((mctx = EVP_MD_CTX_new()) == NULL) + return; + } + + do { + if (deprecated_api) { + if (!hash_deprecated()) + err = 1; + } else if (!hash_evp(mctx, evp_md)) { + err = 1; + } + + if (err) + goto err; + + counts[num]++; + time = ossl_time_now(); + } while (time.t < max_time.t); + +err: + EVP_MD_CTX_free(mctx); +} + +void print_help() +{ + printf("Usage: evp_hash [-h] [-x] [-t] update-times algorithm thread-count\n"); + printf("-h - print this help output\n"); + printf("-x - use deprecated API instead of EVP API\n"); + printf("-t - terse output\n"); + printf("update-times - times to update digest. 1 for one-shot\n"); + printf("algorithm - one of: [SHA1, SHA224, SHA256, SHA384, SHA512]\n"); + printf("thread-count - number of threads\n"); +} + +int main(int argc, char *argv[]) +{ + OSSL_TIME duration; + size_t total_count = 0; + double av; + int terse = 0; + int j, opt, rc = EXIT_FAILURE; + + while ((opt = getopt(argc, argv, "htx")) != -1) { + switch (opt) { + case 't': + terse = 1; + break; + case 'x': + deprecated_api = 1; + break; + case 'h': + default: + print_help(); + goto out; + } + } + + if (argv[optind] == NULL + || argv[optind+1] == NULL + || argv[optind+2] == NULL + || argv[optind+3] != NULL) { + fprintf(stderr, "Incorrect number of arguments\n"); + print_help(); + goto out; + } + + update_times = atoi(argv[optind]); + if (update_times <= 0) { + fprintf(stderr, "update-times must be a positive integer\n"); + goto out; + } + + if (strcmp(argv[optind+1], "SHA1") == 0) { + hash_algorithm = SHA1_ALG; + } else if (strcmp(argv[optind+1], "SHA224") == 0) { + hash_algorithm = SHA224_ALG; + } else if (strcmp(argv[optind+1], "SHA256") == 0) { + hash_algorithm = SHA256_ALG; + } else if (strcmp(argv[optind+1], "SHA384") == 0) { + hash_algorithm = SHA384_ALG; + } else if (strcmp(argv[optind+1], "SHA512") == 0) { + hash_algorithm = SHA512_ALG; + } else { + fprintf(stderr, "algorithm is one of: [SHA1, SHA224, SHA256, SHA384, SHA512]\n"); + print_help(); + goto out; + } + + threadcount = atoi(argv[optind+2]); + if (threadcount < 1) { + fprintf(stderr, "thread-count must be a positive integer\n"); + print_help(); + goto out; + } + + if (!RAND_bytes((unsigned char *)data, sizeof(data))) + goto out; + + max_time = ossl_time_add(ossl_time_now(), ossl_seconds2time(RUN_TIME)); + + counts = OPENSSL_malloc(sizeof(size_t) * threadcount); + if (counts == NULL) { + fprintf(stderr, "Failed to create counts array\n"); + goto out; + } + + if (!perflib_run_multi_thread_test(do_hash, threadcount, &duration)) { + fprintf(stderr, "Failed to run the test\n"); + goto out; + } + + if (err) { + fprintf(stderr, "Error during test\n"); + goto out; + } + + for (j = 0; j < threadcount; j++) + total_count += counts[j]; + + /* + * Hashing is pretty fast, running in only a few us. But ossl_time2us does + * integer division and so because the average us computed above is less + * than the value of OSSL_TIME_US, we wind up with truncation to zero in the + * math. Instead, manually do the division, casting our values as doubles so + * that we compute the proper time. + */ + av = (double)RUN_TIME * 1e6 * threadcount / total_count; + + if (terse) + printf("%lf\n", av); + else + printf("Average time per hash: %lfus\n", av); + + rc = EXIT_SUCCESS; +out: + OPENSSL_free(counts); + return rc; +} From b1c77024d62c577bfa74dc6ccc5e6cd1b09b1530 Mon Sep 17 00:00:00 2001 From: Andrew Dinh Date: Tue, 21 Oct 2025 17:13:13 +0200 Subject: [PATCH 2/7] Extract code from critical section --- source/evp_hash.c | 223 ++++++++++++++++++++++++++++------------------ 1 file changed, 137 insertions(+), 86 deletions(-) diff --git a/source/evp_hash.c b/source/evp_hash.c index 59ab9e2..4f4d616 100644 --- a/source/evp_hash.c +++ b/source/evp_hash.c @@ -45,71 +45,96 @@ typedef enum { } hash_algorithm_type; static unsigned char data[DATA_SIZE]; -static int deprecated_api = 0; static int update_times = 1; -static int hash_algorithm = -1; +static const EVP_MD *evp_md = NULL; +static int (*hash_func_deprecated)(void); -int hash_deprecated() +int hash_sha1_deprecated() { int i; SHA_CTX sha_ctx; - SHA256_CTX sha256_ctx; - SHA512_CTX sha512_ctx; unsigned char md[EVP_MAX_MD_SIZE]; - switch (hash_algorithm) { - case SHA1_ALG: - if (!SHA1_Init(&sha_ctx)) - return 0; - for (i = 0; i < update_times; i++) - if (!SHA1_Update(&sha_ctx, data, sizeof(data))) - return 0; - if (!SHA1_Final(md, &sha_ctx)) - return 0; - break; - case SHA224_ALG: - if (!SHA224_Init(&sha256_ctx)) - return 0; - for (i = 0; i < update_times; i++) - if (!SHA224_Update(&sha256_ctx, data, sizeof(data))) - return 0; - if (!SHA224_Final(md, &sha256_ctx)) - return 0; - break; - case SHA256_ALG: - if (!SHA256_Init(&sha256_ctx)) - return 0; - for (i = 0; i < update_times; i++) - if (!SHA256_Update(&sha256_ctx, data, sizeof(data))) - return 0; - if (!SHA256_Final(md, &sha256_ctx)) + if (!SHA1_Init(&sha_ctx)) + return 0; + for (i = 0; i < update_times; i++) + if (!SHA1_Update(&sha_ctx, data, sizeof(data))) return 0; - break; - case SHA384_ALG: - if (!SHA384_Init(&sha512_ctx)) + if (!SHA1_Final(md, &sha_ctx)) + return 0; + + return 1; +} + +int hash_sha224_deprecated() +{ + int i; + SHA256_CTX sha256_ctx; + unsigned char md[EVP_MAX_MD_SIZE]; + + if (!SHA224_Init(&sha256_ctx)) + return 0; + for (i = 0; i < update_times; i++) + if (!SHA224_Update(&sha256_ctx, data, sizeof(data))) return 0; - for (i = 0; i < update_times; i++) - if (!SHA384_Update(&sha512_ctx, data, sizeof(data))) - return 0; - if (!SHA384_Final(md, &sha512_ctx)) + if (!SHA224_Final(md, &sha256_ctx)) + return 0; + + return 1; +} + +int hash_sha256_deprecated() +{ + int i; + SHA256_CTX sha256_ctx; + unsigned char md[EVP_MAX_MD_SIZE]; + + if (!SHA256_Init(&sha256_ctx)) + return 0; + for (i = 0; i < update_times; i++) + if (!SHA256_Update(&sha256_ctx, data, sizeof(data))) return 0; - break; - case SHA512_ALG: - if (!SHA512_Init(&sha512_ctx)) + if (!SHA256_Final(md, &sha256_ctx)) + return 0; + + return 1; +} + +int hash_sha384_deprecated() +{ + int i; + SHA512_CTX sha512_ctx; + unsigned char md[EVP_MAX_MD_SIZE]; + + if (!SHA384_Init(&sha512_ctx)) + return 0; + for (i = 0; i < update_times; i++) + if (!SHA384_Update(&sha512_ctx, data, sizeof(data))) return 0; - for (i = 0; i < update_times; i++) - if (!SHA512_Update(&sha512_ctx, data, sizeof(data))) - return 0; - if (!SHA512_Final(md, &sha512_ctx)) + if (!SHA384_Final(md, &sha512_ctx)) + return 0; + + return 1; +} + +int hash_sha512_deprecated() +{ + int i; + SHA512_CTX sha512_ctx; + unsigned char md[EVP_MAX_MD_SIZE]; + + if (!SHA512_Init(&sha512_ctx)) + return 0; + for (i = 0; i < update_times; i++) + if (!SHA512_Update(&sha512_ctx, data, sizeof(data))) return 0; - break; - default: + if (!SHA512_Final(md, &sha512_ctx)) return 0; - } return 1; } + int hash_evp(EVP_MD_CTX *mctx, const EVP_MD *evp_md) { int i; @@ -128,50 +153,34 @@ int hash_evp(EVP_MD_CTX *mctx, const EVP_MD *evp_md) return 1; } -void do_hash(size_t num) +void do_hash_deprecated(size_t num) { OSSL_TIME time; - EVP_MD_CTX *mctx = NULL; - const EVP_MD *evp_md = NULL; - counts[num] = 0; - - if (!deprecated_api) { - switch (hash_algorithm) { - case SHA1_ALG: - evp_md = EVP_sha1(); - break; - case SHA224_ALG: - evp_md = EVP_sha224(); - break; - case SHA256_ALG: - evp_md = EVP_sha256(); - break; - case SHA384_ALG: - evp_md = EVP_sha384(); - break; - case SHA512_ALG: - evp_md = EVP_sha512(); - break; - default: + do { + if (!hash_func_deprecated()) { err = 1; return; } - if ((mctx = EVP_MD_CTX_new()) == NULL) - return; - } + counts[num]++; + time = ossl_time_now(); + } while (time.t < max_time.t); +} + +void do_hash_evp(size_t num) +{ + OSSL_TIME time; + EVP_MD_CTX *mctx = EVP_MD_CTX_new(); + + if (mctx == NULL) + return; do { - if (deprecated_api) { - if (!hash_deprecated()) - err = 1; - } else if (!hash_evp(mctx, evp_md)) { + if (!hash_evp(mctx, evp_md)) { err = 1; - } - - if (err) goto err; + } counts[num]++; time = ossl_time_now(); @@ -197,7 +206,7 @@ int main(int argc, char *argv[]) OSSL_TIME duration; size_t total_count = 0; double av; - int terse = 0; + int terse = 0, deprecated_api = 0, hash_algorithm = -1; int j, opt, rc = EXIT_FAILURE; while ((opt = getopt(argc, argv, "htx")) != -1) { @@ -258,15 +267,57 @@ int main(int argc, char *argv[]) max_time = ossl_time_add(ossl_time_now(), ossl_seconds2time(RUN_TIME)); - counts = OPENSSL_malloc(sizeof(size_t) * threadcount); + counts = OPENSSL_zalloc(sizeof(size_t) * threadcount); if (counts == NULL) { fprintf(stderr, "Failed to create counts array\n"); goto out; } - if (!perflib_run_multi_thread_test(do_hash, threadcount, &duration)) { - fprintf(stderr, "Failed to run the test\n"); - goto out; + if (deprecated_api) { + switch (hash_algorithm) { + case SHA1_ALG: + hash_func_deprecated = hash_sha1_deprecated; + break; + case SHA224_ALG: + hash_func_deprecated = hash_sha224_deprecated; + break; + case SHA256_ALG: + hash_func_deprecated = hash_sha256_deprecated; + break; + case SHA384_ALG: + hash_func_deprecated = hash_sha384_deprecated; + break; + case SHA512_ALG: + hash_func_deprecated = hash_sha512_deprecated; + break; + default: + err = 1; + goto out; + } + err = !perflib_run_multi_thread_test(do_hash_deprecated, threadcount, &duration) || err; + } else { + switch (hash_algorithm) { + case SHA1_ALG: + evp_md = EVP_sha1(); + break; + case SHA224_ALG: + evp_md = EVP_sha224(); + break; + case SHA256_ALG: + evp_md = EVP_sha256(); + break; + case SHA384_ALG: + evp_md = EVP_sha384(); + break; + case SHA512_ALG: + evp_md = EVP_sha512(); + break; + default: + err = 1; + goto out; + } + + err = !perflib_run_multi_thread_test(do_hash_evp, threadcount, &duration) || err; } if (err) { From ceac3bccd350e79299d3d85098f9b72449fb851b Mon Sep 17 00:00:00 2001 From: Andrew Dinh Date: Wed, 22 Oct 2025 10:38:13 +0200 Subject: [PATCH 3/7] Make more arguments optional one-shot and SHA1 by default --- source/evp_hash.c | 103 +++++++++++++++++++++------------------------- 1 file changed, 47 insertions(+), 56 deletions(-) diff --git a/source/evp_hash.c b/source/evp_hash.c index 4f4d616..dab67de 100644 --- a/source/evp_hash.c +++ b/source/evp_hash.c @@ -30,11 +30,11 @@ #define RUN_TIME 5 #define DATA_SIZE 1500 +static int threadcount; +static OSSL_TIME max_time; + size_t *counts = NULL; -OSSL_TIME max_time; int err = 0; -static int threadcount; -size_t num_calls; typedef enum { SHA1_ALG = 0, @@ -57,13 +57,12 @@ int hash_sha1_deprecated() if (!SHA1_Init(&sha_ctx)) return 0; + for (i = 0; i < update_times; i++) if (!SHA1_Update(&sha_ctx, data, sizeof(data))) return 0; - if (!SHA1_Final(md, &sha_ctx)) - return 0; - return 1; + return SHA1_Final(md, &sha_ctx); } int hash_sha224_deprecated() @@ -74,13 +73,12 @@ int hash_sha224_deprecated() if (!SHA224_Init(&sha256_ctx)) return 0; + for (i = 0; i < update_times; i++) if (!SHA224_Update(&sha256_ctx, data, sizeof(data))) return 0; - if (!SHA224_Final(md, &sha256_ctx)) - return 0; - return 1; + return SHA224_Final(md, &sha256_ctx); } int hash_sha256_deprecated() @@ -91,13 +89,12 @@ int hash_sha256_deprecated() if (!SHA256_Init(&sha256_ctx)) return 0; + for (i = 0; i < update_times; i++) if (!SHA256_Update(&sha256_ctx, data, sizeof(data))) return 0; - if (!SHA256_Final(md, &sha256_ctx)) - return 0; - return 1; + return SHA256_Final(md, &sha256_ctx); } int hash_sha384_deprecated() @@ -108,13 +105,12 @@ int hash_sha384_deprecated() if (!SHA384_Init(&sha512_ctx)) return 0; + for (i = 0; i < update_times; i++) if (!SHA384_Update(&sha512_ctx, data, sizeof(data))) return 0; - if (!SHA384_Final(md, &sha512_ctx)) - return 0; - return 1; + return SHA384_Final(md, &sha512_ctx); } int hash_sha512_deprecated() @@ -125,13 +121,12 @@ int hash_sha512_deprecated() if (!SHA512_Init(&sha512_ctx)) return 0; + for (i = 0; i < update_times; i++) if (!SHA512_Update(&sha512_ctx, data, sizeof(data))) return 0; - if (!SHA512_Final(md, &sha512_ctx)) - return 0; - return 1; + return SHA512_Final(md, &sha512_ctx); } @@ -147,10 +142,7 @@ int hash_evp(EVP_MD_CTX *mctx, const EVP_MD *evp_md) if (!EVP_DigestUpdate(mctx, data, sizeof(data))) return 0; - if (!EVP_DigestFinal(mctx, md, NULL)) - return 0; - - return 1; + return EVP_DigestFinal(mctx, md, NULL); } void do_hash_deprecated(size_t num) @@ -192,12 +184,12 @@ void do_hash_evp(size_t num) void print_help() { - printf("Usage: evp_hash [-h] [-x] [-t] update-times algorithm thread-count\n"); + printf("Usage: evp_hash [-h] [-x] [-t] [-u update-times] [-a algorithm] thread-count\n"); printf("-h - print this help output\n"); printf("-x - use deprecated API instead of EVP API\n"); printf("-t - terse output\n"); - printf("update-times - times to update digest. 1 for one-shot\n"); - printf("algorithm - one of: [SHA1, SHA224, SHA256, SHA384, SHA512]\n"); + printf("-u update-times - times to update digest. 1 for one-shot. By default, do one-shot\n"); + printf("-a algorithm - One of: [SHA1, SHA224, SHA256, SHA384, SHA512]. By default, use SHA1\n"); printf("thread-count - number of threads\n"); } @@ -206,10 +198,10 @@ int main(int argc, char *argv[]) OSSL_TIME duration; size_t total_count = 0; double av; - int terse = 0, deprecated_api = 0, hash_algorithm = -1; + int terse = 0, deprecated_api = 0, hash_algorithm = SHA1_ALG; int j, opt, rc = EXIT_FAILURE; - while ((opt = getopt(argc, argv, "htx")) != -1) { + while ((opt = getopt(argc, argv, "htxu:a:")) != -1) { switch (opt) { case 't': terse = 1; @@ -217,6 +209,30 @@ int main(int argc, char *argv[]) case 'x': deprecated_api = 1; break; + case 'u': + update_times = atoi(optarg); + if (update_times <= 0) { + fprintf(stderr, "update-times must be a positive integer\n"); + goto out; + } + break; + case 'a': + if (strcmp(optarg, "SHA1") == 0) { + hash_algorithm = SHA1_ALG; + } else if (strcmp(optarg, "SHA224") == 0) { + hash_algorithm = SHA224_ALG; + } else if (strcmp(optarg, "SHA256") == 0) { + hash_algorithm = SHA256_ALG; + } else if (strcmp(optarg, "SHA384") == 0) { + hash_algorithm = SHA384_ALG; + } else if (strcmp(optarg, "SHA512") == 0) { + hash_algorithm = SHA512_ALG; + } else { + fprintf(stderr, "algorithm is one of: [SHA1, SHA224, SHA256, SHA384, SHA512]\n"); + print_help(); + goto out; + } + break; case 'h': default: print_help(); @@ -224,38 +240,13 @@ int main(int argc, char *argv[]) } } - if (argv[optind] == NULL - || argv[optind+1] == NULL - || argv[optind+2] == NULL - || argv[optind+3] != NULL) { + if (argc - optind != 1) { fprintf(stderr, "Incorrect number of arguments\n"); print_help(); goto out; } - update_times = atoi(argv[optind]); - if (update_times <= 0) { - fprintf(stderr, "update-times must be a positive integer\n"); - goto out; - } - - if (strcmp(argv[optind+1], "SHA1") == 0) { - hash_algorithm = SHA1_ALG; - } else if (strcmp(argv[optind+1], "SHA224") == 0) { - hash_algorithm = SHA224_ALG; - } else if (strcmp(argv[optind+1], "SHA256") == 0) { - hash_algorithm = SHA256_ALG; - } else if (strcmp(argv[optind+1], "SHA384") == 0) { - hash_algorithm = SHA384_ALG; - } else if (strcmp(argv[optind+1], "SHA512") == 0) { - hash_algorithm = SHA512_ALG; - } else { - fprintf(stderr, "algorithm is one of: [SHA1, SHA224, SHA256, SHA384, SHA512]\n"); - print_help(); - goto out; - } - - threadcount = atoi(argv[optind+2]); + threadcount = atoi(argv[optind]); if (threadcount < 1) { fprintf(stderr, "thread-count must be a positive integer\n"); print_help(); @@ -265,14 +256,14 @@ int main(int argc, char *argv[]) if (!RAND_bytes((unsigned char *)data, sizeof(data))) goto out; - max_time = ossl_time_add(ossl_time_now(), ossl_seconds2time(RUN_TIME)); - counts = OPENSSL_zalloc(sizeof(size_t) * threadcount); if (counts == NULL) { fprintf(stderr, "Failed to create counts array\n"); goto out; } + max_time = ossl_time_add(ossl_time_now(), ossl_seconds2time(RUN_TIME)); + if (deprecated_api) { switch (hash_algorithm) { case SHA1_ALG: From 4981f8f78bccb933d0ca3fea6cf9054933f45ff8 Mon Sep 17 00:00:00 2001 From: Andrew Dinh Date: Wed, 22 Oct 2025 13:18:53 +0200 Subject: [PATCH 4/7] Suppress deprecation warnings --- README.md | 21 +++++++++++++++++++++ source/evp_hash.c | 10 +++++++--- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index e2d05e3..0d6b826 100644 --- a/README.md +++ b/README.md @@ -195,3 +195,24 @@ The test program supports options as follows: -p - port number to use -t - terse output ``` + +## evp_hash + +Tool that computes hashes using the specified algorithm. +Runs for 5 seconds and prints the average execution time per hash. +Uses the EVP API by default, but this tool can also use the corresponding deprecated API's. +Prints out the average time per hash computation. + +``` +Usage: evp_hash [-h] [-x] [-t] [-u update-times] [-a algorithm] thread-count +-h - print this help output +-x - use deprecated API instead of EVP API +-t - terse output +-u update-times - times to update digest. 1 for one-shot (default: 1) +-a algorithm - One of: [SHA1, SHA224, SHA256, SHA384, SHA512] (default: SHA1) +thread-count - number of threads +``` + +```sh +evp_hash -u 10 -a SHA512 -x 15 +``` diff --git a/source/evp_hash.c b/source/evp_hash.c index dab67de..d0ccce9 100644 --- a/source/evp_hash.c +++ b/source/evp_hash.c @@ -13,6 +13,8 @@ * Prints out the average time per hash computation. */ +#define OPENSSL_SUPPRESS_DEPRECATED + #include #include #ifndef _WIN32 @@ -165,8 +167,10 @@ void do_hash_evp(size_t num) OSSL_TIME time; EVP_MD_CTX *mctx = EVP_MD_CTX_new(); - if (mctx == NULL) + if (mctx == NULL) { + err = 1; return; + } do { if (!hash_evp(mctx, evp_md)) { @@ -188,8 +192,8 @@ void print_help() printf("-h - print this help output\n"); printf("-x - use deprecated API instead of EVP API\n"); printf("-t - terse output\n"); - printf("-u update-times - times to update digest. 1 for one-shot. By default, do one-shot\n"); - printf("-a algorithm - One of: [SHA1, SHA224, SHA256, SHA384, SHA512]. By default, use SHA1\n"); + printf("-u update-times - times to update digest. 1 for one-shot (default: 1)\n"); + printf("-a algorithm - One of: [SHA1, SHA224, SHA256, SHA384, SHA512] (default: SHA1)\n"); printf("thread-count - number of threads\n"); } From e1744e32c9d213664fe88d1c90c5c779cb778fb1 Mon Sep 17 00:00:00 2001 From: Andrew Dinh Date: Wed, 22 Oct 2025 15:57:30 +0200 Subject: [PATCH 5/7] Reuse EVP_MD --- source/evp_hash.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/source/evp_hash.c b/source/evp_hash.c index d0ccce9..678f1f8 100644 --- a/source/evp_hash.c +++ b/source/evp_hash.c @@ -19,9 +19,7 @@ #include #ifndef _WIN32 # include -# include #else -# include # include "perflib/getopt.h" #endif /* _WIN32 */ @@ -132,19 +130,19 @@ int hash_sha512_deprecated() } -int hash_evp(EVP_MD_CTX *mctx, const EVP_MD *evp_md) +int hash_evp(EVP_MD_CTX *mctx) { int i; unsigned char md[EVP_MAX_MD_SIZE]; - if (!EVP_DigestInit(mctx, evp_md)) + if (!EVP_DigestInit_ex(mctx, NULL, NULL)) return 0; for (i = 0; i < update_times; i++) if (!EVP_DigestUpdate(mctx, data, sizeof(data))) return 0; - return EVP_DigestFinal(mctx, md, NULL); + return EVP_DigestFinal_ex(mctx, md, NULL); } void do_hash_deprecated(size_t num) @@ -167,13 +165,13 @@ void do_hash_evp(size_t num) OSSL_TIME time; EVP_MD_CTX *mctx = EVP_MD_CTX_new(); - if (mctx == NULL) { + if (mctx == NULL || !EVP_DigestInit_ex(mctx, evp_md, NULL)) { err = 1; return; } do { - if (!hash_evp(mctx, evp_md)) { + if (!hash_evp(mctx)) { err = 1; goto err; } From 2a34b39e7b1a3c3f850ff41a4f5f2f9b0eccc08c Mon Sep 17 00:00:00 2001 From: Andrew Dinh Date: Fri, 24 Oct 2025 10:19:37 +0100 Subject: [PATCH 6/7] Add option for mode of operation Instead of just choosing between deprecated and EVP API, choose one of [deprecated, evp_isolated, evp_shared] (default: evp_shared) --- source/evp_hash.c | 162 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 129 insertions(+), 33 deletions(-) diff --git a/source/evp_hash.c b/source/evp_hash.c index 678f1f8..6bd3539 100644 --- a/source/evp_hash.c +++ b/source/evp_hash.c @@ -36,6 +36,12 @@ static OSSL_TIME max_time; size_t *counts = NULL; int err = 0; +typedef enum { + DEPRECATED = 0, + EVP_ISOLATED, + EVP_SHARED, +} operation_type; + typedef enum { SHA1_ALG = 0, SHA224_ALG, @@ -47,9 +53,11 @@ typedef enum { static unsigned char data[DATA_SIZE]; static int update_times = 1; static const EVP_MD *evp_md = NULL; -static int (*hash_func_deprecated)(void); +static int (*hash_func_isolated)(void); + +/* These functions are not allowed to take any parameters */ -int hash_sha1_deprecated() +static int hash_deprecated_sha1() { int i; SHA_CTX sha_ctx; @@ -65,7 +73,7 @@ int hash_sha1_deprecated() return SHA1_Final(md, &sha_ctx); } -int hash_sha224_deprecated() +static int hash_deprecated_sha224() { int i; SHA256_CTX sha256_ctx; @@ -81,7 +89,7 @@ int hash_sha224_deprecated() return SHA224_Final(md, &sha256_ctx); } -int hash_sha256_deprecated() +static int hash_deprecated_sha256() { int i; SHA256_CTX sha256_ctx; @@ -97,7 +105,7 @@ int hash_sha256_deprecated() return SHA256_Final(md, &sha256_ctx); } -int hash_sha384_deprecated() +static int hash_deprecated_sha384() { int i; SHA512_CTX sha512_ctx; @@ -113,7 +121,7 @@ int hash_sha384_deprecated() return SHA384_Final(md, &sha512_ctx); } -int hash_sha512_deprecated() +static int hash_deprecated_sha512() { int i; SHA512_CTX sha512_ctx; @@ -129,28 +137,59 @@ int hash_sha512_deprecated() return SHA512_Final(md, &sha512_ctx); } - -int hash_evp(EVP_MD_CTX *mctx) +static int hash_evp(const EVP_MD *evp_md) { - int i; + int i, ret = 0; unsigned char md[EVP_MAX_MD_SIZE]; + EVP_MD_CTX *mctx = EVP_MD_CTX_new(); - if (!EVP_DigestInit_ex(mctx, NULL, NULL)) - return 0; + if (mctx == NULL || !EVP_DigestInit_ex(mctx, evp_md, NULL)) + goto err; for (i = 0; i < update_times; i++) if (!EVP_DigestUpdate(mctx, data, sizeof(data))) - return 0; + goto err; - return EVP_DigestFinal_ex(mctx, md, NULL); + if (!EVP_DigestFinal_ex(mctx, md, NULL)) + goto err; + + ret = 1; +err: + EVP_MD_CTX_free(mctx); + return ret; +} + +static int hash_evp_sha1() +{ + return hash_evp(EVP_sha1()); } -void do_hash_deprecated(size_t num) +static int hash_evp_sha224() +{ + return hash_evp(EVP_sha224()); +} + +static int hash_evp_sha256() +{ + return hash_evp(EVP_sha256()); +} + +static int hash_evp_sha384() +{ + return hash_evp(EVP_sha384()); +} + +static int hash_evp_sha512() +{ + return hash_evp(EVP_sha512()); +} + +static void do_hash_isolated(size_t num) { OSSL_TIME time; do { - if (!hash_func_deprecated()) { + if (!hash_func_isolated()) { err = 1; return; } @@ -160,7 +199,26 @@ void do_hash_deprecated(size_t num) } while (time.t < max_time.t); } -void do_hash_evp(size_t num) +/* + * These functions can access global state, so they can do some initial setup. + */ + +static int hash_evp_shared(EVP_MD_CTX *mctx) +{ + int i; + unsigned char md[EVP_MAX_MD_SIZE]; + + if (!EVP_DigestInit_ex(mctx, NULL, NULL)) + return 0; + + for (i = 0; i < update_times; i++) + if (!EVP_DigestUpdate(mctx, data, sizeof(data))) + return 0; + + return EVP_DigestFinal_ex(mctx, md, NULL); +} + +static void do_hash_evp_shared(size_t num) { OSSL_TIME time; EVP_MD_CTX *mctx = EVP_MD_CTX_new(); @@ -171,7 +229,7 @@ void do_hash_evp(size_t num) } do { - if (!hash_evp(mctx)) { + if (!hash_evp_shared(mctx)) { err = 1; goto err; } @@ -184,12 +242,14 @@ void do_hash_evp(size_t num) EVP_MD_CTX_free(mctx); } -void print_help() +/* Main */ + +static void print_help() { - printf("Usage: evp_hash [-h] [-x] [-t] [-u update-times] [-a algorithm] thread-count\n"); + printf("Usage: evp_hash [-h] [-t] [-o operation] [-u update-times] [-a algorithm] thread-count\n"); printf("-h - print this help output\n"); - printf("-x - use deprecated API instead of EVP API\n"); printf("-t - terse output\n"); + printf("-o operation - mode of operation. One of [deprecated, evp_isolated, evp_shared] (default: evp_shared)\n"); printf("-u update-times - times to update digest. 1 for one-shot (default: 1)\n"); printf("-a algorithm - One of: [SHA1, SHA224, SHA256, SHA384, SHA512] (default: SHA1)\n"); printf("thread-count - number of threads\n"); @@ -200,16 +260,26 @@ int main(int argc, char *argv[]) OSSL_TIME duration; size_t total_count = 0; double av; - int terse = 0, deprecated_api = 0, hash_algorithm = SHA1_ALG; + int terse = 0, operation = EVP_SHARED, hash_algorithm = SHA1_ALG; int j, opt, rc = EXIT_FAILURE; - while ((opt = getopt(argc, argv, "htxu:a:")) != -1) { + while ((opt = getopt(argc, argv, "hto:u:a:")) != -1) { switch (opt) { case 't': terse = 1; break; - case 'x': - deprecated_api = 1; + case 'o': + if (strcmp(optarg, "deprecated") == 0) { + operation = DEPRECATED; + } else if (strcmp(optarg, "evp_isolated") == 0) { + operation = EVP_ISOLATED; + } else if (strcmp(optarg, "evp_shared") == 0) { + operation = EVP_SHARED; + } else { + fprintf(stderr, "operation is one of [deprecated, evp_isolated, evp_shared]\n"); + print_help(); + goto out; + } break; case 'u': update_times = atoi(optarg); @@ -266,29 +336,54 @@ int main(int argc, char *argv[]) max_time = ossl_time_add(ossl_time_now(), ossl_seconds2time(RUN_TIME)); - if (deprecated_api) { + switch (operation) { + case DEPRECATED: + switch (hash_algorithm) { + case SHA1_ALG: + hash_func_isolated = hash_deprecated_sha1; + break; + case SHA224_ALG: + hash_func_isolated = hash_deprecated_sha224; + break; + case SHA256_ALG: + hash_func_isolated = hash_deprecated_sha256; + break; + case SHA384_ALG: + hash_func_isolated = hash_deprecated_sha384; + break; + case SHA512_ALG: + hash_func_isolated = hash_deprecated_sha512; + break; + default: + err = 1; + goto out; + } + err = !perflib_run_multi_thread_test(do_hash_isolated, threadcount, &duration) || err; + break; + case EVP_ISOLATED: switch (hash_algorithm) { case SHA1_ALG: - hash_func_deprecated = hash_sha1_deprecated; + hash_func_isolated = hash_evp_sha1; break; case SHA224_ALG: - hash_func_deprecated = hash_sha224_deprecated; + hash_func_isolated = hash_evp_sha224; break; case SHA256_ALG: - hash_func_deprecated = hash_sha256_deprecated; + hash_func_isolated = hash_evp_sha256; break; case SHA384_ALG: - hash_func_deprecated = hash_sha384_deprecated; + hash_func_isolated = hash_evp_sha384; break; case SHA512_ALG: - hash_func_deprecated = hash_sha512_deprecated; + hash_func_isolated = hash_evp_sha512; break; default: err = 1; goto out; } - err = !perflib_run_multi_thread_test(do_hash_deprecated, threadcount, &duration) || err; - } else { + err = !perflib_run_multi_thread_test(do_hash_isolated, threadcount, &duration) || err; + break; + case EVP_SHARED: switch (hash_algorithm) { case SHA1_ALG: evp_md = EVP_sha1(); @@ -310,7 +405,8 @@ int main(int argc, char *argv[]) goto out; } - err = !perflib_run_multi_thread_test(do_hash_evp, threadcount, &duration) || err; + err = !perflib_run_multi_thread_test(do_hash_evp_shared, threadcount, &duration) || err; + break; } if (err) { From 64da14316dadc3d391ad5eb3db822dfbc47ad0e3 Mon Sep 17 00:00:00 2001 From: Andrew Dinh Date: Wed, 29 Oct 2025 13:33:23 +0100 Subject: [PATCH 7/7] Update README for evp_hash -o options --- README.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 0d6b826..f8c32db 100644 --- a/README.md +++ b/README.md @@ -200,19 +200,22 @@ The test program supports options as follows: Tool that computes hashes using the specified algorithm. Runs for 5 seconds and prints the average execution time per hash. -Uses the EVP API by default, but this tool can also use the corresponding deprecated API's. Prints out the average time per hash computation. +Three modes of operation: +- deprecated: Use deprecated, legacy API's to do hash (e.g. SHA1_Init) +- evp_isolated: Use EVP API and don't allow shared data between threads +- evp_shared (default): Use EVP API and allow shared data between threads ``` -Usage: evp_hash [-h] [-x] [-t] [-u update-times] [-a algorithm] thread-count +Usage: evp_hash [-h] [-t] [-o operation] [-u update-times] [-a algorithm] thread-count -h - print this help output --x - use deprecated API instead of EVP API -t - terse output +-o operation - mode of operation. One of [deprecated, evp_isolated, evp_shared] (default: evp_shared) -u update-times - times to update digest. 1 for one-shot (default: 1) -a algorithm - One of: [SHA1, SHA224, SHA256, SHA384, SHA512] (default: SHA1) thread-count - number of threads ``` ```sh -evp_hash -u 10 -a SHA512 -x 15 +evp_hash -u 10 -a SHA512 -o evp_isolated 15 ```