]> www.wagner.pp.ru Git - openssl-gost/engine.git/commitdiff
initial unified impl magma/kuznetchik MGM mode
authorigrkir <i.kirillov@kryptonite.ru>
Fri, 4 Jun 2021 11:20:59 +0000 (14:20 +0300)
committerDmitry Belyavskiy <beldmit@users.noreply.github.com>
Tue, 8 Jun 2021 11:28:18 +0000 (14:28 +0300)
without any speedup math calculation

e_gost_err.c
e_gost_err.h
gost.txt
gost_crypt.c
gost_eng.c
gost_gost2015.c
gost_gost2015.h
gost_grasshopper_cipher.c
gost_grasshopper_cipher.h
gost_lcl.h

index 9b3c2d54411ea79b9b128a2b989cfc12347dd0e3..4396e002f97607ab0b3625a1ddc2ff9e4c35c35c 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Generated by util/mkerr.pl DO NOT EDIT
- * Copyright 1995-2020 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved.
  *
  * Licensed under the OpenSSL license (the "License").  You may not use
  * this file except in compliance with the License.  You can obtain a copy
@@ -44,8 +44,14 @@ static ERR_STRING_DATA GOST_str_functs[] = {
      "gost_grasshopper_cipher_ctl"},
     {ERR_PACK(0, GOST_F_GOST_GRASSHOPPER_CIPHER_DO_CTRACPKM_OMAC, 0),
      "gost_grasshopper_cipher_do_ctracpkm_omac"},
+    {ERR_PACK(0, GOST_F_GOST_GRASSHOPPER_CIPHER_DO_MGM, 0),
+     "gost_grasshopper_cipher_do_mgm"},
+    {ERR_PACK(0, GOST_F_GOST_GRASSHOPPER_CIPHER_INIT, 0),
+     "gost_grasshopper_cipher_init"},
     {ERR_PACK(0, GOST_F_GOST_GRASSHOPPER_CIPHER_INIT_CTRACPKM_OMAC, 0),
      "gost_grasshopper_cipher_init_ctracpkm_omac"},
+    {ERR_PACK(0, GOST_F_GOST_GRASSHOPPER_MGM_CTRL, 0),
+     "gost_grasshopper_mgm_ctrl"},
     {ERR_PACK(0, GOST_F_GOST_GRASSHOPPER_SET_ASN1_PARAMETERS, 0),
      "gost_grasshopper_set_asn1_parameters"},
     {ERR_PACK(0, GOST_F_GOST_IMIT_CTRL, 0), "gost_imit_ctrl"},
@@ -54,6 +60,12 @@ static ERR_STRING_DATA GOST_str_functs[] = {
     {ERR_PACK(0, GOST_F_GOST_KDFTREE2012_256, 0), "gost_kdftree2012_256"},
     {ERR_PACK(0, GOST_F_GOST_KEXP15, 0), "gost_kexp15"},
     {ERR_PACK(0, GOST_F_GOST_KIMP15, 0), "gost_kimp15"},
+    {ERR_PACK(0, GOST_F_GOST_MAGMA_CIPHER_DO_MGM, 0),
+     "gost_magma_cipher_do_mgm"},
+    {ERR_PACK(0, GOST_F_GOST_MAGMA_MGM_CTRL, 0), "gost_magma_mgm_ctrl"},
+    {ERR_PACK(0, GOST_F_GOST_MGM128_AAD, 0), "gost_mgm128_aad"},
+    {ERR_PACK(0, GOST_F_GOST_MGM128_DECRYPT, 0), "gost_mgm128_decrypt"},
+    {ERR_PACK(0, GOST_F_GOST_MGM128_ENCRYPT, 0), "gost_mgm128_encrypt"},
     {ERR_PACK(0, GOST_F_MAGMA_CIPHER_CTL, 0), "magma_cipher_ctl"},
     {ERR_PACK(0, GOST_F_MAGMA_CIPHER_CTL_ACPKM_OMAC, 0),
      "magma_cipher_ctl_acpkm_omac"},
@@ -118,6 +130,7 @@ static ERR_STRING_DATA GOST_str_reasons[] = {
     "cannot unpack ephemeral key"},
     {ERR_PACK(0, 0, GOST_R_CIPHER_NOT_FOUND), "cipher not found"},
     {ERR_PACK(0, 0, GOST_R_CTRL_CALL_FAILED), "ctrl call failed"},
+    {ERR_PACK(0, 0, GOST_R_DATA_TOO_LARGE), "data too large"},
     {ERR_PACK(0, 0, GOST_R_ERROR_COMPUTING_EXPORT_KEYS),
     "error computing export keys"},
     {ERR_PACK(0, 0, GOST_R_ERROR_COMPUTING_SHARED_KEY),
@@ -141,6 +154,7 @@ static ERR_STRING_DATA GOST_str_reasons[] = {
     {ERR_PACK(0, 0, GOST_R_INVALID_MAC_PARAMS), "invalid mac params"},
     {ERR_PACK(0, 0, GOST_R_INVALID_MAC_SIZE), "invalid mac size"},
     {ERR_PACK(0, 0, GOST_R_INVALID_PARAMSET), "invalid paramset"},
+    {ERR_PACK(0, 0, GOST_R_INVALID_TAG_LENGTH), "invalid tag length"},
     {ERR_PACK(0, 0, GOST_R_KEY_IS_NOT_INITIALIZED), "key is not initialized"},
     {ERR_PACK(0, 0, GOST_R_KEY_PARAMETERS_MISSING), "key parameters missing"},
     {ERR_PACK(0, 0, GOST_R_MAC_KEY_NOT_SET), "mac key not set"},
index d69534f5ad0df2eb8c42d1f5ee0c1948867dfaa6..018e4a42de4889dc879442adf97b61b60bf0ed41 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Generated by util/mkerr.pl DO NOT EDIT
- * Copyright 1995-2020 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved.
  *
  * Licensed under the OpenSSL license (the "License").  You may not use
  * this file except in compliance with the License.  You can obtain a copy
@@ -48,7 +48,10 @@ void ERR_GOST_error(int function, int reason, char *file, int line);
 # define GOST_F_GOST_ENCODE_CMS_PARAMS                    161
 # define GOST_F_GOST_GRASSHOPPER_CIPHER_CTL               111
 # define GOST_F_GOST_GRASSHOPPER_CIPHER_DO_CTRACPKM_OMAC  160
+# define GOST_F_GOST_GRASSHOPPER_CIPHER_DO_MGM            166
+# define GOST_F_GOST_GRASSHOPPER_CIPHER_INIT              167
 # define GOST_F_GOST_GRASSHOPPER_CIPHER_INIT_CTRACPKM_OMAC 162
+# define GOST_F_GOST_GRASSHOPPER_MGM_CTRL                 168
 # define GOST_F_GOST_GRASSHOPPER_SET_ASN1_PARAMETERS      112
 # define GOST_F_GOST_IMIT_CTRL                            113
 # define GOST_F_GOST_IMIT_FINAL                           114
@@ -56,6 +59,11 @@ void ERR_GOST_error(int function, int reason, char *file, int line);
 # define GOST_F_GOST_KDFTREE2012_256                      149
 # define GOST_F_GOST_KEXP15                               143
 # define GOST_F_GOST_KIMP15                               148
+# define GOST_F_GOST_MAGMA_CIPHER_DO_MGM                  170
+# define GOST_F_GOST_MAGMA_MGM_CTRL                       169
+# define GOST_F_GOST_MGM128_AAD                           171
+# define GOST_F_GOST_MGM128_DECRYPT                       172
+# define GOST_F_GOST_MGM128_ENCRYPT                       173
 # define GOST_F_MAGMA_CIPHER_CTL                          163
 # define GOST_F_MAGMA_CIPHER_CTL_ACPKM_OMAC               164
 # define GOST_F_MAGMA_CIPHER_INIT_CTR_ACPKM_OMAC          165
@@ -107,6 +115,7 @@ void ERR_GOST_error(int function, int reason, char *file, int line);
 # define GOST_R_CANNOT_UNPACK_EPHEMERAL_KEY               136
 # define GOST_R_CIPHER_NOT_FOUND                          103
 # define GOST_R_CTRL_CALL_FAILED                          104
+# define GOST_R_DATA_TOO_LARGE                            141
 # define GOST_R_ERROR_COMPUTING_EXPORT_KEYS               135
 # define GOST_R_ERROR_COMPUTING_SHARED_KEY                105
 # define GOST_R_ERROR_DECODING_PUBLIC_KEY                 138
@@ -125,6 +134,7 @@ void ERR_GOST_error(int function, int reason, char *file, int line);
 # define GOST_R_INVALID_MAC_PARAMS                        116
 # define GOST_R_INVALID_MAC_SIZE                          117
 # define GOST_R_INVALID_PARAMSET                          118
+# define GOST_R_INVALID_TAG_LENGTH                        140
 # define GOST_R_KEY_IS_NOT_INITIALIZED                    119
 # define GOST_R_KEY_PARAMETERS_MISSING                    120
 # define GOST_R_MAC_KEY_NOT_SET                           121
index 1ee757d330ebbfd866d0d0c9c3c41e64241b7e42..4a357c87df8f65556b4d7d06df50047da660e9dd 100644 (file)
--- a/gost.txt
+++ b/gost.txt
@@ -1,4 +1,4 @@
-# Copyright 1999-2020 The OpenSSL Project Authors. All Rights Reserved.
+# Copyright 1999-2021 The OpenSSL Project Authors. All Rights Reserved.
 #
 # Licensed under the OpenSSL license (the "License").  You may not use
 # this file except in compliance with the License.  You can obtain a copy
@@ -22,9 +22,15 @@ GOST_F_GOST_EC_COMPUTE_PUBLIC:107:gost_ec_compute_public
 GOST_F_GOST_EC_KEYGEN:108:gost_ec_keygen
 GOST_F_GOST_EC_SIGN:109:gost_ec_sign
 GOST_F_GOST_EC_VERIFY:110:gost_ec_verify
+GOST_F_GOST_ENCODE_CMS_PARAMS:161:gost_encode_cms_params
 GOST_F_GOST_GRASSHOPPER_CIPHER_CTL:111:gost_grasshopper_cipher_ctl
 GOST_F_GOST_GRASSHOPPER_CIPHER_DO_CTRACPKM_OMAC:160:\
        gost_grasshopper_cipher_do_ctracpkm_omac
+GOST_F_GOST_GRASSHOPPER_CIPHER_DO_MGM:166:gost_grasshopper_cipher_do_mgm
+GOST_F_GOST_GRASSHOPPER_CIPHER_INIT:167:gost_grasshopper_cipher_init
+GOST_F_GOST_GRASSHOPPER_CIPHER_INIT_CTRACPKM_OMAC:162:\
+       gost_grasshopper_cipher_init_ctracpkm_omac
+GOST_F_GOST_GRASSHOPPER_MGM_CTRL:168:gost_grasshopper_mgm_ctrl
 GOST_F_GOST_GRASSHOPPER_SET_ASN1_PARAMETERS:112:\
        gost_grasshopper_set_asn1_parameters
 GOST_F_GOST_IMIT_CTRL:113:gost_imit_ctrl
@@ -33,6 +39,14 @@ GOST_F_GOST_IMIT_UPDATE:115:gost_imit_update
 GOST_F_GOST_KDFTREE2012_256:149:gost_kdftree2012_256
 GOST_F_GOST_KEXP15:143:gost_kexp15
 GOST_F_GOST_KIMP15:148:gost_kimp15
+GOST_F_GOST_MAGMA_CIPHER_DO_MGM:170:gost_magma_cipher_do_mgm
+GOST_F_GOST_MAGMA_MGM_CTRL:169:gost_magma_mgm_ctrl
+GOST_F_GOST_MGM128_AAD:171:gost_mgm128_aad
+GOST_F_GOST_MGM128_DECRYPT:172:gost_mgm128_decrypt
+GOST_F_GOST_MGM128_ENCRYPT:173:gost_mgm128_encrypt
+GOST_F_MAGMA_CIPHER_CTL:163:magma_cipher_ctl
+GOST_F_MAGMA_CIPHER_CTL_ACPKM_OMAC:164:magma_cipher_ctl_acpkm_omac
+GOST_F_MAGMA_CIPHER_INIT_CTR_ACPKM_OMAC:165:magma_cipher_init_ctr_acpkm_omac
 GOST_F_OMAC_ACPKM_IMIT_CTRL:144:omac_acpkm_imit_ctrl
 GOST_F_OMAC_ACPKM_IMIT_FINAL:145:omac_acpkm_imit_final
 GOST_F_OMAC_ACPKM_IMIT_UPDATE:146:omac_acpkm_imit_update
@@ -80,6 +94,7 @@ GOST_R_CANNOT_PACK_EPHEMERAL_KEY:102:cannot pack ephemeral key
 GOST_R_CANNOT_UNPACK_EPHEMERAL_KEY:136:cannot unpack ephemeral key
 GOST_R_CIPHER_NOT_FOUND:103:cipher not found
 GOST_R_CTRL_CALL_FAILED:104:ctrl call failed
+GOST_R_DATA_TOO_LARGE:141:data too large
 GOST_R_ERROR_COMPUTING_EXPORT_KEYS:135:error computing export keys
 GOST_R_ERROR_COMPUTING_SHARED_KEY:105:error computing shared key
 GOST_R_ERROR_DECODING_PUBLIC_KEY:138:error decoding public key
@@ -98,6 +113,7 @@ GOST_R_INVALID_MAC_KEY_SIZE:115:invalid mac key size
 GOST_R_INVALID_MAC_PARAMS:116:invalid mac params
 GOST_R_INVALID_MAC_SIZE:117:invalid mac size
 GOST_R_INVALID_PARAMSET:118:invalid paramset
+GOST_R_INVALID_TAG_LENGTH:140:invalid tag length
 GOST_R_KEY_IS_NOT_INITIALIZED:119:key is not initialized
 GOST_R_KEY_PARAMETERS_MISSING:120:key parameters missing
 GOST_R_MAC_KEY_NOT_SET:121:mac key not set
index d70d79306756320cb57971e93ee7c13c82e2c671..a6d5d37ebb42731fd9ffd631dbbd37dd165e94d6 100644 (file)
@@ -43,6 +43,7 @@ static int gost_cipher_do_cnt(EVP_CIPHER_CTX *ctx, unsigned char *out,
                               const unsigned char *in, size_t inl);
 /* Cleanup function */
 static int gost_cipher_cleanup(EVP_CIPHER_CTX *);
+static int gost_magma_mgm_cleanup(EVP_CIPHER_CTX *c);
 /* set/get cipher parameters */
 static int gost89_set_asn1_parameters(EVP_CIPHER_CTX *ctx, ASN1_TYPE *params);
 static int gost89_get_asn1_parameters(EVP_CIPHER_CTX *ctx, ASN1_TYPE *params);
@@ -53,6 +54,8 @@ static int magma_cipher_init(EVP_CIPHER_CTX *ctx, const unsigned char *key,
                              const unsigned char *iv, int enc);
 static int magma_cipher_init_ctr_acpkm_omac(EVP_CIPHER_CTX *ctx, const unsigned char *key,
                              const unsigned char *iv, int enc);
+static int gost_magma_cipher_init_mgm(EVP_CIPHER_CTX *ctx, const unsigned char *key,
+                                 const unsigned char *iv, int enc);
 /* Handles block of data in CBC mode */
 static int magma_cipher_do_cbc(EVP_CIPHER_CTX *ctx, unsigned char *out,
                                const unsigned char *in, size_t inl);
@@ -61,13 +64,15 @@ static int magma_cipher_do_ctr(EVP_CIPHER_CTX *ctx, unsigned char *out,
 
 static int magma_cipher_do_ctr_acpkm_omac(EVP_CIPHER_CTX *ctx, unsigned char *out,
                                const unsigned char *in, size_t inl);
-
+static int gost_magma_cipher_do_mgm(EVP_CIPHER_CTX *ctx, unsigned char *out,
+                                   const unsigned char *in, size_t len);
 /* set/get cipher parameters */
 static int magma_set_asn1_parameters(EVP_CIPHER_CTX *ctx, ASN1_TYPE *params);
 static int magma_get_asn1_parameters(EVP_CIPHER_CTX *ctx, ASN1_TYPE *params);
 /* Control function */
 static int magma_cipher_ctl(EVP_CIPHER_CTX *ctx, int type, int arg, void *ptr);
 static int magma_cipher_ctl_acpkm_omac(EVP_CIPHER_CTX *ctx, int type, int arg, void *ptr);
+static int gost_magma_mgm_ctrl(EVP_CIPHER_CTX *c, int type, int arg, void *ptr);
 
 /*
  * Single level template accessor.
@@ -90,15 +95,15 @@ EVP_CIPHER *GOST_init_cipher(GOST_cipher *c)
     int flags = c->flags | TPL_VAL(c, flags);
     int block_size = TPL(c, block_size);
     switch (flags & EVP_CIPH_MODE) {
-    case EVP_CIPH_CTR_MODE:
-    case EVP_CIPH_CFB_MODE:
-    case EVP_CIPH_OFB_MODE:
-        OPENSSL_assert(block_size == 1);
-        OPENSSL_assert(flags & EVP_CIPH_NO_PADDING);
-        break;
-    default:
+    case EVP_CIPH_CBC_MODE:
+    case EVP_CIPH_ECB_MODE:
+    case EVP_CIPH_WRAP_MODE:
         OPENSSL_assert(block_size != 1);
         OPENSSL_assert(!(flags & EVP_CIPH_NO_PADDING));
+        break;
+    default:
+        OPENSSL_assert(block_size == 1);
+        OPENSSL_assert(flags & EVP_CIPH_NO_PADDING);
     }
 
     if (TPL(c, iv_len))
@@ -234,6 +239,21 @@ GOST_cipher magma_ctr_acpkm_omac_cipher = {
     .ctrl = magma_cipher_ctl_acpkm_omac,
 };
 
+ GOST_cipher magma_mgm_cipher = {
+    .nid = NID_magma_mgm,
+    .template = &magma_template_cipher,
+    .block_size = 1,
+    .iv_len = 8,
+    .flags = EVP_CIPH_NO_PADDING |
+        EVP_CIPH_CUSTOM_IV | EVP_CIPH_FLAG_CUSTOM_CIPHER | 
+        EVP_CIPH_CTRL_INIT | EVP_CIPH_FLAG_AEAD_CIPHER,
+    .init = gost_magma_cipher_init_mgm,
+    .do_cipher = gost_magma_cipher_do_mgm,
+    .ctrl = gost_magma_mgm_ctrl,
+    .cleanup = gost_magma_mgm_cleanup,
+    .ctx_size = sizeof(gost_mgm_ctx)
+ };
+
 GOST_cipher magma_cbc_cipher = {
     .nid = NID_magma_cbc,
     .template = &gost_template_cipher,
@@ -502,6 +522,110 @@ static int magma_cipher_init_ctr_acpkm_omac(EVP_CIPHER_CTX *ctx, const unsigned
        return magma_cipher_init(ctx, key, iv, enc);
 }
 
+void gost_magma_encrypt_wrap(unsigned char *in, unsigned char *out,
+                   struct ossl_gost_cipher_ctx *c) {
+    int i;
+    unsigned char b[8];
+    unsigned char d[8];
+    for (i = 0; i < 8; i++) {
+        b[7 - i] = in[i];
+    }
+    gostcrypt(&(c->cctx), b, d);
+    for (i = 0; i < 8; i++) {
+        out[7 - i] = d[i];
+    }
+}
+
+/* ----------------------------------------------------------------------------------------------- */
+/*! Функция реализует операцию умножения двух элементов конечного поля \f$ \mathbb F_{2^{64}}\f$,
+    порожденного неприводимым многочленом
+    \f$ f(x) = x^{64} + x^4 + x^3 + x + 1 \in \mathbb F_2[x]\f$. Для умножения используется
+    простейшая реализация, основанная на приведении по модулю после каждого шага алгоритма.        */
+/* ----------------------------------------------------------------------------------------------- */
+static void gf64_mul (uint64_t *result, uint64_t *arg1, uint64_t *arg2)
+{
+       int i = 0;
+       register uint64_t t, X0;
+       uint64_t Z0 = 0;
+#ifdef L_ENDIAN
+       X0 = BSWAP64(*arg1);
+#else
+       X0 = *arg1;
+#endif
+
+#ifdef L_ENDIAN
+       t = BSWAP64(*(arg2));
+#else
+       t = *(arg2);
+#endif
+
+       for (i = 0; i < 63; i++) {
+               if (t & 0x1) {
+                       Z0 ^= X0;
+               }
+               t >>= 1;
+               if (X0 & 0x8000000000000000) {
+                       X0 <<= 1;
+                       X0 ^= 0x1b;
+               }
+               else {
+                       X0 <<= 1;
+               }
+       }
+
+       if (t & 0x1) {
+               Z0 ^= X0;
+       }
+
+#ifdef L_ENDIAN
+       *(result) = BSWAP64(Z0);
+#else
+       *(result) = Z0;
+#endif
+}
+
+static int gost_magma_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);
+        if (!gost_cipher_set_param(&mctx->ks.g_ks, NID_id_tc26_gost_28147_param_Z))
+            return 0;
+        magma_key(&(mctx->ks.g_ks.cctx), key);
+        gost_mgm128_init(&mctx->mgm, &mctx->ks, 
+                         (block128_f) gost_magma_encrypt_wrap, gf64_mul, 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;
+}
+
 /*
  * Wrapper around gostcrypt function from gost89.c which perform key meshing
  * when nesseccary
@@ -736,6 +860,58 @@ static int magma_cipher_do_ctr_acpkm_omac(EVP_CIPHER_CTX *ctx, unsigned char *ou
 
        return inl;
 }
+
+static int gost_magma_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_MAGMA_CIPHER_DO_MGM,
+                GOST_R_BAD_ORDER);
+        return -1;
+    }
+
+    if (!mctx->iv_set) {
+        GOSTerr(GOST_F_GOST_MAGMA_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), 8);
+        mctx->taglen = 8;
+        /* Don't reuse the IV */
+        mctx->iv_set = 0;
+        return 0;
+    }
+
+}
+
 /* GOST encryption in CFB mode */
 static int gost_cipher_do_cfb(EVP_CIPHER_CTX *ctx, unsigned char *out,
                        const unsigned char *in, size_t inl)
@@ -865,6 +1041,78 @@ static int gost_cipher_cleanup(EVP_CIPHER_CTX *ctx)
     return 1;
 }
 
+static int gost_magma_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_destroy(&mctx->ks.g_ks.cctx);
+    OPENSSL_cleanse(&mctx->mgm, sizeof(mctx->mgm));
+    EVP_CIPHER_CTX_set_app_data(c, NULL);
+    return 1;
+}
+
+static int gost_magma_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;
+        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 != 8 || enc) {
+            GOSTerr(GOST_F_GOST_MAGMA_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 > 8 || !enc || mctx->taglen < 0) {
+            GOSTerr(GOST_F_GOST_MAGMA_MGM_CTRL,
+                    GOST_R_INVALID_TAG_LENGTH);
+            return 0;
+        }
+        memcpy(ptr, buf, arg);
+        return 1;
+
+    default:
+        return -1;
+    }
+}
+
 /* Control function for gost cipher */
 static int gost_cipher_ctl(EVP_CIPHER_CTX *ctx, int type, int arg, void *ptr)
 {
@@ -955,7 +1203,7 @@ static int magma_cipher_ctl(EVP_CIPHER_CTX *ctx, int type, int arg, void *ptr)
     case EVP_CTRL_RAND_KEY:
             if (RAND_priv_bytes
                 ((unsigned char *)ptr, EVP_CIPHER_CTX_key_length(ctx)) <= 0) {
-                GOSTerr(GOST_F_GOST_CIPHER_CTL, GOST_R_RNG_ERROR);
+                GOSTerr(GOST_F_MAGMA_CIPHER_CTL, GOST_R_RNG_ERROR);
                 return -1;
             }
             break;
index 3fbe2e83d5b90cd6478b132e27daf7a3161212c6..d03e813948e78fe78f1927763f5debf1f10c9aab 100644 (file)
@@ -75,10 +75,12 @@ GOST_cipher *gost_cipher_array[] = {
     &grasshopper_cfb_cipher,
     &grasshopper_ofb_cipher,
     &grasshopper_ctr_cipher,
+    &grasshopper_mgm_cipher,
     &magma_cbc_cipher,
     &magma_ctr_cipher,
     &magma_ctr_acpkm_cipher,
     &magma_ctr_acpkm_omac_cipher,
+    &magma_mgm_cipher,
     &grasshopper_ctr_acpkm_cipher,
     &grasshopper_ctr_acpkm_omac_cipher,
     &magma_kexp15_cipher,
index 1ffa4281a234bf4fa858468ffd3aa71d78a1ae3d..da5b795219bcd18e2eb6e0880d6f4df6df2aa1d8 100644 (file)
@@ -6,6 +6,8 @@
  */
 #include "gost_lcl.h"
 #include "gost_gost2015.h"
+#include "gost_grasshopper_defines.h"
+#include "gost_grasshopper_math.h"
 #include "e_gost_err.h"
 #include <string.h>
 #include <openssl/rand.h>
@@ -201,3 +203,282 @@ int init_zero_kdf_seed(unsigned char *kdf_seed)
 
     return is_zero_kdfseed ? RAND_bytes(kdf_seed, 8) : 1;
 }
+
+void gost_mgm128_init(mgm128_context *ctx, void *key, block128_f block, mul128_f mul_gf, int blen)
+{
+    memset(ctx, 0, sizeof(*ctx));
+    ctx->block = block;
+    ctx->mul_gf = mul_gf;
+    ctx->key = key;
+    ctx->blocklen = blen;
+
+    /* some precalculations place here
+     *
+     */
+}
+
+int gost_mgm128_setiv(mgm128_context *ctx, const unsigned char *iv,
+                         size_t len)
+{
+    ctx->len.u[0] = 0;          /* AAD length */
+    ctx->len.u[1] = 0;          /* message length */
+    ctx->ares = 0;
+    ctx->mres = 0;
+
+    ctx->ACi.u[0] = 0;
+    ctx->ACi.u[1] = 0;
+
+    memcpy(ctx->nonce.c, iv, ctx->blocklen);
+    ctx->nonce.c[0] &= 0x7f;    /* IV - random vector, but 1st bit should be 0 */
+    return 1;
+}
+
+int gost_mgm128_aad(mgm128_context *ctx, const unsigned char *aad,
+                      size_t len)
+{
+    size_t i;
+    unsigned int n;
+    uint64_t alen = ctx->len.u[0];
+    block128_f block = ctx->block;
+    mul128_f mul_gf = ctx->mul_gf;
+    void *key = ctx->key;
+    int bl = ctx->blocklen;
+
+    if (ctx->len.u[1]) {
+        GOSTerr(GOST_F_GOST_MGM128_AAD,
+                GOST_R_BAD_ORDER);
+        return -2;
+    }
+
+    if (alen == 0) {
+        ctx->nonce.c[0] |= 0x80;
+        (*block) (ctx->nonce.c, ctx->Zi.c, key);    // Z_1 = E_K(1 || nonce)
+    }
+    
+    alen += len;
+    if (alen > (U64(1) << (bl * 4 - 3)) ||      // < 2^(n/2)  (len stores in bytes)
+        (sizeof(len) == 8 && alen < len)) {
+            GOSTerr(GOST_F_GOST_MGM128_AAD,
+                    GOST_R_DATA_TOO_LARGE);
+            return -1;
+        }
+    ctx->len.u[0] = alen;
+
+    n = ctx->ares;
+    if (n) {
+        /* Finalize partial_data */
+        while (n && len) {
+            ctx->ACi.c[n] = *(aad++);
+            --len;
+            n = (n + 1) % bl;
+        }
+        if (n == 0) {
+            (*block) (ctx->Zi.c, ctx->Hi.c, key);                   // H_i = E_K(Z_i)
+            mul_gf(ctx->mul.u, ctx->Hi.u, ctx->ACi.u);              // H_i (x) A_i
+            grasshopper_plus128((grasshopper_w128_t*)ctx->sum.u,    // acc XOR
+              (grasshopper_w128_t*)ctx->sum.u, (grasshopper_w128_t*)ctx->mul.u);
+            inc_counter(ctx->Zi.c, bl / 2);                              // Z_{i+1} = incr_l(Z_i)
+        } else {
+            ctx->ares = n;
+            return 0;
+        }
+    }
+    while (len >= bl) {
+        (*block) (ctx->Zi.c, ctx->Hi.c, key);                       // H_i = E_K(Z_i)
+        mul_gf(ctx->mul.u, ctx->Hi.u, (uint64_t *)aad);             // H_i (x) A_i
+        grasshopper_plus128((grasshopper_w128_t*)ctx->sum.u,        // acc XOR
+            (grasshopper_w128_t*)ctx->sum.u, (grasshopper_w128_t*)ctx->mul.u);
+        inc_counter(ctx->Zi.c, bl / 2);                                  // Z_{i+1} = incr_l(Z_i)
+        aad += bl;
+        len -= bl;
+    }
+    if (len) {
+        n = (unsigned int)len;
+        for (i = 0; i < len; ++i)
+            ctx->ACi.c[i] = aad[i];
+    }
+
+    ctx->ares = n;
+    return 0;
+}
+
+int gost_mgm128_encrypt(mgm128_context *ctx, const unsigned char *in, 
+                          unsigned char *out, size_t len)
+{
+    size_t i;
+    unsigned int n, mres;
+    uint64_t alen = ctx->len.u[0];
+    uint64_t mlen = ctx->len.u[1];
+    block128_f block = ctx->block;
+    mul128_f mul_gf = ctx->mul_gf;
+    void *key = ctx->key;
+    int bl = ctx->blocklen;
+
+    if (mlen == 0) {
+        ctx->nonce.c[0] &= 0x7f;
+        (*block) (ctx->nonce.c, ctx->Yi.c, key);    // Y_1 = E_K(0 || nonce)
+    }
+
+    mlen += len;
+    
+    if (mlen > (U64(1) << (bl * 4 - 3)) ||     // < 2^(n/2)  (len stores in bytes)
+        (sizeof(len) == 8 && mlen < len) ||
+        (mlen + alen) > (U64(1) << (bl * 4 - 3))) {
+            GOSTerr(GOST_F_GOST_MGM128_ENCRYPT,
+                    GOST_R_DATA_TOO_LARGE);
+            return -1;
+        }
+    ctx->len.u[1] = mlen;
+
+    mres = ctx->mres;
+
+    if (ctx->ares) {
+        /* First call to encrypt finalizes AAD */
+        memset(ctx->ACi.c + ctx->ares, 0, bl - ctx->ares);
+        (*block) (ctx->Zi.c, ctx->Hi.c, key);                   // H_i = E_K(Z_i)
+        mul_gf(ctx->mul.u, ctx->Hi.u, ctx->ACi.u);              // H_i (x) A_i
+        grasshopper_plus128((grasshopper_w128_t*)ctx->sum.u,    // acc XOR
+            (grasshopper_w128_t*)ctx->sum.u, (grasshopper_w128_t*)ctx->mul.u);
+        inc_counter(ctx->Zi.c, bl / 2);                         // Z_{i+1} = incr_l(Z_i)
+
+        ctx->ares = 0;
+    }
+
+    n = mres % bl;
+    // TODO: full blocks
+    for (i = 0; i < len; ++i) {
+        if (n == 0) {
+            (*block) (ctx->Yi.c, ctx->EKi.c, key);          // E_K(Y_i)
+            inc_counter(ctx->Yi.c + bl / 2, bl / 2);        // Y_i = incr_r(Y_{i-1})
+        }
+        ctx->ACi.c[n] = out[i] = in[i] ^ ctx->EKi.c[n];     // C_i = P_i (xor) E_K(Y_i)
+        mres = n = (n + 1) % bl;
+        if (n == 0) {
+            (*block) (ctx->Zi.c, ctx->Hi.c, key);                   // H_i = E_K(Z_i)
+            mul_gf(ctx->mul.u, ctx->Hi.u, ctx->ACi.u);              // H_i (x) C_i
+            grasshopper_plus128((grasshopper_w128_t*)ctx->sum.u,    // acc XOR
+                (grasshopper_w128_t*)ctx->sum.u, (grasshopper_w128_t*)ctx->mul.u);
+            inc_counter(ctx->Zi.c, bl / 2);                         // Z_{i+1} = incr_l(Z_i)
+        }
+    }
+
+    ctx->mres = mres;
+    return 0;  
+}
+
+int gost_mgm128_decrypt(mgm128_context *ctx, const unsigned char *in, 
+                          unsigned char *out, size_t len)
+{
+    size_t i;
+    unsigned int n, mres;
+    uint64_t alen = ctx->len.u[0];
+    uint64_t mlen = ctx->len.u[1];
+    block128_f block = ctx->block;
+    mul128_f mul_gf = ctx->mul_gf;
+    void *key = ctx->key;
+    int bl = ctx->blocklen;
+
+    if (mlen == 0) {
+        ctx->nonce.c[0] &= 0x7f;
+        (*block) (ctx->nonce.c, ctx->Yi.c, key);  // Y_1 = E_K(0 || nonce)
+    }
+
+    mlen += len;
+    if (mlen > (U64(1) << (bl * 4 - 3)) ||     // < 2^(n/2)  (len stores in bytes)
+        (sizeof(len) == 8 && mlen < len) ||
+        (mlen + alen) > (U64(1) << (bl * 4 - 3))) {
+            GOSTerr(GOST_F_GOST_MGM128_DECRYPT,
+                    GOST_R_DATA_TOO_LARGE);
+            return -1;
+        }
+    ctx->len.u[1] = mlen;
+
+    mres = ctx->mres;
+
+    if (ctx->ares) {
+        /* First call to encrypt finalizes AAD */
+        memset(ctx->ACi.c + ctx->ares, 0, bl - ctx->ares);
+        (*block) (ctx->Zi.c, ctx->Hi.c, key);                   // H_i = E_K(Z_i)
+        mul_gf(ctx->mul.u, ctx->Hi.u, ctx->ACi.u);              // H_i (x) A_i
+        grasshopper_plus128((grasshopper_w128_t*)ctx->sum.u,    // acc XOR
+            (grasshopper_w128_t*)ctx->sum.u, (grasshopper_w128_t*)ctx->mul.u);
+        inc_counter(ctx->Zi.c, bl / 2);                         // Z_{i+1} = incr_l(Z_i)
+
+        ctx->ares = 0;
+    }
+
+    n = mres % bl;
+    // TODO: full blocks
+    for (i = 0; i < len; ++i) {
+        uint8_t c;
+        if (n == 0) {
+            (*block) (ctx->Yi.c, ctx->EKi.c, key);      // E_K(Y_i)
+            inc_counter(ctx->Yi.c + bl / 2, bl / 2);    // Y_i = incr_r(Y_{i-1})
+        }
+        ctx->ACi.c[n] = c = in[i];       
+        out[i] = c ^ ctx->EKi.c[n];             // P_i = C_i (xor) E_K(Y_i)
+        mres = n = (n + 1) % bl;
+        if (n == 0) {
+            (*block) (ctx->Zi.c, ctx->Hi.c, key);                   // H_i = E_K(Z_i)
+            mul_gf(ctx->mul.u, ctx->Hi.u, ctx->ACi.u);              // H_i (x) C_i
+            grasshopper_plus128((grasshopper_w128_t*)ctx->sum.u,    // acc XOR
+                (grasshopper_w128_t*)ctx->sum.u, (grasshopper_w128_t*)ctx->mul.u);
+            inc_counter(ctx->Zi.c, bl / 2);                         // Z_{i+1} = incr_l(Z_i)
+        }
+    }
+
+    ctx->mres = mres;
+    return 0;  
+}
+
+int gost_mgm128_finish(mgm128_context *ctx, const unsigned char *tag,
+                         size_t len)
+{
+    uint64_t alen = ctx->len.u[0] << 3;
+    uint64_t clen = ctx->len.u[1] << 3;
+    block128_f block = ctx->block;
+    mul128_f mul_gf = ctx->mul_gf;
+    void *key = ctx->key;
+    int bl = ctx->blocklen;
+
+    if (ctx->mres || ctx->ares) {
+        /* First call to encrypt finalizes AAD/ENC */
+        memset(ctx->ACi.c + ctx->ares + ctx->mres, 0, bl - (ctx->ares + ctx->mres));
+        (*block) (ctx->Zi.c, ctx->Hi.c, key);                   // H_i = E_K(Z_i)
+        mul_gf(ctx->mul.u, ctx->Hi.u, ctx->ACi.u);              // H_i (x) [A_i or C_i]
+        grasshopper_plus128((grasshopper_w128_t*)ctx->sum.u,    // acc XOR
+            (grasshopper_w128_t*)ctx->sum.u, (grasshopper_w128_t*)ctx->mul.u);
+        inc_counter(ctx->Zi.c, bl / 2);                         // Z_{i+1} = incr_l(Z_i)
+    }
+
+#ifdef L_ENDIAN
+    alen = BSWAP64(alen);
+    clen = BSWAP64(clen);
+#endif
+    if (bl == 16) {
+        ctx->len.u[0] = alen;
+        ctx->len.u[1] = clen;
+    } else {
+        // TODO: check for big-endian
+        ctx->len.u[0] = (alen >> 32) | clen;
+        ctx->len.u[1] = 0;
+    }
+
+    (*block) (ctx->Zi.c, ctx->Hi.c, key);                   // H_i = E_K(Z_i)
+    mul_gf(ctx->mul.u, ctx->Hi.u, ctx->len.u);              // H_i (x) (len(A) || len(C))
+    grasshopper_plus128((grasshopper_w128_t*)ctx->sum.u,    // acc XOR
+            (grasshopper_w128_t*)ctx->sum.u, (grasshopper_w128_t*)ctx->mul.u);
+    (*block) (ctx->sum.c, ctx->tag.c, key);                 // E_K(sum)
+
+    if (tag && len <= sizeof(ctx->tag))
+        return CRYPTO_memcmp(ctx->tag.c, tag, len);         // MSB_S(E_K(sum))
+    else
+        return -1;
+}
+
+void gost_mgm128_tag(mgm128_context *ctx, unsigned char *tag, size_t len)
+{
+    gost_mgm128_finish(ctx, NULL, 0);
+    memcpy(tag, ctx->tag.c,
+           len <= sizeof(ctx->tag.c) ? len : sizeof(ctx->tag.c));
+}
index 663d31536d15185d9fce0a1b308d12255540346a..427524a3b6c8669a8e605b5e7164960c9a65ebab 100644 (file)
@@ -7,13 +7,55 @@
 #ifndef GOST_GOST2015_H
 #define GOST_GOST2015_H
 
+#include "gost_grasshopper_cipher.h"
+
 #include <openssl/evp.h>
 #include <openssl/x509.h>
+#include <openssl/modes.h>
 
 #define MAGMA_MAC_MAX_SIZE 8
 #define KUZNYECHIK_MAC_MAX_SIZE 16
 #define OID_GOST_CMS_MAC "1.2.643.7.1.0.6.1.1"
 
+#define BSWAP64(x) \
+    (((x & 0xFF00000000000000ULL) >> 56) | \
+     ((x & 0x00FF000000000000ULL) >> 40) | \
+     ((x & 0x0000FF0000000000ULL) >> 24) | \
+     ((x & 0x000000FF00000000ULL) >>  8) | \
+     ((x & 0x00000000FF000000ULL) <<  8) | \
+     ((x & 0x0000000000FF0000ULL) << 24) | \
+     ((x & 0x000000000000FF00ULL) << 40) | \
+     ((x & 0x00000000000000FFULL) << 56))
+
+typedef void (*mul128_f) (uint64_t *result, uint64_t *arg1, uint64_t *arg2);
+
+typedef struct {
+    union {
+        uint64_t u[2];
+        uint32_t d[4];
+        uint8_t c[16];
+    } nonce, Yi, Zi, EKi, Hi, len, ACi, mul, sum, tag;
+    // 
+    unsigned int mres, ares;
+    block128_f block;
+    mul128_f mul_gf;
+    int blocklen;
+    void *key;
+} mgm128_context;
+
+typedef struct {
+    union {
+        struct ossl_gost_cipher_ctx g_ks;
+        gost_grasshopper_cipher_ctx gh_ks;       
+    } ks;
+    int key_set;
+    int iv_set;
+    mgm128_context mgm;
+    unsigned char *iv;
+    int ivlen;
+    int taglen;
+} gost_mgm_ctx;
+
 int gost2015_final_call(EVP_CIPHER_CTX *ctx, EVP_MD_CTX *omac_ctx, size_t mac_size,
                        unsigned char *encrypted_mac,
                        int (*do_cipher) (EVP_CIPHER_CTX *ctx,
@@ -36,4 +78,24 @@ int gost2015_acpkm_omac_init(int nid, int enc, const unsigned char *inkey,
                              unsigned char *outkey, unsigned char *kdf_seed);
 int init_zero_kdf_seed(unsigned char *kdf_seed);
 
+
+/* enc/dec mgm mode */
+
+void gost_mgm128_init(mgm128_context *ctx, void *key, block128_f block, 
+                                         mul128_f mul_gf, int blen);
+
+int gost_mgm128_setiv(mgm128_context *ctx, const unsigned char *iv, size_t len);
+
+int gost_mgm128_aad(mgm128_context *ctx, const unsigned char *aad, size_t len);
+
+int gost_mgm128_encrypt(mgm128_context *ctx, const unsigned char *in, 
+                          unsigned char *out, size_t len);
+
+int gost_mgm128_decrypt(mgm128_context *ctx, const unsigned char *in, 
+                          unsigned char *out, size_t len);
+
+int gost_mgm128_finish(mgm128_context *ctx, const unsigned char *tag, size_t len);
+
+void gost_mgm128_tag(mgm128_context *ctx, unsigned char *tag, size_t len);
+
 #endif
index 7734736ef2c7106807192762b272c09ea90c40c8..c0031ad170221b7a12fb8b2e796abed4dfc7de9d 100644 (file)
@@ -13,6 +13,7 @@
 #include <openssl/evp.h>
 #include <openssl/rand.h>
 #include <openssl/err.h>
+
 #include <string.h>
 
 #include "gost_lcl.h"
@@ -26,6 +27,7 @@ enum GRASSHOPPER_CIPHER_TYPE {
     GRASSHOPPER_CIPHER_CTR,
     GRASSHOPPER_CIPHER_CTRACPKM,
     GRASSHOPPER_CIPHER_CTRACPKMOMAC,
+    GRASSHOPPER_CIPHER_MGM,
 };
 
 static GOST_cipher grasshopper_template_cipher = {
@@ -124,6 +126,21 @@ GOST_cipher grasshopper_ctr_acpkm_omac_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 */
@@ -344,6 +361,143 @@ gost_grasshopper_cipher_init_ctracpkm_omac(EVP_CIPHER_CTX
     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
+
+       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;
+               }
+       }
+
+       if (t & 0x1) {
+               Z0 ^= X0;
+               Z1 ^= X1;
+       }
+
+#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_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;
+}
+
 static int gost_grasshopper_cipher_do_ecb(EVP_CIPHER_CTX *ctx, unsigned char *out,
                                           const unsigned char *in, size_t inl)
 {
@@ -582,6 +736,60 @@ static int gost_grasshopper_cipher_do_ctracpkm_omac(EVP_CIPHER_CTX *ctx,
 
     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.
  */
@@ -799,6 +1007,79 @@ gost_grasshopper_get_asn1_parameters(EVP_CIPHER_CTX *ctx, ASN1_TYPE *params)
     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;
+        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;
+
+    default:
+        return -1;
+    }
+}
+
 static int gost_grasshopper_cipher_ctl(EVP_CIPHER_CTX *ctx, int type, int arg, void *ptr)
 {
     switch (type) {
index ecaf1c7aab3c6547fe06f8464d3d5cc75ae351a8..dec659bec2c01d378f64c2fb49645c72f9715488 100644 (file)
@@ -12,6 +12,7 @@ extern "C" {
 
 #include "gost_grasshopper_defines.h"
 
+#include "gost_lcl.h"
 #include <openssl/evp.h>
 
 // not thread safe
@@ -60,6 +61,9 @@ static int gost_grasshopper_cipher_init_ctracpkm(EVP_CIPHER_CTX* ctx,
 static int gost_grasshopper_cipher_init_ctracpkm_omac(EVP_CIPHER_CTX* ctx,
     const unsigned char* key, const unsigned char* iv, int enc);
 
+static int gost_grasshopper_cipher_init_mgm(EVP_CIPHER_CTX* ctx, 
+    const unsigned char* key, const unsigned char* iv, int enc);
+
 static int gost_grasshopper_cipher_init(EVP_CIPHER_CTX* ctx, const unsigned char* key,
     const unsigned char* iv, int enc);
 
@@ -87,14 +91,21 @@ static int gost_grasshopper_cipher_do_ctracpkm(EVP_CIPHER_CTX* ctx, unsigned cha
 static 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_mgm(EVP_CIPHER_CTX* ctx, unsigned char* out,
+    const unsigned char* in, size_t inl);
+
 static int gost_grasshopper_cipher_cleanup(EVP_CIPHER_CTX* ctx);
 
+static int gost_grasshopper_mgm_cleanup(EVP_CIPHER_CTX *c);
+
 static int gost_grasshopper_set_asn1_parameters(EVP_CIPHER_CTX* ctx, ASN1_TYPE* params);
 
 static int gost_grasshopper_get_asn1_parameters(EVP_CIPHER_CTX* ctx, ASN1_TYPE* params);
 
 static int gost_grasshopper_cipher_ctl(EVP_CIPHER_CTX* ctx, int type, int arg, void* ptr);
 
+static int gost_grasshopper_mgm_ctrl(EVP_CIPHER_CTX *ctx, int type, int arg, void *ptr);
+
 const EVP_CIPHER* cipher_gost_grasshopper_ctracpkm();
 
 #if defined(__cplusplus)
index 8471ed062cecde22fe78931015eaec8b0b5eb483..afa19ebb7bc708a5a21d6d8efb21307d1dc02103 100644 (file)
@@ -338,11 +338,13 @@ extern GOST_cipher magma_ctr_cipher;
 extern GOST_cipher magma_ctr_acpkm_cipher;
 extern GOST_cipher magma_ctr_acpkm_omac_cipher;
 extern GOST_cipher magma_cbc_cipher;
+extern GOST_cipher magma_mgm_cipher;
 extern GOST_cipher grasshopper_ecb_cipher;
 extern GOST_cipher grasshopper_cbc_cipher;
 extern GOST_cipher grasshopper_cfb_cipher;
 extern GOST_cipher grasshopper_ofb_cipher;
 extern GOST_cipher grasshopper_ctr_cipher;
+extern GOST_cipher grasshopper_mgm_cipher;
 extern GOST_cipher grasshopper_ctr_acpkm_cipher;
 extern GOST_cipher grasshopper_ctr_acpkm_omac_cipher;
 extern GOST_cipher magma_kexp15_cipher;