From: Vitaly Chikunov Date: Sun, 5 Aug 2018 00:44:46 +0000 (+0300) Subject: Add grasshopper_omac_acpkm (OMAC-ACPKM) X-Git-Tag: v3.0.0~384 X-Git-Url: http://www.wagner.pp.ru/gitweb/?p=openssl-gost%2Fengine.git;a=commitdiff_plain;h=28ab2b8b0ab2d1677df3940cf4fcdf1597da4ccf Add grasshopper_omac_acpkm (OMAC-ACPKM) --- diff --git a/CMakeLists.txt b/CMakeLists.txt index 0add5fd..a937569 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -91,6 +91,7 @@ set(GOST_EC_SOURCE_FILES set (GOST_OMAC_SOURCE_FILES gost_omac.c + gost_omac_acpkm.c ) set(GOST_LIB_SOURCE_FILES @@ -109,6 +110,7 @@ set(GOST_ENGINE_SOURCE_FILES gost_md2012.c gost_pmeth.c gost_omac.c + gost_omac_acpkm.c ) add_executable(test_grasshopper test_grasshopper.c) diff --git a/gost_eng.c b/gost_eng.c index 6ed13c7..11344db 100644 --- a/gost_eng.c +++ b/gost_eng.c @@ -123,6 +123,7 @@ static int gost_engine_destroy(ENGINE* e) { imit_gost_cp_12_destroy(); magma_omac_destroy(); grasshopper_omac_destroy(); + grasshopper_omac_acpkm_destroy(); cipher_gost_destroy(); cipher_gost_grasshopper_destroy(); @@ -301,6 +302,8 @@ static int gost_digests(ENGINE* e, const EVP_MD** digest, *digest = magma_omac(); } else if (nid == NID_grasshopper_mac) { *digest = grasshopper_omac(); + } else if (nid == NID_id_tc26_cipher_gostr3412_2015_kuznyechik_ctracpkm_omac) { + *digest = grasshopper_omac_acpkm(); } else { ok = 0; *digest = NULL; diff --git a/gost_lcl.h b/gost_lcl.h index 75d59b7..528794a 100644 --- a/gost_lcl.h +++ b/gost_lcl.h @@ -183,7 +183,9 @@ void imit_gost_cp_12_destroy(void); EVP_MD *magma_omac(void); void magma_omac_destroy(void); EVP_MD *grasshopper_omac(void); +EVP_MD *grasshopper_omac_acpkm(void); void grasshopper_omac_destroy(void); +void grasshopper_omac_acpkm_destroy(void); /* Cipher context used for EVP_CIPHER operation */ struct ossl_gost_cipher_ctx { int paramNID; diff --git a/gost_omac_acpkm.c b/gost_omac_acpkm.c new file mode 100644 index 0000000..6542bbf --- /dev/null +++ b/gost_omac_acpkm.c @@ -0,0 +1,521 @@ +/* + * Copyright (C) 2018 vt@altlinux.org. All Rights Reserved. + * Copyright (c) 2010 The OpenSSL Project. All rights reserved. + * + * Contents licensed under the terms of the OpenSSL license + * See https://www.openssl.org/source/license.html for details + */ +#include +#include +#include +#include +#include + +#include "e_gost_err.h" +#include "gost_lcl.h" +#include "gost_grasshopper_defines.h" +#include "gost_grasshopper_cipher.h" + +#define ACPKM_T_MAX (GRASSHOPPER_KEY_SIZE + GRASSHOPPER_BLOCK_SIZE) +/* + * CMAC code from crypto/cmac/cmac.c with ACPKM tweaks + */ +struct CMAC_ACPKM_CTX_st { + /* Cipher context to use */ + EVP_CIPHER_CTX *cctx; + /* CTR-ACPKM cipher */ + EVP_CIPHER_CTX *actx; + unsigned char km[ACPKM_T_MAX]; /* Key material */ + /* Temporary block */ + unsigned char tbl[EVP_MAX_BLOCK_LENGTH]; + /* Last (possibly partial) block */ + unsigned char last_block[EVP_MAX_BLOCK_LENGTH]; + /* Number of bytes in last block: -1 means context not initialised */ + int nlast_block; + unsigned int section_size; /* N */ + unsigned int num; /* processed bytes until section_size */ +}; +typedef struct CMAC_ACPKM_CTX_st CMAC_ACPKM_CTX; + +static unsigned char zero_iv[ACPKM_T_MAX]; + +/* Make temporary keys K1 and K2 */ + +static void make_kn(unsigned char *k1, unsigned char *l, int bl) +{ + int i; + /* Shift block to left, including carry */ + for (i = 0; i < bl; i++) { + k1[i] = l[i] << 1; + if (i < bl - 1 && l[i + 1] & 0x80) + k1[i] |= 1; + } + /* If MSB set fixup with R */ + if (l[0] & 0x80) + k1[bl - 1] ^= bl == 16 ? 0x87 : 0x1b; +} + +static CMAC_ACPKM_CTX *CMAC_ACPKM_CTX_new(void) +{ + CMAC_ACPKM_CTX *ctx; + ctx = OPENSSL_malloc(sizeof(CMAC_ACPKM_CTX)); + if (!ctx) + return NULL; + ctx->cctx = EVP_CIPHER_CTX_new(); + if (ctx->cctx == NULL) { + OPENSSL_free(ctx); + return NULL; + } + ctx->actx = EVP_CIPHER_CTX_new(); + if (ctx->actx == NULL) { + OPENSSL_free(ctx); + return NULL; + } + ctx->nlast_block = -1; + ctx->num = 0; + ctx->section_size = 4096; /* recommended value for Kuznyechik */ + return ctx; +} + +static void CMAC_ACPKM_CTX_cleanup(CMAC_ACPKM_CTX *ctx) +{ + EVP_CIPHER_CTX_cleanup(ctx->cctx); + EVP_CIPHER_CTX_cleanup(ctx->actx); + OPENSSL_cleanse(ctx->tbl, EVP_MAX_BLOCK_LENGTH); + OPENSSL_cleanse(ctx->km, ACPKM_T_MAX); + OPENSSL_cleanse(ctx->last_block, EVP_MAX_BLOCK_LENGTH); + ctx->nlast_block = -1; +} + +static void CMAC_ACPKM_CTX_free(CMAC_ACPKM_CTX *ctx) +{ + if (!ctx) + return; + CMAC_ACPKM_CTX_cleanup(ctx); + EVP_CIPHER_CTX_free(ctx->cctx); + EVP_CIPHER_CTX_free(ctx->actx); + OPENSSL_free(ctx); +} + +int CMAC_ACPKM_CTX_copy(CMAC_ACPKM_CTX *out, const CMAC_ACPKM_CTX *in) +{ + int bl; + if (in->nlast_block == -1) + return 0; + if (!EVP_CIPHER_CTX_copy(out->cctx, in->cctx)) + return 0; + if (!EVP_CIPHER_CTX_copy(out->actx, in->actx)) + return 0; + bl = EVP_CIPHER_CTX_block_size(in->cctx); + memcpy(out->km, in->km, ACPKM_T_MAX); + memcpy(out->tbl, in->tbl, bl); + memcpy(out->last_block, in->last_block, bl); + out->nlast_block = in->nlast_block; + out->section_size = in->section_size; + out->num = in->num; + return 1; +} + +static int CMAC_ACPKM_Init(CMAC_ACPKM_CTX *ctx, const void *key, size_t keylen, + const EVP_CIPHER *cipher, ENGINE *impl) +{ + /* All zeros means restart */ + if (!key && !cipher && !impl && keylen == 0) { + /* Not initialised */ + if (ctx->nlast_block == -1) + return 0; + if (!EVP_EncryptInit_ex(ctx->cctx, NULL, NULL, NULL, zero_iv)) + return 0; + memset(ctx->tbl, 0, EVP_CIPHER_CTX_block_size(ctx->cctx)); + ctx->nlast_block = 0; + /* No restart for ACPKM */ + return 1; + } + /* Initialise context */ + if (cipher) { + const EVP_CIPHER *acpkm; + + if (!EVP_EncryptInit_ex(ctx->cctx, cipher, impl, NULL, NULL)) + return 0; + switch (EVP_CIPHER_nid(cipher)) { + case NID_grasshopper_cbc: + acpkm = cipher_gost_grasshopper_ctracpkm(); + break; + default: + return 0; + } + if (!EVP_EncryptInit_ex(ctx->actx, acpkm, impl, NULL, NULL)) + return 0; + } + /* Non-NULL key means initialisation is complete */ + if (key) { + unsigned char acpkm_iv[EVP_MAX_BLOCK_LENGTH]; + + /* Initialize CTR for ACPKM-Master */ + if (!EVP_CIPHER_CTX_cipher(ctx->actx)) + return 0; + /* block size of ACPKM cipher could be 1, but, + * cbc cipher is same with correct block_size */ + const int block_size = EVP_CIPHER_CTX_block_size(ctx->cctx); + /* Wide IV = 1^{n/2} || 0, + * where a^r denotes the string that consists of r 'a' bits */ + memset(acpkm_iv, 0xff, block_size / 2); + memset(acpkm_iv + block_size / 2, 0, block_size / 2); + if (!EVP_EncryptInit_ex(ctx->actx, NULL, NULL, key, acpkm_iv)) + return 0; + /* EVP_CIPHER key_len may be different from EVP_CIPHER_CTX key_len */ + int key_len = EVP_CIPHER_key_length(EVP_CIPHER_CTX_cipher(ctx->actx)); + + /* Generate first key material (K^1 || K^1_1) */ + if (!EVP_Cipher(ctx->actx, ctx->km, zero_iv, key_len + block_size)) + return 0; + + /* Initialize cbc for CMAC */ + if (!EVP_CIPHER_CTX_cipher(ctx->cctx) || + !EVP_CIPHER_CTX_set_key_length(ctx->cctx, key_len)) + return 0; + /* set CBC key to K^1 */ + if (!EVP_EncryptInit_ex(ctx->cctx, NULL, NULL, ctx->km, zero_iv)) + return 0; + ctx->nlast_block = 0; + } + return 1; +} + +/* Encrypt zeros with master key + * to generate T*-sized key material */ +static int CMAC_ACPKM_Master(CMAC_ACPKM_CTX *ctx) +{ + return EVP_Cipher(ctx->actx, ctx->km, zero_iv, + EVP_CIPHER_key_length(EVP_CIPHER_CTX_cipher(ctx->actx)) + + EVP_CIPHER_CTX_block_size(ctx->cctx)); +} + +static int CMAC_ACPKM_Mesh(CMAC_ACPKM_CTX *ctx) +{ + if (ctx->num < ctx->section_size) + return 1; + ctx->num = 0; + if (!CMAC_ACPKM_Master(ctx)) + return 0; + /* Restart cbc with new key */ + if (!EVP_EncryptInit_ex(ctx->cctx, NULL, NULL, ctx->km, + EVP_CIPHER_CTX_iv(ctx->cctx))) + return 0; + return 1; +} + +static int CMAC_ACPKM_Update(CMAC_ACPKM_CTX *ctx, const void *in, size_t dlen) +{ + const unsigned char *data = in; + size_t bl; + if (ctx->nlast_block == -1) + return 0; + if (dlen == 0) + return 1; + bl = EVP_CIPHER_CTX_block_size(ctx->cctx); + /* Copy into partial block if we need to */ + if (ctx->nlast_block > 0) { + size_t nleft; + nleft = bl - ctx->nlast_block; + if (dlen < nleft) + nleft = dlen; + memcpy(ctx->last_block + ctx->nlast_block, data, nleft); + dlen -= nleft; + ctx->nlast_block += nleft; + /* If no more to process return */ + if (dlen == 0) + return 1; + data += nleft; + /* Else not final block so encrypt it */ + if (!CMAC_ACPKM_Mesh(ctx)) + return 0; + if (!EVP_Cipher(ctx->cctx, ctx->tbl, ctx->last_block, bl)) + return 0; + ctx->num += bl; + } + /* Encrypt all but one of the complete blocks left */ + while (dlen > bl) { + if (!CMAC_ACPKM_Mesh(ctx)) + return 0; + if (!EVP_Cipher(ctx->cctx, ctx->tbl, data, bl)) + return 0; + dlen -= bl; + data += bl; + ctx->num += bl; + } + /* Copy any data left to last block buffer */ + memcpy(ctx->last_block, data, dlen); + ctx->nlast_block = dlen; + return 1; + +} + +static int CMAC_ACPKM_Final(CMAC_ACPKM_CTX *ctx, unsigned char *out, + size_t *poutlen) +{ + int i, bl, lb; + if (ctx->nlast_block == -1) + return 0; + bl = EVP_CIPHER_CTX_block_size(ctx->cctx); + *poutlen = (size_t) bl; + if (!out) + return 1; + lb = ctx->nlast_block; + + if (!CMAC_ACPKM_Mesh(ctx)) + return 0; + int key_len = EVP_CIPHER_key_length(EVP_CIPHER_CTX_cipher(ctx->actx)); + /* Keys k1 and k2 */ + unsigned char *k1 = ctx->km + key_len; + unsigned char k2[EVP_MAX_BLOCK_LENGTH]; + make_kn(k2, ctx->km + key_len, bl); + + /* Is last block complete? */ + if (lb == bl) { + for (i = 0; i < bl; i++) + out[i] = ctx->last_block[i] ^ k1[i]; + } else { + ctx->last_block[lb] = 0x80; + if (bl - lb > 1) + memset(ctx->last_block + lb + 1, 0, bl - lb - 1); + for (i = 0; i < bl; i++) + out[i] = ctx->last_block[i] ^ k2[i]; + } + OPENSSL_cleanse(k1, bl); + OPENSSL_cleanse(k2, bl); + OPENSSL_cleanse(ctx->km, ACPKM_T_MAX); + if (!EVP_Cipher(ctx->cctx, out, out, bl)) { + OPENSSL_cleanse(out, bl); + return 0; + } + return 1; +} + +/* + * End of CMAC code from crypto/cmac/cmac.c with ACPKM tweaks + */ + +typedef struct omac_acpkm_ctx { + CMAC_ACPKM_CTX *cmac_ctx; + size_t dgst_size; + int cipher_nid; + int key_set; +} OMAC_ACPKM_CTX; + +#define MAX_GOST_OMAC_ACPKM_SIZE 16 + +static int omac_acpkm_init(EVP_MD_CTX *ctx, int cipher_nid) +{ + OMAC_ACPKM_CTX *c = EVP_MD_CTX_md_data(ctx); + memset(c, 0, sizeof(OMAC_ACPKM_CTX)); + c->cipher_nid = cipher_nid; + c->key_set = 0; + + switch (cipher_nid) { + case NID_grasshopper_cbc: + c->dgst_size = 16; + break; + } + + return 1; +} + +static int grasshopper_omac_acpkm_init(EVP_MD_CTX *ctx) +{ + return omac_acpkm_init(ctx, NID_grasshopper_cbc); +} + +static int omac_acpkm_imit_update(EVP_MD_CTX *ctx, const void *data, + size_t count) +{ + OMAC_ACPKM_CTX *c = EVP_MD_CTX_md_data(ctx); + if (!c->key_set) { + GOSTerr(GOST_F_OMAC_IMIT_UPDATE, GOST_R_MAC_KEY_NOT_SET); + return 0; + } + + return CMAC_ACPKM_Update(c->cmac_ctx, data, count); +} + +int omac_acpkm_imit_final(EVP_MD_CTX *ctx, unsigned char *md) +{ + OMAC_ACPKM_CTX *c = EVP_MD_CTX_md_data(ctx); + unsigned char mac[MAX_GOST_OMAC_ACPKM_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_ACPKM_Final(c->cmac_ctx, mac, &mac_size); + + memcpy(md, mac, c->dgst_size); + return 1; +} + +int omac_acpkm_imit_copy(EVP_MD_CTX *to, const EVP_MD_CTX *from) +{ + OMAC_ACPKM_CTX *c_to = EVP_MD_CTX_md_data(to); + const OMAC_ACPKM_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; + } else { + return 0; + } + if (!c_from->cmac_ctx) { + if (c_to->cmac_ctx) { + CMAC_ACPKM_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_ACPKM_CTX_new(); + } + return CMAC_ACPKM_CTX_copy(c_to->cmac_ctx, c_from->cmac_ctx); +} + +/* Clean up imit ctx */ +int omac_acpkm_imit_cleanup(EVP_MD_CTX *ctx) +{ + OMAC_ACPKM_CTX *c = EVP_MD_CTX_md_data(ctx); + + if (c) { + CMAC_ACPKM_CTX_free(c->cmac_ctx); + memset(EVP_MD_CTX_md_data(ctx), 0, sizeof(OMAC_ACPKM_CTX)); + } + return 1; +} + +static int omac_acpkm_key(OMAC_ACPKM_CTX *c, const EVP_CIPHER *cipher, + const unsigned char *key, size_t key_size) +{ + int ret = 0; + + c->cmac_ctx = CMAC_ACPKM_CTX_new(); + if (c->cmac_ctx == NULL) { + GOSTerr(GOST_F_OMAC_KEY, ERR_R_MALLOC_FAILURE); + return 0; + } + + ret = CMAC_ACPKM_Init(c->cmac_ctx, key, key_size, cipher, NULL); + if (ret > 0) { + c->key_set = 1; + } + return 1; +} + +int omac_acpkm_imit_ctrl(EVP_MD_CTX *ctx, int type, int arg, void *ptr) +{ + switch (type) { + case EVP_MD_CTRL_KEY_LEN: + *((unsigned int *)(ptr)) = 32; + return 1; + case EVP_MD_CTRL_SET_KEY: + { + OMAC_ACPKM_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_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); + if (c->key_set) { + GOSTerr(GOST_F_OMAC_IMIT_CTRL, GOST_R_BAD_ORDER); + return 0; + } + if (arg == 0) { + struct gost_mac_key *key = (struct gost_mac_key *)ptr; + return omac_acpkm_key(c, cipher, key->key, 32); + } else if (arg == 32) { + return omac_acpkm_key(c, cipher, ptr, 32); + } + GOSTerr(GOST_F_OMAC_IMIT_CTRL, GOST_R_INVALID_MAC_KEY_SIZE); + return 0; + } + case EVP_CTRL_KEY_MESH: + { + OMAC_ACPKM_CTX *c = EVP_MD_CTX_md_data(ctx); + if (!arg || (arg % EVP_MD_block_size(EVP_MD_CTX_md(ctx)))) + return -1; + c->cmac_ctx->section_size = arg; + if (ptr && *(int *)ptr) { + /* Set parameter T */ + if (!EVP_CIPHER_CTX_ctrl(c->cmac_ctx->actx, EVP_CTRL_KEY_MESH, *(int *)ptr, NULL)) + return 0; + } + return 1; + } + case EVP_MD_CTRL_MAC_LEN: + { + OMAC_ACPKM_CTX *c = EVP_MD_CTX_md_data(ctx); + switch (c->cipher_nid) { + 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; + } + return 1; + } + + default: + return 0; + } +} + +static EVP_MD *_hidden_grasshopper_omac_acpkm_md = NULL; + +EVP_MD *grasshopper_omac_acpkm(void) +{ + if (_hidden_grasshopper_omac_acpkm_md == NULL) { + EVP_MD *md; + + if ((md = + EVP_MD_meth_new(NID_id_tc26_cipher_gostr3412_2015_kuznyechik_ctracpkm_omac, + NID_undef)) == NULL + || !EVP_MD_meth_set_result_size(md, MAX_GOST_OMAC_ACPKM_SIZE) + || !EVP_MD_meth_set_input_blocksize(md, GRASSHOPPER_BLOCK_SIZE) + || !EVP_MD_meth_set_app_datasize(md, sizeof(OMAC_ACPKM_CTX)) + || !EVP_MD_meth_set_flags(md, 0) + || !EVP_MD_meth_set_init(md, grasshopper_omac_acpkm_init) + || !EVP_MD_meth_set_update(md, omac_acpkm_imit_update) + || !EVP_MD_meth_set_final(md, omac_acpkm_imit_final) + || !EVP_MD_meth_set_copy(md, omac_acpkm_imit_copy) + || !EVP_MD_meth_set_cleanup(md, omac_acpkm_imit_cleanup) + || !EVP_MD_meth_set_ctrl(md, omac_acpkm_imit_ctrl)) { + EVP_MD_meth_free(md); + md = NULL; + } + _hidden_grasshopper_omac_acpkm_md = md; + } + return _hidden_grasshopper_omac_acpkm_md; +} + +void grasshopper_omac_acpkm_destroy(void) +{ + EVP_MD_meth_free(_hidden_grasshopper_omac_acpkm_md); + _hidden_grasshopper_omac_acpkm_md = NULL; +} diff --git a/test_grasshopper.c b/test_grasshopper.c index ab6e200..0134c67 100644 --- a/test_grasshopper.c +++ b/test_grasshopper.c @@ -33,7 +33,7 @@ printf(cGREEN "Test passed\n" cNORM);} /* Test key from both GOST R 34.12-2015 and GOST R 34.13-2015. */ -static const unsigned char K[] = { +static const unsigned char K[32] = { 0x88,0x99,0xaa,0xbb,0xcc,0xdd,0xee,0xff,0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77, 0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10,0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef, }; @@ -56,6 +56,19 @@ static const unsigned char P_acpkm[] = { 0x44,0x55,0x66,0x77,0x88,0x99,0xAA,0xBB,0xCC,0xEE,0xFF,0x0A,0x00,0x11,0x22,0x33, 0x55,0x66,0x77,0x88,0x99,0xAA,0xBB,0xCC,0xEE,0xFF,0x0A,0x00,0x11,0x22,0x33,0x44, }; +/* OMAC-ACPKM test vector from R 1323565.1.017-2018 A.4.1 */ +static const unsigned char P_omac_acpkm1[] = { + 0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x00,0xFF,0xEE,0xDD,0xCC,0xBB,0xAA,0x99,0x88, + 0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77, +}; +/* OMAC-ACPKM test vector from R 1323565.1.017-2018 A.4.2 */ +static const unsigned char P_omac_acpkm2[] = { + 0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x00,0xFF,0xEE,0xDD,0xCC,0xBB,0xAA,0x99,0x88, + 0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0xAA,0xBB,0xCC,0xEE,0xFF,0x0A, + 0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0xAA,0xBB,0xCC,0xEE,0xFF,0x0A,0x00, + 0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0xAA,0xBB,0xCC,0xEE,0xFF,0x0A,0x00,0x11, + 0x33,0x44,0x55,0x66,0x77,0x88,0x99,0xAA,0xBB,0xCC,0xEE,0xFF,0x0A,0x00,0x11,0x22, +}; static const unsigned char E_ecb[] = { /* ECB test vectors from GOST R 34.13-2015 A.1.1 */ /* first 16 bytes is vector (b) from GOST R 34.12-2015 A.1 */ @@ -134,6 +147,14 @@ static const unsigned char iv_128bit[] = { 0x12,0x34,0x56,0x78,0x90,0xab,0xce,0x /* Universal IV for ACPKM-Master. */ static const unsigned char iv_acpkm_m[] = { 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }; +static const unsigned char MAC_omac[] = { 0x33,0x6f,0x4d,0x29,0x60,0x59,0xfb,0xe3 }; +static const unsigned char MAC_omac_acpkm1[] = { + 0xB5,0x36,0x7F,0x47,0xB6,0x2B,0x99,0x5E,0xEB,0x2A,0x64,0x8C,0x58,0x43,0x14,0x5E, +}; +static const unsigned char MAC_omac_acpkm2[] = { + 0xFB,0xB8,0xDC,0xEE,0x45,0xBE,0xA6,0x7C,0x35,0xF5,0x8C,0x57,0x00,0x89,0x8E,0x5D, +}; + struct testcase { const char *name; const EVP_CIPHER *(*type)(void); @@ -291,34 +312,37 @@ static int test_stream(const EVP_CIPHER *type, const char *name, return ret; } -static int test_omac() +static int test_mac(const char *name, const char *from, + const EVP_MD *type, int acpkm, int acpkm_t, + const unsigned char *pt, size_t pt_size, + const unsigned char *mac, size_t mac_size) { EVP_MD_CTX *ctx = EVP_MD_CTX_new(); - unsigned char mac[] = { 0x33,0x6f,0x4d,0x29,0x60,0x59,0xfb,0xe3 }; unsigned char md_value[EVP_MAX_MD_SIZE]; unsigned int md_len; int test; OPENSSL_assert(ctx); - printf("OMAC test from GOST R 34.13-2015\n"); + printf("%s test from %s\n", name, from); EVP_MD_CTX_init(ctx); - /* preload cbc cipher for omac set key */ - EVP_add_cipher(cipher_gost_grasshopper_cbc()); - T(EVP_DigestInit_ex(ctx, grasshopper_omac(), NULL)); - if (EVP_MD_CTX_size(ctx) != sizeof(mac)) { + T(EVP_DigestInit_ex(ctx, type, NULL)); + if (EVP_MD_CTX_size(ctx) != mac_size) { /* strip const out of EVP_MD_CTX_md() to * overwrite output size, as test vector is 8 bytes */ - printf("Resize result size from %d to %zu\n", EVP_MD_CTX_size(ctx), sizeof(mac)); - T(EVP_MD_meth_set_result_size((EVP_MD *)EVP_MD_CTX_md(ctx), sizeof(mac))); + printf("Resize result size from %d to %zu\n", EVP_MD_CTX_size(ctx), mac_size); + T(EVP_MD_meth_set_result_size((EVP_MD *)EVP_MD_CTX_md(ctx), mac_size)); } T(EVP_MD_meth_get_ctrl(EVP_MD_CTX_md(ctx))(ctx, EVP_MD_CTRL_SET_KEY, sizeof(K), (void *)K)); - T(EVP_DigestUpdate(ctx, P, sizeof(P))); + if (acpkm) + T(EVP_MD_meth_get_ctrl(EVP_MD_CTX_md(ctx))(ctx, + EVP_CTRL_KEY_MESH, acpkm, acpkm_t ? &acpkm_t : NULL)); + T(EVP_DigestUpdate(ctx, pt, pt_size)); T(EVP_DigestFinal_ex(ctx, md_value, &md_len)); EVP_MD_CTX_free(ctx); printf(" MAC[%u] = ", md_len); hexdump(md_value, md_len); - TEST_ASSERT(md_len != sizeof(mac) || + TEST_ASSERT(md_len != mac_size || memcmp(mac, md_value, md_len)); return test; @@ -339,7 +363,19 @@ int main(int argc, char **argv) t->iv, t->iv_size, t->acpkm); } - ret |= test_omac(); + /* preload cbc cipher for omac set key */ + EVP_add_cipher(cipher_gost_grasshopper_cbc()); + + ret |= test_mac("OMAC", "GOST R 34.13-2015", grasshopper_omac(), 0, 0, + P, sizeof(P), MAC_omac, sizeof(MAC_omac)); + ret |= test_mac("OMAC-ACPKM", "R 1323565.1.017-2018 A.4.1", + grasshopper_omac_acpkm(), 32, 768 / 8, + P_omac_acpkm1, sizeof(P_omac_acpkm1), + MAC_omac_acpkm1, sizeof(MAC_omac_acpkm1)); + ret |= test_mac("OMAC-ACPKM", "R 1323565.1.017-2018 A.4.2", + grasshopper_omac_acpkm(), 32, 768 / 8, + P_omac_acpkm2, sizeof(P_omac_acpkm2), + MAC_omac_acpkm2, sizeof(MAC_omac_acpkm2)); if (ret) printf(cDRED "= Some tests FAILED!\n" cNORM);