2 * Copyright (c) 2019 Dmitry Belyavskiy <beldmit@gmail.com>
3 * Copyright (c) 2020 Vitaly Chikunov <vt@altlinux.org>
5 * Contents licensed under the terms of the OpenSSL license
6 * See https://www.openssl.org/source/license.html for details
9 #include <openssl/cmac.h>
10 #include <openssl/conf.h>
11 #include <openssl/err.h>
12 #include <openssl/evp.h>
14 #include "e_gost_err.h"
17 #define min(a,b) (((a) < (b)) ? (a) : (b))
19 typedef struct omac_ctx {
25 * Here begins stuff related to TLSTREE processing
26 * We MUST store the original key to derive TLSTREE keys from it
29 unsigned char key[32];
32 * TLSTREE intermediate values should be recalculated only when
33 * C_i & (seq_no+1) != C_i & (seq_no)
34 * so somewhen we will store C_i & (seq_no) in this structure
35 * to avoid redundant hash calculations.
39 #define MAX_GOST_OMAC_SIZE 16
41 static int omac_init(EVP_MD_CTX *ctx, int cipher_nid)
43 OMAC_CTX *c = EVP_MD_CTX_md_data(ctx);
44 memset(c, 0, sizeof(OMAC_CTX));
45 c->cipher_nid = cipher_nid;
53 case NID_grasshopper_cbc:
61 static int magma_imit_init(EVP_MD_CTX *ctx)
63 return omac_init(ctx, NID_magma_cbc);
66 static int grasshopper_imit_init(EVP_MD_CTX *ctx)
68 return omac_init(ctx, NID_grasshopper_cbc);
71 static int omac_imit_update(EVP_MD_CTX *ctx, const void *data, size_t count)
73 OMAC_CTX *c = EVP_MD_CTX_md_data(ctx);
75 GOSTerr(GOST_F_OMAC_IMIT_UPDATE, GOST_R_MAC_KEY_NOT_SET);
79 return CMAC_Update(c->cmac_ctx, data, count);
82 int omac_imit_final(EVP_MD_CTX *ctx, unsigned char *md)
84 OMAC_CTX *c = EVP_MD_CTX_md_data(ctx);
85 unsigned char mac[MAX_GOST_OMAC_SIZE];
86 size_t mac_size = sizeof(mac);
89 GOSTerr(GOST_F_OMAC_IMIT_FINAL, GOST_R_MAC_KEY_NOT_SET);
93 CMAC_Final(c->cmac_ctx, mac, &mac_size);
95 memcpy(md, mac, c->dgst_size);
99 int omac_imit_copy(EVP_MD_CTX *to, const EVP_MD_CTX *from)
101 OMAC_CTX *c_to = EVP_MD_CTX_md_data(to);
102 const OMAC_CTX *c_from = EVP_MD_CTX_md_data(from);
104 if (c_from && c_to) {
105 c_to->dgst_size = c_from->dgst_size;
106 c_to->cipher_nid = c_from->cipher_nid;
107 c_to->key_set = c_from->key_set;
108 memcpy(c_to->key, c_from->key, 32);
112 if (!c_from->cmac_ctx) {
113 if (c_to->cmac_ctx) {
114 CMAC_CTX_free(c_to->cmac_ctx);
115 c_to->cmac_ctx = NULL;
119 if (c_to->cmac_ctx == c_from->cmac_ctx) {
120 c_to->cmac_ctx = CMAC_CTX_new();
122 return CMAC_CTX_copy(c_to->cmac_ctx, c_from->cmac_ctx);
125 /* Clean up imit ctx */
126 int omac_imit_cleanup(EVP_MD_CTX *ctx)
128 OMAC_CTX *c = EVP_MD_CTX_md_data(ctx);
131 CMAC_CTX_free(c->cmac_ctx);
132 memset(EVP_MD_CTX_md_data(ctx), 0, sizeof(OMAC_CTX));
137 static int omac_key(OMAC_CTX * c, const EVP_CIPHER *cipher,
138 const unsigned char *key, size_t key_size)
142 CMAC_CTX_free(c->cmac_ctx);
143 c->cmac_ctx = CMAC_CTX_new();
144 if (c->cmac_ctx == NULL) {
145 GOSTerr(GOST_F_OMAC_KEY, ERR_R_MALLOC_FAILURE);
149 ret = CMAC_Init(c->cmac_ctx, key, key_size, cipher, NULL);
156 int omac_imit_ctrl(EVP_MD_CTX *ctx, int type, int arg, void *ptr)
159 case EVP_MD_CTRL_KEY_LEN:
160 *((unsigned int *)(ptr)) = 32;
162 case EVP_MD_CTRL_SET_KEY:
164 OMAC_CTX *c = EVP_MD_CTX_md_data(ctx);
165 const EVP_MD *md = EVP_MD_CTX_md(ctx);
166 const EVP_CIPHER *cipher = NULL;
169 if (c->cipher_nid == NID_undef) {
170 switch (EVP_MD_nid(md)) {
172 c->cipher_nid = NID_magma_cbc;
175 case NID_grasshopper_mac:
176 c->cipher_nid = NID_grasshopper_cbc;
180 cipher = EVP_get_cipherbynid(c->cipher_nid);
182 if (cipher == NULL) {
183 GOSTerr(GOST_F_OMAC_IMIT_CTRL, GOST_R_CIPHER_NOT_FOUND);
186 if (EVP_MD_meth_get_init(EVP_MD_CTX_md(ctx)) (ctx) <= 0) {
187 GOSTerr(GOST_F_OMAC_IMIT_CTRL, GOST_R_MAC_KEY_NOT_SET);
190 EVP_MD_CTX_set_flags(ctx, EVP_MD_CTX_FLAG_NO_INIT);
193 GOSTerr(GOST_F_OMAC_IMIT_CTRL, GOST_R_BAD_ORDER);
198 struct gost_mac_key *key = (struct gost_mac_key *)ptr;
199 ret = omac_key(c, cipher, key->key, 32);
201 memcpy(c->key, key->key, 32);
203 } else if (arg == 32) {
204 ret = omac_key(c, cipher, ptr, 32);
206 memcpy(c->key, ptr, 32);
209 GOSTerr(GOST_F_OMAC_IMIT_CTRL, GOST_R_INVALID_MAC_KEY_SIZE);
212 case EVP_MD_CTRL_XOF_LEN: /* Supported in OpenSSL */
214 OMAC_CTX *c = EVP_MD_CTX_md_data(ctx);
215 switch (c->cipher_nid) {
217 if (arg < 1 || arg > 8) {
218 GOSTerr(GOST_F_OMAC_IMIT_CTRL, GOST_R_INVALID_MAC_SIZE);
223 case NID_grasshopper_cbc:
224 if (arg < 1 || arg > 16) {
225 GOSTerr(GOST_F_OMAC_IMIT_CTRL, GOST_R_INVALID_MAC_SIZE);
235 #ifdef EVP_MD_CTRL_TLSTREE
236 case EVP_MD_CTRL_TLSTREE:
238 OMAC_CTX *c = EVP_MD_CTX_md_data(ctx);
240 unsigned char diversed_key[32];
241 return gost_tlstree(c->cipher_nid, c->key, diversed_key,
242 (const unsigned char *)ptr) ?
243 omac_key(c, EVP_get_cipherbynid(c->cipher_nid),
244 diversed_key, 32) : 0;
246 GOSTerr(GOST_F_OMAC_IMIT_CTRL, GOST_R_BAD_ORDER);
256 static GOST_digest omac_template_digest = {
257 .input_blocksize = 8,
258 .app_datasize = sizeof(OMAC_CTX),
259 .flags = EVP_MD_FLAG_XOF,
260 .update = omac_imit_update,
261 .final = omac_imit_final,
262 .copy = omac_imit_copy,
263 .cleanup = omac_imit_cleanup,
264 .ctrl = omac_imit_ctrl,
267 GOST_digest magma_mac_digest = {
268 .nid = NID_magma_mac,
269 .template = &omac_template_digest,
271 .init = magma_imit_init,
274 GOST_digest grasshopper_mac_digest = {
275 .nid = NID_grasshopper_mac,
276 .template = &omac_template_digest,
278 .init = grasshopper_imit_init,
281 EVP_MD *magma_omac(void)
283 return GOST_init_digest(&magma_mac_digest);
286 void magma_omac_destroy(void)
288 GOST_deinit_digest(&magma_mac_digest);
291 EVP_MD *grasshopper_omac(void)
293 return GOST_init_digest(&grasshopper_mac_digest);
296 void grasshopper_omac_destroy(void)
298 GOST_deinit_digest(&grasshopper_mac_digest);