From b4247b2de1624811aa03898b7f52d4c4dd2f0ac4 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Wed, 25 Mar 2020 23:37:12 +0300 Subject: [PATCH 47/87] regress/evp: add simple test for AEAD ciphers Add a companion to evptest.c and aeadtest.c: test for AEAD ciphers using EVP_CIPHER interface. For now it is capable of testing only GCM mode. Signed-off-by: Dmitry Baryshkov --- src/regress/lib/libcrypto/evp/evpaeadtest.c | 382 ++++++++++++++++++ .../lib/libcrypto/evp/evpaeadtests.txt | 14 + 2 files changed, 396 insertions(+) create mode 100644 src/regress/lib/libcrypto/evp/evpaeadtest.c create mode 100644 src/regress/lib/libcrypto/evp/evpaeadtests.txt diff --git a/src/regress/lib/libcrypto/evp/evpaeadtest.c b/src/regress/lib/libcrypto/evp/evpaeadtest.c new file mode 100644 index 000000000..6d3970ee3 --- /dev/null +++ b/src/regress/lib/libcrypto/evp/evpaeadtest.c @@ -0,0 +1,382 @@ +/* $OpenBSD: evptest.c,v 1.9 2020/01/26 02:46:26 tb Exp $ */ +/* Written by Ben Laurie, 2001 */ +/* + * Copyright (c) 2001 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include + +#include +#include +#ifndef OPENSSL_NO_ENGINE +#include +#endif +#include +#include + +static void +hexdump(FILE *f, const char *title, const unsigned char *s, int l) +{ + int n = 0; + + fprintf(f, "%s",title); + for (; n < l; ++n) { + if ((n % 16) == 0) + fprintf(f, "\n%04x",n); + fprintf(f, " %02x",s[n]); + } + fprintf(f, "\n"); +} + +static int +convert(unsigned char *s) +{ + unsigned char *d; + + for (d = s; *s; s += 2,++d) { + unsigned int n; + + if (!s[1]) { + fprintf(stderr, "Odd number of hex digits!\n"); + exit(4); + } + if (sscanf((char *)s, "%2x", &n) != 1) { + fprintf(stderr, "Invalid hex value at %s\n", s); + exit(4); + } + + *d = (unsigned char)n; + } + return s - d; +} + +static char * +sstrsep(char **string, const char *delim) +{ + char isdelim[256]; + char *token = *string; + + if (**string == 0) + return NULL; + + memset(isdelim, 0, 256); + isdelim[0] = 1; + + while (*delim) { + isdelim[(unsigned char)(*delim)] = 1; + delim++; + } + + while (!isdelim[(unsigned char)(**string)]) { + (*string)++; + } + + if (**string) { + **string = 0; + (*string)++; + } + + return token; +} + +static unsigned char * +ustrsep(char **p, const char *sep) +{ + return (unsigned char *)sstrsep(p, sep); +} + +static int +test1_exit(int ec) +{ + exit(ec); + return(0); /* To keep some compilers quiet */ +} + +static int +test_cipher(const char *cipher, const unsigned char *key, int kn, + const unsigned char *iv, int in, + const unsigned char *aad, int an, + const unsigned char *plaintext, int pn, + const unsigned char *ciphertext, int cn, + const unsigned char *tag, int tn, + int encdec) +{ + EVP_CIPHER_CTX ctx; + unsigned char out[4096]; + const unsigned char *eiv; + int outl, outl2; + + const EVP_CIPHER *c; + + c = EVP_get_cipherbyname(cipher); + if (!c) + return 0; + + printf("Testing cipher %s%s\n", EVP_CIPHER_name(c), + (encdec == 1 ? "(encrypt)" : (encdec == 0 ? "(decrypt)" : "(encrypt/decrypt)"))); + hexdump(stdout, "Key",key,kn); + hexdump(stdout, "IV",iv,in); + hexdump(stdout, "AAD",aad,an); + hexdump(stdout, "Plaintext",plaintext,pn); + hexdump(stdout, "Ciphertext",ciphertext,cn); + hexdump(stdout, "Tag",tag,tn); + + if (kn != c->key_len) { + fprintf(stderr, "Key length doesn't match, got %d expected %lu\n",kn, + (unsigned long)c->key_len); + test1_exit(1); + } + EVP_CIPHER_CTX_init(&ctx); + EVP_CIPHER_CTX_set_flags(&ctx, EVP_CIPHER_CTX_FLAG_WRAP_ALLOW); + if (encdec != 0) { + eiv = iv; + if (EVP_CIPHER_mode(c) == EVP_CIPH_WRAP_MODE && in == 0) + eiv = NULL; + if (!EVP_EncryptInit_ex(&ctx, c, NULL, key, eiv)) { + fprintf(stderr, "EncryptInit failed\n"); + ERR_print_errors_fp(stderr); + test1_exit(2); + } + EVP_CIPHER_CTX_set_padding(&ctx, 0); + + if (!EVP_EncryptUpdate(&ctx, NULL, &outl, aad, an)) { + fprintf(stderr, "Encrypt failed\n"); + ERR_print_errors_fp(stderr); + test1_exit(3); + } + if (!EVP_EncryptUpdate(&ctx, out, &outl, plaintext, pn)) { + fprintf(stderr, "Encrypt failed\n"); + ERR_print_errors_fp(stderr); + test1_exit(4); + } + if (!EVP_EncryptFinal_ex(&ctx, out + outl, &outl2)) { + fprintf(stderr, "EncryptFinal failed\n"); + ERR_print_errors_fp(stderr); + test1_exit(5); + } + + if (outl + outl2 != cn) { + fprintf(stderr, "Ciphertext length mismatch got %d expected %d\n", + outl + outl2, cn); + test1_exit(6); + } + + if (memcmp(out, ciphertext, cn)) { + fprintf(stderr, "Ciphertext mismatch\n"); + hexdump(stderr, "Got",out,cn); + hexdump(stderr, "Expected",ciphertext,cn); + test1_exit(7); + } + + if (!EVP_CIPHER_CTX_ctrl(&ctx, EVP_CTRL_GCM_GET_TAG, tn, out)) { + fprintf(stderr, "GET_TAG failed\n"); + ERR_print_errors_fp(stderr); + test1_exit(8); + } + + if (memcmp(out, tag, tn)) { + fprintf(stderr, "Ciphertext mismatch\n"); + hexdump(stderr, "Got",out,tn); + hexdump(stderr, "Expected",tag,cn); + test1_exit(9); + } + + } + + if (encdec <= 0) { + eiv = iv; + if (EVP_CIPHER_mode(c) == EVP_CIPH_WRAP_MODE && in == 0) + eiv = NULL; + if (!EVP_DecryptInit_ex(&ctx, c,NULL, key, eiv)) { + fprintf(stderr, "DecryptInit failed\n"); + ERR_print_errors_fp(stderr); + test1_exit(10); + } + EVP_CIPHER_CTX_set_padding(&ctx, 0); + + if (!EVP_DecryptUpdate(&ctx, NULL, &outl, aad, an)) { + fprintf(stderr, "Encrypt failed\n"); + ERR_print_errors_fp(stderr); + test1_exit(10); + } + if (!EVP_DecryptUpdate(&ctx, out, &outl, ciphertext, cn)) { + fprintf(stderr, "Decrypt failed\n"); + ERR_print_errors_fp(stderr); + test1_exit(12); + } + + if(!EVP_CIPHER_CTX_ctrl(&ctx, EVP_CTRL_GCM_SET_TAG, tn, (void *)tag)) { + fprintf(stderr, "SET_TAG failed\n"); + ERR_print_errors_fp(stderr); + test1_exit(13); + } + + if (!EVP_DecryptFinal_ex(&ctx, out + outl, &outl2)) { + fprintf(stderr, "DecryptFinal failed\n"); + ERR_print_errors_fp(stderr); + test1_exit(14); + } + + if (outl + outl2 != pn) { + fprintf(stderr, "Plaintext length mismatch got %d expected %d\n", + outl + outl2, pn); + test1_exit(15); + } + + if (memcmp(out, plaintext, pn)) { + fprintf(stderr, "Plaintext mismatch\n"); + hexdump(stderr, "Got",out,pn); + hexdump(stderr, "Expected",plaintext,pn); + test1_exit(16); + } + } + + EVP_CIPHER_CTX_cleanup(&ctx); + + printf("\n"); + + return 1; +} + +int +main(int argc, char **argv) +{ + const char *szTestFile; + FILE *f; + + if (argc != 2) { + fprintf(stderr, "%s \n",argv[0]); + exit(1); + } + + szTestFile = argv[1]; + + f=fopen(szTestFile, "r"); + if (!f) { + perror(szTestFile); + exit(2); + } + + /* Load up the software EVP_CIPHER and EVP_MD definitions */ + OpenSSL_add_all_ciphers(); +#ifndef OPENSSL_NO_ENGINE + /* Load all compiled-in ENGINEs */ + ENGINE_load_builtin_engines(); +#endif +#if 0 + OPENSSL_config(); +#endif +#ifndef OPENSSL_NO_ENGINE + /* Register all available ENGINE implementations of ciphers and digests. + * This could perhaps be changed to "ENGINE_register_all_complete()"? */ + ENGINE_register_all_ciphers(); + /* If we add command-line options, this statement should be switchable. + * It'll prevent ENGINEs being ENGINE_init()ialised for cipher/digest use if + * they weren't already initialised. */ + /* ENGINE_set_cipher_flags(ENGINE_CIPHER_FLAG_NOINIT); */ +#endif + + for (;;) { + char line[8 * 1024]; + char *p; + char *cipher; + unsigned char *iv, *key, *plaintext, *ciphertext, *aad, *tag; + int encdec; + int kn, in, pn, cn, an, tn; + + if (!fgets((char *)line, sizeof line, f)) + break; + if (line[0] == '#' || line[0] == '\n') + continue; + p = line; + cipher=sstrsep(&p, ":"); + key=ustrsep(&p, ":"); + iv=ustrsep(&p, ":"); + aad=ustrsep(&p, ":"); + plaintext=ustrsep(&p, ":"); + ciphertext=ustrsep(&p, ":"); + tag=ustrsep(&p, ":"); + if (p[-1] == '\n') { + p[-1] = '\0'; + encdec = -1; + } else { + encdec = atoi(sstrsep(&p, "\n")); + } + + kn = convert(key); + in = convert(iv); + an = convert(aad); + pn = convert(plaintext); + cn = convert(ciphertext); + tn = convert(tag); + + if (!test_cipher(cipher, key, kn, iv, in, aad, an, plaintext, pn, ciphertext, cn, tag, tn, encdec)) { +#ifdef OPENSSL_NO_GOST + if (strstr(cipher, "magma") == cipher || + strstr(cipher, "kuznyechik") == cipher) { + fprintf(stdout, "Cipher disabled, skipping %s\n", cipher); + continue; + } +#endif + fprintf(stderr, "Can't find %s\n",cipher); + exit(3); + } + } + fclose(f); + +#ifndef OPENSSL_NO_ENGINE + ENGINE_cleanup(); +#endif + EVP_cleanup(); + CRYPTO_cleanup_all_ex_data(); + ERR_remove_thread_state(NULL); + ERR_free_strings(); + CRYPTO_mem_leaks_fp(stderr); + + return 0; +} diff --git a/src/regress/lib/libcrypto/evp/evpaeadtests.txt b/src/regress/lib/libcrypto/evp/evpaeadtests.txt new file mode 100644 index 000000000..68156e7a5 --- /dev/null +++ b/src/regress/lib/libcrypto/evp/evpaeadtests.txt @@ -0,0 +1,14 @@ +# $OpenBSD: evptests.txt,v 1.9 2020/01/26 03:31:40 tb Exp $ +#cipher:key:iv:aad:plaintext:ciphertext:tag:0/1(decrypt/encrypt) + +aes-128-gcm:013FE00B5F11BE7F866D0CBBC55A7A90:7CFDE9F9E33724C68932D612:84C5D513D2AAF6E5BBD2727788E523008932D6127CFDE9F9E33724C608000F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F0005:::217867E50C2DAD74C28C3B50ABDF695A:1 +aes-128-gcm:013FE00B5F11BE7F866D0CBBC55A7A90:7CFDE9F9E33724C68932D612:84C5D513D2AAF6E5BBD2727788E523008932D6127CFDE9F9E33724C608000F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F0005:::217867E50C2DAD74C28C3B50ABDF695A:0 + +aes-256-gcm:83C093B58DE7FFE1C0DA926AC43FB3609AC1C80FEE1B624497EF942E2F79A823:7CFDE9F9E33724C68932D612:84C5D513D2AAF6E5BBD2727788E523008932D6127CFDE9F9E33724C608000F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F0005:::6EE160E8FAECA4B36C86B234920CA975:1 +aes-256-gcm:83C093B58DE7FFE1C0DA926AC43FB3609AC1C80FEE1B624497EF942E2F79A823:7CFDE9F9E33724C68932D612:84C5D513D2AAF6E5BBD2727788E523008932D6127CFDE9F9E33724C608000F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F0005:::6EE160E8FAECA4B36C86B234920CA975:0 + +aes-128-gcm:88EE087FD95DA9FBF6725AA9D757B0CD:7AE8E2CA4EC500012E58495C:68F2E77696CE7AE8E2CA4EC588E54D002E58495C:08000F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748490008:C31F53D99E5687F7365119B832D2AAE70741D593F1F9E2AB3455779B078EB8FEACDFEC1F8E3E5277F8180B43361F6512ADB16D2E38548A2C719DBA7228D840:88F8757ADB8AA788D8F65AD668BE70E7:1 +aes-128-gcm:88EE087FD95DA9FBF6725AA9D757B0CD:7AE8E2CA4EC500012E58495C:68F2E77696CE7AE8E2CA4EC588E54D002E58495C:08000F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748490008:C31F53D99E5687F7365119B832D2AAE70741D593F1F9E2AB3455779B078EB8FEACDFEC1F8E3E5277F8180B43361F6512ADB16D2E38548A2C719DBA7228D840:88F8757ADB8AA788D8F65AD668BE70E7:0 + +aes-256-gcm:4C973DBC7364621674F8B5B89E5C15511FCED9216490FB1C1A2CAA0FFE0407E5:7AE8E2CA4EC500012E58495C:68F2E77696CE7AE8E2CA4EC588E54D002E58495C:08000F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748490008:BA8AE31BC506486D6873E4FCE460E7DC57591FF00611F31C3834FE1C04AD80B66803AFCF5B27E6333FA67C99DA47C2F0CED68D531BD741A943CFF7A6713BD0:2611CD7DAA01D61C5C886DC1A8170107:1 +aes-256-gcm:4C973DBC7364621674F8B5B89E5C15511FCED9216490FB1C1A2CAA0FFE0407E5:7AE8E2CA4EC500012E58495C:68F2E77696CE7AE8E2CA4EC588E54D002E58495C:08000F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748490008:BA8AE31BC506486D6873E4FCE460E7DC57591FF00611F31C3834FE1C04AD80B66803AFCF5B27E6333FA67C99DA47C2F0CED68D531BD741A943CFF7A6713BD0:2611CD7DAA01D61C5C886DC1A8170107:0 -- 2.17.1