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
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 <passphrase>
Encryption with GOST 28147 CNT mode
openssl enc -gost89-cnt -out encrypted-file -in plain-text-file -k <passphrase>
-
+ Encryption with GOST 28147 CBC mode
+ openssl enc -gost89-cbc -out encrypted-file -in plain-text-file -k <passphrase>
6. Encrypting private keys and PKCS12
openssl speed -evp gost89
openssl speed -evp gost89-cnt
+ openssl speed -evp gost89-cbc
PROGRAMMING INTERFACES DETAILS
{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"},
# 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
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,
/* 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);
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 */
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
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)
c->count = 0;
c->bytes_left = 0;
c->key_meshing = 1;
+ c->dgst_size = 4;
gost_init(&(c->cctx), block);
return 1;
}
}
mac_block_mesh(c, c->partial_block);
}
- get_mac(c->buffer, 32, md);
+ get_mac(c->buffer, 8 * c->dgst_size, md);
return 1;
}
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;
}
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;
}
NID_id_Gost28147_89,
NID_gost89_cnt,
NID_gost89_cnt_12,
+ NID_gost89_cbc,
0
};
|| !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)
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) {
*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;
/* 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
};
struct gost_mac_pmeth_data {
- int key_set;
+ short int key_set;
+ short int mac_size;
EVP_MD *md;
unsigned char key[32];
};
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[];
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,
if (!data)
return 0;
memset(data, 0, sizeof(*data));
+ data->mac_size = 4;
EVP_PKEY_CTX_set_data(ctx, data);
return 1;
}
}
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;
}
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;
}
{
unsigned int tmpsiglen;
int ret;
+ struct gost_mac_pmeth_data *data = EVP_PKEY_CTX_get_data(ctx);
if (!siglen)
return 0;
* 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;
}