X-Git-Url: http://wagner.pp.ru/gitweb/?a=blobdiff_plain;f=gost_grasshopper_cipher.c;h=c0031ad170221b7a12fb8b2e796abed4dfc7de9d;hb=785a1ea49f67e9f25a269155905236ef44dccda6;hp=22ca71781bca3a45ae7858cce90a0b380d8179fd;hpb=970934039a4481b67c9c6433e20ca3002098cae6;p=openssl-gost%2Fengine.git diff --git a/gost_grasshopper_cipher.c b/gost_grasshopper_cipher.c index 22ca717..c0031ad 100644 --- a/gost_grasshopper_cipher.c +++ b/gost_grasshopper_cipher.c @@ -13,6 +13,7 @@ #include #include #include + #include #include "gost_lcl.h" @@ -26,6 +27,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 +126,21 @@ GOST_cipher grasshopper_ctr_acpkm_omac_cipher = { .ctx_size = sizeof(gost_grasshopper_cipher_ctx_ctr), }; +GOST_cipher grasshopper_mgm_cipher = { + .nid = NID_kuznyechik_mgm, + .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) +}; + /* 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 */ @@ -151,7 +168,7 @@ static void acpkm_next(gost_grasshopper_cipher_ctx * c) } /* Set 256 bit key into context */ -GRASSHOPPER_INLINE void +static GRASSHOPPER_INLINE void gost_grasshopper_cipher_key(gost_grasshopper_cipher_ctx * c, const uint8_t *k) { int i; @@ -165,7 +182,7 @@ gost_grasshopper_cipher_key(gost_grasshopper_cipher_ctx * c, const uint8_t *k) } /* Set master 256-bit key to be used in TLSTREE calculation into context */ -GRASSHOPPER_INLINE void +static GRASSHOPPER_INLINE void gost_grasshopper_master_key(gost_grasshopper_cipher_ctx * c, const uint8_t *k) { int i; @@ -176,7 +193,7 @@ gost_grasshopper_master_key(gost_grasshopper_cipher_ctx * c, const uint8_t *k) } /* Cleans up key from context */ -GRASSHOPPER_INLINE void +static GRASSHOPPER_INLINE void gost_grasshopper_cipher_destroy(gost_grasshopper_cipher_ctx * c) { int i; @@ -205,7 +222,7 @@ gost_grasshopper_cipher_destroy_ctr(gost_grasshopper_cipher_ctx * c) grasshopper_zero128(&ctx->partial_buffer); } -int gost_grasshopper_cipher_init(EVP_CIPHER_CTX *ctx, +static int gost_grasshopper_cipher_init(EVP_CIPHER_CTX *ctx, const unsigned char *key, const unsigned char *iv, int enc) { @@ -238,45 +255,50 @@ int gost_grasshopper_cipher_init(EVP_CIPHER_CTX *ctx, return 1; } -GRASSHOPPER_INLINE int gost_grasshopper_cipher_init_ecb(EVP_CIPHER_CTX *ctx, const unsigned char - *key, const unsigned char - *iv, int enc) +static GRASSHOPPER_INLINE int +gost_grasshopper_cipher_init_ecb(EVP_CIPHER_CTX *ctx, const unsigned char + *key, const unsigned char + *iv, int enc) { gost_grasshopper_cipher_ctx *c = EVP_CIPHER_CTX_get_cipher_data(ctx); c->type = GRASSHOPPER_CIPHER_ECB; return gost_grasshopper_cipher_init(ctx, key, iv, enc); } -GRASSHOPPER_INLINE int gost_grasshopper_cipher_init_cbc(EVP_CIPHER_CTX *ctx, const unsigned char - *key, const unsigned char - *iv, int enc) +static GRASSHOPPER_INLINE int +gost_grasshopper_cipher_init_cbc(EVP_CIPHER_CTX *ctx, const unsigned char + *key, const unsigned char + *iv, int enc) { gost_grasshopper_cipher_ctx *c = EVP_CIPHER_CTX_get_cipher_data(ctx); c->type = GRASSHOPPER_CIPHER_CBC; return gost_grasshopper_cipher_init(ctx, key, iv, enc); } -GRASSHOPPER_INLINE int gost_grasshopper_cipher_init_ofb(EVP_CIPHER_CTX *ctx, const unsigned char - *key, const unsigned char - *iv, int enc) +static GRASSHOPPER_INLINE +int gost_grasshopper_cipher_init_ofb(EVP_CIPHER_CTX *ctx, const unsigned char + *key, const unsigned char + *iv, int enc) { gost_grasshopper_cipher_ctx *c = EVP_CIPHER_CTX_get_cipher_data(ctx); c->type = GRASSHOPPER_CIPHER_OFB; return gost_grasshopper_cipher_init(ctx, key, iv, enc); } -GRASSHOPPER_INLINE int gost_grasshopper_cipher_init_cfb(EVP_CIPHER_CTX *ctx, const unsigned char - *key, const unsigned char - *iv, int enc) +static GRASSHOPPER_INLINE int +gost_grasshopper_cipher_init_cfb(EVP_CIPHER_CTX *ctx, const unsigned char + *key, const unsigned char + *iv, int enc) { gost_grasshopper_cipher_ctx *c = EVP_CIPHER_CTX_get_cipher_data(ctx); c->type = GRASSHOPPER_CIPHER_CFB; return gost_grasshopper_cipher_init(ctx, key, iv, enc); } -GRASSHOPPER_INLINE int gost_grasshopper_cipher_init_ctr(EVP_CIPHER_CTX *ctx, const unsigned char - *key, const unsigned char - *iv, int enc) +static GRASSHOPPER_INLINE int +gost_grasshopper_cipher_init_ctr(EVP_CIPHER_CTX *ctx, const unsigned char + *key, const unsigned char + *iv, int enc) { gost_grasshopper_cipher_ctx_ctr *c = EVP_CIPHER_CTX_get_cipher_data(ctx); @@ -288,10 +310,11 @@ GRASSHOPPER_INLINE int gost_grasshopper_cipher_init_ctr(EVP_CIPHER_CTX *ctx, con return gost_grasshopper_cipher_init(ctx, key, iv, enc); } -GRASSHOPPER_INLINE int gost_grasshopper_cipher_init_ctracpkm(EVP_CIPHER_CTX - *ctx, const unsigned - char *key, const unsigned - char *iv, int enc) +static GRASSHOPPER_INLINE int +gost_grasshopper_cipher_init_ctracpkm(EVP_CIPHER_CTX + *ctx, const unsigned + char *key, const unsigned + char *iv, int enc) { gost_grasshopper_cipher_ctx_ctr *c = EVP_CIPHER_CTX_get_cipher_data(ctx); @@ -303,42 +326,180 @@ GRASSHOPPER_INLINE int gost_grasshopper_cipher_init_ctracpkm(EVP_CIPHER_CTX return gost_grasshopper_cipher_init(ctx, key, iv, enc); } -GRASSHOPPER_INLINE int gost_grasshopper_cipher_init_ctracpkm_omac(EVP_CIPHER_CTX - *ctx, const unsigned - char *key, const unsigned - char *iv, int enc) +static GRASSHOPPER_INLINE int +gost_grasshopper_cipher_init_ctracpkm_omac(EVP_CIPHER_CTX + *ctx, const unsigned + 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 (c->omac_ctx == NULL) { + GOSTerr(GOST_F_GOST_GRASSHOPPER_CIPHER_INIT_CTRACPKM_OMAC, ERR_R_MALLOC_FAILURE); + return 0; + } - if (key) { - unsigned char cipher_key[32]; - c->omac_ctx = EVP_MD_CTX_new(); + 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 - if (c->omac_ctx == NULL) { - GOSTerr(GOST_F_GOST_GRASSHOPPER_CIPHER_INIT_CTRACPKM_OMAC, ERR_R_MALLOC_FAILURE); - return 0; + 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; + } + } + + //second 64 bits of arg2 +#ifdef L_ENDIAN + t = BSWAP64(*arg2); +#else + t = *arg2; +#endif - 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; + 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; } -int gost_grasshopper_cipher_do_ecb(EVP_CIPHER_CTX *ctx, unsigned char *out, - const unsigned char *in, size_t inl) +static int gost_grasshopper_cipher_do_ecb(EVP_CIPHER_CTX *ctx, unsigned char *out, + const unsigned char *in, size_t inl) { gost_grasshopper_cipher_ctx *c = (gost_grasshopper_cipher_ctx *) EVP_CIPHER_CTX_get_cipher_data(ctx); @@ -367,8 +528,8 @@ int gost_grasshopper_cipher_do_ecb(EVP_CIPHER_CTX *ctx, unsigned char *out, return 1; } -int gost_grasshopper_cipher_do_cbc(EVP_CIPHER_CTX *ctx, unsigned char *out, - const unsigned char *in, size_t inl) +static int gost_grasshopper_cipher_do_cbc(EVP_CIPHER_CTX *ctx, unsigned char *out, + const unsigned char *in, size_t inl) { gost_grasshopper_cipher_ctx *c = (gost_grasshopper_cipher_ctx *) EVP_CIPHER_CTX_get_cipher_data(ctx); @@ -428,8 +589,8 @@ static void ctr128_inc(unsigned char *counter) inc_counter(counter, 16); } -int gost_grasshopper_cipher_do_ctr(EVP_CIPHER_CTX *ctx, unsigned char *out, - const unsigned char *in, size_t inl) +static int gost_grasshopper_cipher_do_ctr(EVP_CIPHER_CTX *ctx, unsigned char *out, + const unsigned char *in, size_t inl) { gost_grasshopper_cipher_ctx_ctr *c = (gost_grasshopper_cipher_ctx_ctr *) EVP_CIPHER_CTX_get_cipher_data(ctx); @@ -466,7 +627,7 @@ int gost_grasshopper_cipher_do_ctr(EVP_CIPHER_CTX *ctx, unsigned char *out, 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) { @@ -497,9 +658,10 @@ static inline void apply_acpkm_grasshopper(gost_grasshopper_cipher_ctx_ctr * /* If meshing is not configured via ctrl (setting section_size) * this function works exactly like plain ctr */ -int gost_grasshopper_cipher_do_ctracpkm(EVP_CIPHER_CTX *ctx, - unsigned char *out, - const unsigned char *in, size_t inl) +static int gost_grasshopper_cipher_do_ctracpkm(EVP_CIPHER_CTX *ctx, + unsigned char *out, + const unsigned char *in, + size_t inl) { gost_grasshopper_cipher_ctx_ctr *c = EVP_CIPHER_CTX_get_cipher_data(ctx); unsigned char *iv = EVP_CIPHER_CTX_iv_noconst(ctx); @@ -528,7 +690,7 @@ 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 @@ -547,32 +709,87 @@ int gost_grasshopper_cipher_do_ctracpkm(EVP_CIPHER_CTX *ctx, return inl; } -int gost_grasshopper_cipher_do_ctracpkm_omac(EVP_CIPHER_CTX *ctx, - unsigned char *out, - const unsigned char *in, size_t inl) +static int gost_grasshopper_cipher_do_ctracpkm_omac(EVP_CIPHER_CTX *ctx, + unsigned char *out, + 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 && 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); + 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); + /* 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; + return result; } + + + +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; + } + +} + /* * Fixed 128-bit IV implementation make shift regiser redundant. */ @@ -587,8 +804,8 @@ static void gost_grasshopper_cnt_next(gost_grasshopper_cipher_ctx * ctx, memcpy(iv, buf, 16); } -int gost_grasshopper_cipher_do_ofb(EVP_CIPHER_CTX *ctx, unsigned char *out, - const unsigned char *in, size_t inl) +static int gost_grasshopper_cipher_do_ofb(EVP_CIPHER_CTX *ctx, unsigned char *out, + const unsigned char *in, size_t inl) { gost_grasshopper_cipher_ctx *c = (gost_grasshopper_cipher_ctx *) EVP_CIPHER_CTX_get_cipher_data(ctx); @@ -651,8 +868,8 @@ int gost_grasshopper_cipher_do_ofb(EVP_CIPHER_CTX *ctx, unsigned char *out, return 1; } -int gost_grasshopper_cipher_do_cfb(EVP_CIPHER_CTX *ctx, unsigned char *out, - const unsigned char *in, size_t inl) +static int gost_grasshopper_cipher_do_cfb(EVP_CIPHER_CTX *ctx, unsigned char *out, + const unsigned char *in, size_t inl) { gost_grasshopper_cipher_ctx *c = (gost_grasshopper_cipher_ctx *) EVP_CIPHER_CTX_get_cipher_data(ctx); @@ -737,7 +954,7 @@ int gost_grasshopper_cipher_do_cfb(EVP_CIPHER_CTX *ctx, unsigned char *out, return 1; } -int gost_grasshopper_cipher_cleanup(EVP_CIPHER_CTX *ctx) +static int gost_grasshopper_cipher_cleanup(EVP_CIPHER_CTX *ctx) { gost_grasshopper_cipher_ctx *c = (gost_grasshopper_cipher_ctx *) EVP_CIPHER_CTX_get_cipher_data(ctx); @@ -753,45 +970,117 @@ int gost_grasshopper_cipher_cleanup(EVP_CIPHER_CTX *ctx) return 1; } -int gost_grasshopper_set_asn1_parameters(EVP_CIPHER_CTX *ctx, ASN1_TYPE *params) +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; } -GRASSHOPPER_INLINE int gost_grasshopper_get_asn1_parameters(EVP_CIPHER_CTX - *ctx, ASN1_TYPE - *params) +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; + } } -int gost_grasshopper_cipher_ctl(EVP_CIPHER_CTX *ctx, int type, int arg, void *ptr) +static int gost_grasshopper_cipher_ctl(EVP_CIPHER_CTX *ctx, int type, int arg, void *ptr) { switch (type) { case EVP_CTRL_RAND_KEY:{ @@ -806,9 +1095,9 @@ int gost_grasshopper_cipher_ctl(EVP_CIPHER_CTX *ctx, int type, int arg, void *pt 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; @@ -892,7 +1181,7 @@ int gost_grasshopper_cipher_ctl(EVP_CIPHER_CTX *ctx, int type, int arg, void *pt 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); @@ -904,23 +1193,23 @@ int gost_grasshopper_cipher_ctl(EVP_CIPHER_CTX *ctx, int type, int arg, void *pt } 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);