From: Victor Wagner Date: Sun, 23 Aug 2015 12:31:58 +0000 (+0300) Subject: Added CBC mode for gost and contril command to set size of MAC (from 1 to 8 bytes) X-Git-Tag: v1.1.0.2~44^2~1 X-Git-Url: http://www.wagner.pp.ru/gitweb/?p=openssl-gost%2Fengine.git;a=commitdiff_plain;h=be94de0b86a7ac68bfe5949e113ad08fd444f374 Added CBC mode for gost and contril command to set size of MAC (from 1 to 8 bytes) --- diff --git a/README.gost b/README.gost index abc5a9b..3a48d95 100644 --- a/README.gost +++ b/README.gost @@ -28,6 +28,8 @@ GOST 28147-89 MAC mode. Message authentication code. While most MAC It has 256-bit symmetric key and only 32 bits of MAC value (while HMAC has same key size and value size). + Really, this algorithm supports from 8 to 64 bits of the MAC value + It is implemented as combination of EVP_PKEY type and EVP_MD type. USAGE OF THESE ALGORITHMS @@ -198,11 +200,30 @@ Russian clients and RSA/DSA ciphersuites for foreign clients. implementation of this mac) and OpenSSL is clever enough to find out this. + Following mac options are supported: + + key:(32 bytes of key) + + hexkey:(64 hexadecimal digits of key) + + Engine support calculation of mac with size different from default 32 + bits. You can set mac size to any value from 1 to 8 bytes using + + -sigopt size:(number from 1 to 8 - mac size in bytes) + + (dgst command uses different EVP_PKEY_CTX for initialization and for + finalization of MAC. Option of first are set via -macopt, and for + second via -sigopt. Key should be set during initialization and size + during finalization. If you use API functions + EVP_DigestSignInit/EVP_DigestSignFinal, you can set both options at + the same time). + Encryption with GOST 28147 CFB mode openssl enc -gost89 -out encrypted-file -in plain-text-file -k Encryption with GOST 28147 CNT mode openssl enc -gost89-cnt -out encrypted-file -in plain-text-file -k - + Encryption with GOST 28147 CBC mode + openssl enc -gost89-cbc -out encrypted-file -in plain-text-file -k 6. Encrypting private keys and PKCS12 @@ -221,6 +242,7 @@ accessed by cipher-specific functions, only via generic evp interface openssl speed -evp gost89 openssl speed -evp gost89-cnt + openssl speed -evp gost89-cbc PROGRAMMING INTERFACES DETAILS diff --git a/e_gost_err.c b/e_gost_err.c index c641c60..376d18b 100644 --- a/e_gost_err.c +++ b/e_gost_err.c @@ -139,6 +139,8 @@ static ERR_STRING_DATA GOST_str_reasons[] = { {ERR_REASON(GOST_R_INVALID_DIGEST_TYPE), "invalid digest type"}, {ERR_REASON(GOST_R_INVALID_IV_LENGTH), "invalid iv length"}, {ERR_REASON(GOST_R_INVALID_MAC_KEY_LENGTH), "invalid mac key length"}, + {ERR_REASON(GOST_R_INVALID_MAC_KEY_SIZE) ,"invalid mac key size"}, + {ERR_REASON(GOST_R_INVALID_MAC_SIZE) ,"invalid mac size"}, {ERR_REASON(GOST_R_INVALID_PARAMSET), "invalid paramset"}, {ERR_REASON(GOST_R_KEY_IS_NOT_INITALIZED), "key is not initalized"}, {ERR_REASON(GOST_R_KEY_IS_NOT_INITIALIZED), "key is not initialized"}, diff --git a/e_gost_err.h b/e_gost_err.h index 5e7e8e4..b2d9a4f 100644 --- a/e_gost_err.h +++ b/e_gost_err.h @@ -132,6 +132,8 @@ void ERR_GOST_error(int function, int reason, char *file, int line); # define GOST_R_INVALID_DIGEST_TYPE 110 # define GOST_R_INVALID_IV_LENGTH 111 # define GOST_R_INVALID_MAC_KEY_LENGTH 112 +# define GOST_R_INVALID_MAC_KEY_SIZE 145 +# define GOST_R_INVALID_MAC_SIZE 146 # define GOST_R_INVALID_PARAMSET 113 # define GOST_R_KEY_IS_NOT_INITALIZED 114 # define GOST_R_KEY_IS_NOT_INITIALIZED 115 diff --git a/gost_crypt.c b/gost_crypt.c index 668e881..d1e8113 100644 --- a/gost_crypt.c +++ b/gost_crypt.c @@ -22,6 +22,8 @@ static int gost_cipher_init(EVP_CIPHER_CTX *ctx, const unsigned char *key, const unsigned char *iv, int enc); +static int gost_cipher_init_cbc(EVP_CIPHER_CTX *ctx, const unsigned char *key, + const unsigned char *iv, int enc); static int gost_cipher_init_cpa(EVP_CIPHER_CTX *ctx, const unsigned char *key, const unsigned char *iv, int enc); static int gost_cipher_init_cp_12(EVP_CIPHER_CTX *ctx, @@ -30,6 +32,9 @@ static int gost_cipher_init_cp_12(EVP_CIPHER_CTX *ctx, /* Handles block of data in CFB mode */ static int gost_cipher_do_cfb(EVP_CIPHER_CTX *ctx, unsigned char *out, const unsigned char *in, size_t inl); +/* Handles block of data in CBC mode */ +static int gost_cipher_do_cbc(EVP_CIPHER_CTX *ctx, unsigned char *out, + const unsigned char *in, size_t inl); /* Handles block of data in CNT mode */ static int gost_cipher_do_cnt(EVP_CIPHER_CTX *ctx, unsigned char *out, const unsigned char *in, size_t inl); @@ -58,6 +63,24 @@ EVP_CIPHER cipher_gost = { NULL, }; +EVP_CIPHER cipher_gost_cbc = + { + NID_gost89_cbc, + 8,/*block_size*/ + 32,/*key_size*/ + 8,/*iv_len */ + EVP_CIPH_CBC_MODE| + EVP_CIPH_CUSTOM_IV| EVP_CIPH_RAND_KEY | EVP_CIPH_ALWAYS_CALL_INIT, + gost_cipher_init_cbc, + gost_cipher_do_cbc, + gost_cipher_cleanup, + sizeof(struct ossl_gost_cipher_ctx),/* ctx_size */ + gost89_set_asn1_parameters, + gost89_get_asn1_parameters, + gost_cipher_ctl, + NULL, + }; + EVP_CIPHER cipher_gost_cpacnt = { NID_gost89_cnt, 1, /* block_size */ @@ -277,6 +300,15 @@ int gost_cipher_init(EVP_CIPHER_CTX *ctx, const unsigned char *key, EVP_CIPH_CFB_MODE); } +/* Initializes EVP_CIPHER_CTX with default values */ +int gost_cipher_init_cbc(EVP_CIPHER_CTX *ctx, const unsigned char *key, + const unsigned char *iv, int enc) +{ + return gost_cipher_init_param(ctx, key, iv, enc, NID_undef, + EVP_CIPH_CBC_MODE); +} + + /* * Wrapper around gostcrypt function from gost89.c which perform key meshing * when nesseccary @@ -326,6 +358,47 @@ static void gost_cnt_next(void *ctx, unsigned char *iv, unsigned char *buf) c->count = c->count % 1024 + 8; } +/* GOST encryptoon in CBC mode */ +int gost_cipher_do_cbc(EVP_CIPHER_CTX *ctx, unsigned char *out, + const unsigned char *in, size_t inl) + { + OPENSSL_assert(inl % 8 ==0); + unsigned char b[8]; + const unsigned char *in_ptr=in; + unsigned char *out_ptr=out; + int i; + struct ossl_gost_cipher_ctx *c = ctx->cipher_data; + if (ctx->encrypt) + { + while(inl>0) + { + for (i=0;i<8;i++) + { + b[i]=ctx->iv[i]^in_ptr[i]; + } + gostcrypt(&(c->cctx),b,out_ptr); + memcpy(ctx->iv,out_ptr,8); + out_ptr+=8; + in_ptr+=8; + inl-=8; + } + } + else + { + while (inl>0) { + gostdecrypt(&(c->cctx),in_ptr,b); + for (i=0;i<8;i++) + { + out_ptr[i]=ctx->iv[i]^b[i]; + } + memcpy(ctx->iv,in_ptr,8); + out_ptr+=8; + in_ptr+=8; + inl-=8; + } + } + return 1; + } /* GOST encryption in CFB mode */ int gost_cipher_do_cfb(EVP_CIPHER_CTX *ctx, unsigned char *out, const unsigned char *in, size_t inl) @@ -594,6 +667,7 @@ static int gost_imit_init(EVP_MD_CTX *ctx, gost_subst_block * block) c->count = 0; c->bytes_left = 0; c->key_meshing = 1; + c->dgst_size = 4; gost_init(&(c->cctx), block); return 1; } @@ -676,7 +750,7 @@ int gost_imit_final(EVP_MD_CTX *ctx, unsigned char *md) } mac_block_mesh(c, c->partial_block); } - get_mac(c->buffer, 32, md); + get_mac(c->buffer, 8 * c->dgst_size, md); return 1; } @@ -689,7 +763,7 @@ int gost_imit_ctrl(EVP_MD_CTX *ctx, int type, int arg, void *ptr) case EVP_MD_CTRL_SET_KEY: { if (arg != 32) { - GOSTerr(GOST_F_GOST_IMIT_CTRL, GOST_R_INVALID_MAC_KEY_LENGTH); + GOSTerr(GOST_F_GOST_IMIT_CTRL, GOST_R_INVALID_MAC_KEY_SIZE); return 0; } @@ -699,6 +773,17 @@ int gost_imit_ctrl(EVP_MD_CTX *ctx, int type, int arg, void *ptr) return 1; } + case EVP_MD_CTRL_MAC_LEN: + { + if (arg < 1 || arg > 8) { + GOSTerr(GOST_F_GOST_IMIT_CTRL, GOST_R_INVALID_MAC_SIZE); + return 0; + } + struct ossl_gost_imit_ctx *c = ctx->md_data; + c->dgst_size=arg; + return 1; + } + default: return 0; } diff --git a/gost_eng.c b/gost_eng.c index 9df6a74..86d1a05 100644 --- a/gost_eng.c +++ b/gost_eng.c @@ -37,6 +37,7 @@ static int gost_cipher_nids[] = { NID_id_Gost28147_89, NID_gost89_cnt, NID_gost89_cnt_12, + NID_gost89_cbc, 0 }; @@ -186,6 +187,7 @@ static int bind_gost(ENGINE *e, const char *id) || !ENGINE_register_pkey_meths(e) /* These two actually should go in LIST_ADD command */ || !EVP_add_cipher(&cipher_gost) + || !EVP_add_cipher(&cipher_gost_cbc) || !EVP_add_cipher(&cipher_gost_cpacnt) || !EVP_add_cipher(&cipher_gost_cpcnt_12) || !EVP_add_digest(&digest_gost) @@ -238,7 +240,7 @@ static int gost_ciphers(ENGINE *e, const EVP_CIPHER **cipher, int ok = 1; if (!cipher) { *nids = gost_cipher_nids; - return 3; /* three ciphers are supported */ + return 4; /* three ciphers are supported */ } if (nid == NID_id_Gost28147_89) { @@ -247,6 +249,8 @@ static int gost_ciphers(ENGINE *e, const EVP_CIPHER **cipher, *cipher = &cipher_gost_cpacnt; } else if (nid == NID_gost89_cnt_12) { *cipher = &cipher_gost_cpcnt_12; + } else if (nid == NID_gost89_cbc) { + *cipher = &cipher_gost_cbc; } else { ok = 0; *cipher = NULL; diff --git a/gost_lcl.h b/gost_lcl.h index 4e1c4ea..b89c453 100644 --- a/gost_lcl.h +++ b/gost_lcl.h @@ -58,7 +58,9 @@ int register_pmeth_gost(int id, EVP_PKEY_METHOD **pmeth, int flags); /* For GOST 28147 MAC */ # define key_ctrl_string "key" # define hexkey_ctrl_string "hexkey" +# define maclen_ctrl_string "size" # define EVP_PKEY_CTRL_GOST_MAC_HEXKEY (EVP_PKEY_ALG_CTRL+3) +# define EVP_PKEY_CTRL_MAC_LEN (EVP_PKEY_ALG_CTRL+5) /* Pmeth internal representation */ struct gost_pmeth_data { int sign_param_nid; /* Should be set whenever parameters are @@ -69,7 +71,8 @@ struct gost_pmeth_data { }; struct gost_mac_pmeth_data { - int key_set; + short int key_set; + short int mac_size; EVP_MD *md; unsigned char key[32]; }; @@ -184,6 +187,7 @@ struct ossl_gost_imit_ctx { int key_meshing; int bytes_left; int key_set; + int dgst_size; }; /* Table which maps parameter NID to S-blocks */ extern struct gost_cipher_info gost_cipher_list[]; @@ -191,10 +195,12 @@ extern struct gost_cipher_info gost_cipher_list[]; const struct gost_cipher_info *get_encryption_params(ASN1_OBJECT *obj); /* Implementation of GOST 28147-89 cipher in CFB and CNT modes */ extern EVP_CIPHER cipher_gost; +extern EVP_CIPHER cipher_gost_cbc; extern EVP_CIPHER cipher_gost_cpacnt; extern EVP_CIPHER cipher_gost_cpcnt_12; # define EVP_MD_CTRL_KEY_LEN (EVP_MD_CTRL_ALG_CTRL+3) # define EVP_MD_CTRL_SET_KEY (EVP_MD_CTRL_ALG_CTRL+4) +# define EVP_MD_CTRL_MAC_LEN (EVP_MD_CTRL_ALG_CTRL+5) /* EVP_PKEY_METHOD key encryption callbacks */ /* From gost_ec_keyx.c */ int pkey_GOST_ECcp_encrypt(EVP_PKEY_CTX *ctx, unsigned char *out, diff --git a/gost_pmeth.c b/gost_pmeth.c index a825217..896dabb 100644 --- a/gost_pmeth.c +++ b/gost_pmeth.c @@ -470,6 +470,7 @@ static int pkey_gost_mac_init(EVP_PKEY_CTX *ctx) if (!data) return 0; memset(data, 0, sizeof(*data)); + data->mac_size = 4; EVP_PKEY_CTX_set_data(ctx, data); return 1; } @@ -553,6 +554,17 @@ static int pkey_gost_mac_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2) } return mctx->digest->md_ctrl(mctx, EVP_MD_CTRL_SET_KEY, 32, key); } + case EVP_PKEY_CTRL_MAC_LEN: + { + if (p1<1 || p1>8) + { + + GOSTerr(GOST_F_PKEY_GOST_MAC_CTRL,GOST_R_INVALID_MAC_SIZE); + return 0; + } + data->mac_size = p1; + return 1; + } } return -2; } @@ -584,6 +596,16 @@ static int pkey_gost_mac_ctrl_str(EVP_PKEY_CTX *ctx, return ret; } + if (!strcmp(type,maclen_ctrl_string)) { + char *endptr; + long size=strtol(value,&endptr,10); + if (*endptr!='\0') { + GOSTerr(GOST_F_PKEY_GOST_MAC_CTRL_STR, + GOST_R_INVALID_MAC_SIZE); + return 0; + } + return pkey_gost_mac_ctrl(ctx, EVP_PKEY_CTRL_MAC_LEN,size,NULL); + } return -2; } @@ -624,6 +646,7 @@ static int pkey_gost_mac_signctx(EVP_PKEY_CTX *ctx, unsigned char *sig, { unsigned int tmpsiglen; int ret; + struct gost_mac_pmeth_data *data = EVP_PKEY_CTX_get_data(ctx); if (!siglen) return 0; @@ -631,11 +654,13 @@ static int pkey_gost_mac_signctx(EVP_PKEY_CTX *ctx, unsigned char *sig, * sizeof(size_t) */ if (!sig) { - *siglen = 4; + *siglen = data->mac_size; return 1; } + + mctx->digest->md_ctrl(mctx, EVP_MD_CTRL_MAC_LEN, data->mac_size, NULL); ret = EVP_DigestFinal_ex(mctx, sig, &tmpsiglen); - *siglen = tmpsiglen; + *siglen = data->mac_size; return ret; }