chiark / gitweb /
debian/.gitignore: Ignore `catacomb-data' directory.
[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/quis.h>
327 #include <mLib/testrig.h>
328
329 #define CMAC_TESTX(PRE, pre, name, fname)                               \
330                                                                         \
331 static int macverify(dstr *v)                                           \
332 {                                                                       \
333   pre##_cmacctx cctx;                                                   \
334   pre##_cmackey ckey;                                                   \
335   int ok = 1;                                                           \
336   int i;                                                                \
337   octet *p;                                                             \
338   int szs[] = { 1, 7, 192, -1, 0 }, *ip;                                \
339   size_t csz;                                                           \
340   dstr d;                                                               \
341                                                                         \
342   dstr_create(&d);                                                      \
343   dstr_ensure(&d, PRE##_BLKSZ);                                         \
344   d.len = PRE##_BLKSZ;                                                  \
345                                                                         \
346   pre##_cmacsetkey(&ckey, v[0].buf, v[0].len);                          \
347                                                                         \
348   for (ip = szs; *ip; ip++) {                                           \
349     i = *ip;                                                            \
350     csz = v[1].len;                                                     \
351     if (i == -1)                                                        \
352       i = csz;                                                          \
353     if (i > csz)                                                        \
354       continue;                                                         \
355     p = (octet *)v[1].buf;                                              \
356     pre##_cmacinit(&cctx, &ckey);                                       \
357     while (csz) {                                                       \
358       if (i > csz)                                                      \
359         i = csz;                                                        \
360       pre##_cmachash(&cctx, p, i);                                      \
361       p += i;                                                           \
362       csz -= i;                                                         \
363     }                                                                   \
364     pre##_cmacdone(&cctx, d.buf);                                       \
365     if (memcmp(d.buf, v[2].buf, PRE##_BLKSZ) != 0) {                    \
366       printf("\nfail:\n\tstep = %i\n\tkey = ", *ip);                    \
367       type_hex.dump(&v[0], stdout);                                     \
368       fputs("\n\tinput = ", stdout);                                    \
369       type_hex.dump(&v[1], stdout);                                     \
370       fputs("\n\texpected = ", stdout);                                 \
371       type_hex.dump(&v[2], stdout);                                     \
372       fputs("\n\tcomputed = ", stdout);                                 \
373       type_hex.dump(&d, stdout);                                        \
374       putchar('\n');                                                    \
375       ok = 0;                                                           \
376     }                                                                   \
377   }                                                                     \
378                                                                         \
379   dstr_destroy(&d);                                                     \
380   return (ok);                                                          \
381 }                                                                       \
382                                                                         \
383 static test_chunk macdefs[] = {                                         \
384   { name "-cmac", macverify,                                            \
385     { &type_hex, &type_hex, &type_hex, 0 } },                           \
386   { 0, 0, { 0 } }                                                       \
387 };                                                                      \
388                                                                         \
389 int main(int argc, char *argv[])                                        \
390 {                                                                       \
391   ego(argv[0]);                                                         \
392   test_run(argc, argv, macdefs, SRCDIR"/t/" fname);                     \
393   return (0);                                                           \
394 }
395
396 #else
397 #  define CMAC_TESTX(PRE, pre, name, fname)
398 #endif
399
400 /*----- That's all, folks -------------------------------------------------*/
401
402 #ifdef __cplusplus
403   }
404 #endif
405
406 #endif