X-Git-Url: http://www.wagner.pp.ru/gitweb/?a=blobdiff_plain;f=gost_grasshopper_cipher.c;h=ef06e2d3f68dabdbba79c320913421a8c5a5bb2a;hb=HEAD;hp=7b5330b3e985c9e845335a88ceee04bd71896bc7;hpb=6036eb9be5403af769f211b1056d34bf65028aea;p=openssl-gost%2Fengine.git diff --git a/gost_grasshopper_cipher.c b/gost_grasshopper_cipher.c index 7b5330b..ef06e2d 100644 --- a/gost_grasshopper_cipher.c +++ b/gost_grasshopper_cipher.c @@ -26,6 +26,7 @@ enum GRASSHOPPER_CIPHER_TYPE { GRASSHOPPER_CIPHER_CTR, GRASSHOPPER_CIPHER_CTRACPKM, GRASSHOPPER_CIPHER_CTRACPKMOMAC, + GRASSHOPPER_CIPHER_MGM, }; static GOST_cipher grasshopper_template_cipher = { @@ -124,6 +125,32 @@ GOST_cipher grasshopper_ctr_acpkm_omac_cipher = { .ctx_size = sizeof(gost_grasshopper_cipher_ctx_ctr), }; +GOST_cipher grasshopper_mgm_cipher = { + .nid = NID_undef, + .template = &grasshopper_template_cipher, + .block_size = 1, + .iv_len = 16, + .flags = EVP_CIPH_NO_PADDING | + EVP_CIPH_CUSTOM_IV | EVP_CIPH_FLAG_CUSTOM_CIPHER | + EVP_CIPH_CTRL_INIT | EVP_CIPH_FLAG_AEAD_CIPHER, + .cleanup = gost_grasshopper_mgm_cleanup, + .ctrl = gost_grasshopper_mgm_ctrl, + .init = gost_grasshopper_cipher_init_mgm, + .do_cipher = gost_grasshopper_cipher_do_mgm, + .ctx_size = sizeof(gost_mgm_ctx) +}; + +static void kuznyechik_NID_callback (int nid) +{ + grasshopper_mgm_cipher.nid = nid; +} + +GOST_NID_JOB kuznyechik_mgm_NID = { + .sn = SN_kuznyechik_mgm, + .ln = SN_kuznyechik_mgm, + .callback = kuznyechik_NID_callback, +}; + /* first 256 bit of D from draft-irtf-cfrg-re-keying-12 */ static const unsigned char ACPKM_D_2018[] = { 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 64 bit */ @@ -315,33 +342,170 @@ gost_grasshopper_cipher_init_ctracpkm_omac(EVP_CIPHER_CTX char *key, const unsigned char *iv, int enc) { - gost_grasshopper_cipher_ctx_ctr *c = EVP_CIPHER_CTX_get_cipher_data(ctx); + gost_grasshopper_cipher_ctx_ctr *c = EVP_CIPHER_CTX_get_cipher_data(ctx); + + /* NB: setting type makes EVP do_cipher callback useless */ + c->c.type = GRASSHOPPER_CIPHER_CTRACPKMOMAC; + EVP_CIPHER_CTX_set_num(ctx, 0); + c->section_size = 4096; - /* NB: setting type makes EVP do_cipher callback useless */ - c->c.type = GRASSHOPPER_CIPHER_CTRACPKMOMAC; - EVP_CIPHER_CTX_set_num(ctx, 0); - c->section_size = 4096; + if (key) { + unsigned char cipher_key[32]; + c->omac_ctx = EVP_MD_CTX_new(); - if (key) { - unsigned char cipher_key[32]; - c->omac_ctx = EVP_MD_CTX_new(); + if (c->omac_ctx == NULL) { + GOSTerr(GOST_F_GOST_GRASSHOPPER_CIPHER_INIT_CTRACPKM_OMAC, ERR_R_MALLOC_FAILURE); + return 0; + } - if (c->omac_ctx == NULL) { - GOSTerr(GOST_F_GOST_GRASSHOPPER_CIPHER_INIT_CTRACPKM_OMAC, ERR_R_MALLOC_FAILURE); - return 0; + if (gost2015_acpkm_omac_init(NID_kuznyechik_mac, enc, key, + c->omac_ctx, cipher_key, c->kdf_seed) != 1) { + EVP_MD_CTX_free(c->omac_ctx); + c->omac_ctx = NULL; + return 0; + } + + return gost_grasshopper_cipher_init(ctx, cipher_key, iv, enc); + } + + return gost_grasshopper_cipher_init(ctx, key, iv, enc); +} + +// TODO: const *in, const *c +void gost_grasshopper_encrypt_wrap(unsigned char *in, unsigned char *out, + gost_grasshopper_cipher_ctx *c) { + grasshopper_encrypt_block(&c->encrypt_round_keys, + (grasshopper_w128_t *) in, + (grasshopper_w128_t *) out, + &c->buffer); +} + + + +/* ----------------------------------------------------------------------------------------------- */ +/*! Функция реализует операцию умножения двух элементов конечного поля \f$ \mathbb F_{2^{128}}\f$, + порожденного неприводимым многочленом + \f$ f(x) = x^{128} + x^7 + x^2 + x + 1 \in \mathbb F_2[x]\f$. Для умножения используется + простейшая реализация, основанная на приведении по модулю после каждого шага алгоритма. */ +/* ----------------------------------------------------------------------------------------------- */ +static void gf128_mul_uint64 (uint64_t *result, uint64_t *arg1, uint64_t *arg2) +{ + int i = 0; + register uint64_t t, X0, X1; + uint64_t Z0 = 0, Z1 = 0; + +#ifdef L_ENDIAN + X0 = BSWAP64(*(arg1 + 1)); + X1 = BSWAP64(*arg1); +#else + X0 = *(arg1 + 1); + X1 = *arg1; +#endif + + //first 64 bits of arg1 +#ifdef L_ENDIAN + t = BSWAP64(*(arg2 + 1)); +#else + t = *(arg2 + 1); +#endif + + for (i = 0; i < 64; i++) { + if (t & 0x1) { + Z0 ^= X0; + Z1 ^= X1; + } + t >>= 1; + if (X1 & 0x8000000000000000) { + X1 <<= 1; + X1 ^= X0>>63; + X0 <<= 1; + X0 ^= 0x87; } + else { + X1 <<= 1; + X1 ^= X0>>63; + X0 <<= 1; + } + } - if (gost2015_acpkm_omac_init(NID_kuznyechik_mac, enc, key, - c->omac_ctx, cipher_key, c->kdf_seed) != 1) { - EVP_MD_CTX_free(c->omac_ctx); - c->omac_ctx = NULL; - return 0; + //second 64 bits of arg2 +#ifdef L_ENDIAN + t = BSWAP64(*arg2); +#else + t = *arg2; +#endif + + for (i = 0; i < 63; i++) { + if (t & 0x1) { + Z0 ^= X0; + Z1 ^= X1; + } + t >>= 1; + if (X1 & 0x8000000000000000) { + X1 <<= 1; + X1 ^= X0>>63; + X0 <<= 1; + X0 ^= 0x87; } + else { + X1 <<= 1; + X1 ^= X0>>63; + X0 <<= 1; + } + } - return gost_grasshopper_cipher_init(ctx, cipher_key, iv, enc); + if (t & 0x1) { + Z0 ^= X0; + Z1 ^= X1; } - return gost_grasshopper_cipher_init(ctx, key, iv, enc); +#ifdef L_ENDIAN + result[0] = BSWAP64(Z1); + result[1] = BSWAP64(Z0); +#else + result[0] = Z1; + result[1] = Z0; +#endif +} + +static GRASSHOPPER_INLINE int +gost_grasshopper_cipher_init_mgm(EVP_CIPHER_CTX *ctx, const unsigned char *key, + const unsigned char *iv, int enc) +{ + gost_mgm_ctx *mctx = + (gost_mgm_ctx *)EVP_CIPHER_CTX_get_cipher_data(ctx); + int bl; + + if (!iv && !key) + return 1; + if (key) { + bl = EVP_CIPHER_CTX_iv_length(ctx); + gost_grasshopper_cipher_key(&mctx->ks.gh_ks, key); + gost_mgm128_init(&mctx->mgm, &mctx->ks, + (block128_f) gost_grasshopper_encrypt_wrap, gf128_mul_uint64, bl); + + /* + * If we have an iv can set it directly, otherwise use saved IV. + */ + if (iv == NULL && mctx->iv_set) + iv = mctx->iv; + if (iv) { + if (gost_mgm128_setiv(&mctx->mgm, iv, mctx->ivlen) != 1) + return 0; + mctx->iv_set = 1; + } + mctx->key_set = 1; + } else { + /* If key set use IV, otherwise copy */ + if (mctx->key_set) { + if (gost_mgm128_setiv(&mctx->mgm, iv, mctx->ivlen) != 1) + return 0; + } + else + memcpy(mctx->iv, iv, mctx->ivlen); + mctx->iv_set = 1; + } + return 1; } static int gost_grasshopper_cipher_do_ecb(EVP_CIPHER_CTX *ctx, unsigned char *out, @@ -473,7 +637,7 @@ static int gost_grasshopper_cipher_do_ctr(EVP_CIPHER_CTX *ctx, unsigned char *ou ctr128_inc(iv_buffer->b); current_in += GRASSHOPPER_BLOCK_SIZE; current_out += GRASSHOPPER_BLOCK_SIZE; - lasted -= GRASSHOPPER_BLOCK_SIZE; + lasted -= GRASSHOPPER_BLOCK_SIZE; } if (lasted > 0) { @@ -536,7 +700,7 @@ static int gost_grasshopper_cipher_do_ctracpkm(EVP_CIPHER_CTX *ctx, in += GRASSHOPPER_BLOCK_SIZE; out += GRASSHOPPER_BLOCK_SIZE; num += GRASSHOPPER_BLOCK_SIZE; - lasted -= GRASSHOPPER_BLOCK_SIZE; + lasted -= GRASSHOPPER_BLOCK_SIZE; } // last part @@ -560,28 +724,82 @@ static int gost_grasshopper_cipher_do_ctracpkm_omac(EVP_CIPHER_CTX *ctx, const unsigned char *in, size_t inl) { - int result; - gost_grasshopper_cipher_ctx_ctr *c = EVP_CIPHER_CTX_get_cipher_data(ctx); - /* As in and out can be the same pointer, process unencrypted here */ - if (EVP_CIPHER_CTX_encrypting(ctx)) - EVP_DigestSignUpdate(c->omac_ctx, in, inl); + int result; + gost_grasshopper_cipher_ctx_ctr *c = EVP_CIPHER_CTX_get_cipher_data(ctx); + /* As in and out can be the same pointer, process unencrypted here */ + if (EVP_CIPHER_CTX_encrypting(ctx)) + EVP_DigestSignUpdate(c->omac_ctx, in, inl); + + if (in == NULL && inl == 0) { /* Final call */ + return gost2015_final_call(ctx, c->omac_ctx, KUZNYECHIK_MAC_MAX_SIZE, c->tag, gost_grasshopper_cipher_do_ctracpkm); + } + + if (in == NULL) { + GOSTerr(GOST_F_GOST_GRASSHOPPER_CIPHER_DO_CTRACPKM_OMAC, ERR_R_EVP_LIB); + return -1; + } + result = gost_grasshopper_cipher_do_ctracpkm(ctx, out, in, inl); + + /* As in and out can be the same pointer, process decrypted here */ + if (!EVP_CIPHER_CTX_encrypting(ctx)) + EVP_DigestSignUpdate(c->omac_ctx, out, inl); + + return result; +} - if (in == NULL && inl == 0) { /* Final call */ - return gost2015_final_call(ctx, c->omac_ctx, KUZNYECHIK_MAC_MAX_SIZE, c->tag, gost_grasshopper_cipher_do_ctracpkm); - } - if (in == NULL) { - GOSTerr(GOST_F_GOST_GRASSHOPPER_CIPHER_DO_CTRACPKM_OMAC, ERR_R_EVP_LIB); - return -1; - } - result = gost_grasshopper_cipher_do_ctracpkm(ctx, out, in, inl); - /* As in and out can be the same pointer, process decrypted here */ - if (!EVP_CIPHER_CTX_encrypting(ctx)) - EVP_DigestSignUpdate(c->omac_ctx, out, inl); +static int gost_grasshopper_cipher_do_mgm(EVP_CIPHER_CTX *ctx, unsigned char *out, + const unsigned char *in, size_t len) +{ + gost_mgm_ctx *mctx = + (gost_mgm_ctx *)EVP_CIPHER_CTX_get_cipher_data(ctx); + int enc = EVP_CIPHER_CTX_encrypting(ctx); + + /* If not set up, return error */ + if (!mctx->key_set) { + GOSTerr(GOST_F_GOST_GRASSHOPPER_CIPHER_DO_MGM, + GOST_R_BAD_ORDER); + return -1; + } + + if (!mctx->iv_set) { + GOSTerr(GOST_F_GOST_GRASSHOPPER_CIPHER_DO_MGM, + GOST_R_BAD_ORDER); + return -1; + } + if (in) { + if (out == NULL) { + if (gost_mgm128_aad(&mctx->mgm, in, len)) + return -1; + } else if (enc) { + if (gost_mgm128_encrypt(&mctx->mgm, in, out, len)) + return -1; + } else { + if (gost_mgm128_decrypt(&mctx->mgm, in, out, len)) + return -1; + } + return len; + } else { + if (!enc) { + if (mctx->taglen < 0) + return -1; + if (gost_mgm128_finish(&mctx->mgm, + EVP_CIPHER_CTX_buf_noconst(ctx), + mctx->taglen) != 0) + return -1; + mctx->iv_set = 0; + return 0; + } + gost_mgm128_tag(&mctx->mgm, EVP_CIPHER_CTX_buf_noconst(ctx), 16); + mctx->taglen = 16; + /* Don't reuse the IV */ + mctx->iv_set = 0; + return 0; + } - return result; } + /* * Fixed 128-bit IV implementation make shift regiser redundant. */ @@ -764,39 +982,112 @@ static int gost_grasshopper_cipher_cleanup(EVP_CIPHER_CTX *ctx) static int gost_grasshopper_set_asn1_parameters(EVP_CIPHER_CTX *ctx, ASN1_TYPE *params) { - if (EVP_CIPHER_CTX_mode(ctx) == EVP_CIPH_CTR_MODE) { - gost_grasshopper_cipher_ctx_ctr *ctr = EVP_CIPHER_CTX_get_cipher_data(ctx); + if (EVP_CIPHER_CTX_mode(ctx) == EVP_CIPH_CTR_MODE) { + gost_grasshopper_cipher_ctx_ctr *ctr = EVP_CIPHER_CTX_get_cipher_data(ctx); - /* CMS implies 256kb section_size */ - ctr->section_size = 256*1024; + /* CMS implies 256kb section_size */ + ctr->section_size = 256*1024; - return gost2015_set_asn1_params(params, EVP_CIPHER_CTX_original_iv(ctx), 8, - ctr->kdf_seed); - } - return 0; + return gost2015_set_asn1_params(params, + EVP_CIPHER_CTX_original_iv(ctx), 8, ctr->kdf_seed); + } + return 0; } static GRASSHOPPER_INLINE int gost_grasshopper_get_asn1_parameters(EVP_CIPHER_CTX *ctx, ASN1_TYPE *params) { - if (EVP_CIPHER_CTX_mode(ctx) == EVP_CIPH_CTR_MODE) { - gost_grasshopper_cipher_ctx_ctr *ctr = EVP_CIPHER_CTX_get_cipher_data(ctx); + if (EVP_CIPHER_CTX_mode(ctx) == EVP_CIPH_CTR_MODE) { + gost_grasshopper_cipher_ctx_ctr *ctr = EVP_CIPHER_CTX_get_cipher_data(ctx); - int iv_len = 16; - unsigned char iv[16]; + int iv_len = 16; + unsigned char iv[16]; - if (gost2015_get_asn1_params(params, 16, iv, 8, ctr->kdf_seed) == 0) { - return 0; - } + if (gost2015_get_asn1_params(params, 16, iv, 8, ctr->kdf_seed) == 0) { + return 0; + } - memcpy(EVP_CIPHER_CTX_iv_noconst(ctx), iv, iv_len); - memcpy((unsigned char *)EVP_CIPHER_CTX_original_iv(ctx), iv, iv_len); + memcpy(EVP_CIPHER_CTX_iv_noconst(ctx), iv, iv_len); + memcpy((unsigned char *)EVP_CIPHER_CTX_original_iv(ctx), iv, iv_len); - /* CMS implies 256kb section_size */ - ctr->section_size = 256*1024; - return 1; - } - return 0; + /* CMS implies 256kb section_size */ + ctr->section_size = 256*1024; + return 1; + } + return 0; +} + +static int gost_grasshopper_mgm_cleanup(EVP_CIPHER_CTX *c) +{ + gost_mgm_ctx *mctx = + (gost_mgm_ctx *)EVP_CIPHER_CTX_get_cipher_data(c); + if (mctx == NULL) + return 0; + gost_grasshopper_cipher_destroy(&mctx->ks.gh_ks); + OPENSSL_cleanse(&mctx->mgm, sizeof(mctx->mgm)); + if (mctx->iv != EVP_CIPHER_CTX_iv_noconst(c)) + OPENSSL_free(mctx->iv); + return 1; +} + +static int gost_grasshopper_mgm_ctrl(EVP_CIPHER_CTX *c, int type, int arg, void *ptr) +{ + gost_mgm_ctx *mctx = + (gost_mgm_ctx *)EVP_CIPHER_CTX_get_cipher_data(c); + unsigned char *buf, *iv; + int ivlen, enc; + + switch (type) { + case EVP_CTRL_INIT: + ivlen = EVP_CIPHER_iv_length(EVP_CIPHER_CTX_cipher(c)); + iv = EVP_CIPHER_CTX_iv_noconst(c); + mctx->key_set = 0; + mctx->iv_set = 0; + mctx->ivlen = ivlen; + mctx->iv = iv; + mctx->taglen = -1; + return 1; + + case EVP_CTRL_GET_IVLEN: + *(int *)ptr = mctx->ivlen; + return 1; + + case EVP_CTRL_AEAD_SET_IVLEN: + if (arg <= 0) + return 0; + if ((arg > EVP_MAX_IV_LENGTH) && (arg > mctx->ivlen)) { + // TODO: Allocate memory for IV or set error + return 0; + } + mctx->ivlen = arg; + return 1; + + case EVP_CTRL_AEAD_SET_TAG: + buf = EVP_CIPHER_CTX_buf_noconst(c); + enc = EVP_CIPHER_CTX_encrypting(c); + if (arg <= 0 || arg != 16 || enc) { + GOSTerr(GOST_F_GOST_GRASSHOPPER_MGM_CTRL, + GOST_R_INVALID_TAG_LENGTH); + return 0; + } + memcpy(buf, ptr, arg); + mctx->taglen = arg; + return 1; + + case EVP_CTRL_AEAD_GET_TAG: + buf = EVP_CIPHER_CTX_buf_noconst(c); + enc = EVP_CIPHER_CTX_encrypting(c); + if (arg <= 0 || arg > 16 || !enc || mctx->taglen < 0) { + GOSTerr(GOST_F_GOST_GRASSHOPPER_MGM_CTRL, + GOST_R_INVALID_TAG_LENGTH); + return 0; + } + memcpy(ptr, buf, arg); + return 1; + + default: + return -1; + } } static int gost_grasshopper_cipher_ctl(EVP_CIPHER_CTX *ctx, int type, int arg, void *ptr) @@ -814,48 +1105,45 @@ static int gost_grasshopper_cipher_ctl(EVP_CIPHER_CTX *ctx, int type, int arg, v gost_grasshopper_cipher_ctx_ctr *c = EVP_CIPHER_CTX_get_cipher_data(ctx); if ((c->c.type != GRASSHOPPER_CIPHER_CTRACPKM && - c->c.type != GRASSHOPPER_CIPHER_CTRACPKMOMAC) - || (arg == 0) - || (arg % GRASSHOPPER_BLOCK_SIZE)) + c->c.type != GRASSHOPPER_CIPHER_CTRACPKMOMAC) + || (arg == 0) + || (arg % GRASSHOPPER_BLOCK_SIZE)) return -1; c->section_size = arg; break; } -#ifdef EVP_CTRL_TLS1_2_TLSTREE - case EVP_CTRL_TLS1_2_TLSTREE: + case EVP_CTRL_TLSTREE: { unsigned char newkey[32]; int mode = EVP_CIPHER_CTX_mode(ctx); - static const unsigned char zeroseq[8]; gost_grasshopper_cipher_ctx_ctr *ctr_ctx = NULL; gost_grasshopper_cipher_ctx *c = NULL; unsigned char adjusted_iv[16]; unsigned char seq[8]; - int j, carry; + int j, carry, decrement_arg; if (mode != EVP_CIPH_CTR_MODE) - return -1; + return -1; ctr_ctx = (gost_grasshopper_cipher_ctx_ctr *) - EVP_CIPHER_CTX_get_cipher_data(ctx); + EVP_CIPHER_CTX_get_cipher_data(ctx); c = &(ctr_ctx->c); + /* + * 'arg' parameter indicates what we should do with sequence value. + * + * When function called, seq is incremented after MAC calculation. + * In ETM mode, we use seq 'as is' in the ctrl-function (arg = 0) + * Otherwise we have to decrease it in the implementation (arg = 1). + */ memcpy(seq, ptr, 8); - if (EVP_CIPHER_CTX_encrypting(ctx)) { - /* - * OpenSSL increments seq after mac calculation. - * As we have Mac-Then-Encrypt, we need decrement it here on encryption - * to derive the key correctly. - * */ - if (memcmp(seq, zeroseq, 8) != 0) - { - for(j=7; j>=0; j--) - { - if (seq[j] != 0) {seq[j]--; break;} - else seq[j] = 0xFF; - } - } + decrement_arg = arg; + if (!decrement_sequence(seq, decrement_arg)) + { + GOSTerr(GOST_F_GOST_GRASSHOPPER_CIPHER_CTL, GOST_R_CTRL_CALL_FAILED); + return -1; } + if (gost_tlstree(NID_grasshopper_cbc, c->master_key.k.b, newkey, (const unsigned char *)seq) > 0) { memset(adjusted_iv, 0, 16); @@ -874,7 +1162,6 @@ static int gost_grasshopper_cipher_ctl(EVP_CIPHER_CTX *ctx, int type, int arg, v } } return -1; -#endif #if 0 case EVP_CTRL_AEAD_GET_TAG: case EVP_CTRL_AEAD_SET_TAG: @@ -900,7 +1187,7 @@ static int gost_grasshopper_cipher_ctl(EVP_CIPHER_CTX *ctx, int type, int arg, v return 1; } #endif - case EVP_CTRL_PROCESS_UNPROTECTED: + case EVP_CTRL_PROCESS_UNPROTECTED: { STACK_OF(X509_ATTRIBUTE) *x = ptr; gost_grasshopper_cipher_ctx_ctr *c = EVP_CIPHER_CTX_get_cipher_data(ctx); @@ -910,25 +1197,24 @@ static int gost_grasshopper_cipher_ctl(EVP_CIPHER_CTX *ctx, int type, int arg, v return gost2015_process_unprotected_attributes(x, arg, KUZNYECHIK_MAC_MAX_SIZE, c->tag); } - return 1; case EVP_CTRL_COPY: { - EVP_CIPHER_CTX *out = ptr; - - gost_grasshopper_cipher_ctx_ctr *out_cctx = EVP_CIPHER_CTX_get_cipher_data(out); - gost_grasshopper_cipher_ctx_ctr *in_cctx = EVP_CIPHER_CTX_get_cipher_data(ctx); - - if (in_cctx->c.type != GRASSHOPPER_CIPHER_CTRACPKMOMAC) - return -1; - - if (in_cctx->omac_ctx == out_cctx->omac_ctx) { - out_cctx->omac_ctx = EVP_MD_CTX_new(); - if (out_cctx->omac_ctx == NULL) { - GOSTerr(GOST_F_GOST_GRASSHOPPER_CIPHER_CTL, ERR_R_MALLOC_FAILURE); - return -1; - } - } - return EVP_MD_CTX_copy(out_cctx->omac_ctx, in_cctx->omac_ctx); - } + EVP_CIPHER_CTX *out = ptr; + + gost_grasshopper_cipher_ctx_ctr *out_cctx = EVP_CIPHER_CTX_get_cipher_data(out); + gost_grasshopper_cipher_ctx_ctr *in_cctx = EVP_CIPHER_CTX_get_cipher_data(ctx); + + if (in_cctx->c.type != GRASSHOPPER_CIPHER_CTRACPKMOMAC) + return -1; + + if (in_cctx->omac_ctx == out_cctx->omac_ctx) { + out_cctx->omac_ctx = EVP_MD_CTX_new(); + if (out_cctx->omac_ctx == NULL) { + GOSTerr(GOST_F_GOST_GRASSHOPPER_CIPHER_CTL, ERR_R_MALLOC_FAILURE); + return -1; + } + } + return EVP_MD_CTX_copy(out_cctx->omac_ctx, in_cctx->omac_ctx); + } default: GOSTerr(GOST_F_GOST_GRASSHOPPER_CIPHER_CTL, GOST_R_UNSUPPORTED_CIPHER_CTL_COMMAND); @@ -938,7 +1224,7 @@ static int gost_grasshopper_cipher_ctl(EVP_CIPHER_CTX *ctx, int type, int arg, v } /* Called directly by CMAC_ACPKM_Init() */ -const GRASSHOPPER_INLINE EVP_CIPHER *cipher_gost_grasshopper_ctracpkm() +const EVP_CIPHER *cipher_gost_grasshopper_ctracpkm() { return GOST_init_cipher(&grasshopper_ctr_acpkm_cipher); }