#include <openssl/evp.h>
#include <openssl/rand.h>
#include <openssl/err.h>
+
#include <string.h>
#include "gost_lcl.h"
GRASSHOPPER_CIPHER_CTR,
GRASSHOPPER_CIPHER_CTRACPKM,
GRASSHOPPER_CIPHER_CTRACPKMOMAC,
+ GRASSHOPPER_CIPHER_MGM,
};
static GOST_cipher grasshopper_template_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 */
}
/* 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;
}
/* 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;
}
/* Cleans up key from context */
-GRASSHOPPER_INLINE void
+static GRASSHOPPER_INLINE void
gost_grasshopper_cipher_destroy(gost_grasshopper_cipher_ctx * c)
{
int i;
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)
{
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);
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);
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;
+
+ if (key) {
+ unsigned char cipher_key[32];
+ c->omac_ctx = EVP_MD_CTX_new();
- /* 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 (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;
+ }
- if (c->omac_ctx == NULL) {
- GOSTerr(GOST_F_GOST_GRASSHOPPER_CIPHER_INIT_CTRACPKM_OMAC, ERR_R_MALLOC_FAILURE);
- 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
+
+ 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_grasshopper_master_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);
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);
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);
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) {
/* 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);
in += GRASSHOPPER_BLOCK_SIZE;
out += GRASSHOPPER_BLOCK_SIZE;
num += GRASSHOPPER_BLOCK_SIZE;
- lasted -= GRASSHOPPER_BLOCK_SIZE;
+ lasted -= GRASSHOPPER_BLOCK_SIZE;
}
// last part
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.
*/
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);
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);
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);
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;
+ mctx->tlstree_mode = TLSTREE_MODE_NONE;
+ 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;
+
+ case EVP_CTRL_SET_TLSTREE_PARAMS:
+ if (strcmp((char *)ptr, "short") == 0)
+ mctx->tlstree_mode = TLSTREE_MODE_S;
+ else if (strcmp((char *)ptr, "long") == 0)
+ mctx->tlstree_mode = TLSTREE_MODE_L;
+ else {
+ // TODO: set err
+ return 0;
+ }
+ return 1;
+
+ case EVP_CTRL_TLSTREE:
+ {
+ unsigned char newkey[32];
+ if (gost_tlstree(NID_kuznyechik_mgm,
+ mctx->ks.gh_ks.master_key.k.b, newkey,
+ (const unsigned char *)ptr, mctx->tlstree_mode)
+ > 0) {
+ gost_grasshopper_cipher_key(&mctx->ks.gh_ks, newkey);
+ memset(newkey, 0, sizeof(newkey));
+ }
+ }
+ 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:{
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;
}
}
if (gost_tlstree(NID_grasshopper_cbc, c->master_key.k.b, newkey,
- (const unsigned char *)seq) > 0) {
+ (const unsigned char *)seq, TLSTREE_MODE_NONE) > 0) {
memset(adjusted_iv, 0, 16);
memcpy(adjusted_iv, EVP_CIPHER_CTX_original_iv(ctx), 8);
for(j=7,carry=0; j>=0; j--)
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);
}
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);