Created
November 6, 2021 18:22
-
-
Save schwabe/029dc5e5a690df8e2e3f774a13ec7bce to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// c++ -O2 -std=c++14 -g -I/usr/local/opt/openssl@3/include -L/usr/local/opt/openssl@3/lib -lcrypto -lssl -lbenchmark scratch.cpp && ./a.out | |
#include <benchmark/benchmark.h> | |
#include <openssl/rand.h> | |
#include <openssl/evp.h> | |
#include <iostream> | |
static uint8_t *nonce_data = NULL; /* GLOBAL */ | |
const EVP_MD *nonce_md = NULL; | |
int nonce_secret_len = 16; | |
#define PRNG_NONCE_RESET_BYTES 8192 | |
#define md_kt_size EVP_MD_size | |
/* Reset the nonce value, also done periodically to refresh entropy */ | |
static void | |
prng_reset_nonce(void) | |
{ | |
const int size = md_kt_size(nonce_md) + nonce_secret_len; | |
if (!RAND_bytes(nonce_data, size)) | |
{ | |
std::cerr << "ERROR: Random number generator cannot obtain entropy for PRNG" << std::endl; | |
} | |
} | |
int | |
md_full(const EVP_MD *kt, const uint8_t *src, int src_len, uint8_t *dst) | |
{ | |
unsigned int in_md_len = 0; | |
return EVP_Digest(src, src_len, dst, &in_md_len, kt, NULL); | |
} | |
void | |
prng_init() | |
{ | |
nonce_md = ::EVP_sha1(); | |
if (nonce_md) | |
{ | |
{ | |
const int size = md_kt_size(nonce_md) + nonce_secret_len; | |
nonce_data = (uint8_t *) malloc(size); | |
//check_malloc_return(nonce_data); | |
prng_reset_nonce(); | |
} | |
} | |
} | |
int | |
prng_bytes(uint8_t *output, int len) | |
{ | |
static size_t processed = 0; | |
if (nonce_md) | |
{ | |
const int md_size = md_kt_size(nonce_md); | |
while (len > 0) | |
{ | |
const int blen = std::min(len, md_size); | |
md_full(nonce_md, nonce_data, md_size + nonce_secret_len, nonce_data); | |
memcpy(output, nonce_data, blen); | |
output += blen; | |
len -= blen; | |
/* Ensure that random data is reset regularly */ | |
processed += blen; | |
if (processed > PRNG_NONCE_RESET_BYTES) | |
{ | |
prng_reset_nonce(); | |
processed = 0; | |
} | |
} | |
} | |
return 1; | |
} | |
int | |
dummy_prng(uint8_t *output, int len) | |
{ | |
*output = 42; | |
return 1; | |
} | |
static void BM_Encrypt_AES_CBC(benchmark::State &state, decltype(&prng_bytes) rnd) | |
{ | |
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); | |
uint8_t key[32]; | |
uint8_t iv[32]; | |
RAND_bytes(key, 32); | |
uint8_t input[1400]; | |
uint8_t output[1500]; | |
RAND_bytes(input, 140); | |
int ivlen=EVP_CIPHER_iv_length(EVP_aes_128_cbc()); | |
assert(EVP_EncryptInit_ex(ctx, EVP_aes_128_cbc(), NULL, key, iv)); | |
for (auto _: state) | |
{ | |
rnd(iv, ivlen); | |
assert(EVP_EncryptInit_ex(ctx, NULL, NULL, NULL, iv)); | |
int len; | |
/* The EVP_EncryptFinal method will write to the dst+len pointer even | |
* though there is nothing to encrypt anymore, provide space for that to | |
* not overflow the stack */ | |
assert(EVP_EncryptUpdate(ctx, output, &len, input, sizeof(input))); | |
assert(EVP_EncryptFinal(ctx, output + len, &len)); | |
} | |
EVP_CIPHER_CTX_free(ctx); | |
} | |
static void BM_Encrypt_AES_CBC_dummy(benchmark::State &state) | |
{ | |
BM_Encrypt_AES_CBC(state, dummy_prng); | |
} | |
static void BM_Encrypt_AES_CBC_RAND_bytes(benchmark::State &state) | |
{ | |
BM_Encrypt_AES_CBC(state, RAND_bytes); | |
} | |
static void BM_Encrypt_AES_CBC_prng_bytes(benchmark::State &state) | |
{ | |
prng_init(); | |
BM_Encrypt_AES_CBC(state, prng_bytes); | |
} | |
static void BM_OpenVPN_RAND(benchmark::State &state) | |
{ | |
prng_init(); | |
for (auto _: state) | |
{ | |
// This code gets timed | |
uint8_t out[16]; | |
prng_bytes(out, 16); | |
} | |
} | |
static void BM_OpenSSL_RAND(benchmark::State &state) | |
{ | |
// Perform setup here | |
for (auto _: state) | |
{ | |
// This code gets timed | |
uint8_t out[16]; | |
RAND_bytes(out, 16); | |
} | |
} | |
// Register the function as a benchmark | |
BENCHMARK(BM_OpenSSL_RAND); | |
BENCHMARK(BM_OpenVPN_RAND); | |
BENCHMARK(BM_Encrypt_AES_CBC_dummy); | |
BENCHMARK(BM_Encrypt_AES_CBC_RAND_bytes); | |
BENCHMARK(BM_Encrypt_AES_CBC_prng_bytes); | |
// Run the benchmark | |
BENCHMARK_MAIN(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment