+ if (c->omac_ctx == NULL) {
+ GOSTerr(GOST_F_GOST_GRASSHOPPER_CIPHER_INIT_CTRACPKM_OMAC, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+
+ 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;
+ }
+
+ 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
+
+ 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;