X-Git-Url: http://www.wagner.pp.ru/gitweb/?a=blobdiff_plain;f=gost_omac.c;h=648cd8f39550bee5a31aa982c118ec71f07f1c43;hb=HEAD;hp=fa7ab746ba5119a485003521324f17803f47ab33;hpb=0ee4f8fc839278672e47213549bfb152ad3d2654;p=openssl-gost%2Fengine.git diff --git a/gost_omac.c b/gost_omac.c index fa7ab74..648cd8f 100644 --- a/gost_omac.c +++ b/gost_omac.c @@ -1,3 +1,10 @@ +/* + * Copyright (c) 2019 Dmitry Belyavskiy + * Copyright (c) 2020 Vitaly Chikunov + * + * Contents licensed under the terms of the OpenSSL license + * See https://www.openssl.org/source/license.html for details + */ #include #include #include @@ -7,127 +14,146 @@ #include "e_gost_err.h" #include "gost_lcl.h" +#define min(a,b) (((a) < (b)) ? (a) : (b)) + typedef struct omac_ctx { - CMAC_CTX *cmac_ctx; - size_t dgst_size; - int cipher_nid; - int key_set; + CMAC_CTX *cmac_ctx; + size_t dgst_size; + const char *cipher_name; + int key_set; +/* + * Here begins stuff related to TLSTREE processing + * We MUST store the original key to derive TLSTREE keys from it + * and TLS seq no. + * */ + unsigned char key[32]; +/* + * TODO + * TLSTREE intermediate values should be recalculated only when + * C_i & (seq_no+1) != C_i & (seq_no) + * so somewhen we will store C_i & (seq_no) in this structure + * to avoid redundant hash calculations. + * */ } OMAC_CTX; #define MAX_GOST_OMAC_SIZE 16 -static int omac_init(EVP_MD_CTX *ctx, int cipher_nid) +static int omac_init(EVP_MD_CTX *ctx, const char *cipher_name) { OMAC_CTX *c = EVP_MD_CTX_md_data(ctx); - memset(c, 0, sizeof(OMAC_CTX)); - c->cipher_nid = cipher_nid; - c->key_set = 0; - - switch(cipher_nid) { - case NID_magma_cbc: - c->dgst_size = 4; - break; - - case NID_grasshopper_cbc: - c->dgst_size = 8; - break; - } + memset(c, 0, sizeof(OMAC_CTX)); + c->cipher_name = cipher_name; + c->key_set = 0; + + switch (OBJ_txt2nid(cipher_name)) { + case NID_magma_cbc: + c->dgst_size = 8; + break; + + case NID_grasshopper_cbc: + c->dgst_size = 16; + break; + } return 1; } static int magma_imit_init(EVP_MD_CTX *ctx) { - return omac_init(ctx, NID_magma_cbc); + return omac_init(ctx, SN_magma_cbc); } static int grasshopper_imit_init(EVP_MD_CTX *ctx) { - return omac_init(ctx, NID_grasshopper_cbc); + return omac_init(ctx, SN_grasshopper_cbc); } static int omac_imit_update(EVP_MD_CTX *ctx, const void *data, size_t count) { OMAC_CTX *c = EVP_MD_CTX_md_data(ctx); - if (!c->key_set) - { + if (!c->key_set) { GOSTerr(GOST_F_OMAC_IMIT_UPDATE, GOST_R_MAC_KEY_NOT_SET); return 0; - } + } - return CMAC_Update(c->cmac_ctx, data, count); + return CMAC_Update(c->cmac_ctx, data, count); } -int omac_imit_final(EVP_MD_CTX *ctx, unsigned char *md) +static int omac_imit_final(EVP_MD_CTX *ctx, unsigned char *md) { OMAC_CTX *c = EVP_MD_CTX_md_data(ctx); - unsigned char mac[MAX_GOST_OMAC_SIZE]; - size_t mac_size = sizeof(mac); + unsigned char mac[MAX_GOST_OMAC_SIZE]; + size_t mac_size = sizeof(mac); if (!c->key_set) { GOSTerr(GOST_F_OMAC_IMIT_FINAL, GOST_R_MAC_KEY_NOT_SET); return 0; } - CMAC_Final(c->cmac_ctx, mac, &mac_size); + CMAC_Final(c->cmac_ctx, mac, &mac_size); memcpy(md, mac, c->dgst_size); return 1; } -int omac_imit_copy(EVP_MD_CTX *to, const EVP_MD_CTX *from) +static int omac_imit_copy(EVP_MD_CTX *to, const EVP_MD_CTX *from) { OMAC_CTX *c_to = EVP_MD_CTX_md_data(to); - const OMAC_CTX *c_from = EVP_MD_CTX_md_data(from); + const OMAC_CTX *c_from = EVP_MD_CTX_md_data(from); if (c_from && c_to) { - c_to->dgst_size = c_from->dgst_size; - c_to->cipher_nid = c_from->cipher_nid; - c_to->key_set = c_from->key_set; + c_to->dgst_size = c_from->dgst_size; + c_to->cipher_name = c_from->cipher_name; + c_to->key_set = c_from->key_set; + memcpy(c_to->key, c_from->key, 32); + } else { + return 0; } - else - { - return 0; - } - if (c_to->cmac_ctx == c_from->cmac_ctx) - { - return 1; - } - return CMAC_CTX_copy(c_to->cmac_ctx, c_from->cmac_ctx); + if (!c_from->cmac_ctx) { + if (c_to->cmac_ctx) { + CMAC_CTX_free(c_to->cmac_ctx); + c_to->cmac_ctx = NULL; + } + return 1; + } + if (c_to->cmac_ctx == c_from->cmac_ctx) { + c_to->cmac_ctx = CMAC_CTX_new(); + } + return CMAC_CTX_copy(c_to->cmac_ctx, c_from->cmac_ctx); } /* Clean up imit ctx */ -int omac_imit_cleanup(EVP_MD_CTX *ctx) +static int omac_imit_cleanup(EVP_MD_CTX *ctx) { OMAC_CTX *c = EVP_MD_CTX_md_data(ctx); - if (c) - { - CMAC_CTX_free(c->cmac_ctx); - memset(EVP_MD_CTX_md_data(ctx), 0, sizeof(OMAC_CTX)); - } + if (c) { + CMAC_CTX_free(c->cmac_ctx); + memset(EVP_MD_CTX_md_data(ctx), 0, sizeof(OMAC_CTX)); + } return 1; } -static int omac_key(OMAC_CTX *c, const EVP_CIPHER *cipher, const unsigned char *key, size_t key_size) +static int omac_key(OMAC_CTX * c, const EVP_CIPHER *cipher, + const unsigned char *key, size_t key_size) { - int ret = 0; + int ret = 0; - c->cmac_ctx = CMAC_CTX_new(); - if (c->cmac_ctx == NULL) - { - GOSTerr(GOST_F_OMAC_KEY, ERR_R_MALLOC_FAILURE); - return 0; - } + CMAC_CTX_free(c->cmac_ctx); + c->cmac_ctx = CMAC_CTX_new(); + if (c->cmac_ctx == NULL) { + GOSTerr(GOST_F_OMAC_KEY, ERR_R_MALLOC_FAILURE); + return 0; + } - ret = CMAC_Init(c->cmac_ctx, key, key_size, cipher, NULL); - if (ret > 0) - { - c->key_set = 1; - } - return 1; -} + ret = CMAC_Init(c->cmac_ctx, key, key_size, cipher, NULL); + if (ret > 0) { + c->key_set = 1; + } + return 1; +} +/* Called directly by gost_kexp15() */ int omac_imit_ctrl(EVP_MD_CTX *ctx, int type, int arg, void *ptr) { switch (type) { @@ -135,144 +161,127 @@ int omac_imit_ctrl(EVP_MD_CTX *ctx, int type, int arg, void *ptr) *((unsigned int *)(ptr)) = 32; return 1; case EVP_MD_CTRL_SET_KEY: - { - OMAC_CTX *c = EVP_MD_CTX_md_data(ctx); - const EVP_MD *md = EVP_MD_CTX_md(ctx); - const EVP_CIPHER *cipher = NULL; - - if (c->cipher_nid == NID_undef) - { - switch (EVP_MD_nid(md)) - { - case NID_magma_mac: - c->cipher_nid = NID_magma_cbc; - break; - - case NID_grasshopper_mac: - c->cipher_nid = NID_grasshopper_cbc; - break; - } - } - cipher = EVP_get_cipherbynid(c->cipher_nid); - - if (cipher == NULL) - { - GOSTerr(GOST_F_OMAC_IMIT_CTRL, GOST_R_CIPHER_NOT_FOUND); - } - - if (EVP_MD_meth_get_init(EVP_MD_CTX_md(ctx)) (ctx) <= 0) { - GOSTerr(GOST_F_OMAC_IMIT_CTRL, GOST_R_MAC_KEY_NOT_SET); - return 0; - } - EVP_MD_CTX_set_flags(ctx, EVP_MD_CTX_FLAG_NO_INIT); + { + OMAC_CTX *c = EVP_MD_CTX_md_data(ctx); + const EVP_MD *md = EVP_MD_CTX_md(ctx); + EVP_CIPHER *cipher = NULL; + int ret = 0; + + if (c->cipher_name == NULL) { + if (EVP_MD_is_a(md, SN_magma_mac)) + c->cipher_name = SN_magma_cbc; + else if (EVP_MD_is_a(md, SN_grasshopper_mac)) + c->cipher_name = SN_grasshopper_cbc; + } + if ((cipher = + (EVP_CIPHER *)EVP_get_cipherbyname(c->cipher_name)) == NULL + && (cipher = + EVP_CIPHER_fetch(NULL, c->cipher_name, NULL)) == NULL) { + GOSTerr(GOST_F_OMAC_IMIT_CTRL, GOST_R_CIPHER_NOT_FOUND); + goto set_key_end; + } - if (c->key_set) - { - GOSTerr(GOST_F_OMAC_IMIT_CTRL, GOST_R_BAD_ORDER); - return 0; - } + if (EVP_MD_meth_get_init(EVP_MD_CTX_md(ctx)) (ctx) <= 0) { + GOSTerr(GOST_F_OMAC_IMIT_CTRL, GOST_R_MAC_KEY_NOT_SET); + goto set_key_end; + } + EVP_MD_CTX_set_flags(ctx, EVP_MD_CTX_FLAG_NO_INIT); - if (arg == 0) { - struct gost_mac_key *key = (struct gost_mac_key *)ptr; - return omac_key(c, cipher, key->key, 32); + if (c->key_set) { + GOSTerr(GOST_F_OMAC_IMIT_CTRL, GOST_R_BAD_ORDER); + goto set_key_end; + } - } else if (arg == 32) { - return omac_key(c, cipher, ptr, 32); - } - GOSTerr(GOST_F_OMAC_IMIT_CTRL, GOST_R_INVALID_MAC_KEY_SIZE); - return 0; - } - case EVP_MD_CTRL_MAC_LEN: + if (arg == 0) { + struct gost_mac_key *key = (struct gost_mac_key *)ptr; + ret = omac_key(c, cipher, key->key, 32); + if (ret > 0) + memcpy(c->key, key->key, 32); + goto set_key_end; + } else if (arg == 32) { + ret = omac_key(c, cipher, ptr, 32); + if (ret > 0) + memcpy(c->key, ptr, 32); + goto set_key_end; + } + GOSTerr(GOST_F_OMAC_IMIT_CTRL, GOST_R_INVALID_MAC_KEY_SIZE); + set_key_end: + EVP_CIPHER_free(cipher); + if (ret > 0) + return ret; + return 0; + } + case EVP_MD_CTRL_XOF_LEN: /* Supported in OpenSSL */ { - OMAC_CTX *c = EVP_MD_CTX_md_data(ctx); - switch (c->cipher_nid) - { - case NID_magma_cbc: - if (arg < 1 || arg > 8) { - GOSTerr(GOST_F_OMAC_IMIT_CTRL, GOST_R_INVALID_MAC_SIZE); + OMAC_CTX *c = EVP_MD_CTX_md_data(ctx); + switch (OBJ_txt2nid(c->cipher_name)) { + case NID_magma_cbc: + if (arg < 1 || arg > 8) { + GOSTerr(GOST_F_OMAC_IMIT_CTRL, GOST_R_INVALID_MAC_SIZE); + return 0; + } + c->dgst_size = arg; + break; + case NID_grasshopper_cbc: + if (arg < 1 || arg > 16) { + GOSTerr(GOST_F_OMAC_IMIT_CTRL, GOST_R_INVALID_MAC_SIZE); + return 0; + } + c->dgst_size = arg; + break; + default: return 0; } - c->dgst_size = arg; - break; - case NID_grasshopper_cbc: - if (arg < 1 || arg > 16) { - GOSTerr(GOST_F_OMAC_IMIT_CTRL, GOST_R_INVALID_MAC_SIZE); - return 0; + return 1; + } +#ifdef EVP_MD_CTRL_TLSTREE + case EVP_MD_CTRL_TLSTREE: + { + OMAC_CTX *c = EVP_MD_CTX_md_data(ctx); + if (c->key_set) { + unsigned char diversed_key[32]; + int ret = 0; + if (gost_tlstree(OBJ_txt2nid(c->cipher_name), + c->key, diversed_key, + (const unsigned char *)ptr)) { + EVP_CIPHER *cipher; + if ((cipher = (EVP_CIPHER *)EVP_get_cipherbyname(c->cipher_name)) + || (cipher = EVP_CIPHER_fetch(NULL, c->cipher_name, NULL))) + ret = omac_key(c, cipher, diversed_key, 32); + EVP_CIPHER_free(cipher); + } + return ret; } - c->dgst_size = arg; - break; - default: - return 0; - } - return 1; + GOSTerr(GOST_F_OMAC_IMIT_CTRL, GOST_R_BAD_ORDER); + return 0; } - +#endif default: return 0; } } -static EVP_MD *_hidden_magma_mac_md = NULL; - -EVP_MD *magma_omac(void) -{ - if (_hidden_magma_mac_md == NULL) { - EVP_MD *md; - - if ((md = EVP_MD_meth_new(NID_magma_mac, NID_undef)) == NULL - || !EVP_MD_meth_set_result_size(md, 4) - || !EVP_MD_meth_set_input_blocksize(md, 8) - || !EVP_MD_meth_set_app_datasize(md, sizeof(OMAC_CTX)) - || !EVP_MD_meth_set_flags(md, 0) - || !EVP_MD_meth_set_init(md, magma_imit_init) - || !EVP_MD_meth_set_update(md, omac_imit_update) - || !EVP_MD_meth_set_final(md, omac_imit_final) - || !EVP_MD_meth_set_copy(md, omac_imit_copy) - || !EVP_MD_meth_set_cleanup(md, omac_imit_cleanup) - || !EVP_MD_meth_set_ctrl(md, omac_imit_ctrl)) { - EVP_MD_meth_free(md); - md = NULL; - } - _hidden_magma_mac_md = md; - } - return _hidden_magma_mac_md; -} - -void magma_omac_destroy(void) -{ - EVP_MD_meth_free(_hidden_magma_mac_md); - _hidden_magma_mac_md = NULL; -} - -static EVP_MD *_hidden_grasshopper_mac_md = NULL; - -EVP_MD *grasshopper_omac(void) -{ - if (_hidden_grasshopper_mac_md == NULL) { - EVP_MD *md; - - if ((md = EVP_MD_meth_new(NID_grasshopper_mac, NID_undef)) == NULL - || !EVP_MD_meth_set_result_size(md, 4) - || !EVP_MD_meth_set_input_blocksize(md, 8) - || !EVP_MD_meth_set_app_datasize(md, sizeof(OMAC_CTX)) - || !EVP_MD_meth_set_flags(md, 0) - || !EVP_MD_meth_set_init(md, grasshopper_imit_init) - || !EVP_MD_meth_set_update(md, omac_imit_update) - || !EVP_MD_meth_set_final(md, omac_imit_final) - || !EVP_MD_meth_set_copy(md, omac_imit_copy) - || !EVP_MD_meth_set_cleanup(md, omac_imit_cleanup) - || !EVP_MD_meth_set_ctrl(md, omac_imit_ctrl)) { - EVP_MD_meth_free(md); - md = NULL; - } - _hidden_grasshopper_mac_md = md; - } - return _hidden_grasshopper_mac_md; -} - -void grasshopper_omac_destroy(void) -{ - EVP_MD_meth_free(_hidden_grasshopper_mac_md); - _hidden_grasshopper_mac_md = NULL; -} - +static GOST_digest omac_template_digest = { + .input_blocksize = 8, + .app_datasize = sizeof(OMAC_CTX), + .flags = EVP_MD_FLAG_XOF, + .update = omac_imit_update, + .final = omac_imit_final, + .copy = omac_imit_copy, + .cleanup = omac_imit_cleanup, + .ctrl = omac_imit_ctrl, +}; + +GOST_digest magma_mac_digest = { + .nid = NID_magma_mac, + .template = &omac_template_digest, + .result_size = 8, + .init = magma_imit_init, +}; + +GOST_digest grasshopper_mac_digest = { + .nid = NID_grasshopper_mac, + .template = &omac_template_digest, + .result_size = 16, + .init = grasshopper_imit_init, +};