symm/*-def.h: Fix repeated garbled commentary by adding the missing word.
[catacomb] / symm / ccm-def.h
CommitLineData
55b6b722
MW
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
78extern 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
91extern 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
105extern 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 \
122const octet pre##_ccmnoncesz[] = \
123 { KSZ_RANGE, PRE##_BLKSZ/2 - (PRE##_BLKSZ <= 16 ? 1 : 2), \
124 CCM_NSZMIN(PRE), CCM_NSZMAX(PRE), 1 }; \
125const octet pre##_ccmtagsz[] = \
126 { KSZ_RANGE, CCM_TSZMAX(PRE), \
127 CCM_TSZMIN(PRE), CCM_TSZMAX(PRE), PRE##_BLKSZ == 16 ? 2 : 1 }; \
128 \
129static 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 \
144static 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 \
174int 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 \
194int 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 \
259void 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 \
279static 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 \
323int 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; \
799e63b4
MW
341 * the start portion, which originally contained mask bytes we've \
342 * already used, will hold the input plaintext, which will \
343 * eventually be collected into the CBC-MAC state. \
55b6b722
MW
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 \
412int 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; \
799e63b4
MW
430 * the start portion, which originally mask contained bytes we've \
431 * already used, will hold the recovered plaintext, which will \
432 * eventually be collected into the CBC-MAC state. \
55b6b722
MW
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 \
493static 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 \
542int 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 \
576int 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 \
592typedef struct gctx { \
593 gaead_aad a; \
594 pre##_ccmctx ctx; \
595} gctx; \
596 \
597static void gahash(gaead_aad *a, const void *h, size_t hsz) \
598 { gctx *ctx = (gctx *)a; pre##_ccmaadhash(&ctx->ctx, h, hsz); } \
599 \
600static void gadestroy(gaead_aad *a) { ; } \
601 \
602static const gaead_aadops gaops = \
603 { &pre##_ccm, 0, gahash, gadestroy }; \
604 \
605typedef struct gectx { \
606 gaead_enc e; \
607 gctx g; \
608} gectx; \
609 \
610static gaead_aad *geaad(gaead_enc *e) \
611 { gectx *enc = (gectx *)e; return (&enc->g.a); } \
612 \
613static 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 \
620static 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 \
626static 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 \
634static void gedestroy(gaead_enc *e) \
635 { gectx *enc = (gectx *)e; BURN(*enc); S_DESTROY(enc); } \
636 \
637static const gaead_encops geops = \
638 { &pre##_ccm, geaad, gereinit, geenc, gedone, gedestroy }; \
639 \
640typedef struct gdctx { \
641 gaead_dec d; \
642 gctx g; \
643} gdctx; \
644 \
645static gaead_aad *gdaad(gaead_dec *d) \
646 { gdctx *dec = (gdctx *)d; return (&dec->g.a); } \
647 \
648static 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 \
655static 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 \
661static 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 \
669static void gddestroy(gaead_dec *d) \
670 { gdctx *dec = (gdctx *)d; BURN(*dec); S_DESTROY(dec); } \
671 \
672static const gaead_decops gdops = \
673 { &pre##_ccm, gdaad, gdreinit, gddec, gddone, gddestroy }; \
674 \
675typedef struct gkctx { \
676 gaead_key k; \
677 pre##_ctx key; \
678} gkctx; \
679 \
680static 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 \
692static 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 \
704static void gkdestroy(gaead_key *k) \
705 { gkctx *key = (gkctx *)k; BURN(*key); S_DESTROY(key); } \
706 \
707static const gaead_keyops gkops = \
708 { &pre##_ccm, 0, gkenc, gkdec, gkdestroy }; \
709 \
710static 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 \
718const 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 \
727CCM_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>
141c1284 745#include <mLib/macros.h>
55b6b722
MW
746#include <mLib/quis.h>
747#include <mLib/testrig.h>
748
749#define CCM_TESTX(PRE, pre, name, fname) \
750 \
751static 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 || \
141c1284
MW
806 MEMCMP(d.buf, !=, v[4].buf, v[4].len) || \
807 MEMCMP(t.buf, !=, v[5].buf, v[5].len)) { \
55b6b722
MW
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 || \
141c1284 859 MEMCMP(d.buf, !=, v[3].buf, v[3].len)) { \
55b6b722
MW
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 \
879static 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 \
886int 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