]> www.wagner.pp.ru Git - openssl-gost/engine.git/blob - gost_omac.c
Allow EVP_MD_CTX_copy_ex OMAC before key is set
[openssl-gost/engine.git] / gost_omac.c
1 #include <string.h>
2 #include <openssl/cmac.h>
3 #include <openssl/conf.h>
4 #include <openssl/err.h>
5 #include <openssl/evp.h>
6
7 #include "e_gost_err.h"
8 #include "gost_lcl.h"
9
10 #define min(a,b) (((a) < (b)) ? (a) : (b))
11
12 typedef struct omac_ctx {
13         CMAC_CTX *cmac_ctx;
14         size_t   dgst_size;
15         int      cipher_nid;
16         int      key_set;
17 } OMAC_CTX;
18
19 #define MAX_GOST_OMAC_SIZE 16
20
21 static int omac_init(EVP_MD_CTX *ctx, int cipher_nid)
22 {
23     OMAC_CTX *c = EVP_MD_CTX_md_data(ctx);
24                 memset(c, 0, sizeof(OMAC_CTX));
25                 c->cipher_nid = cipher_nid;
26                 c->key_set    = 0;
27
28                 switch(cipher_nid) {
29                         case NID_magma_cbc:
30                                 c->dgst_size = 4;
31                         break;
32
33                         case NID_grasshopper_cbc:
34                                 c->dgst_size = 8;
35                         break;
36                 }
37
38     return 1;
39 }
40
41 static int magma_imit_init(EVP_MD_CTX *ctx)
42 {
43     return omac_init(ctx, NID_magma_cbc);
44 }
45
46 static int grasshopper_imit_init(EVP_MD_CTX *ctx)
47 {
48     return omac_init(ctx, NID_grasshopper_cbc);
49 }
50
51 static int omac_imit_update(EVP_MD_CTX *ctx, const void *data, size_t count)
52 {
53     OMAC_CTX *c = EVP_MD_CTX_md_data(ctx);
54                 if (!c->key_set)
55                 {
56         GOSTerr(GOST_F_OMAC_IMIT_UPDATE, GOST_R_MAC_KEY_NOT_SET);
57         return 0;
58                 }
59
60                 return CMAC_Update(c->cmac_ctx, data, count);
61 }
62
63 int omac_imit_final(EVP_MD_CTX *ctx, unsigned char *md)
64 {
65     OMAC_CTX *c = EVP_MD_CTX_md_data(ctx);
66                 unsigned char mac[MAX_GOST_OMAC_SIZE];
67                 size_t mac_size = sizeof(mac);
68
69     if (!c->key_set) {
70         GOSTerr(GOST_F_OMAC_IMIT_FINAL, GOST_R_MAC_KEY_NOT_SET);
71         return 0;
72     }
73
74                 CMAC_Final(c->cmac_ctx, mac, &mac_size);
75
76     int md_size = EVP_MD_meth_get_result_size(EVP_MD_CTX_md(ctx));
77     memcpy(md, mac, min(md_size, c->dgst_size));
78     return 1;
79 }
80
81 int omac_imit_copy(EVP_MD_CTX *to, const EVP_MD_CTX *from)
82 {
83     OMAC_CTX *c_to = EVP_MD_CTX_md_data(to);
84                 const OMAC_CTX *c_from = EVP_MD_CTX_md_data(from);
85
86     if (c_from && c_to) {
87                         c_to->dgst_size  = c_from->dgst_size;
88                         c_to->cipher_nid = c_from->cipher_nid;
89                         c_to->key_set    = c_from->key_set;
90     }
91                 else
92                 {
93                         return 0;
94                 }
95                 if (!c_from->cmac_ctx) {
96                     if (c_to->cmac_ctx) {
97                         CMAC_CTX_free(c_to->cmac_ctx);
98                         c_to->cmac_ctx = NULL;
99                     }
100                     return 1;
101                 }
102                 if (c_to->cmac_ctx == c_from->cmac_ctx)
103                 {
104                     c_to->cmac_ctx = CMAC_CTX_new();
105                 }
106                 return CMAC_CTX_copy(c_to->cmac_ctx, c_from->cmac_ctx);
107 }
108
109 /* Clean up imit ctx */
110 int omac_imit_cleanup(EVP_MD_CTX *ctx)
111 {
112     OMAC_CTX *c = EVP_MD_CTX_md_data(ctx);
113
114                 if (c)
115                 {
116                         CMAC_CTX_free(c->cmac_ctx);
117             memset(EVP_MD_CTX_md_data(ctx), 0, sizeof(OMAC_CTX));
118                 }
119     return 1;
120 }
121
122 static int omac_key(OMAC_CTX *c, const EVP_CIPHER *cipher, const unsigned char *key, size_t key_size)
123 {
124         int ret = 0;
125
126         c->cmac_ctx = CMAC_CTX_new();
127         if (c->cmac_ctx == NULL)
128         {
129                 GOSTerr(GOST_F_OMAC_KEY, ERR_R_MALLOC_FAILURE);
130                 return 0;
131         }
132
133         ret = CMAC_Init(c->cmac_ctx, key, key_size, cipher, NULL);
134         if (ret > 0)
135         {
136                 c->key_set = 1;
137         }
138         return 1;
139 }                                               
140
141 int omac_imit_ctrl(EVP_MD_CTX *ctx, int type, int arg, void *ptr)
142 {
143     switch (type) {
144     case EVP_MD_CTRL_KEY_LEN:
145         *((unsigned int *)(ptr)) = 32;
146         return 1;
147     case EVP_MD_CTRL_SET_KEY:
148                                 {
149                                         OMAC_CTX *c = EVP_MD_CTX_md_data(ctx);
150                                         const EVP_MD *md = EVP_MD_CTX_md(ctx);
151                                         const EVP_CIPHER *cipher = NULL;
152
153                                         if (c->cipher_nid == NID_undef)
154                                         {
155                                                 switch (EVP_MD_nid(md))
156                                                 {
157                                                         case NID_magma_mac:
158                                                                 c->cipher_nid = NID_magma_cbc;
159                                                                 break;
160
161                                                         case NID_grasshopper_mac:
162                                                                 c->cipher_nid = NID_grasshopper_cbc;
163                                                                 break;
164                                                 }
165                                         }
166                                         cipher = EVP_get_cipherbynid(c->cipher_nid);
167
168                                         if (cipher == NULL)
169                                         {
170                                                 GOSTerr(GOST_F_OMAC_IMIT_CTRL, GOST_R_CIPHER_NOT_FOUND);
171                                         }
172
173                                         if (EVP_MD_meth_get_init(EVP_MD_CTX_md(ctx)) (ctx) <= 0) {
174                                                 GOSTerr(GOST_F_OMAC_IMIT_CTRL, GOST_R_MAC_KEY_NOT_SET);
175                                                 return 0;
176                                         }
177                                         EVP_MD_CTX_set_flags(ctx, EVP_MD_CTX_FLAG_NO_INIT);
178
179                                         if (c->key_set)
180                                         {
181                                                 GOSTerr(GOST_F_OMAC_IMIT_CTRL, GOST_R_BAD_ORDER);
182                                                 return 0;
183                                         }
184
185                                         if (arg == 0) {
186                                                 struct gost_mac_key *key = (struct gost_mac_key *)ptr;
187                                                 return omac_key(c, cipher, key->key, 32);
188
189                                         } else if (arg == 32) {
190                                                 return omac_key(c, cipher, ptr, 32);
191                                         }
192                                         GOSTerr(GOST_F_OMAC_IMIT_CTRL, GOST_R_INVALID_MAC_KEY_SIZE);
193                                         return 0;
194                                 }
195     case EVP_MD_CTRL_MAC_LEN:
196         {
197                                         OMAC_CTX *c = EVP_MD_CTX_md_data(ctx);
198                                         switch (c->cipher_nid)
199                                         {
200                                                 case NID_magma_cbc:
201             if (arg < 1 || arg > 8) {
202                 GOSTerr(GOST_F_OMAC_IMIT_CTRL, GOST_R_INVALID_MAC_SIZE);
203                 return 0;
204             }
205             c->dgst_size = arg;
206                                                 break;
207                                                 case NID_grasshopper_cbc:
208             if (arg < 1 || arg > 16) {
209                 GOSTerr(GOST_F_OMAC_IMIT_CTRL, GOST_R_INVALID_MAC_SIZE);
210                 return 0;
211             }
212             c->dgst_size = arg;
213                                                 break;
214                                                 default:
215                                                 return 0;
216                                         }
217           return 1;
218         }
219
220     default:
221         return 0;
222     }
223 }
224
225 static EVP_MD *_hidden_magma_mac_md = NULL;
226
227 EVP_MD *magma_omac(void)
228 {
229     if (_hidden_magma_mac_md == NULL) {
230         EVP_MD *md;
231
232         if ((md = EVP_MD_meth_new(NID_magma_mac, NID_undef)) == NULL
233             || !EVP_MD_meth_set_result_size(md, 4)
234             || !EVP_MD_meth_set_input_blocksize(md, 8)
235             || !EVP_MD_meth_set_app_datasize(md, sizeof(OMAC_CTX))
236             || !EVP_MD_meth_set_flags(md, 0)
237             || !EVP_MD_meth_set_init(md, magma_imit_init)
238             || !EVP_MD_meth_set_update(md, omac_imit_update)
239             || !EVP_MD_meth_set_final(md, omac_imit_final)
240             || !EVP_MD_meth_set_copy(md, omac_imit_copy)
241             || !EVP_MD_meth_set_cleanup(md, omac_imit_cleanup)
242             || !EVP_MD_meth_set_ctrl(md, omac_imit_ctrl)) {
243             EVP_MD_meth_free(md);
244             md = NULL;
245         }
246        _hidden_magma_mac_md = md;
247     }
248     return _hidden_magma_mac_md;
249 }
250
251 void magma_omac_destroy(void)
252 {
253     EVP_MD_meth_free(_hidden_magma_mac_md);
254     _hidden_magma_mac_md = NULL;
255 }
256
257 static EVP_MD *_hidden_grasshopper_mac_md = NULL;
258
259 EVP_MD *grasshopper_omac(void)
260 {
261     if (_hidden_grasshopper_mac_md == NULL) {
262         EVP_MD *md;
263
264         if ((md = EVP_MD_meth_new(NID_grasshopper_mac, NID_undef)) == NULL
265             || !EVP_MD_meth_set_result_size(md, 8)
266             || !EVP_MD_meth_set_input_blocksize(md, 8)
267             || !EVP_MD_meth_set_app_datasize(md, sizeof(OMAC_CTX))
268             || !EVP_MD_meth_set_flags(md, 0)
269             || !EVP_MD_meth_set_init(md, grasshopper_imit_init)
270             || !EVP_MD_meth_set_update(md, omac_imit_update)
271             || !EVP_MD_meth_set_final(md, omac_imit_final)
272             || !EVP_MD_meth_set_copy(md, omac_imit_copy)
273             || !EVP_MD_meth_set_cleanup(md, omac_imit_cleanup)
274             || !EVP_MD_meth_set_ctrl(md, omac_imit_ctrl)) {
275             EVP_MD_meth_free(md);
276             md = NULL;
277         }
278        _hidden_grasshopper_mac_md = md;
279     }
280     return _hidden_grasshopper_mac_md;
281 }
282
283 void grasshopper_omac_destroy(void)
284 {
285     EVP_MD_meth_free(_hidden_grasshopper_mac_md);
286     _hidden_grasshopper_mac_md = NULL;
287 }
288