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
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),
- 8,
- 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),
- 8,
- 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 */
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);
}
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 keys[64];
+ const EVP_MD *md = EVP_get_digestbynid(NID_kuznyechik_mac);
+ EVP_PKEY *mac_key;
+
+ if (md == NULL)
+ return 0;
+
+ if (enc) {
+ if (RAND_bytes(c->kdf_seed, 8) != 1)
+ return 0;
+ }
+
+ if (gost_kdftree2012_256(keys, 64, key, 32, (const unsigned char *)"kdf tree", 8, c->kdf_seed, 8, 1) <= 0)
+ return 0;
+
+ c->omac_ctx = EVP_MD_CTX_new();
+ mac_key = EVP_PKEY_new_mac_key(NID_kuznyechik_mac, NULL, keys+32, 32);
+
+ if (mac_key == NULL || c->omac_ctx == NULL) {
+ EVP_PKEY_free(mac_key);
+ return 0;
+ }
+
+ if (EVP_DigestInit_ex(c->omac_ctx, md, NULL) <= 0 ||
+ EVP_DigestSignInit(c->omac_ctx, NULL, md, NULL, mac_key) <= 0) {
+ EVP_PKEY_free(mac_key);
+ return 0;
+ }
+ EVP_PKEY_free(mac_key);
+
+ return gost_grasshopper_cipher_init(ctx, keys, 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,
}
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);
+ }
+
+ 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.
*/
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;
+
return gost2015_set_asn1_params(params, EVP_CIPHER_CTX_original_iv(ctx), 8,
ctr->kdf_seed);
}
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 mesh_section_size */
+ /* CMS implies 256kb section_size */
ctr->section_size = 256*1024;
return 1;
}
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;
}
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:
+ {
+ gost_grasshopper_cipher_ctx_ctr *c = EVP_CIPHER_CTX_get_cipher_data(ctx);
+ ASN1_OBJECT *cmsmacobj = NULL;
+ if (c->c.type != GRASSHOPPER_CIPHER_CTRACPKMOMAC)
+ return -1;
+ cmsmacobj = OBJ_txt2obj(OID_GOST_CMS_MAC, 1);
+ if (cmsmacobj == NULL) {
+ GOSTerr(GOST_F_GOST_GRASSHOPPER_CIPHER_CTL, ERR_R_MALLOC_FAILURE);
+ return -1;
+ }
+ if (arg == 0) /*Decrypting*/ {
+ STACK_OF(X509_ATTRIBUTE) *x = ptr;
+ ASN1_OCTET_STRING *osExpectedMac = X509at_get0_data_by_OBJ(x,
+ cmsmacobj, -3, V_ASN1_OCTET_STRING);
+ ASN1_OBJECT_free(cmsmacobj);
+
+ if (ptr == NULL || osExpectedMac ==NULL || osExpectedMac->length != KUZNYECHIK_MAC_MAX_SIZE)
+ return -1;
+
+ memcpy(c->tag, osExpectedMac->data, osExpectedMac->length);
+ return 1;
+ } else {
+ STACK_OF(X509_ATTRIBUTE) *x = ptr;
+ return (X509at_add1_attr_by_OBJ(&x, cmsmacobj,
+ V_ASN1_OCTET_STRING, c->tag, KUZNYECHIK_MAC_MAX_SIZE) == NULL) ? -1 : 1;
+ }
+ }
+ 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);
}
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)
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];
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);
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]);
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;
}