X-Git-Url: https://wagner.pp.ru/gitweb/?a=blobdiff_plain;f=gost_grasshopper_cipher.c;h=2c2ea88119b411dd2d08775a6d035ba01eeae0e2;hb=2ed1909a235ade9dd9c99e9d2be4c32bca9a8396;hp=f6b8a39edb62fc472a043c94c6b4c486e05cbbf4;hpb=d1cf560c742d85ab1986fb0cabe0f9e3a1f0eb23;p=openssl-gost%2Fengine.git diff --git a/gost_grasshopper_cipher.c b/gost_grasshopper_cipher.c index f6b8a39..2c2ea88 100644 --- a/gost_grasshopper_cipher.c +++ b/gost_grasshopper_cipher.c @@ -7,6 +7,7 @@ #include "gost_grasshopper_defines.h" #include "gost_grasshopper_math.h" #include "gost_grasshopper_core.h" +#include "gost_gost2015.h" #include #include @@ -23,10 +24,11 @@ enum GRASSHOPPER_CIPHER_TYPE { GRASSHOPPER_CIPHER_CFB, GRASSHOPPER_CIPHER_CTR, GRASSHOPPER_CIPHER_CTRACPKM, + GRASSHOPPER_CIPHER_CTRACPKMOMAC, }; -static EVP_CIPHER *gost_grasshopper_ciphers[6] = { - NULL, NULL, NULL, NULL, NULL, NULL, +static EVP_CIPHER *gost_grasshopper_ciphers[7] = { + NULL, NULL, NULL, NULL, NULL, NULL, NULL }; static GRASSHOPPER_INLINE void @@ -41,72 +43,87 @@ struct GRASSHOPPER_CIPHER_PARAMS { int ctx_size; int iv_size; bool padding; + int extra_flags; }; -static struct GRASSHOPPER_CIPHER_PARAMS gost_cipher_params[6] = { - { - NID_grasshopper_ecb, - gost_grasshopper_cipher_init_ecb, - gost_grasshopper_cipher_do_ecb, - NULL, - 16, - sizeof(gost_grasshopper_cipher_ctx), - 0, - true} - , - { - NID_grasshopper_cbc, - gost_grasshopper_cipher_init_cbc, - gost_grasshopper_cipher_do_cbc, - NULL, - 16, - sizeof(gost_grasshopper_cipher_ctx), - 16, - true} - , - { - NID_grasshopper_ofb, - gost_grasshopper_cipher_init_ofb, - gost_grasshopper_cipher_do_ofb, - NULL, - 1, - sizeof(gost_grasshopper_cipher_ctx), - 16, - false} - , - { - NID_grasshopper_cfb, - gost_grasshopper_cipher_init_cfb, - gost_grasshopper_cipher_do_cfb, - NULL, - 1, - sizeof(gost_grasshopper_cipher_ctx), - 16, - false} - , - { - NID_grasshopper_ctr, - gost_grasshopper_cipher_init_ctr, - gost_grasshopper_cipher_do_ctr, - gost_grasshopper_cipher_destroy_ctr, - 1, - sizeof(gost_grasshopper_cipher_ctx_ctr), - /* IV size is set to match full block, to make it responsibility of - * user to assign correct values (IV || 0), and to make naive context - * copy possible (for software such as openssh) */ - 16, - false} - , - { - NID_id_tc26_cipher_gostr3412_2015_kuznyechik_ctracpkm, - gost_grasshopper_cipher_init_ctracpkm, - gost_grasshopper_cipher_do_ctracpkm, - gost_grasshopper_cipher_destroy_ctr, - 1, - sizeof(gost_grasshopper_cipher_ctx_ctr), - 16, - false} - , +static struct GRASSHOPPER_CIPHER_PARAMS gost_cipher_params[7] = { + { + NID_grasshopper_ecb, + gost_grasshopper_cipher_init_ecb, + gost_grasshopper_cipher_do_ecb, + NULL, + 16, + sizeof(gost_grasshopper_cipher_ctx), + 0, + true, + 0 + }, + { + NID_grasshopper_cbc, + gost_grasshopper_cipher_init_cbc, + gost_grasshopper_cipher_do_cbc, + NULL, + 16, + sizeof(gost_grasshopper_cipher_ctx), + 16, + true, + 0 + }, + { + NID_grasshopper_ofb, + gost_grasshopper_cipher_init_ofb, + gost_grasshopper_cipher_do_ofb, + NULL, + 1, + sizeof(gost_grasshopper_cipher_ctx), + 16, + false, + 0 + }, + { + NID_grasshopper_cfb, + gost_grasshopper_cipher_init_cfb, + gost_grasshopper_cipher_do_cfb, + NULL, + 1, + sizeof(gost_grasshopper_cipher_ctx), + 16, + false, + 0 + }, + { + NID_grasshopper_ctr, + gost_grasshopper_cipher_init_ctr, + gost_grasshopper_cipher_do_ctr, + gost_grasshopper_cipher_destroy_ctr, + 1, + sizeof(gost_grasshopper_cipher_ctx_ctr), + 8, + false, + 0 + }, + { + NID_kuznyechik_ctr_acpkm, + gost_grasshopper_cipher_init_ctracpkm, + gost_grasshopper_cipher_do_ctracpkm, + gost_grasshopper_cipher_destroy_ctr, + 1, + sizeof(gost_grasshopper_cipher_ctx_ctr), + 8, + false, + 0 + }, + { + NID_kuznyechik_ctr_acpkm_omac, + gost_grasshopper_cipher_init_ctracpkm_omac, + gost_grasshopper_cipher_do_ctracpkm_omac, + gost_grasshopper_cipher_destroy_ctr, + 1, + sizeof(gost_grasshopper_cipher_ctx_ctr), + 8, + false, + EVP_CIPH_FLAG_CUSTOM_CIPHER|EVP_CIPH_FLAG_CIPHER_WITH_MAC|EVP_CIPH_CUSTOM_COPY + }, }; /* first 256 bit of D from draft-irtf-cfrg-re-keying-12 */ @@ -184,6 +201,9 @@ gost_grasshopper_cipher_destroy_ctr(gost_grasshopper_cipher_ctx * c) gost_grasshopper_cipher_ctx_ctr *ctx = (gost_grasshopper_cipher_ctx_ctr *) c; + if (ctx->omac_ctx) + EVP_MD_CTX_free(ctx->omac_ctx); + grasshopper_zero128(&ctx->partial_buffer); } @@ -195,6 +215,11 @@ int gost_grasshopper_cipher_init(EVP_CIPHER_CTX *ctx, if (EVP_CIPHER_CTX_get_app_data(ctx) == NULL) { EVP_CIPHER_CTX_set_app_data(ctx, EVP_CIPHER_CTX_get_cipher_data(ctx)); + if (enc && c->type == GRASSHOPPER_CIPHER_CTRACPKM) { + gost_grasshopper_cipher_ctx_ctr *ctr = EVP_CIPHER_CTX_get_cipher_data(ctx); + if (init_zero_kdf_seed(ctr->kdf_seed) == 0) + return -1; + } } if (key != NULL) { @@ -280,6 +305,40 @@ 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) +{ + 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; + + 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 (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); +} + GRASSHOPPER_INLINE int gost_grasshopper_cipher_do(EVP_CIPHER_CTX *ctx, unsigned char *out, const unsigned char *in, @@ -394,19 +453,19 @@ int gost_grasshopper_cipher_do_ctr(EVP_CIPHER_CTX *ctx, unsigned char *out, grasshopper_w128_t *currentInputBlock; grasshopper_w128_t *currentOutputBlock; unsigned int n = EVP_CIPHER_CTX_num(ctx); - size_t lasted; + size_t lasted = inl; size_t i; size_t blocks; grasshopper_w128_t *iv_buffer; grasshopper_w128_t tmp; - while (n && inl) { + while (n && lasted) { *(current_out++) = *(current_in++) ^ c->partial_buffer.b[n]; - --inl; + --lasted; n = (n + 1) % GRASSHOPPER_BLOCK_SIZE; } EVP_CIPHER_CTX_set_num(ctx, n); - blocks = inl / GRASSHOPPER_BLOCK_SIZE; + blocks = lasted / GRASSHOPPER_BLOCK_SIZE; iv_buffer = (grasshopper_w128_t *) iv; @@ -421,10 +480,9 @@ 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; } - // last part - lasted = inl - blocks * GRASSHOPPER_BLOCK_SIZE; if (lasted > 0) { currentInputBlock = (grasshopper_w128_t *) current_in; currentOutputBlock = (grasshopper_w128_t *) current_out; @@ -438,7 +496,7 @@ int gost_grasshopper_cipher_do_ctr(EVP_CIPHER_CTX *ctx, unsigned char *out, ctr128_inc(iv_buffer->b); } - return 1; + return inl; } #define GRASSHOPPER_BLOCK_MASK (GRASSHOPPER_BLOCK_SIZE - 1) @@ -460,15 +518,15 @@ int gost_grasshopper_cipher_do_ctracpkm(EVP_CIPHER_CTX *ctx, gost_grasshopper_cipher_ctx_ctr *c = EVP_CIPHER_CTX_get_cipher_data(ctx); unsigned char *iv = EVP_CIPHER_CTX_iv_noconst(ctx); unsigned int num = EVP_CIPHER_CTX_num(ctx); - size_t blocks, i, lasted; + size_t blocks, i, lasted = inl; grasshopper_w128_t tmp; - while ((num & GRASSHOPPER_BLOCK_MASK) && inl) { + while ((num & GRASSHOPPER_BLOCK_MASK) && lasted) { *out++ = *in++ ^ c->partial_buffer.b[num & GRASSHOPPER_BLOCK_MASK]; - --inl; + --lasted; num++; } - blocks = inl / GRASSHOPPER_BLOCK_SIZE; + blocks = lasted / GRASSHOPPER_BLOCK_SIZE; // full parts for (i = 0; i < blocks; i++) { @@ -484,10 +542,10 @@ 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; } // last part - lasted = inl - blocks * GRASSHOPPER_BLOCK_SIZE; if (lasted > 0) { apply_acpkm_grasshopper(c, &num); grasshopper_encrypt_block(&c->c.encrypt_round_keys, @@ -500,9 +558,35 @@ int gost_grasshopper_cipher_do_ctracpkm(EVP_CIPHER_CTX *ctx, } EVP_CIPHER_CTX_set_num(ctx, num); - return 1; + return inl; } +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); + + 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; +} /* * Fixed 128-bit IV implementation make shift regiser redundant. */ @@ -690,36 +774,43 @@ int gost_grasshopper_cipher_cleanup(EVP_CIPHER_CTX *ctx) int gost_grasshopper_set_asn1_parameters(EVP_CIPHER_CTX *ctx, ASN1_TYPE *params) { - int len = 0; - unsigned char *buf = NULL; - ASN1_OCTET_STRING *os = ASN1_OCTET_STRING_new(); + if (EVP_CIPHER_CTX_mode(ctx) == EVP_CIPH_CTR_MODE) { + gost_grasshopper_cipher_ctx_ctr *ctr = EVP_CIPHER_CTX_get_cipher_data(ctx); - if (!os || !ASN1_OCTET_STRING_set(os, buf, len)) { - ASN1_OCTET_STRING_free(os); - OPENSSL_free(buf); - GOSTerr(GOST_F_GOST_GRASSHOPPER_SET_ASN1_PARAMETERS, - ERR_R_MALLOC_FAILURE); - return 0; - } - OPENSSL_free(buf); + /* CMS implies 256kb section_size */ + ctr->section_size = 256*1024; - ASN1_TYPE_set(params, V_ASN1_SEQUENCE, os); - return 1; + 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) { - if (ASN1_TYPE_get(params) != V_ASN1_SEQUENCE) { - return -1; - } + if (EVP_CIPHER_CTX_mode(ctx) == EVP_CIPH_CTR_MODE) { + gost_grasshopper_cipher_ctx_ctr *ctr = EVP_CIPHER_CTX_get_cipher_data(ctx); - return 1; + int iv_len = 16; + unsigned char iv[16]; + + 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); + + /* CMS implies 256kb section_size */ + ctr->section_size = 256*1024; + return 1; + } + return 0; } -int gost_grasshopper_cipher_ctl(EVP_CIPHER_CTX *ctx, int type, int arg, - void *ptr) +int gost_grasshopper_cipher_ctl(EVP_CIPHER_CTX *ctx, int type, int arg, void *ptr) { switch (type) { case EVP_CTRL_RAND_KEY:{ @@ -733,7 +824,9 @@ int gost_grasshopper_cipher_ctl(EVP_CIPHER_CTX *ctx, int type, int arg, case EVP_CTRL_KEY_MESH:{ gost_grasshopper_cipher_ctx_ctr *c = EVP_CIPHER_CTX_get_cipher_data(ctx); - if (c->c.type != GRASSHOPPER_CIPHER_CTRACPKM || !arg + if ((c->c.type != GRASSHOPPER_CIPHER_CTRACPKM && + c->c.type != GRASSHOPPER_CIPHER_CTRACPKMOMAC) + || (arg == 0) || (arg % GRASSHOPPER_BLOCK_SIZE)) return -1; c->section_size = arg; @@ -793,6 +886,60 @@ int gost_grasshopper_cipher_ctl(EVP_CIPHER_CTX *ctx, int type, int arg, } return -1; #endif +#if 0 + case EVP_CTRL_AEAD_GET_TAG: + case EVP_CTRL_AEAD_SET_TAG: + { + int taglen = arg; + unsigned char *tag = ptr; + + gost_grasshopper_cipher_ctx *c = EVP_CIPHER_CTX_get_cipher_data(ctx); + if (c->c.type != GRASSHOPPER_CIPHER_MGM) + return -1; + + if (taglen > KUZNYECHIK_MAC_MAX_SIZE) { + CRYPTOCOMerr(CRYPTOCOM_F_GOST_GRASSHOPPER_CIPHER_CTL, + CRYPTOCOM_R_INVALID_TAG_LENGTH); + return -1; + } + + if (type == EVP_CTRL_AEAD_GET_TAG) + memcpy(tag, c->final_tag, taglen); + else + memcpy(c->final_tag, tag, taglen); + + return 1; + } +#endif + case EVP_CTRL_PROCESS_UNPROTECTED: + { + STACK_OF(X509_ATTRIBUTE) *x = ptr; + gost_grasshopper_cipher_ctx_ctr *c = EVP_CIPHER_CTX_get_cipher_data(ctx); + + if (c->c.type != GRASSHOPPER_CIPHER_CTRACPKMOMAC) + return -1; + + 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); + } default: GOSTerr(GOST_F_GOST_GRASSHOPPER_CIPHER_CTL, GOST_R_UNSUPPORTED_CIPHER_CTL_COMMAND); @@ -810,20 +957,16 @@ GRASSHOPPER_INLINE EVP_CIPHER *cipher_gost_grasshopper_create(int } const int cipher_gost_grasshopper_setup(EVP_CIPHER *cipher, uint8_t mode, - int iv_size, bool padding) + int iv_size, bool padding, int extra_flags) { + unsigned long flags = (unsigned long)(mode + | ((!padding) ? EVP_CIPH_NO_PADDING : 0) + | ((iv_size > 0) ? EVP_CIPH_CUSTOM_IV : 0) + | EVP_CIPH_RAND_KEY | EVP_CIPH_ALWAYS_CALL_INIT + | extra_flags); + return EVP_CIPHER_meth_set_iv_length(cipher, iv_size) - && EVP_CIPHER_meth_set_flags(cipher, - (unsigned long)(mode | - ((!padding) ? - EVP_CIPH_NO_PADDING : - 0) | ((iv_size > - 0) ? - EVP_CIPH_CUSTOM_IV - : 0) | - EVP_CIPH_RAND_KEY | - EVP_CIPH_ALWAYS_CALL_INIT) - ) + && EVP_CIPHER_meth_set_flags(cipher, flags) && EVP_CIPHER_meth_set_cleanup(cipher, gost_grasshopper_cipher_cleanup) && EVP_CIPHER_meth_set_set_asn1_params(cipher, gost_grasshopper_set_asn1_parameters) @@ -843,7 +986,7 @@ const GRASSHOPPER_INLINE EVP_CIPHER *cipher_gost_grasshopper(uint8_t mode, if (*cipher == NULL) { grasshopper_init_cipher_func init_cipher; - int nid, block_size, ctx_size, iv_size; + int nid, block_size, ctx_size, iv_size, extra_flags; bool padding; params = &gost_cipher_params[num]; @@ -854,13 +997,14 @@ const GRASSHOPPER_INLINE EVP_CIPHER *cipher_gost_grasshopper(uint8_t mode, ctx_size = params->ctx_size; iv_size = params->iv_size; padding = params->padding; + extra_flags = params->extra_flags; *cipher = cipher_gost_grasshopper_create(nid, block_size); if (*cipher == NULL) { return NULL; } - if (!cipher_gost_grasshopper_setup(*cipher, mode, iv_size, padding) + if (!cipher_gost_grasshopper_setup(*cipher, mode, iv_size, padding, extra_flags) || !EVP_CIPHER_meth_set_init(*cipher, init_cipher) || !EVP_CIPHER_meth_set_impl_ctx_size(*cipher, ctx_size)) { EVP_CIPHER_meth_free(*cipher); @@ -902,6 +1046,12 @@ const GRASSHOPPER_INLINE EVP_CIPHER *cipher_gost_grasshopper_ctracpkm() GRASSHOPPER_CIPHER_CTRACPKM); } +const GRASSHOPPER_INLINE EVP_CIPHER *cipher_gost_grasshopper_ctracpkm_omac() +{ + return cipher_gost_grasshopper(EVP_CIPH_CTR_MODE, + GRASSHOPPER_CIPHER_CTRACPKMOMAC); +} + void cipher_gost_grasshopper_destroy(void) { EVP_CIPHER_meth_free(gost_grasshopper_ciphers[GRASSHOPPER_CIPHER_ECB]); @@ -916,4 +1066,6 @@ void cipher_gost_grasshopper_destroy(void) gost_grasshopper_ciphers[GRASSHOPPER_CIPHER_CTR] = NULL; EVP_CIPHER_meth_free(gost_grasshopper_ciphers[GRASSHOPPER_CIPHER_CTRACPKM]); gost_grasshopper_ciphers[GRASSHOPPER_CIPHER_CTRACPKM] = NULL; + EVP_CIPHER_meth_free(gost_grasshopper_ciphers[GRASSHOPPER_CIPHER_CTRACPKMOMAC]); + gost_grasshopper_ciphers[GRASSHOPPER_CIPHER_CTRACPKMOMAC] = NULL; }