]> www.wagner.pp.ru Git - openssl-gost/engine.git/blobdiff - gost_grasshopper_cipher.c
gost_grasshopper_cipher: Rework cipher registration
[openssl-gost/engine.git] / gost_grasshopper_cipher.c
index 9cef0c5f02fa1a596177385d32531c230e98e46a..2b3d112fa6e1a7a02876c85fcb13c036feed8644 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Maxim Tishkov 2016
+ * Copyright (c) 2020 Vitaly Chikunov <vt@altlinux.org>
  * This file is distributed under the same license as OpenSSL
  */
 
@@ -46,6 +47,103 @@ struct GRASSHOPPER_CIPHER_PARAMS {
     int extra_flags;
 };
 
+static GOST_cipher grasshopper_template_cipher = {
+    .block_size = GRASSHOPPER_BLOCK_SIZE,
+    .key_len = GRASSHOPPER_KEY_SIZE,
+    .flags = EVP_CIPH_RAND_KEY |
+        EVP_CIPH_ALWAYS_CALL_INIT,
+    .do_cipher = gost_grasshopper_cipher_do,
+    .cleanup = gost_grasshopper_cipher_cleanup,
+    .ctx_size = sizeof(gost_grasshopper_cipher_ctx),
+    .set_asn1_parameters = gost_grasshopper_set_asn1_parameters,
+    .get_asn1_parameters = gost_grasshopper_get_asn1_parameters,
+    .ctrl = gost_grasshopper_cipher_ctl,
+};
+
+GOST_cipher grasshopper_ecb_cipher = {
+    .nid = NID_grasshopper_ecb,
+    .template = &grasshopper_template_cipher,
+    .flags = EVP_CIPH_ECB_MODE,
+    .init = gost_grasshopper_cipher_init_ecb,
+    .do_cipher = gost_grasshopper_cipher_do_ecb,
+};
+
+GOST_cipher grasshopper_cbc_cipher = {
+    .nid = NID_grasshopper_cbc,
+    .template = &grasshopper_template_cipher,
+    .iv_len = 16,
+    .flags = EVP_CIPH_CBC_MODE |
+        EVP_CIPH_CUSTOM_IV,
+    .init = gost_grasshopper_cipher_init_cbc,
+    .do_cipher = gost_grasshopper_cipher_do_cbc,
+};
+
+GOST_cipher grasshopper_ofb_cipher = {
+    .nid = NID_grasshopper_ofb,
+    .template = &grasshopper_template_cipher,
+    .block_size = 1,
+    .iv_len = 16,
+    .flags = EVP_CIPH_OFB_MODE |
+        EVP_CIPH_NO_PADDING |
+        EVP_CIPH_CUSTOM_IV,
+    .init = gost_grasshopper_cipher_init_ofb,
+    .do_cipher = gost_grasshopper_cipher_do_ofb,
+};
+
+GOST_cipher grasshopper_cfb_cipher = {
+    .nid = NID_grasshopper_cfb,
+    .template = &grasshopper_template_cipher,
+    .block_size = 1,
+    .iv_len = 16,
+    .flags = EVP_CIPH_CFB_MODE |
+        EVP_CIPH_NO_PADDING |
+        EVP_CIPH_CUSTOM_IV,
+    .init = gost_grasshopper_cipher_init_cfb,
+    .do_cipher = gost_grasshopper_cipher_do_cfb,
+};
+
+GOST_cipher grasshopper_ctr_cipher = {
+    .nid = NID_grasshopper_ctr,
+    .template = &grasshopper_template_cipher,
+    .block_size = 1,
+    .iv_len = 8,
+    .flags = EVP_CIPH_CTR_MODE |
+        EVP_CIPH_NO_PADDING |
+        EVP_CIPH_CUSTOM_IV,
+    .init = gost_grasshopper_cipher_init_ctr,
+    .do_cipher = gost_grasshopper_cipher_do_ctr,
+    .ctx_size = sizeof(gost_grasshopper_cipher_ctx_ctr),
+};
+
+GOST_cipher grasshopper_ctr_acpkm_cipher = {
+    .nid = NID_kuznyechik_ctr_acpkm,
+    .template = &grasshopper_template_cipher,
+    .block_size = 1,
+    .iv_len = 8,
+    .flags = EVP_CIPH_CTR_MODE |
+        EVP_CIPH_NO_PADDING |
+        EVP_CIPH_CUSTOM_IV,
+    .init = gost_grasshopper_cipher_init_ctracpkm,
+    .do_cipher = gost_grasshopper_cipher_do_ctracpkm,
+    .ctx_size = sizeof(gost_grasshopper_cipher_ctx_ctr),
+};
+
+GOST_cipher grasshopper_ctr_acpkm_omac_cipher = {
+    .nid = NID_kuznyechik_ctr_acpkm_omac,
+    .template = &grasshopper_template_cipher,
+    .block_size = 1,
+    .iv_len = 8,
+    .flags = EVP_CIPH_CTR_MODE |
+        EVP_CIPH_NO_PADDING |
+        EVP_CIPH_CUSTOM_IV |
+        EVP_CIPH_FLAG_CUSTOM_CIPHER |
+        EVP_CIPH_FLAG_CIPHER_WITH_MAC |
+        EVP_CIPH_CUSTOM_COPY,
+    .init = gost_grasshopper_cipher_init_ctracpkm_omac,
+    .do_cipher = gost_grasshopper_cipher_do_ctracpkm_omac,
+    .ctx_size = sizeof(gost_grasshopper_cipher_ctx_ctr),
+};
+
 static struct GRASSHOPPER_CIPHER_PARAMS gost_cipher_params[7] = {
        {
                NID_grasshopper_ecb,
@@ -215,6 +313,11 @@ int gost_grasshopper_cipher_init(EVP_CIPHER_CTX *ctx,
 
     if (EVP_CIPHER_CTX_get_app_data(ctx) == NULL) {
         EVP_CIPHER_CTX_set_app_data(ctx, EVP_CIPHER_CTX_get_cipher_data(ctx));
+        if (enc && c->type == GRASSHOPPER_CIPHER_CTRACPKM) {
+            gost_grasshopper_cipher_ctx_ctr *ctr = EVP_CIPHER_CTX_get_cipher_data(ctx);
+            if (init_zero_kdf_seed(ctr->kdf_seed) == 0)
+                return -1;
+        }
     }
 
     if (key != NULL) {
@@ -313,38 +416,24 @@ GRASSHOPPER_INLINE int gost_grasshopper_cipher_init_ctracpkm_omac(EVP_CIPHER_CTX
        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;
-
+               unsigned char cipher_key[32];
                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 (c->omac_ctx == NULL) {
+                   GOSTerr(GOST_F_GOST_GRASSHOPPER_CIPHER_INIT_CTRACPKM_OMAC, ERR_R_MALLOC_FAILURE);
+                               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;
+               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;
                }
-               EVP_PKEY_free(mac_key);
 
-               return gost_grasshopper_cipher_init(ctx, keys, iv, enc);
+               return gost_grasshopper_cipher_init(ctx, cipher_key, iv, enc);
        }
+
        return gost_grasshopper_cipher_init(ctx, key, iv, enc);
 }
 
@@ -462,19 +551,19 @@ int gost_grasshopper_cipher_do_ctr(EVP_CIPHER_CTX *ctx, unsigned char *out,
     grasshopper_w128_t *currentInputBlock;
     grasshopper_w128_t *currentOutputBlock;
     unsigned int n = EVP_CIPHER_CTX_num(ctx);
-    size_t lasted;
+    size_t lasted = inl;
     size_t i;
     size_t blocks;
     grasshopper_w128_t *iv_buffer;
     grasshopper_w128_t tmp;
 
-    while (n && inl) {
+    while (n && lasted) {
         *(current_out++) = *(current_in++) ^ c->partial_buffer.b[n];
-        --inl;
+        --lasted;
         n = (n + 1) % GRASSHOPPER_BLOCK_SIZE;
     }
     EVP_CIPHER_CTX_set_num(ctx, n);
-    blocks = inl / GRASSHOPPER_BLOCK_SIZE;
+    blocks = lasted / GRASSHOPPER_BLOCK_SIZE;
 
     iv_buffer = (grasshopper_w128_t *) iv;
 
@@ -489,10 +578,9 @@ int gost_grasshopper_cipher_do_ctr(EVP_CIPHER_CTX *ctx, unsigned char *out,
         ctr128_inc(iv_buffer->b);
         current_in += GRASSHOPPER_BLOCK_SIZE;
         current_out += GRASSHOPPER_BLOCK_SIZE;
+                               lasted -= GRASSHOPPER_BLOCK_SIZE;
     }
 
-    // last part
-    lasted = inl - blocks * GRASSHOPPER_BLOCK_SIZE;
     if (lasted > 0) {
         currentInputBlock = (grasshopper_w128_t *) current_in;
         currentOutputBlock = (grasshopper_w128_t *) current_out;
@@ -506,7 +594,7 @@ int gost_grasshopper_cipher_do_ctr(EVP_CIPHER_CTX *ctx, unsigned char *out,
         ctr128_inc(iv_buffer->b);
     }
 
-    return 1;
+    return inl;
 }
 
 #define GRASSHOPPER_BLOCK_MASK (GRASSHOPPER_BLOCK_SIZE - 1)
@@ -528,15 +616,15 @@ int gost_grasshopper_cipher_do_ctracpkm(EVP_CIPHER_CTX *ctx,
     gost_grasshopper_cipher_ctx_ctr *c = EVP_CIPHER_CTX_get_cipher_data(ctx);
     unsigned char *iv = EVP_CIPHER_CTX_iv_noconst(ctx);
     unsigned int num = EVP_CIPHER_CTX_num(ctx);
-    size_t blocks, i, lasted;
+    size_t blocks, i, lasted = inl;
     grasshopper_w128_t tmp;
 
-    while ((num & GRASSHOPPER_BLOCK_MASK) && inl) {
+    while ((num & GRASSHOPPER_BLOCK_MASK) && lasted) {
         *out++ = *in++ ^ c->partial_buffer.b[num & GRASSHOPPER_BLOCK_MASK];
-        --inl;
+        --lasted;
         num++;
     }
-    blocks = inl / GRASSHOPPER_BLOCK_SIZE;
+    blocks = lasted / GRASSHOPPER_BLOCK_SIZE;
 
     // full parts
     for (i = 0; i < blocks; i++) {
@@ -552,10 +640,10 @@ int gost_grasshopper_cipher_do_ctracpkm(EVP_CIPHER_CTX *ctx,
         in += GRASSHOPPER_BLOCK_SIZE;
         out += GRASSHOPPER_BLOCK_SIZE;
         num += GRASSHOPPER_BLOCK_SIZE;
+                               lasted -= GRASSHOPPER_BLOCK_SIZE;
     }
 
     // last part
-    lasted = inl - blocks * GRASSHOPPER_BLOCK_SIZE;
     if (lasted > 0) {
         apply_acpkm_grasshopper(c, &num);
         grasshopper_encrypt_block(&c->c.encrypt_round_keys,
@@ -585,6 +673,10 @@ int gost_grasshopper_cipher_do_ctracpkm_omac(EVP_CIPHER_CTX *ctx,
                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);
 
        /* As in and out can be the same pointer, process decrypted here */
@@ -816,8 +908,7 @@ GRASSHOPPER_INLINE int gost_grasshopper_get_asn1_parameters(EVP_CIPHER_CTX
        return 0;
 }
 
-int gost_grasshopper_cipher_ctl(EVP_CIPHER_CTX *ctx, int type, int arg,
-                                void *ptr)
+int gost_grasshopper_cipher_ctl(EVP_CIPHER_CTX *ctx, int type, int arg, void *ptr)
 {
     switch (type) {
     case EVP_CTRL_RAND_KEY:{
@@ -919,34 +1010,16 @@ int gost_grasshopper_cipher_ctl(EVP_CIPHER_CTX *ctx, int type, int arg,
         }
 #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;
+    {
+      STACK_OF(X509_ATTRIBUTE) *x = ptr;
+      gost_grasshopper_cipher_ctx_ctr *c = EVP_CIPHER_CTX_get_cipher_data(ctx);
+
+      if (c->c.type != GRASSHOPPER_CIPHER_CTRACPKMOMAC)
+        return -1;
+
+      return gost2015_process_unprotected_attributes(x, arg, KUZNYECHIK_MAC_MAX_SIZE, c->tag);
+    }
+    return 1;
     case EVP_CTRL_COPY: {
                        EVP_CIPHER_CTX *out = ptr;
 
@@ -1094,3 +1167,4 @@ void cipher_gost_grasshopper_destroy(void)
     EVP_CIPHER_meth_free(gost_grasshopper_ciphers[GRASSHOPPER_CIPHER_CTRACPKMOMAC]);
     gost_grasshopper_ciphers[GRASSHOPPER_CIPHER_CTRACPKMOMAC] = NULL;
 }
+/* vim: set expandtab cinoptions=\:0,l1,t0,g0,(0 sw=4 : */