X-Git-Url: http://www.wagner.pp.ru/gitweb/?a=blobdiff_plain;f=test_context.c;h=d9ef57926e11d20b640064495ed7a92a3d2c756a;hb=HEAD;hp=72e10579909f55d746e590a3fde2c2b8a65bf8ef;hpb=202c7936ade6929c86ec91a8b11ebf0b3c59844d;p=openssl-gost%2Fengine.git diff --git a/test_context.c b/test_context.c index 72e1057..d9ef579 100644 --- a/test_context.c +++ b/test_context.c @@ -1,25 +1,29 @@ /* - * Copyright (C) 2018 vt@altlinux.org. All Rights Reserved. + * Copyright (C) 2018,2020 Vitaly Chikunov All Rights Reserved. * * Contents licensed under the terms of the OpenSSL license * See https://www.openssl.org/source/license.html for details */ -#include "gost_grasshopper_cipher.h" -#include "gost_grasshopper_defines.h" -#include "gost_grasshopper_math.h" -#include "gost_grasshopper_core.h" -#include "e_gost_err.h" -#include "gost_lcl.h" +#ifdef _MSC_VER +# pragma warning(push, 3) +# include +# pragma warning(pop) +#endif +#include #include #include #include #include #include +#ifndef EVP_MD_CTRL_SET_KEY +# include "gost_lcl.h" +#endif -#define T(e) if (!(e)) {\ - ERR_print_errors_fp(stderr);\ - OpenSSLDie(__FILE__, __LINE__, #e);\ +#define T(e) \ + if (!(e)) { \ + ERR_print_errors_fp(stderr); \ + OpenSSLDie(__FILE__, __LINE__, #e); \ } #define cRED "\033[1;31m" @@ -30,9 +34,9 @@ #define cDBLUE "\033[0;34m" #define cNORM "\033[m" #define TEST_ASSERT(e) {if ((test = (e))) \ - printf(cRED " Test FAILED\n" cNORM); \ + printf(cRED " Test FAILED" cNORM "\n"); \ else \ - printf(cGREEN " Test passed\n" cNORM);} + printf(cGREEN " Test passed" cNORM "\n");} static void hexdump(const void *ptr, size_t len) { @@ -49,40 +53,64 @@ static void hexdump(const void *ptr, size_t len) #define TEST_SIZE 256 #define STEP_SIZE 16 -static int test_contexts(const EVP_CIPHER *type, const int enc, const char *msg, - int acpkm) +static int test_contexts_cipher(const char *name, const int enc, int acpkm) { EVP_CIPHER_CTX *ctx, *save; unsigned char pt[TEST_SIZE] = {1}; - unsigned char b[TEST_SIZE]; - unsigned char c[TEST_SIZE]; + unsigned char b[TEST_SIZE]; /* base output */ + unsigned char c[TEST_SIZE]; /* cloned output */ unsigned char K[32] = {1}; unsigned char iv[16] = {1}; int outlen, tmplen; int ret = 0, test = 0; - printf(cBLUE "%s test for %s\n" cNORM, enc ? "Encryption" : "Decryption", msg); + EVP_CIPHER *type; + ERR_set_mark(); + T((type = (EVP_CIPHER *)EVP_get_cipherbyname(name)) + || (type = EVP_CIPHER_fetch(NULL, name, NULL))); + ERR_pop_to_mark(); + + printf(cBLUE "%s test for %s" cNORM "\n", + enc ? "Encryption" : "Decryption", name); /* produce base encryption */ ctx = EVP_CIPHER_CTX_new(); T(ctx); T(EVP_CipherInit_ex(ctx, type, NULL, K, iv, enc)); - if (acpkm) - T(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_KEY_MESH, acpkm, NULL)); + if (acpkm) { + if (EVP_CIPHER_get0_provider(type) != NULL) { + OSSL_PARAM params[] = { OSSL_PARAM_END, OSSL_PARAM_END }; + size_t v = (size_t)acpkm; + + params[0] = OSSL_PARAM_construct_size_t("key-mesh", &v); + T(EVP_CIPHER_CTX_set_params(ctx, params)); + } else { + T(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_KEY_MESH, acpkm, NULL)); + } + } T(EVP_CIPHER_CTX_set_padding(ctx, 0)); T(EVP_CipherUpdate(ctx, b, &outlen, pt, sizeof(b))); T(EVP_CipherFinal_ex(ctx, b + outlen, &tmplen)); /* and now tests */ - printf(" cloned contexts\n"); EVP_CIPHER_CTX_reset(ctx); EVP_CIPHER_CTX_reset(ctx); /* double call is intentional */ T(EVP_CipherInit_ex(ctx, type, NULL, K, iv, enc)); T(EVP_CIPHER_CTX_set_padding(ctx, 0)); - if (acpkm) - T(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_KEY_MESH, acpkm, NULL)); + if (acpkm) { + if (EVP_CIPHER_get0_provider(type) != NULL) { + OSSL_PARAM params[] = { OSSL_PARAM_END, OSSL_PARAM_END }; + size_t v = (size_t)acpkm; + params[0] = OSSL_PARAM_construct_size_t("key-mesh", &v); + T(EVP_CIPHER_CTX_set_params(ctx, params)); + } else { + T(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_KEY_MESH, acpkm, NULL)); + } + } save = ctx; + + printf(" cloned contexts: "); int i; memset(c, 0, sizeof(c)); for (i = 0; i < TEST_SIZE / STEP_SIZE; i++) { @@ -94,10 +122,10 @@ static int test_contexts(const EVP_CIPHER *type, const int enc, const char *msg, ctx = copy; T(EVP_CipherUpdate(ctx, c + STEP_SIZE * i, &outlen, - pt + STEP_SIZE * i, STEP_SIZE)); + pt + STEP_SIZE * i, STEP_SIZE)); } - outlen = i * GRASSHOPPER_BLOCK_SIZE; + outlen = i * STEP_SIZE; T(EVP_CipherFinal_ex(ctx, c + outlen, &tmplen)); TEST_ASSERT(outlen != TEST_SIZE || memcmp(c, b, TEST_SIZE)); EVP_CIPHER_CTX_free(ctx); @@ -110,7 +138,7 @@ static int test_contexts(const EVP_CIPHER *type, const int enc, const char *msg, ret |= test; /* resume original context */ - printf(" base context\n"); + printf(" base context: "); memset(c, 0, sizeof(c)); T(EVP_CipherUpdate(save, c, &outlen, pt, sizeof(c))); T(EVP_CipherFinal_ex(save, c + outlen, &tmplen)); @@ -118,6 +146,7 @@ static int test_contexts(const EVP_CIPHER *type, const int enc, const char *msg, EVP_CIPHER_CTX_cleanup(save); /* multiple calls are intentional */ EVP_CIPHER_CTX_cleanup(save); EVP_CIPHER_CTX_free(save); + EVP_CIPHER_free(type); if (test) { printf(" b[%d] = ", outlen); hexdump(b, outlen); @@ -129,25 +158,205 @@ static int test_contexts(const EVP_CIPHER *type, const int enc, const char *msg, return ret; } +static int test_contexts_digest_or_legacy_mac(const EVP_MD *type, int mac) +{ + int ret = 0, test = 0; + unsigned char K[32] = {1}; + + /* produce base digest */ + EVP_MD_CTX *ctx, *save; + unsigned char pt[TEST_SIZE] = {1}; + unsigned char b[EVP_MAX_MD_SIZE] = {0}; + unsigned char c[EVP_MAX_MD_SIZE]; + unsigned int outlen, tmplen; + + /* Simply digest whole input. */ + T(ctx = EVP_MD_CTX_new()); + T(EVP_DigestInit_ex(ctx, type, NULL)); + if (mac) + T(EVP_MD_CTX_ctrl(ctx, EVP_MD_CTRL_SET_KEY, sizeof(K), (void *)K)); + T(EVP_DigestUpdate(ctx, pt, sizeof(pt))); + T(EVP_DigestFinal_ex(ctx, b, &tmplen)); + save = ctx; /* will be not freed while cloning */ + + /* cloned digest */ + EVP_MD_CTX_reset(ctx); /* test double reset */ + EVP_MD_CTX_reset(ctx); + T(EVP_DigestInit_ex(ctx, type, NULL)); + if (mac) + T(EVP_MD_CTX_ctrl(ctx, EVP_MD_CTRL_SET_KEY, sizeof(K), (void *)K)); + printf(" cloned contexts: "); + memset(c, 0, sizeof(c)); + int i; + for (i = 0; i < TEST_SIZE / STEP_SIZE; i++) { + /* Clone and continue digesting next part of input. */ + EVP_MD_CTX *copy; + T(copy = EVP_MD_CTX_new()); + T(EVP_MD_CTX_copy_ex(copy, ctx)); + + /* rolling */ + if (save != ctx) + EVP_MD_CTX_free(ctx); + ctx = copy; + + T(EVP_DigestUpdate(ctx, pt + STEP_SIZE * i, STEP_SIZE)); + } + outlen = i * STEP_SIZE; + T(EVP_DigestFinal_ex(ctx, c, &tmplen)); + /* Should be same as the simple digest. */ + TEST_ASSERT(outlen != TEST_SIZE || memcmp(c, b, EVP_MAX_MD_SIZE)); + EVP_MD_CTX_free(ctx); + if (test) { + printf(" b[%d] = ", outlen); + hexdump(b, outlen); + printf(" c[%d] = ", outlen); + hexdump(c, outlen); + } + ret |= test; + + /* Resume original context, what if it's damaged? */ + printf(" base context: "); + memset(c, 0, sizeof(c)); + T(EVP_DigestUpdate(save, pt, sizeof(pt))); + T(EVP_DigestFinal_ex(save, c, &tmplen)); + TEST_ASSERT(outlen != TEST_SIZE || memcmp(c, b, EVP_MAX_MD_SIZE)); + EVP_MD_CTX_free(save); + if (test) { + printf(" b[%d] = ", outlen); + hexdump(b, outlen); + printf(" c[%d] = ", outlen); + hexdump(c, outlen); + } + ret |= test; + return ret; +} + +static int test_contexts_digest(const char *name) +{ + EVP_MD *type; + ERR_set_mark(); + T((type = (EVP_MD *)EVP_get_digestbyname(name)) + || (type = EVP_MD_fetch(NULL, name, NULL))); + ERR_pop_to_mark(); + + printf(cBLUE "Digest test for %s" cNORM "\n", name); + int ret = test_contexts_digest_or_legacy_mac(type, 0); + EVP_MD_free(type); + return ret; +} + +static int test_contexts_mac(const char *name) +{ + int ret = 0, test = 0; + unsigned char K[32] = {1}; + const EVP_MD *type = EVP_get_digestbyname(name); + EVP_MAC *mac; + + if (type) { + printf(cBLUE "Mac via EVP_MD test for %s" cNORM "\n", name); + return test_contexts_digest_or_legacy_mac(type, 1); + } + + T(mac = EVP_MAC_fetch(NULL, name, NULL)); + printf(cBLUE "Mac test for %s" cNORM "\n", name); + + /* produce base mac */ + EVP_MAC_CTX *ctx; + unsigned char pt[TEST_SIZE] = {1}; + unsigned char b[EVP_MAX_MD_SIZE] = {0}; + unsigned char c[EVP_MAX_MD_SIZE] = {0}; + size_t outlen, tmplen; + + /* Simply mac whole input. */ + T(ctx = EVP_MAC_CTX_new(mac)); + T(EVP_MAC_init(ctx, K, sizeof(K), NULL)); + T(EVP_MAC_update(ctx, pt, sizeof(pt))); + T(EVP_MAC_final(ctx, b, &tmplen, sizeof(b))); + EVP_MAC_CTX_free(ctx); + + /* Mac with rolling input. */ + printf(" cloned contexts: "); + T(ctx = EVP_MAC_CTX_new(mac)); + T(EVP_MAC_init(ctx, K, sizeof(K), NULL)); + int i; + for (i = 0; i < TEST_SIZE / STEP_SIZE; i++) { + T(EVP_MAC_update(ctx, pt + STEP_SIZE * i, STEP_SIZE)); + } + outlen = i * STEP_SIZE; + T(EVP_MAC_final(ctx, c, &tmplen, sizeof(c))); + EVP_MAC_CTX_free(ctx); + EVP_MAC_free(mac); + + /* Rolling mac should give the same result as the simple mac. */ + TEST_ASSERT(outlen != TEST_SIZE || memcmp(c, b, EVP_MAX_MD_SIZE)); + + if (test) { + printf(" b[%d] = ", (int)outlen); + hexdump(b, outlen); + printf(" c[%d] = ", (int)outlen); + hexdump(c, outlen); + } + ret |= test; + + return ret; +} + +static struct testcase_cipher { + const char *name; + int acpkm; +} testcases_ciphers[] = { + { SN_id_Gost28147_89, }, + { SN_gost89_cnt, }, + { SN_gost89_cnt_12, }, + { SN_gost89_cbc, }, + { SN_grasshopper_ecb, }, + { SN_grasshopper_cbc, }, + { SN_grasshopper_cfb, }, + { SN_grasshopper_ofb, }, + { SN_grasshopper_ctr, }, + { SN_magma_cbc, }, + { SN_magma_ctr, }, + { SN_id_tc26_cipher_gostr3412_2015_kuznyechik_ctracpkm, 256 / 8 }, + { 0 }, +}; + +static struct testcase_digest { + const char *name; + int mac; +} testcases_digests[] = { + { SN_id_GostR3411_94, }, + { SN_id_Gost28147_89_MAC, 1 }, + { SN_id_GostR3411_2012_256, }, + { SN_id_GostR3411_2012_512, }, + { SN_gost_mac_12, 1 }, + { SN_magma_mac, 1 }, + { SN_grasshopper_mac, 1 }, + { SN_id_tc26_cipher_gostr3412_2015_kuznyechik_ctracpkm_omac, 1 }, + { 0 }, +}; int main(int argc, char **argv) { int ret = 0; - ret |= test_contexts(cipher_gost_grasshopper_ecb(), 1, "grasshopper ecb", 0); - ret |= test_contexts(cipher_gost_grasshopper_ecb(), 0, "grasshopper ecb", 0); - ret |= test_contexts(cipher_gost_grasshopper_cbc(), 1, "grasshopper cbc", 0); - ret |= test_contexts(cipher_gost_grasshopper_cbc(), 0, "grasshopper cbc", 0); - ret |= test_contexts(cipher_gost_grasshopper_ctr(), 1, "grasshopper ctr", 0); - ret |= test_contexts(cipher_gost_grasshopper_ctr(), 0, "grasshopper ctr", 0); - ret |= test_contexts(cipher_gost_grasshopper_ofb(), 1, "grasshopper ofb", 0); - ret |= test_contexts(cipher_gost_grasshopper_ofb(), 0, "grasshopper ofb", 0); - ret |= test_contexts(cipher_gost_grasshopper_ctracpkm(), 1, "grasshopper ctracpkm", 256 / 8); - ret |= test_contexts(cipher_gost_grasshopper_ctracpkm(), 0, "grasshopper ctracpkm", 256 / 8); + OPENSSL_add_all_algorithms_conf(); + + const struct testcase_cipher *tc; + for (tc = testcases_ciphers; tc->name; tc++) { + ret |= test_contexts_cipher(tc->name, 1, tc->acpkm); + ret |= test_contexts_cipher(tc->name, 0, tc->acpkm); + } + const struct testcase_digest *td; + for (td = testcases_digests; td->name; td++) { + if (td->mac) + ret |= test_contexts_mac(td->name); + else + ret |= test_contexts_digest(td->name); + } if (ret) - printf(cDRED "= Some tests FAILED!\n" cNORM); + printf(cDRED "= Some tests FAILED!" cNORM "\n"); else - printf(cDGREEN "= All tests passed!\n" cNORM); + printf(cDGREEN "= All tests passed!" cNORM "\n"); return ret; }