Deploy the new <ctype.h> and `foocmp' macros from mLib.
[catacomb] / symm / cmac-def.h
1 /* -*-c-*-
2 *
3 * The CMAC message-authentication code
4 *
5 * (c) 2017 Straylight/Edgeware
6 */
7
8 /*----- Licensing notice --------------------------------------------------*
9 *
10 * This file is part of Catacomb.
11 *
12 * Catacomb is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU Library General Public License as
14 * published by the Free Software Foundation; either version 2 of the
15 * License, or (at your option) any later version.
16 *
17 * Catacomb is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU Library General Public License for more details.
21 *
22 * You should have received a copy of the GNU Library General Public
23 * License along with Catacomb; if not, write to the Free
24 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
25 * MA 02111-1307, USA.
26 */
27
28 #ifndef CATACOMB_CMAC_DEF_H
29 #define CATACOMB_CMAC_DEF_H
30
31 #ifdef __cplusplus
32 extern "C" {
33 #endif
34
35 /*----- Header files ------------------------------------------------------*/
36
37 #include <string.h>
38
39 #include <mLib/bits.h>
40 #include <mLib/sub.h>
41
42 #ifndef CATACOMB_ARENA_H
43 # include "arena.h"
44 #endif
45
46 #ifndef CATACOMB_BLKC_H
47 # include "blkc.h"
48 #endif
49
50 #ifndef CATACOMB_GMAC_H
51 # include "gmac.h"
52 #endif
53
54 #ifndef CATACOMB_PARANOIA_H
55 # include "paranoia.h"
56 #endif
57
58 #ifndef CATACOMB_RSVR_H
59 # include "rsvr.h"
60 #endif
61
62 /*----- Low-level OMAC definitions ----------------------------------------*/
63
64 /* --- @OMAC_BLOCK@ --- *
65 *
66 * Arguments: @PRE@, @pre@ = prefixes for the underlying block cipher
67 * @pre_ctx *k@ = pointer to expanded blockcipher key
68 * @uint32 *a@ = accumulator state to update
69 * @octet *p@ = pointer to input block to accumulate
70 *
71 * Use: Update the state @a@ from the input block @p@.
72 */
73
74 #define OMAC_BLOCK(PRE, pre, k, a, p) do { \
75 pre##_ctx *_k = (k); uint32 *_a = (a); const octet *_pp = (p); \
76 BLKC_XLOAD(PRE, _a, _pp); pre##_eblk(_k, _a, _a); \
77 } while (0)
78
79 /* --- @OMAC_DEF@ --- *
80 *
81 * Arguments: @PRE@, @pre@ = prefixes for the underlying block cipher
82 *
83 * Use: Creates low-level implementation for the OMAC message-
84 * authentication mode.
85 */
86
87 #define OMAC_DEF(PRE, pre) \
88 \
89 /* Buffering policy for OMAC. */ \
90 const rsvr_policy pre##_omacpolicy = \
91 { RSVRF_FULL, PRE##_BLKSZ, PRE##_BLKSZ }; \
92 \
93 /* --- @pre_omacmasks@ --- * \
94 * \
95 * Arguments: @pre_ctx *k@ = pointer to expanded blockcipher key \
96 * @uint32 *m0, *m1@ = buffers to store the masks \
97 * \
98 * Returns: --- \
99 * \
100 * Use: Initialize the OMAC masks. The mask buffers are \
101 * @PRE_BLKSZ/4@ words long. The mmask @m0@ is applied to \
102 * messages which are a whole number of blocks long; @m1@ \
103 * is applied to messages with an incomplete final block, \
104 * following the 10* padding. \
105 */ \
106 \
107 void pre##_omacmasks(pre##_ctx *k, uint32 *m0, uint32 *m1) \
108 { \
109 uint32 t[PRE##_BLKSZ/4]; \
110 \
111 BLKC_ZERO(PRE, t); pre##_eblk(k, t, t); \
112 BLKC_BLSHIFT(PRE, IRRED, m0, t); \
113 BLKC_BLSHIFT(PRE, IRRED, m1, m0); \
114 } \
115 \
116 /* --- @pre_omacdone@ --- * \
117 * \
118 * Arguments: @pre_ctx *k@ = pointer to expanded blockcipher key \
119 * @const uint32 *m0, *m1@ = masks \
120 * @uint32 *a@ = accumulator state to update \
121 * @octet *p@ = pointer to input buffer (clobbered) \
122 * @unsigned n@ = size of input buffer (no more than \
123 * @PRE_BLKSZ@) \
124 * \
125 * Returns: --- \
126 * \
127 * Use: Update and finalize the OMAC hash state with the last \
128 * few bytes of input. The final tag is left in @a@. \
129 */ \
130 \
131 void pre##_omacdone(pre##_ctx *k, const uint32 *m0, const uint32 *m1, \
132 uint32 *a, octet *p, unsigned n) \
133 { \
134 /* Do any necessary padding and apply the appropriate mask to the \
135 * accumulator. \
136 */ \
137 if (n == PRE##_BLKSZ) \
138 BLKC_XMOVE(PRE, a, m0); \
139 else { \
140 p[n] = 0x80; memset(p + n + 1, 0, PRE##_BLKSZ - n - 1); \
141 BLKC_XMOVE(PRE, a, m1); \
142 } \
143 \
144 /* Fetch the buffer contents and cycle the block cipher one last \
145 * time. \
146 */ \
147 BLKC_XLOAD(PRE, a, p); \
148 pre##_eblk(k, a, a); \
149 }
150
151 /*----- Properly cooked CMAC ----------------------------------------------*/
152
153 /* --- @CMAC_DEF@ --- *
154 *
155 * Arguments: @PRE@, @pre@ = prefixes for the underlying block cipher
156 *
157 * Use: Creates an implementation for the CMAC message-authentication
158 * mode.
159 */
160
161 #define CMAC_DEF(PRE, pre) CMAC_DEFX(PRE, pre, #pre, #pre)
162
163 #define CMAC_DEFX(PRE, pre, name, fname) \
164 \
165 OMAC_DEF(PRE, pre) \
166 \
167 /* --- @pre_cmacsetkey@ --- * \
168 * \
169 * Arguments: @pre_cmackey *key@ = pointer to CMAC key block \
170 * @ocnst void *k@ = pointer to key material \
171 * @size_t ksz@ = size of key material \
172 * \
173 * Returns: --- \
174 * \
175 * Use: Initializes a CMAC key. This can be used for several \
176 * MAC operations. \
177 */ \
178 \
179 void pre##_cmacsetkey(pre##_cmackey *key, const void *k, size_t ksz) \
180 { \
181 pre##_init(&key->ctx, k, ksz); \
182 pre##_omacmasks(&key->ctx, key->m0, key->m1); \
183 } \
184 \
185 /* --- @pre##_cmacinit@ --- * \
186 * \
187 * Arguments: @pre_cmacctx *ctx@ = pointer to context block \
188 * @pre_cmackey *k@ = key block \
189 * \
190 * Returns: --- \
191 * \
192 * Use: Initializes a CMAC context ready to process a message. \
193 * It's not necessary to keep the key around. \
194 */ \
195 \
196 void pre##_cmacinit(pre##_cmacctx *ctx, const pre##_cmackey *k) \
197 { ctx->k = *k; ctx->off = 0; BLKC_ZERO(PRE, ctx->a); } \
198 \
199 /* --- @pre_cmachash@ --- * \
200 * \
201 * Arguments: @pre_cmacctx *ctx@ = pointer to CMAC context block \
202 * @ocnst void *p@ = pointer to message buffer \
203 * @size_t sz@ = size of message buffer \
204 * \
205 * Returns: --- \
206 * \
207 * Use: Hashes some input data. \
208 */ \
209 \
210 void pre##_cmachash(pre##_cmacctx *ctx, const void *p, size_t sz) \
211 { \
212 rsvr_state st; \
213 const octet *q; \
214 \
215 rsvr_setup(&st, &pre##_omacpolicy, ctx->b, &ctx->off, p, sz); \
216 RSVR_DO(&st) while ((q = RSVR_NEXT(&st, PRE##_BLKSZ)) != 0) \
217 OMAC_BLOCK(PRE, pre, &ctx->k.ctx, ctx->a, q); \
218 } \
219 \
220 /* --- @pre_cmacdone@ --- * \
221 * \
222 * Arguments: @pre_cmacctx *ctx@ = pointer to CMAC context block \
223 * @void *t@ = where to write the tag \
224 * \
225 * Returns: --- \
226 * \
227 * Use: Finishes a MAC operation and produces the tag. The \
228 * context is clobbered and can't be used for anything \
229 * useful any more. \
230 */ \
231 \
232 void pre##_cmacdone(pre##_cmacctx *ctx, void *t) \
233 { \
234 pre##_omacdone(&ctx->k.ctx, ctx->k.m0, ctx->k.m1, \
235 ctx->a, ctx->b, ctx->off); \
236 BLKC_STORE(PRE, t, ctx->a); \
237 } \
238 \
239 /* --- Generic MAC interface --- */ \
240 \
241 static const gmac_ops gkops; \
242 static const ghash_ops gops; \
243 \
244 typedef struct gkctx { \
245 gmac m; \
246 pre##_cmackey k; \
247 } gkctx; \
248 \
249 typedef struct gctx { \
250 ghash h; \
251 pre##_cmacctx c; \
252 octet buf[PRE##_BLKSZ]; \
253 } gctx; \
254 \
255 static ghash *gkinit(gmac *m) \
256 { \
257 gkctx *gk = (gkctx *)m; \
258 gctx *g = S_CREATE(gctx); \
259 g->h.ops = &gops; \
260 pre##_cmacinit(&g->c, &gk->k); \
261 return (&g->h); \
262 } \
263 \
264 static gmac *gkey(const void *k, size_t sz) \
265 { \
266 gkctx *gk = S_CREATE(gkctx); \
267 gk->m.ops = &gkops; \
268 pre##_cmacsetkey(&gk->k, k, sz); \
269 return (&gk->m); \
270 } \
271 \
272 static void ghhash(ghash *h, const void *p, size_t sz) \
273 { gctx *g = (gctx *)h; pre##_cmachash(&g->c, p, sz); } \
274 \
275 static octet *ghdone(ghash *h, void *buf) \
276 { \
277 gctx *g = (gctx *)h; \
278 if (!buf) buf = g->buf; \
279 pre##_cmacdone(&g->c, buf); \
280 return (buf); \
281 } \
282 \
283 static ghash *ghcopy(ghash *h) \
284 { \
285 gctx *g = (gctx *)h; \
286 gctx *gg = S_CREATE(gctx); \
287 memcpy(gg, g, sizeof(gctx)); \
288 return (&gg->h); \
289 } \
290 \
291 static void ghdestroy(ghash *h) \
292 { gctx *g = (gctx *)h; BURN(*g); S_DESTROY(g); } \
293 \
294 static void gkdestroy(gmac *m) \
295 { gkctx *gk = (gkctx *)m; BURN(*gk); S_DESTROY(gk); } \
296 \
297 static ghash *ghinit(void) \
298 { \
299 assert(((void)"Attempt to instantiate an unkeyed MAC", 0)); \
300 return (0); \
301 } \
302 \
303 const gcmac pre##_cmac = \
304 { name "-cmac", PRE##_BLKSZ, pre##_keysz, gkey }; \
305 static const gmac_ops gkops = { &pre##_cmac, gkinit, gkdestroy }; \
306 static const gchash gch = { name "-cmac", PRE##_BLKSZ, ghinit }; \
307 static const ghash_ops gops = \
308 { &gch, ghhash, ghdone, ghdestroy, ghcopy }; \
309 \
310 CMAC_TESTX(PRE, pre, name, fname)
311
312 #define CMAC_TEST(PRE, pre) HMAC_TESTX(PRE, pre, #pre, #pre)
313
314 /* --- @CMAC_TEST@ --- *
315 *
316 * Arguments: @PRE@, @pre@ = prefixes for the underlying block cipher
317 *
318 * Use: Standard test rig for CMAC functions.
319 */
320
321 #ifdef TEST_RIG
322
323 #include <stdio.h>
324
325 #include <mLib/dstr.h>
326 #include <mLib/macros.h>
327 #include <mLib/quis.h>
328 #include <mLib/testrig.h>
329
330 #define CMAC_TESTX(PRE, pre, name, fname) \
331 \
332 static int macverify(dstr *v) \
333 { \
334 pre##_cmacctx cctx; \
335 pre##_cmackey ckey; \
336 int ok = 1; \
337 int i; \
338 octet *p; \
339 int szs[] = { 1, 7, 192, -1, 0 }, *ip; \
340 size_t csz; \
341 dstr d; \
342 \
343 dstr_create(&d); \
344 dstr_ensure(&d, PRE##_BLKSZ); \
345 d.len = PRE##_BLKSZ; \
346 \
347 pre##_cmacsetkey(&ckey, v[0].buf, v[0].len); \
348 \
349 for (ip = szs; *ip; ip++) { \
350 i = *ip; \
351 csz = v[1].len; \
352 if (i == -1) \
353 i = csz; \
354 if (i > csz) \
355 continue; \
356 p = (octet *)v[1].buf; \
357 pre##_cmacinit(&cctx, &ckey); \
358 while (csz) { \
359 if (i > csz) \
360 i = csz; \
361 pre##_cmachash(&cctx, p, i); \
362 p += i; \
363 csz -= i; \
364 } \
365 pre##_cmacdone(&cctx, d.buf); \
366 if (MEMCMP(d.buf, !=, v[2].buf, PRE##_BLKSZ)) { \
367 printf("\nfail:\n\tstep = %i\n\tkey = ", *ip); \
368 type_hex.dump(&v[0], stdout); \
369 fputs("\n\tinput = ", stdout); \
370 type_hex.dump(&v[1], stdout); \
371 fputs("\n\texpected = ", stdout); \
372 type_hex.dump(&v[2], stdout); \
373 fputs("\n\tcomputed = ", stdout); \
374 type_hex.dump(&d, stdout); \
375 putchar('\n'); \
376 ok = 0; \
377 } \
378 } \
379 \
380 dstr_destroy(&d); \
381 return (ok); \
382 } \
383 \
384 static test_chunk macdefs[] = { \
385 { name "-cmac", macverify, \
386 { &type_hex, &type_hex, &type_hex, 0 } }, \
387 { 0, 0, { 0 } } \
388 }; \
389 \
390 int main(int argc, char *argv[]) \
391 { \
392 ego(argv[0]); \
393 test_run(argc, argv, macdefs, SRCDIR"/t/" fname); \
394 return (0); \
395 }
396
397 #else
398 # define CMAC_TESTX(PRE, pre, name, fname)
399 #endif
400
401 /*----- That's all, folks -------------------------------------------------*/
402
403 #ifdef __cplusplus
404 }
405 #endif
406
407 #endif