progs/perftest.c: Use from Glibc syscall numbers.
[catacomb] / symm / cmac-def.h
CommitLineData
ea054059
MW
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. */ \
90const 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 \
107void 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 \
131void 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 \
165OMAC_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 \
179void 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 \
196void 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 \
210void 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 \
232void 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 \
241static const gmac_ops gkops; \
242static const ghash_ops gops; \
243 \
244typedef struct gkctx { \
245 gmac m; \
246 pre##_cmackey k; \
247} gkctx; \
248 \
249typedef struct gctx { \
250 ghash h; \
251 pre##_cmacctx c; \
252 octet buf[PRE##_BLKSZ]; \
253} gctx; \
254 \
255static 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 \
264static 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 \
272static void ghhash(ghash *h, const void *p, size_t sz) \
273 { gctx *g = (gctx *)h; pre##_cmachash(&g->c, p, sz); } \
274 \
275static 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 \
283static 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 \
291static void ghdestroy(ghash *h) \
292 { gctx *g = (gctx *)h; BURN(*g); S_DESTROY(g); } \
293 \
294static void gkdestroy(gmac *m) \
295 { gkctx *gk = (gkctx *)m; BURN(*gk); S_DESTROY(gk); } \
296 \
297static ghash *ghinit(void) \
298{ \
299 assert(((void)"Attempt to instantiate an unkeyed MAC", 0)); \
300 return (0); \
301} \
302 \
303const gcmac pre##_cmac = \
304 { name "-cmac", PRE##_BLKSZ, pre##_keysz, gkey }; \
305static const gmac_ops gkops = { &pre##_cmac, gkinit, gkdestroy }; \
306static const gchash gch = { name "-cmac", PRE##_BLKSZ, ghinit }; \
307static const ghash_ops gops = \
308 { &gch, ghhash, ghdone, ghdestroy, ghcopy }; \
309 \
310CMAC_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>
141c1284 326#include <mLib/macros.h>
ea054059
MW
327#include <mLib/quis.h>
328#include <mLib/testrig.h>
329
330#define CMAC_TESTX(PRE, pre, name, fname) \
331 \
332static 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); \
141c1284 366 if (MEMCMP(d.buf, !=, v[2].buf, PRE##_BLKSZ)) { \
ea054059
MW
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 \
384static test_chunk macdefs[] = { \
385 { name "-cmac", macverify, \
386 { &type_hex, &type_hex, &type_hex, 0 } }, \
387 { 0, 0, { 0 } } \
388}; \
389 \
390int 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