aboutsummaryrefslogtreecommitdiff
path: root/gost_gost2015.c
blob: c0a914d80da563b4d5f9280f3fdc49392cefe304 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
#include "gost_lcl.h"
#include "gost_gost2015.h"
#include "e_gost_err.h"
#include <string.h>

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,
				unsigned char *out,
				const unsigned char *in,
				size_t inl))
{
  unsigned char calculated_mac[KUZNYECHIK_MAC_MAX_SIZE];
  memset(calculated_mac, 0, KUZNYECHIK_MAC_MAX_SIZE);

  if (EVP_CIPHER_CTX_encrypting(ctx)) {
    EVP_DigestSignFinal(omac_ctx, calculated_mac, &mac_size);

    if (do_cipher(ctx, encrypted_mac, calculated_mac, mac_size) <= 0) {
        return -1;
    }
  } else {
    unsigned char expected_mac[KUZNYECHIK_MAC_MAX_SIZE];

    memset(expected_mac, 0, KUZNYECHIK_MAC_MAX_SIZE);
    EVP_DigestSignFinal(omac_ctx, calculated_mac, &mac_size);

    if (do_cipher(ctx, expected_mac, encrypted_mac, mac_size) <= 0) {
        return -1;
    }

    if (CRYPTO_memcmp(expected_mac, calculated_mac, mac_size) != 0)
      return -1;
  }
  return 0;
}

/*
 * UKM = iv|kdf_seed
 * */
#define MAX_GOST2015_UKM_SIZE 16
#define KDF_SEED_SIZE 8
int gost2015_get_asn1_params(const ASN1_TYPE *params, size_t ukm_size,
  unsigned char *iv, size_t ukm_offset, unsigned char *kdf_seed)
{
  int iv_len = 16;
  GOST2015_CIPHER_PARAMS *gcp = NULL;

  unsigned char *p = NULL;

  memset(iv, 0, iv_len);

  /* Проверяем тип params */
  if (ASN1_TYPE_get(params) != V_ASN1_SEQUENCE) {
      GOSTerr(GOST_F_GOST2015_GET_ASN1_PARAMS, GOST_R_INVALID_CIPHER_PARAMS);
      return 0;
  }

  p = params->value.sequence->data;
  /* Извлекаем структуру параметров */
  gcp = d2i_GOST2015_CIPHER_PARAMS(NULL, (const unsigned char **)&p, params->value.sequence->length);
  if (gcp == NULL) {
      GOSTerr(GOST_F_GOST2015_GET_ASN1_PARAMS, GOST_R_INVALID_CIPHER_PARAMS);
      return 0;
  }

  /* Проверяем длину синхропосылки */
  if (gcp->ukm->length != (int)ukm_size) {
      GOSTerr(GOST_F_GOST2015_GET_ASN1_PARAMS, GOST_R_INVALID_CIPHER_PARAMS);
      GOST2015_CIPHER_PARAMS_free(gcp);
      return 0;
  }

  memcpy(iv, gcp->ukm->data, ukm_offset);
  memcpy(kdf_seed, gcp->ukm->data+ukm_offset, KDF_SEED_SIZE);

  GOST2015_CIPHER_PARAMS_free(gcp);
  return 1;
}

int gost2015_set_asn1_params(ASN1_TYPE *params,
  const unsigned char *iv, size_t iv_size, const unsigned char *kdf_seed)
{
  GOST2015_CIPHER_PARAMS *gcp = GOST2015_CIPHER_PARAMS_new();
  int ret = 0, len = 0;

  ASN1_OCTET_STRING *os = NULL;
  unsigned char ukm_buf[MAX_GOST2015_UKM_SIZE];
  unsigned char *buf = NULL;

  if (gcp == NULL) {
      GOSTerr(GOST_F_GOST2015_SET_ASN1_PARAMS, ERR_R_MALLOC_FAILURE);
      return 0;
  }

  memcpy(ukm_buf, iv, iv_size);
  memcpy(ukm_buf+iv_size, kdf_seed, KDF_SEED_SIZE);

  if (ASN1_STRING_set(gcp->ukm, ukm_buf, iv_size + KDF_SEED_SIZE) == 0) {
      GOSTerr(GOST_F_GOST2015_SET_ASN1_PARAMS, ERR_R_MALLOC_FAILURE);
      goto end;
  }

  len = i2d_GOST2015_CIPHER_PARAMS(gcp, &buf);

  if (len <= 0
      || (os = ASN1_OCTET_STRING_new()) == NULL
      || ASN1_OCTET_STRING_set(os, buf, len) == 0) {
      goto end;
  }

  ASN1_TYPE_set(params, V_ASN1_SEQUENCE, os);
  ret = 1;

end:
  OPENSSL_free(buf);
  if (ret <= 0 && os)
    ASN1_OCTET_STRING_free(os);

  GOST2015_CIPHER_PARAMS_free(gcp);
  return ret;
}