summaryrefslogtreecommitdiffstats
path: root/apps
diff options
context:
space:
mode:
authorMohammed Alhabib <zelda923@gmail.com>2024-10-29 10:00:54 +0100
committerTomas Mraz <tomas@openssl.org>2024-11-04 10:04:23 +0100
commit607a46d003f472d4bce646f3df6e85725094d68a (patch)
treedadeac6f0db77d97d4e405ee77ec554441c3a438 /apps
parentapps: Change default cipher to aes-256-cbc for req, cms and smime apps (diff)
downloadopenssl-607a46d003f472d4bce646f3df6e85725094d68a.tar.xz
openssl-607a46d003f472d4bce646f3df6e85725094d68a.zip
apps/speed.c: Fix the benchmarking for AEAD ciphers
Fixed the benchmarking for the evp aead interface for ccm, gcm, ocb, and siv, where decryption fails when executing `openssl speed -evp aes-128-ccm -decrypt` and `openssl speed -evp aes-128-gcm -decrypt`. Related issues are [24686](https://github.com/openssl/openssl/issues/24686) and [24250](https://github.com/openssl/openssl/issues/24250). Now both encryption and decryption, with or without AAD, executes correctly without issues. Reviewed-by: Tom Cosgrove <tom.cosgrove@arm.com> Reviewed-by: Tomas Mraz <tomas@openssl.org> (Merged from https://github.com/openssl/openssl/pull/25823)
Diffstat (limited to 'apps')
-rw-r--r--apps/speed.c360
1 files changed, 285 insertions, 75 deletions
diff --git a/apps/speed.c b/apps/speed.c
index c3bc223a9d..4b24cd37a5 100644
--- a/apps/speed.c
+++ b/apps/speed.c
@@ -515,6 +515,14 @@ static double sigs_results[MAX_SIG_NUM][3]; /* keygen, sign, verify */
#define COND(unused_cond) (run && count < (testmode ? 1 : INT_MAX))
#define COUNT(d) (count)
+#define TAG_LEN 16
+
+static unsigned int mode_op; /* AE Mode of operation */
+static unsigned int aead = 0; /* AEAD flag */
+static unsigned char aead_iv[12]; /* For AEAD modes */
+static unsigned char aad[EVP_AEAD_TLS1_AAD_LEN] = { 0xcc };
+static int aead_ivlen = sizeof(aead_iv);
+
typedef struct loopargs_st {
ASYNC_JOB *inprogress_job;
ASYNC_WAIT_CTX *wait_ctx;
@@ -523,6 +531,7 @@ typedef struct loopargs_st {
unsigned char *buf_malloc;
unsigned char *buf2_malloc;
unsigned char *key;
+ unsigned char tag[TAG_LEN];
size_t buflen;
size_t sigsize;
size_t encsize;
@@ -875,12 +884,8 @@ static int EVP_Update_loop(void *args)
unsigned char *buf = tempargs->buf;
EVP_CIPHER_CTX *ctx = tempargs->ctx;
int outl, count, rc;
- unsigned char faketag[16] = { 0xcc };
if (decrypt) {
- if (EVP_CIPHER_get_flags(EVP_CIPHER_CTX_get0_cipher(ctx)) & EVP_CIPH_FLAG_AEAD_CIPHER) {
- (void)EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, sizeof(faketag), faketag);
- }
for (count = 0; COND(c[D_EVP][testnum]); count++) {
rc = EVP_DecryptUpdate(ctx, buf, &outl, buf, lengths[testnum]);
if (rc != 1) {
@@ -908,44 +913,71 @@ static int EVP_Update_loop(void *args)
}
/*
+ * To make AEAD benchmarking more relevant perform TLS-like operations,
+ * 13-byte AAD followed by payload. But don't use TLS-formatted AAD, as
+ * payload length is not actually limited by 16KB...
* CCM does not support streaming. For the purpose of performance measurement,
* each message is encrypted using the same (key,iv)-pair. Do not use this
* code in your application.
*/
-static int EVP_Update_loop_ccm(void *args)
+static int EVP_Update_loop_aead_enc(void *args)
{
loopargs_t *tempargs = *(loopargs_t **) args;
unsigned char *buf = tempargs->buf;
+ unsigned char *key = tempargs->key;
EVP_CIPHER_CTX *ctx = tempargs->ctx;
- int outl, count, realcount = 0, final;
- unsigned char tag[12];
+ int outl, count, realcount = 0;
- if (decrypt) {
- for (count = 0; COND(c[D_EVP][testnum]); count++) {
- if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, sizeof(tag),
- tag) > 0
- /* reset iv */
- && EVP_DecryptInit_ex(ctx, NULL, NULL, NULL, iv) > 0
- /* counter is reset on every update */
- && EVP_DecryptUpdate(ctx, buf, &outl, buf, lengths[testnum]) > 0)
- realcount++;
+ for (count = 0; COND(c[D_EVP][testnum]); count++) {
+ /* Set length of iv (Doesn't apply to SIV mode) */
+ if (mode_op != EVP_CIPH_SIV_MODE) {
+ if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN,
+ aead_ivlen, NULL)) {
+ BIO_printf(bio_err, "\nFailed to set iv length\n");
+ dofail();
+ exit(1);
+ }
}
- } else {
- for (count = 0; COND(c[D_EVP][testnum]); count++) {
- /* restore iv length field */
- if (EVP_EncryptUpdate(ctx, NULL, &outl, NULL, lengths[testnum]) > 0
- /* counter is reset on every update */
- && EVP_EncryptUpdate(ctx, buf, &outl, buf, lengths[testnum]) > 0)
- realcount++;
+ /* Set tag_len (Not for GCM/SIV at encryption stage) */
+ if (mode_op != EVP_CIPH_GCM_MODE
+ && mode_op != EVP_CIPH_SIV_MODE
+ && mode_op != EVP_CIPH_GCM_SIV_MODE) {
+ if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG,
+ TAG_LEN, NULL)) {
+ BIO_printf(bio_err, "\nFailed to set tag length\n");
+ dofail();
+ exit(1);
+ }
+ }
+ if (!EVP_CipherInit_ex(ctx, NULL, NULL, key, aead_iv, -1)) {
+ BIO_printf(bio_err, "\nFailed to set key and iv\n");
+ dofail();
+ exit(1);
+ }
+ /* Set total length of input. Only required for CCM */
+ if (mode_op == EVP_CIPH_CCM_MODE) {
+ if (!EVP_EncryptUpdate(ctx, NULL, &outl,
+ NULL, lengths[testnum])) {
+ BIO_printf(bio_err, "\nCouldn't set input text length\n");
+ dofail();
+ exit(1);
+ }
}
+ if (aead) {
+ if (!EVP_EncryptUpdate(ctx, NULL, &outl, aad, sizeof(aad))) {
+ BIO_printf(bio_err, "\nCouldn't insert AAD when encrypting\n");
+ dofail();
+ exit(1);
+ }
+ }
+ if (!EVP_EncryptUpdate(ctx, buf, &outl, buf, lengths[testnum])) {
+ BIO_printf(bio_err, "\nFailed to encrypt the data\n");
+ dofail();
+ exit(1);
+ }
+ if (EVP_EncryptFinal_ex(ctx, buf, &outl))
+ realcount++;
}
- if (decrypt)
- final = EVP_DecryptFinal_ex(ctx, buf, &outl);
- else
- final = EVP_EncryptFinal_ex(ctx, buf, &outl);
-
- if (final == 0)
- BIO_printf(bio_err, "Error finalizing ccm loop\n");
return realcount;
}
@@ -953,34 +985,87 @@ static int EVP_Update_loop_ccm(void *args)
* To make AEAD benchmarking more relevant perform TLS-like operations,
* 13-byte AAD followed by payload. But don't use TLS-formatted AAD, as
* payload length is not actually limited by 16KB...
+ * CCM does not support streaming. For the purpose of performance measurement,
+ * each message is decrypted using the same (key,iv)-pair. Do not use this
+ * code in your application.
+ * For decryption, we will use buf2 to preserve the input text in buf.
*/
-static int EVP_Update_loop_aead(void *args)
+static int EVP_Update_loop_aead_dec(void *args)
{
loopargs_t *tempargs = *(loopargs_t **) args;
unsigned char *buf = tempargs->buf;
+ unsigned char *outbuf = tempargs->buf2;
+ unsigned char *key = tempargs->key;
+ unsigned char tag[TAG_LEN];
EVP_CIPHER_CTX *ctx = tempargs->ctx;
int outl, count, realcount = 0;
- unsigned char aad[13] = { 0xcc };
- unsigned char faketag[16] = { 0xcc };
- if (decrypt) {
- for (count = 0; COND(c[D_EVP][testnum]); count++) {
- if (EVP_DecryptInit_ex(ctx, NULL, NULL, NULL, iv) > 0
- && EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG,
- sizeof(faketag), faketag) > 0
- && EVP_DecryptUpdate(ctx, NULL, &outl, aad, sizeof(aad)) > 0
- && EVP_DecryptUpdate(ctx, buf, &outl, buf, lengths[testnum]) > 0
- && EVP_DecryptFinal_ex(ctx, buf + outl, &outl) > 0)
- realcount++;
+ for (count = 0; COND(c[D_EVP][testnum]); count++) {
+ /* Set the length of iv (Doesn't apply to SIV mode) */
+ if (mode_op != EVP_CIPH_SIV_MODE) {
+ if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN,
+ aead_ivlen, NULL)) {
+ BIO_printf(bio_err, "\nFailed to set iv length\n");
+ dofail();
+ exit(1);
+ }
}
- } else {
- for (count = 0; COND(c[D_EVP][testnum]); count++) {
- if (EVP_EncryptInit_ex(ctx, NULL, NULL, NULL, iv) > 0
- && EVP_EncryptUpdate(ctx, NULL, &outl, aad, sizeof(aad)) > 0
- && EVP_EncryptUpdate(ctx, buf, &outl, buf, lengths[testnum]) > 0
- && EVP_EncryptFinal_ex(ctx, buf + outl, &outl) > 0)
- realcount++;
+
+ /* Set the tag length (Doesn't apply to SIV mode) */
+ if (mode_op != EVP_CIPH_SIV_MODE
+ && mode_op != EVP_CIPH_GCM_MODE
+ && mode_op != EVP_CIPH_GCM_SIV_MODE) {
+ if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG,
+ TAG_LEN, NULL)) {
+ BIO_printf(bio_err, "\nFailed to set tag length\n");
+ dofail();
+ exit(1);
+ }
}
+ if (!EVP_CipherInit_ex(ctx, NULL, NULL, key, aead_iv, -1)) {
+ BIO_printf(bio_err, "\nFailed to set key and iv\n");
+ dofail();
+ exit(1);
+ }
+ /* Set iv before decryption (Doesn't apply to SIV mode) */
+ if (mode_op != EVP_CIPH_SIV_MODE) {
+ if (!EVP_DecryptInit_ex(ctx, NULL, NULL, NULL, aead_iv)) {
+ BIO_printf(bio_err, "\nFailed to set iv\n");
+ dofail();
+ exit(1);
+ }
+ }
+ memcpy(tag, tempargs->tag, TAG_LEN);
+
+ if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG,
+ TAG_LEN, tag)) {
+ BIO_printf(bio_err, "\nFailed to set tag\n");
+ dofail();
+ exit(1);
+ }
+ /* Set the total length of cipher text. Only required for CCM */
+ if (mode_op == EVP_CIPH_CCM_MODE) {
+ if (!EVP_DecryptUpdate(ctx, NULL, &outl,
+ NULL, lengths[testnum])) {
+ BIO_printf(bio_err, "\nCouldn't set cipher text length\n");
+ dofail();
+ exit(1);
+ }
+ }
+ if (aead) {
+ if (!EVP_DecryptUpdate(ctx, NULL, &outl, aad, sizeof(aad))) {
+ BIO_printf(bio_err, "\nCouldn't insert AAD when decrypting\n");
+ dofail();
+ exit(1);
+ }
+ }
+ if (!EVP_DecryptUpdate(ctx, outbuf, &outl, buf, lengths[testnum])) {
+ BIO_printf(bio_err, "\nFailed to decrypt the data\n");
+ dofail();
+ exit(1);
+ }
+ if (EVP_DecryptFinal_ex(ctx, outbuf, &outl))
+ realcount++;
}
return realcount;
}
@@ -1803,14 +1888,14 @@ int speed_main(int argc, char **argv)
OPTION_CHOICE o;
int async_init = 0, multiblock = 0, pr_header = 0;
uint8_t doit[ALGOR_NUM] = { 0 };
- int ret = 1, misalign = 0, lengths_single = 0, aead = 0;
+ int ret = 1, misalign = 0, lengths_single = 0;
STACK_OF(EVP_KEM) *kem_stack = NULL;
STACK_OF(EVP_SIGNATURE) *sig_stack = NULL;
long count = 0;
unsigned int size_num = SIZE_NUM;
unsigned int i, k, loopargs_len = 0, async_jobs = 0;
unsigned int idx;
- int keylen;
+ int keylen = 0;
int buflen;
size_t declen;
BIGNUM *bn = NULL;
@@ -2839,12 +2924,20 @@ int speed_main(int argc, char **argv)
}
}
+ /*-
+ * There are three scenarios for D_EVP:
+ * 1- Using authenticated encryption (AE) e.g. CCM, GCM, OCB etc.
+ * 2- Using AE + associated data (AD) i.e. AEAD using CCM, GCM, OCB etc.
+ * 3- Not using AE or AD e.g. ECB, CBC, CFB etc.
+ */
if (doit[D_EVP]) {
if (evp_cipher != NULL) {
- int (*loopfunc) (void *) = EVP_Update_loop;
+ int (*loopfunc) (void *);
+ int outlen = 0;
+ unsigned int ae_mode = 0;
- if (multiblock && (EVP_CIPHER_get_flags(evp_cipher) &
- EVP_CIPH_FLAG_TLS1_1_MULTIBLOCK)) {
+ if (multiblock && (EVP_CIPHER_get_flags(evp_cipher)
+ & EVP_CIPH_FLAG_TLS1_1_MULTIBLOCK)) {
multiblock_speed(evp_cipher, lengths_single, &seconds);
ret = 0;
goto end;
@@ -2852,16 +2945,27 @@ int speed_main(int argc, char **argv)
names[D_EVP] = EVP_CIPHER_get0_name(evp_cipher);
- if (EVP_CIPHER_get_mode(evp_cipher) == EVP_CIPH_CCM_MODE) {
- loopfunc = EVP_Update_loop_ccm;
- } else if (aead && (EVP_CIPHER_get_flags(evp_cipher) &
- EVP_CIPH_FLAG_AEAD_CIPHER)) {
- loopfunc = EVP_Update_loop_aead;
+ mode_op = EVP_CIPHER_get_mode(evp_cipher);
+
+ if (aead) {
if (lengths == lengths_list) {
lengths = aead_lengths_list;
size_num = OSSL_NELEM(aead_lengths_list);
}
}
+ if (mode_op == EVP_CIPH_GCM_MODE
+ || mode_op == EVP_CIPH_CCM_MODE
+ || mode_op == EVP_CIPH_OCB_MODE
+ || mode_op == EVP_CIPH_SIV_MODE
+ || mode_op == EVP_CIPH_GCM_SIV_MODE) {
+ ae_mode = 1;
+ if (decrypt)
+ loopfunc = EVP_Update_loop_aead_dec;
+ else
+ loopfunc = EVP_Update_loop_aead_enc;
+ } else {
+ loopfunc = EVP_Update_loop;
+ }
for (testnum = 0; testnum < size_num; testnum++) {
print_message(names[D_EVP], lengths[testnum], seconds.sym);
@@ -2872,38 +2976,145 @@ int speed_main(int argc, char **argv)
BIO_printf(bio_err, "\nEVP_CIPHER_CTX_new failure\n");
exit(1);
}
+
+ /*
+ * For AE modes, we must first encrypt the data to get
+ * a valid tag that enables us to decrypt. If we don't
+ * encrypt first, we won't have a valid tag that enables
+ * authenticity and hence decryption will fail.
+ */
if (!EVP_CipherInit_ex(loopargs[k].ctx, evp_cipher, NULL,
- NULL, iv, decrypt ? 0 : 1)) {
- BIO_printf(bio_err, "\nEVP_CipherInit_ex failure\n");
+ NULL, NULL, ae_mode ? 1 : !decrypt)) {
+ BIO_printf(bio_err, "\nCouldn't init the context\n");
dofail();
exit(1);
}
+ /* Padding isn't needed */
EVP_CIPHER_CTX_set_padding(loopargs[k].ctx, 0);
keylen = EVP_CIPHER_CTX_get_key_length(loopargs[k].ctx);
loopargs[k].key = app_malloc(keylen, "evp_cipher key");
EVP_CIPHER_CTX_rand_key(loopargs[k].ctx, loopargs[k].key);
- if (!EVP_CipherInit_ex(loopargs[k].ctx, NULL, NULL,
- loopargs[k].key, NULL, -1)) {
- BIO_printf(bio_err, "\nEVP_CipherInit_ex failure\n");
- dofail();
- exit(1);
- }
- OPENSSL_clear_free(loopargs[k].key, keylen);
- /* GCM-SIV/SIV mode only allows for a single Update operation */
- if (EVP_CIPHER_get_mode(evp_cipher) == EVP_CIPH_SIV_MODE
- || EVP_CIPHER_get_mode(evp_cipher) == EVP_CIPH_GCM_SIV_MODE)
- (void)EVP_CIPHER_CTX_ctrl(loopargs[k].ctx,
- EVP_CTRL_SET_SPEED, 1, NULL);
+ if (!ae_mode) {
+ if (!EVP_CipherInit_ex(loopargs[k].ctx, NULL, NULL,
+ loopargs[k].key, NULL, -1)) {
+ BIO_printf(bio_err, "\nFailed to set the key\n");
+ dofail();
+ exit(1);
+ }
+ } else if (mode_op == EVP_CIPH_SIV_MODE
+ || mode_op == EVP_CIPH_GCM_SIV_MODE) {
+ EVP_CIPHER_CTX_ctrl(loopargs[k].ctx,
+ EVP_CTRL_SET_SPEED, 1, NULL);
+ }
+ if (ae_mode && decrypt) {
+ /* Set length of iv (Doesn't apply to SIV mode) */
+ if (mode_op != EVP_CIPH_SIV_MODE) {
+ if (!EVP_CIPHER_CTX_ctrl(loopargs[k].ctx,
+ EVP_CTRL_AEAD_SET_IVLEN,
+ aead_ivlen, NULL)) {
+ BIO_printf(bio_err, "\nFailed to set iv length\n");
+ dofail();
+ exit(1);
+ }
+ }
+ /* Set tag_len (Not for GCM/SIV at encryption stage) */
+ if (mode_op != EVP_CIPH_GCM_MODE
+ && mode_op != EVP_CIPH_SIV_MODE
+ && mode_op != EVP_CIPH_GCM_SIV_MODE) {
+ if (!EVP_CIPHER_CTX_ctrl(loopargs[k].ctx,
+ EVP_CTRL_AEAD_SET_TAG,
+ TAG_LEN, NULL)) {
+ BIO_printf(bio_err,
+ "\nFailed to set tag length\n");
+ dofail();
+ exit(1);
+ }
+ }
+ if (!EVP_CipherInit_ex(loopargs[k].ctx, NULL, NULL,
+ loopargs[k].key, aead_iv, -1)) {
+ BIO_printf(bio_err, "\nFailed to set the key\n");
+ dofail();
+ exit(1);
+ }
+ /* Set total length of input. Only required for CCM */
+ if (mode_op == EVP_CIPH_CCM_MODE) {
+ if (!EVP_EncryptUpdate(loopargs[k].ctx, NULL,
+ &outlen, NULL,
+ lengths[testnum])) {
+ BIO_printf(bio_err,
+ "\nCouldn't set input text length\n");
+ dofail();
+ exit(1);
+ }
+ }
+ if (aead) {
+ if (!EVP_EncryptUpdate(loopargs[k].ctx, NULL,
+ &outlen, aad, sizeof(aad))) {
+ BIO_printf(bio_err,
+ "\nCouldn't insert AAD when encrypting\n");
+ dofail();
+ exit(1);
+ }
+ }
+ if (!EVP_EncryptUpdate(loopargs[k].ctx, loopargs[k].buf,
+ &outlen, loopargs[k].buf,
+ lengths[testnum])) {
+ BIO_printf(bio_err,
+ "\nFailed to to encrypt the data\n");
+ dofail();
+ exit(1);
+ }
+
+ if (!EVP_EncryptFinal_ex(loopargs[k].ctx,
+ loopargs[k].buf, &outlen)) {
+ BIO_printf(bio_err,
+ "\nFailed finalize the encryption\n");
+ dofail();
+ exit(1);
+ }
+
+ if (!EVP_CIPHER_CTX_ctrl(loopargs[k].ctx, EVP_CTRL_AEAD_GET_TAG,
+ TAG_LEN, &loopargs[k].tag)) {
+ BIO_printf(bio_err, "\nFailed to get the tag\n");
+ dofail();
+ exit(1);
+ }
+
+ EVP_CIPHER_CTX_free(loopargs[k].ctx);
+ loopargs[k].ctx = EVP_CIPHER_CTX_new();
+ if (loopargs[k].ctx == NULL) {
+ BIO_printf(bio_err,
+ "\nEVP_CIPHER_CTX_new failure\n");
+ exit(1);
+ }
+ if (!EVP_CipherInit_ex(loopargs[k].ctx, evp_cipher,
+ NULL, NULL, NULL, 0)) {
+ BIO_printf(bio_err,
+ "\nFailed initializing the context\n");
+ dofail();
+ exit(1);
+ }
+
+ EVP_CIPHER_CTX_set_padding(loopargs[k].ctx, 0);
+
+ /* GCM-SIV/SIV only allows for a single Update operation */
+ if (mode_op == EVP_CIPH_SIV_MODE
+ || mode_op == EVP_CIPH_GCM_SIV_MODE)
+ EVP_CIPHER_CTX_ctrl(loopargs[k].ctx,
+ EVP_CTRL_SET_SPEED, 1, NULL);
+ }
}
Time_F(START);
count = run_benchmark(async_jobs, loopfunc, loopargs);
d = Time_F(STOP);
- for (k = 0; k < loopargs_len; k++)
+ for (k = 0; k < loopargs_len; k++) {
+ OPENSSL_clear_free(loopargs[k].key, keylen);
EVP_CIPHER_CTX_free(loopargs[k].ctx);
+ }
print_result(D_EVP, testnum, count, d);
}
} else if (evp_md_name != NULL) {
@@ -4881,7 +5092,6 @@ static void multiblock_speed(const EVP_CIPHER *evp_cipher, int lengths_single,
print_message(alg_name, mblengths[j], seconds->sym);
Time_F(START);
for (count = 0; run && COND(count); count++) {
- unsigned char aad[EVP_AEAD_TLS1_AAD_LEN];
EVP_CTRL_TLS1_1_MULTIBLOCK_PARAM mb_param;
size_t len = mblengths[j];
int packlen;