chiark / gitweb /
progs/mkphrase.c: Fix trailing spaces in usage message.
[catacomb] / symm / ccm-def.h
1 /* -*-c-*-
2  *
3  * The CCM authenticated-encryption mode
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_CCM_DEF_H
29 #define CATACOMB_CCM_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_CT_H
51 #  include "ct.h"
52 #endif
53
54 #ifndef CATACOMB_KEYSZ_H
55 #  include "keysz.h"
56 #endif
57
58 #ifndef CATACOMB_PARANOIA_H
59 #  include "paranoia.h"
60 #endif
61
62 #ifndef CATACOMB_RSVR_H
63 #  include "rsvr.h"
64 #endif
65
66 /*----- Common machinery --------------------------------------------------*/
67
68 /* --- @ccm_check@ --- *
69  *
70  * Arguments:   @const ccm_params *p@ = pointer to parameters
71  *
72  * Returns:     True (nonzero) if the parameters are OK; false (zero) if
73  *              there's a problem.
74  *
75  * Use:         Verify that the CCM parameters are acceptable.
76  */
77
78 extern int ccm_check(const ccm_params */*p*/);
79
80 /* --- @ccm_fmthdr@ --- *
81  *
82  * Arguments:   @const ccm_params *p@ = pointer to parameters
83  *              @octet *b@ = block-size buffer to write header
84  *              @const void *n@ = pointer to nonce
85  *
86  * Returns:     ---
87  *
88  * Use:         Format a MAC header block.
89  */
90
91 extern void ccm_fmthdr(const ccm_params */*p*/,
92                        octet */*b*/, const void */*n*/);
93
94 /* --- @ccm_fmtctr@ --- *
95  *
96  * Arguments:   @const ccm_params *p@ = pointer to parameters
97  *              @octet *b@ = block-size buffer to write header
98  *              @const void *n@ = pointer to nonce
99  *
100  * Returns:     ---
101  *
102  * Use:         Format an initial counter block.
103  */
104
105 extern void ccm_fmtctr(const ccm_params */*p*/,
106                        octet */*b*/, const void */*n*/);
107
108 /*----- Macros ------------------------------------------------------------*/
109
110 /* --- @CCM_DEF@ --- *
111  *
112  * Arguments:   @PRE@, @pre@ = prefixes for the underlying block cipher
113  *
114  * Use:         Creates an implementation for the CCM authenticated-
115  *              encryption mode.
116  */
117
118 #define CCM_DEF(PRE, pre) CCM_DEFX(PRE, pre, #pre, #pre)
119
120 #define CCM_DEFX(PRE, pre, name, fname)                                 \
121                                                                         \
122 const octet pre##_ccmnoncesz[] =                                        \
123   { KSZ_RANGE, PRE##_BLKSZ/2 - (PRE##_BLKSZ <= 16 ? 1 : 2),             \
124     CCM_NSZMIN(PRE), CCM_NSZMAX(PRE), 1 };                              \
125 const octet pre##_ccmtagsz[] =                                          \
126   { KSZ_RANGE, CCM_TSZMAX(PRE),                                         \
127     CCM_TSZMIN(PRE), CCM_TSZMAX(PRE), PRE##_BLKSZ == 16 ? 2 : 1 };      \
128                                                                         \
129 static const rsvr_policy pre##_ccmpolicy =                              \
130   { RSVRF_FULL, PRE##_BLKSZ, PRE##_BLKSZ };                             \
131                                                                         \
132 /* --- @pre_ccminthash@ --- *                                           \
133  *                                                                      \
134  * Arguments:   @pre_ccmctx *ctx@ = pointer to context block            \
135  *              @const void *p@ = pointer to material to hash           \
136  *              @size_t sz@ = size of the input buffer                  \
137  *                                                                      \
138  * Returns:     ---                                                     \
139  *                                                                      \
140  * Use:         Internal operation for feeding stuff into the CBC-MAC   \
141  *              context.                                                \
142  */                                                                     \
143                                                                         \
144 static void pre##_ccminthash(pre##_ccmctx *ctx,                         \
145                              const void *p, size_t sz)                  \
146 {                                                                       \
147   rsvr_state st;                                                        \
148   const octet *q;                                                       \
149                                                                         \
150   rsvr_setup(&st, &pre##_ccmpolicy, ctx->b, &ctx->off, p, sz);          \
151   RSVR_DO(&st) while ((q = RSVR_NEXT(&st, PRE##_BLKSZ)) != 0) {         \
152     BLKC_XLOAD(PRE, ctx->a, q);                                         \
153     pre##_eblk(&ctx->k, ctx->a, ctx->a);                                \
154   }                                                                     \
155 }                                                                       \
156                                                                         \
157 /* --- @pre_ccminit@ --- *                                              \
158  *                                                                      \
159  * Arguments:   @pre_ccmctx *aad@ = pointer to CCM context              \
160  *              @const pre_ctx *k@ = pointer to key material            \
161  *              @const void *n@ = pointer to nonce                      \
162  *              @size_t nsz@ = size of the nonce                        \
163  *              @size_t hsz@ = size of the AAD                          \
164  *              @size_t msz@ = size of the message/ciphertext           \
165  *              @size_t tsz@ = size of the tag to produce               \
166  *                                                                      \
167  * Returns:     Zero on success; nonzero if the parameters are invalid. \
168  *                                                                      \
169  * Use:         Initialize an CCM operation context with a given key.   \
170  *                                                                      \
171  *              The original key needn't be kept around any more.       \
172  */                                                                     \
173                                                                         \
174 int pre##_ccminit(pre##_ccmctx *ctx, const pre##_ctx *k,                \
175                   const void *n, size_t nsz,                            \
176                   size_t hsz, size_t msz, size_t tsz)                   \
177   { ctx->k = *k; return (pre##_ccmreinit(ctx, n, nsz, hsz, msz, tsz)); } \
178                                                                         \
179 /* --- @pre_ccmreinit@ --- *                                            \
180  *                                                                      \
181  * Arguments:   @pre_ccmctx *ctx@ = pointer to CCM context              \
182  *              @const void *n@ = pointer to nonce                      \
183  *              @size_t nsz@ = size of nonce                            \
184  *              @size_t hsz@ = size of the AAD                          \
185  *              @size_t msz@ = size of the message/ciphertext           \
186  *              @size_t tsz@ = size of the tag to produce               \
187  *                                                                      \
188  * Returns:     Zero on success; nonzero if the parameters are invalid. \
189  *                                                                      \
190  * Use:         Reinitialize an CCM operation context, changing the     \
191  *              nonce.                                                  \
192  */                                                                     \
193                                                                         \
194 int pre##_ccmreinit(pre##_ccmctx *ctx, const void *n, size_t nsz,       \
195                     size_t hsz, size_t msz, size_t tsz)                 \
196 {                                                                       \
197   kludge64 t;                                                           \
198   octet b[12];                                                          \
199   size_t sz;                                                            \
200                                                                         \
201   /* Set up the parameters and check that they make sense. */           \
202   ctx->p.hsz = hsz; ctx->p.msz = msz;                                   \
203   ctx->p.bsz = PRE##_BLKSZ; ctx->p.nsz = nsz; ctx->p.tsz = tsz;         \
204   if (!ccm_check(&ctx->p)) return (-1);                                 \
205                                                                         \
206   /* Prepare the counter and the final MAC mask.  The initial counter   \
207    * is used to make the MAC mask, so generate that, keeping it for     \
208    * later.                                                             \
209    */                                                                   \
210   ccm_fmtctr(&ctx->p, ctx->b, n);                                       \
211   BLKC_LOAD(PRE, ctx->c, ctx->b);                                       \
212   pre##_eblk(&ctx->k, ctx->c, ctx->s0);                                 \
213                                                                         \
214   /* Prepare the MAC header and leave it in the buffer. */              \
215   ccm_fmthdr(&ctx->p, ctx->b, n);                                       \
216   BLKC_ZERO(PRE, ctx->a);                                               \
217                                                                         \
218   /* Initialize our state.  The buffer is currently full (with the      \
219    * MAC header), and we're always awaiting AAD, though we've not yet   \
220    * seen any.  (Even if we're not expecting AAD, this will trigger     \
221    * appropriate initialization when encryption or decryption begins.)  \
222    */                                                                   \
223   ctx->off = PRE##_BLKSZ; ctx->i = 0;                                   \
224   ctx->st = CCMST_AAD;                                                  \
225                                                                         \
226   /* If there's AAD to come, then do the AAD framing.  This aligns      \
227    * badly with the blocking, so feed the framing in the hard way.      \
228    */                                                                   \
229   if (hsz) {                                                            \
230     if (hsz < 0xfffe)                                                   \
231       { STORE16(b, hsz); sz = 2; }                                      \
232     else if (hsz <= MASK32)                                             \
233       { b[0] = 0xff; b[1] = 0xfe; STORE32(b + 2, hsz); sz = 6; }        \
234     else {                                                              \
235       b[0] = b[1] = 0xff;                                               \
236       ASSIGN64(t, hsz); STORE64_(b + 2, t);                             \
237       sz = 10;                                                          \
238     }                                                                   \
239     pre##_ccminthash(ctx, b, sz);                                       \
240   }                                                                     \
241                                                                         \
242   /* All done. */                                                       \
243   return (0);                                                           \
244 }                                                                       \
245                                                                         \
246 /* --- @pre_ccmaadhash@ --- *                                           \
247  *                                                                      \
248  * Arguments:   @pre_ccmctx *ctx@ = pointer to AAD context              \
249  *              @const void *p@ = pointer to AAD material               \
250  *              @size_t sz@ = length of AAD material                    \
251  *                                                                      \
252  * Returns:     ---                                                     \
253  *                                                                      \
254  * Use:         Feeds AAD into the context.  This must be done before   \
255  *              any of the message/ciphertext is processed because CCM  \
256  *              is really annoying like that.                           \
257  */                                                                     \
258                                                                         \
259 void pre##_ccmaadhash(pre##_ccmctx *ctx, const void *p, size_t sz)      \
260 {                                                                       \
261   assert(ctx->st == CCMST_AAD);                                         \
262   assert(sz <= ctx->p.hsz - ctx->i);                                    \
263   ctx->i += sz;                                                         \
264   pre##_ccminthash(ctx, p, sz);                                         \
265 }                                                                       \
266                                                                         \
267 /* --- @pre_ccmencdecsetup@ --- *                                       \
268  *                                                                      \
269  * Arguments:   @pre_ccmctx *ctx@ = pointer to context block            \
270  *              @size_t sz@ = size of message block                     \
271  *                                                                      \
272  * Returns:     ---                                                     \
273  *                                                                      \
274  * Use:         Prepares for an encrypt or decryption operation,        \
275  *              transitioning from the AAD state and updating the       \
276  *              message size.                                           \
277  */                                                                     \
278                                                                         \
279 static void pre##_ccmencdecsetup(pre##_ccmctx *ctx, size_t sz)          \
280 {                                                                       \
281   if (ctx->st != CCMST_MSG) {                                           \
282     /* Make sure we're currently in the AAD state and we've seen all of \
283      * the AAD we expected.                                             \
284      */                                                                 \
285     assert(ctx->st == CCMST_AAD);                                       \
286     assert(ctx->i == ctx->p.hsz);                                       \
287                                                                         \
288     /* Pad the final AAD block out until we hit a block boundary.  Note \
289      * that we don't cycle the block cipher here: instead, leave the    \
290      * buffer full so that we do that next time.                        \
291      */                                                                 \
292     memset(ctx->b + ctx->off, 0, PRE##_BLKSZ - ctx->off);               \
293     ctx->off = PRE##_BLKSZ;                                             \
294                                                                         \
295     /* Now we're ready to process the message text. */                  \
296     ctx->st = CCMST_MSG; ctx->i = 0;                                    \
297   }                                                                     \
298                                                                         \
299   /* Update the size. */                                                \
300   assert(sz <= ctx->p.msz - ctx->i);                                    \
301   ctx->i += sz;                                                         \
302 }                                                                       \
303                                                                         \
304 /* --- @pre_ccmencrypt@ --- *                                           \
305  *                                                                      \
306  * Arguments:   @pre_ccmctx *ctx@ = pointer to CCM operation context    \
307  *              @const void *src@ = pointer to plaintext message chunk  \
308  *              @size_t sz@ = size of the plaintext                     \
309  *              @buf *dst@ = a buffer to write the ciphertext to        \
310  *                                                                      \
311  * Returns:     Zero on success; @-1@ on failure.                       \
312  *                                                                      \
313  * Use:         Encrypts a chunk of a plaintext message, writing a      \
314  *              chunk of ciphertext to the output buffer and updating   \
315  *              the operation state.                                    \
316  *                                                                      \
317  *              For CCM, we always write a ciphertext chunk the same    \
318  *              size as the plaintext.  The messing about with @buf@    \
319  *              objects makes the interface consistent with other AEAD  \
320  *              schemes which can't do this.                            \
321  */                                                                     \
322                                                                         \
323 int pre##_ccmencrypt(pre##_ccmctx *ctx,                                 \
324                      const void *src, size_t sz, buf *dst)              \
325 {                                                                       \
326   rsvr_plan plan;                                                       \
327   uint32 t[PRE##_BLKSZ/4], u[PRE##_BLKSZ];                              \
328   const octet *p = src;                                                 \
329   octet *q, *r, y;                                                      \
330                                                                         \
331   /* Allocate space for the ciphertext. */                              \
332   if (sz) { q = buf_get(dst, sz); if (!q) return (-1); }                \
333   else q = 0;                                                           \
334                                                                         \
335   /* Set stuff up. */                                                   \
336   pre##_ccmencdecsetup(ctx, sz);                                        \
337                                                                         \
338   /* Determine the buffering plan.  Our buffer is going to do double-   \
339    * duty here.  The end portion is going to contain mask from the      \
340    * encrypted counter which we mix into the plaintext to encrypt it;   \
341    * the start portion, which originally mask bytes we've already used, \
342    * will hold the input plaintext, which will eventually be            \
343    * collected into the CBC-MAC state.                                  \
344    */                                                                   \
345   rsvr_mkplan(&plan, &pre##_ccmpolicy, ctx->off, sz);                   \
346                                                                         \
347   /* Initial portion, fulfilled from the buffer.  If the buffer is      \
348    * empty, then that means that we haven't yet encrypted the current   \
349    * counter, so we should do that and advance it.                      \
350    */                                                                   \
351   if (plan.head) {                                                      \
352     if (!ctx->off) {                                                    \
353       BLKC_BSTEP(PRE, ctx->c); pre##_eblk(&ctx->k, ctx->c, t);          \
354       BLKC_STORE(PRE, ctx->b, t);                                       \
355     }                                                                   \
356     r = ctx->b + ctx->off; ctx->off += plan.head;                       \
357     while (plan.head--) { y = *p++; *q++ = y ^ *r; *r++ = y; }          \
358   }                                                                     \
359                                                                         \
360   /* If we've filled up the buffer then we need to cycle the MAC and    \
361    * reset the offset.                                                  \
362    */                                                                   \
363   if (plan.from_rsvr) {                                                 \
364     BLKC_XLOAD(PRE, ctx->a, ctx->b);                                    \
365     pre##_eblk(&ctx->k, ctx->a, ctx->a);                                \
366     ctx->off = 0;                                                       \
367   }                                                                     \
368                                                                         \
369   /* Now to process the main body of the input. */                      \
370   while (plan.from_input) {                                             \
371     BLKC_BSTEP(PRE, ctx->c); pre##_eblk(&ctx->k, ctx->c, t);            \
372     BLKC_LOAD(PRE, u, p); p += PRE##_BLKSZ;                             \
373     BLKC_XSTORE(PRE, q, t, u); q += PRE##_BLKSZ;                        \
374     BLKC_XMOVE(PRE, ctx->a, u); pre##_eblk(&ctx->k, ctx->a, ctx->a);    \
375     plan.from_input -= PRE##_BLKSZ;                                     \
376   }                                                                     \
377                                                                         \
378   /* Finally, deal with any final portion.  If there is one, we know    \
379    * that the buffer is empty: we must have filled it above, or this    \
380    * would all count as `initial' data.                                 \
381    */                                                                   \
382   if (plan.tail) {                                                      \
383     BLKC_BSTEP(PRE, ctx->c); pre##_eblk(&ctx->k, ctx->c, t);            \
384     BLKC_STORE(PRE, ctx->b, t);                                         \
385     r = ctx->b; ctx->off = plan.tail;                                   \
386     while (plan.tail--) { y = *p++; *q++ = y ^ *r; *r++ = y; }          \
387   }                                                                     \
388                                                                         \
389   /* Done. */                                                           \
390   return (0);                                                           \
391 }                                                                       \
392                                                                         \
393 /* --- @pre_ccmdecrypt@ --- *                                           \
394  *                                                                      \
395  * Arguments:   @pre_ccmctx *ctx@ = pointer to CCM operation context    \
396  *              @const void *src@ = pointer to ciphertext message chunk \
397  *              @size_t sz@ = size of the ciphertext                    \
398  *              @buf *dst@ = a buffer to write the plaintext to         \
399  *                                                                      \
400  * Returns:     Zero on success; @-1@ on failure.                       \
401  *                                                                      \
402  * Use:         Decrypts a chunk of a ciphertext message, writing a     \
403  *              chunk of plaintext to the output buffer and updating    \
404  *              the operation state.                                    \
405  *                                                                      \
406  *              For CCM, we always write a plaintext chunk the same     \
407  *              size as the ciphertext.  The messing about with @buf@   \
408  *              objects makes the interface consistent with other AEAD  \
409  *              schemes which can't do this.                            \
410  */                                                                     \
411                                                                         \
412 int pre##_ccmdecrypt(pre##_ccmctx *ctx,                                 \
413                      const void *src, size_t sz, buf *dst)              \
414 {                                                                       \
415   rsvr_plan plan;                                                       \
416   uint32 t[PRE##_BLKSZ/4];                                              \
417   const octet *p = src;                                                 \
418   octet *q, *r, y;                                                      \
419                                                                         \
420   /* Allocate space for the plaintext. */                               \
421   if (sz) { q = buf_get(dst, sz); if (!q) return (-1); }                \
422   else q = 0;                                                           \
423                                                                         \
424   /* Set stuff up. */                                                   \
425   pre##_ccmencdecsetup(ctx, sz);                                        \
426                                                                         \
427   /* Determine the buffering plan.  Our buffer is going to do double-   \
428    * duty here.  The end portion is going to contain mask from the      \
429    * encrypted counter which we mix into the plaintext to encrypt it;   \
430    * the start portion, which originally mask bytes we've already used, \
431    * will hold the recovered plaintext, which will eventually be        \
432    * collected into the CBC-MAC state.                                  \
433    */                                                                   \
434   rsvr_mkplan(&plan, &pre##_ccmpolicy, ctx->off, sz);                   \
435                                                                         \
436   /* Initial portion, fulfilled from the buffer.  If the buffer is      \
437    * empty, then that means that we haven't yet encrypted the current   \
438    * counter, so we should do that and advance it.                      \
439    */                                                                   \
440   if (plan.head) {                                                      \
441     if (!ctx->off) {                                                    \
442       BLKC_BSTEP(PRE, ctx->c); pre##_eblk(&ctx->k, ctx->c, t);          \
443       BLKC_STORE(PRE, ctx->b, t);                                       \
444     }                                                                   \
445     r = ctx->b + ctx->off; ctx->off += plan.head;                       \
446     while (plan.head--) { y = *p++ ^ *r; *q++ = *r++ = y; }             \
447   }                                                                     \
448                                                                         \
449   /* If we've filled up the buffer then we need to cycle the MAC and    \
450    * reset the offset.                                                  \
451    */                                                                   \
452   if (plan.from_rsvr) {                                                 \
453     BLKC_XLOAD(PRE, ctx->a, ctx->b);                                    \
454     pre##_eblk(&ctx->k, ctx->a, ctx->a);                                \
455     ctx->off = 0;                                                       \
456   }                                                                     \
457                                                                         \
458   /* Now to process the main body of the input. */                      \
459   while (plan.from_input) {                                             \
460     BLKC_BSTEP(PRE, ctx->c); pre##_eblk(&ctx->k, ctx->c, t);            \
461     BLKC_XLOAD(PRE, t, p); p += PRE##_BLKSZ;                            \
462     BLKC_STORE(PRE, q, t); q += PRE##_BLKSZ;                            \
463     BLKC_XMOVE(PRE, ctx->a, t); pre##_eblk(&ctx->k, ctx->a, ctx->a);    \
464     plan.from_input -= PRE##_BLKSZ;                                     \
465   }                                                                     \
466                                                                         \
467   /* Finally, deal with any final portion.  If there is one, we know    \
468    * that the buffer is empty: we must have filled it above, or this    \
469    * would all count as `initial' data.                                 \
470    */                                                                   \
471   if (plan.tail) {                                                      \
472     BLKC_BSTEP(PRE, ctx->c); pre##_eblk(&ctx->k, ctx->c, t);            \
473     BLKC_STORE(PRE, ctx->b, t);                                         \
474     r = ctx->b; ctx->off = plan.tail;                                   \
475     while (plan.tail--) { y = *p++ ^ *r; *q++ = *r++ = y; }             \
476   }                                                                     \
477                                                                         \
478   /* Done. */                                                           \
479   return (0);                                                           \
480 }                                                                       \
481                                                                         \
482 /* --- @pre_ccmtag@ --- *                                               \
483  *                                                                      \
484  * Arguments:   @pre_ccmctx *ctx@ = pointer to an CCM context           \
485  *              @octet *t@ = where to write a (full-length) tag         \
486  *              @size_t tsz@ = size of the tag (to check)               \
487  *                                                                      \
488  * Returns:     ---                                                     \
489  *                                                                      \
490  * Use:         Finishes an CCM operation, by calculating the tag.      \
491  */                                                                     \
492                                                                         \
493 static void pre##_ccmtag(pre##_ccmctx *ctx, octet *t, size_t tsz)       \
494 {                                                                       \
495   /* Make sure we're in good shape.  It's just about possible that      \
496    * we're still in the AAD state, but there was no actual message, so  \
497    * handle this situation.                                             \
498    */                                                                   \
499   switch (ctx->st) {                                                    \
500     case CCMST_AAD:                                                     \
501       assert(ctx->i == ctx->p.hsz);                                     \
502       assert(!ctx->p.msz);                                              \
503       break;                                                            \
504     case CCMST_MSG:                                                     \
505       /* hsz already checked in `pre_ccmencdecsetup'. */                \
506       assert(ctx->i == ctx->p.msz);                                     \
507       break;                                                            \
508     default: abort();                                                   \
509   }                                                                     \
510   assert(tsz == ctx->p.tsz);                                            \
511                                                                         \
512   /* Pad the final plaintext block out and cycle the block cipher one   \
513    * last time.                                                         \
514    */                                                                   \
515   memset(ctx->b + ctx->off, 0, PRE##_BLKSZ - ctx->off);                 \
516   BLKC_XLOAD(PRE, ctx->a, ctx->b);                                      \
517   pre##_eblk(&ctx->k, ctx->a, ctx->a);                                  \
518                                                                         \
519   /* Mask the CBC-MAC tag (which prevents the standard extension        \
520    * attack) and store the result.                                      \
521    */                                                                   \
522   BLKC_XSTORE(PRE, t, ctx->a, ctx->s0);                                 \
523 }                                                                       \
524                                                                         \
525 /* --- @pre_ccmencryptdone@ --- *                                       \
526  *                                                                      \
527  * Arguments:   @pre_ccmctx *ctx@ = pointer to an CCM context           \
528  *              @buf *dst@ = buffer for remaining ciphertext            \
529  *              @void *tag@ = where to write the tag                    \
530  *              @size_t tsz@ = length of tag to store                   \
531  *                                                                      \
532  * Returns:     Zero on success; @-1@ on failure.                       \
533  *                                                                      \
534  * Use:         Completes an CCM encryption operation.  The @aad@       \
535  *              pointer may be null if there is no additional           \
536  *              authenticated data.  CCM doesn't buffer ciphertext, but \
537  *              the output buffer is provided anyway for consistency    \
538  *              with other AEAD schemes which don't have this property; \
539  *              the function will fail if the output buffer is broken.  \
540  */                                                                     \
541                                                                         \
542 int pre##_ccmencryptdone(pre##_ccmctx *ctx, buf *dst,                   \
543                          void *tag, size_t tsz)                         \
544 {                                                                       \
545   octet t[PRE##_BLKSZ];                                                 \
546                                                                         \
547   /* Some initial checks. */                                            \
548   if (!BOK(dst)) return (-1);                                           \
549                                                                         \
550   /* Calculate and return the tag. */                                   \
551   pre##_ccmtag(ctx, t, tsz);                                            \
552   memcpy(tag, t, tsz);                                                  \
553                                                                         \
554   /* Done. */                                                           \
555   return (0);                                                           \
556 }                                                                       \
557                                                                         \
558 /* --- @pre_ccmdecryptdone@ --- *                                       \
559  *                                                                      \
560  * Arguments:   @pre_ccmctx *ctx@ = pointer to an CCM context           \
561  *              @buf *dst@ = buffer for remaining plaintext             \
562  *              @const void *tag@ = tag to verify                       \
563  *              @size_t tsz@ = length of tag                            \
564  *                                                                      \
565  * Returns:     @+1@ for complete success; @0@ if tag verification      \
566  *              failed; @-1@ for other kinds of errors.                 \
567  *                                                                      \
568  * Use:         Completes an CCM decryption operation.  The @aad@       \
569  *              pointer may be null if there is no additional           \
570  *              authenticated data.  CCM doesn't buffer plaintext, but  \
571  *              the output buffer is provided anyway for consistency    \
572  *              with other AEAD schemes which don't have this property; \
573  *              the function will fail if the output buffer is broken.  \
574  */                                                                     \
575                                                                         \
576 int pre##_ccmdecryptdone(pre##_ccmctx *ctx, buf *dst,                   \
577                          const void *tag, size_t tsz)                   \
578 {                                                                       \
579   octet t[PRE##_BLKSZ];                                                 \
580                                                                         \
581   /* Some initial checks. */                                            \
582   if (!BOK(dst)) return (-1);                                           \
583                                                                         \
584   /* Calculate and check the tag. */                                    \
585   pre##_ccmtag(ctx, t, tsz);                                            \
586   if (!ct_memeq(tag, t, tsz)) return (0);                               \
587   else return (+1);                                                     \
588 }                                                                       \
589                                                                         \
590 /* --- Generic AEAD interface --- */                                    \
591                                                                         \
592 typedef struct gctx {                                                   \
593   gaead_aad a;                                                          \
594   pre##_ccmctx ctx;                                                     \
595 } gctx;                                                                 \
596                                                                         \
597 static void gahash(gaead_aad *a, const void *h, size_t hsz)             \
598   { gctx *ctx = (gctx *)a; pre##_ccmaadhash(&ctx->ctx, h, hsz); }       \
599                                                                         \
600 static void gadestroy(gaead_aad *a) { ; }                               \
601                                                                         \
602 static const gaead_aadops gaops =                                       \
603   { &pre##_ccm, 0, gahash, gadestroy };                                 \
604                                                                         \
605 typedef struct gectx {                                                  \
606   gaead_enc e;                                                          \
607   gctx g;                                                               \
608 } gectx;                                                                \
609                                                                         \
610 static gaead_aad *geaad(gaead_enc *e)                                   \
611   { gectx *enc = (gectx *)e; return (&enc->g.a); }                      \
612                                                                         \
613 static int gereinit(gaead_enc *e, const void *n, size_t nsz,            \
614                     size_t hsz, size_t msz, size_t tsz)                 \
615 {                                                                       \
616   gectx *enc = (gectx *)e;                                              \
617   return (pre##_ccmreinit(&enc->g.ctx, n, nsz, hsz, msz, tsz));         \
618 }                                                                       \
619                                                                         \
620 static int geenc(gaead_enc *e, const void *m, size_t msz, buf *b)       \
621 {                                                                       \
622   gectx *enc = (gectx *)e;                                              \
623   return (pre##_ccmencrypt(&enc->g.ctx, m, msz, b));                    \
624 }                                                                       \
625                                                                         \
626 static int gedone(gaead_enc *e, const gaead_aad *a,                     \
627                   buf *b, void *t, size_t tsz)                          \
628 {                                                                       \
629   gectx *enc = (gectx *)e;                                              \
630   assert((!a && !enc->g.ctx.p.hsz) || a == &enc->g.a);                  \
631   return (pre##_ccmencryptdone(&enc->g.ctx, b, t, tsz));                \
632 }                                                                       \
633                                                                         \
634 static void gedestroy(gaead_enc *e)                                     \
635   { gectx *enc = (gectx *)e; BURN(*enc); S_DESTROY(enc); }              \
636                                                                         \
637 static const gaead_encops geops =                                       \
638   { &pre##_ccm, geaad, gereinit, geenc, gedone, gedestroy };            \
639                                                                         \
640 typedef struct gdctx {                                                  \
641   gaead_dec d;                                                          \
642   gctx g;                                                               \
643 } gdctx;                                                                \
644                                                                         \
645 static gaead_aad *gdaad(gaead_dec *d)                                   \
646   { gdctx *dec = (gdctx *)d; return (&dec->g.a); }                      \
647                                                                         \
648 static int gdreinit(gaead_dec *d, const void *n, size_t nsz,            \
649                     size_t hsz, size_t csz, size_t tsz)                 \
650 {                                                                       \
651   gdctx *dec = (gdctx *)d;                                              \
652   return (pre##_ccmreinit(&dec->g.ctx, n, nsz, hsz, csz, tsz));         \
653 }                                                                       \
654                                                                         \
655 static int gddec(gaead_dec *d, const void *c, size_t csz, buf *b)       \
656 {                                                                       \
657   gdctx *dec = (gdctx *)d;                                              \
658   return (pre##_ccmdecrypt(&dec->g.ctx, c, csz, b));                    \
659 }                                                                       \
660                                                                         \
661 static int gddone(gaead_dec *d, const gaead_aad *a,                     \
662                   buf *b, const void *t, size_t tsz)                    \
663 {                                                                       \
664   gdctx *dec = (gdctx *)d;                                              \
665   assert((!a && !dec->g.ctx.p.hsz) || a == &dec->g.a);                  \
666   return (pre##_ccmdecryptdone(&dec->g.ctx, b, t, tsz));                \
667 }                                                                       \
668                                                                         \
669 static void gddestroy(gaead_dec *d)                                     \
670   { gdctx *dec = (gdctx *)d; BURN(*dec); S_DESTROY(dec); }              \
671                                                                         \
672 static const gaead_decops gdops =                                       \
673   { &pre##_ccm, gdaad, gdreinit, gddec, gddone, gddestroy };            \
674                                                                         \
675 typedef struct gkctx {                                                  \
676   gaead_key k;                                                          \
677   pre##_ctx key;                                                        \
678 } gkctx;                                                                \
679                                                                         \
680 static gaead_enc *gkenc(const gaead_key *k, const void *n, size_t nsz,  \
681                         size_t hsz, size_t msz, size_t tsz)             \
682 {                                                                       \
683   gkctx *key = (gkctx *)k;                                              \
684   gectx *enc = S_CREATE(gectx);                                         \
685                                                                         \
686   enc->e.ops = &geops; enc->g.a.ops = &gaops;                           \
687   if (pre##_ccminit(&enc->g.ctx, &key->key, n, nsz, hsz, msz, tsz))     \
688     { gedestroy(&enc->e); return (0); }                                 \
689   return (&enc->e);                                                     \
690 }                                                                       \
691                                                                         \
692 static gaead_dec *gkdec(const gaead_key *k, const void *n, size_t nsz,  \
693                         size_t hsz, size_t csz, size_t tsz)             \
694 {                                                                       \
695   gkctx *key = (gkctx *)k;                                              \
696   gdctx *dec = S_CREATE(gdctx);                                         \
697                                                                         \
698   dec->d.ops = &gdops; dec->g.a.ops = &gaops;                           \
699   if (pre##_ccminit(&dec->g.ctx, &key->key, n, nsz, hsz, csz, tsz))     \
700     { gddestroy(&dec->d); return (0); }                                 \
701   return (&dec->d);                                                     \
702 }                                                                       \
703                                                                         \
704 static void gkdestroy(gaead_key *k)                                     \
705   { gkctx *key = (gkctx *)k; BURN(*key); S_DESTROY(key); }              \
706                                                                         \
707 static const gaead_keyops gkops =                                       \
708   { &pre##_ccm, 0, gkenc, gkdec, gkdestroy };                           \
709                                                                         \
710 static gaead_key *gckey(const void *k, size_t ksz)                      \
711 {                                                                       \
712   gkctx *key = S_CREATE(gkctx);                                         \
713   key->k.ops = &gkops;                                                  \
714   pre##_init(&key->key, k, ksz);                                        \
715   return (&key->k);                                                     \
716 }                                                                       \
717                                                                         \
718 const gcaead pre##_ccm = {                                              \
719   name "-ccm",                                                          \
720   pre##_keysz, pre##_ccmnoncesz, pre##_ccmtagsz,                        \
721   PRE##_BLKSZ, 0, 0,                                                    \
722   AEADF_PCHSZ | AEADF_PCMSZ | AEADF_PCTSZ |                             \
723   AEADF_AADNDEP | AEADF_AADFIRST,                                       \
724   gckey                                                                 \
725 };                                                                      \
726                                                                         \
727 CCM_TESTX(PRE, pre, name, fname)
728
729 /*----- Test rig ----------------------------------------------------------*/
730
731 #define CCM_TEST(PRE, pre) CCM_TESTX(PRE, pre, #pre, #pre)
732
733 /* --- @CCM_TEST@ --- *
734  *
735  * Arguments:   @PRE, pre@ = prefixes for the underlying block cipher
736  *
737  * Use:         Standard test rig for CCM functions.
738  */
739
740 #ifdef TEST_RIG
741
742 #include <stdio.h>
743
744 #include <mLib/dstr.h>
745 #include <mLib/macros.h>
746 #include <mLib/quis.h>
747 #include <mLib/testrig.h>
748
749 #define CCM_TESTX(PRE, pre, name, fname)                                \
750                                                                         \
751 static int ccmverify(dstr *v)                                           \
752 {                                                                       \
753   pre##_ctx key;                                                        \
754   pre##_ccmctx ctx;                                                     \
755   int ok = 1, win;                                                      \
756   int i;                                                                \
757   octet *p;                                                             \
758   int szs[] = { 1, 7, 192, -1, 0 }, *ip;                                \
759   size_t hsz, msz;                                                      \
760   dstr d = DSTR_INIT, t = DSTR_INIT;                                    \
761   buf b;                                                                \
762                                                                         \
763   dstr_ensure(&d, v[4].len > v[3].len ? v[4].len : v[3].len);           \
764   dstr_ensure(&t, v[5].len); t.len = v[5].len;                          \
765                                                                         \
766   pre##_init(&key, v[0].buf, v[0].len);                                 \
767                                                                         \
768   for (ip = szs; *ip; ip++) {                                           \
769                                                                         \
770     pre##_ccminit(&ctx, &key, (octet *)v[1].buf, v[1].len,              \
771                   v[2].len, v[3].len, v[5].len);                        \
772                                                                         \
773     i = *ip;                                                            \
774     hsz = v[2].len;                                                     \
775     if (i == -1) i = hsz;                                               \
776     if (i > hsz) continue;                                              \
777     p = (octet *)v[2].buf;                                              \
778     while (hsz) {                                                       \
779       if (i > hsz) i = hsz;                                             \
780       pre##_ccmaadhash(&ctx, p, i);                                     \
781       p += i; hsz -= i;                                                 \
782     }                                                                   \
783                                                                         \
784     buf_init(&b, d.buf, d.sz);                                          \
785     i = *ip;                                                            \
786     msz = v[3].len;                                                     \
787     if (i == -1) i = msz;                                               \
788     if (i > msz) continue;                                              \
789     p = (octet *)v[3].buf;                                              \
790     while (msz) {                                                       \
791       if (i > msz) i = msz;                                             \
792       if (pre##_ccmencrypt(&ctx, p, i, &b)) {                           \
793         puts("!! ccmencrypt reports failure");                          \
794         goto fail_enc;                                                  \
795       }                                                                 \
796       p += i; msz -= i;                                                 \
797     }                                                                   \
798                                                                         \
799     if (pre##_ccmencryptdone(&ctx, &b, (octet *)t.buf, t.len)) {        \
800       puts("!! ccmencryptdone reports failure");                        \
801       goto fail_enc;                                                    \
802     }                                                                   \
803     d.len = BLEN(&b);                                                   \
804                                                                         \
805     if (d.len != v[4].len ||                                            \
806         MEMCMP(d.buf, !=, v[4].buf, v[4].len) ||                        \
807         MEMCMP(t.buf, !=, v[5].buf, v[5].len)) {                        \
808     fail_enc:                                                           \
809       printf("\nfail encrypt:\n\tstep = %i", *ip);                      \
810       fputs("\n\tkey = ", stdout); type_hex.dump(&v[0], stdout);        \
811       fputs("\n\tnonce = ", stdout); type_hex.dump(&v[1], stdout);      \
812       fputs("\n\theader = ", stdout); type_hex.dump(&v[2], stdout);     \
813       fputs("\n\tmessage = ", stdout); type_hex.dump(&v[3], stdout);    \
814       fputs("\n\texp ct = ", stdout); type_hex.dump(&v[4], stdout);     \
815       fputs("\n\tcalc ct = ", stdout); type_hex.dump(&d, stdout);       \
816       fputs("\n\texp tag = ", stdout); type_hex.dump(&v[5], stdout);    \
817       fputs("\n\tcalc tag = ", stdout); type_hex.dump(&t, stdout);      \
818       putchar('\n');                                                    \
819       ok = 0;                                                           \
820     }                                                                   \
821                                                                         \
822     pre##_ccminit(&ctx, &key, (octet *)v[1].buf, v[1].len,              \
823                   v[2].len, v[4].len, v[5].len);                        \
824                                                                         \
825     i = *ip;                                                            \
826     hsz = v[2].len;                                                     \
827     if (i == -1) i = hsz;                                               \
828     if (i > hsz) continue;                                              \
829     p = (octet *)v[2].buf;                                              \
830     while (hsz) {                                                       \
831       if (i > hsz) i = hsz;                                             \
832       pre##_ccmaadhash(&ctx, p, i);                                     \
833       p += i; hsz -= i;                                                 \
834     }                                                                   \
835                                                                         \
836     buf_init(&b, d.buf, d.sz);                                          \
837     i = *ip;                                                            \
838     msz = v[4].len;                                                     \
839     if (i == -1) i = msz;                                               \
840     if (i > msz) continue;                                              \
841     p = (octet *)v[4].buf;                                              \
842     while (msz) {                                                       \
843       if (i > msz) i = msz;                                             \
844       if (pre##_ccmdecrypt(&ctx, p, i, &b)) {                           \
845         puts("!! ccmdecrypt reports failure");                          \
846         win = 0; goto fail_dec;                                         \
847       }                                                                 \
848       p += i; msz -= i;                                                 \
849     }                                                                   \
850                                                                         \
851     win = pre##_ccmdecryptdone(&ctx, &b, (octet *)v[5].buf, v[5].len);  \
852     if (win < 0) {                                                      \
853       puts("!! ccmdecryptdone reports failure");                        \
854       goto fail_dec;                                                    \
855     }                                                                   \
856     d.len = BLEN(&b);                                                   \
857                                                                         \
858     if (d.len != v[3].len || !win ||                                    \
859         MEMCMP(d.buf, !=, v[3].buf, v[3].len)) {                        \
860     fail_dec:                                                           \
861       printf("\nfail decrypt:\n\tstep = %i", *ip);                      \
862       fputs("\n\tkey = ", stdout); type_hex.dump(&v[0], stdout);        \
863       fputs("\n\tnonce = ", stdout); type_hex.dump(&v[1], stdout);      \
864       fputs("\n\theader = ", stdout); type_hex.dump(&v[2], stdout);     \
865       fputs("\n\tciphertext = ", stdout); type_hex.dump(&v[4], stdout); \
866       fputs("\n\texp pt = ", stdout); type_hex.dump(&v[3], stdout);     \
867       fputs("\n\tcalc pt = ", stdout); type_hex.dump(&d, stdout);       \
868       fputs("\n\ttag = ", stdout); type_hex.dump(&v[5], stdout);        \
869       printf("\n\tverify %s", win ? "ok" : "FAILED");                   \
870       putchar('\n');                                                    \
871       ok = 0;                                                           \
872     }                                                                   \
873   }                                                                     \
874                                                                         \
875   dstr_destroy(&d); dstr_destroy(&t);                                   \
876   return (ok);                                                          \
877 }                                                                       \
878                                                                         \
879 static test_chunk aeaddefs[] = {                                        \
880   { name "-ccm", ccmverify,                                             \
881     { &type_hex, &type_hex, &type_hex, &type_hex,                       \
882       &type_hex, &type_hex, 0 } },                                      \
883   { 0, 0, { 0 } }                                                       \
884 };                                                                      \
885                                                                         \
886 int main(int argc, char *argv[])                                        \
887 {                                                                       \
888   ego(argv[0]);                                                         \
889   test_run(argc, argv, aeaddefs, SRCDIR"/t/" fname);                    \
890   return (0);                                                           \
891 }
892
893 #else
894 #  define CCM_TESTX(PRE, pre, name, fname)
895 #endif
896
897 /*----- That's all, folks -------------------------------------------------*/
898
899 #ifdef __cplusplus
900   }
901 #endif
902
903 #endif