3 * The EAX authenticated-encryption mode
5 * (c) 2017 Straylight/Edgeware
8 /*----- Licensing notice --------------------------------------------------*
10 * This file is part of Catacomb.
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.
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.
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,
28 #ifndef CATACOMB_EAX_DEF_H
29 #define CATACOMB_EAX_DEF_H
35 /*----- Header files ------------------------------------------------------*/
39 #include <mLib/bits.h>
42 #ifndef CATACOMB_ARENA_H
46 #ifndef CATACOMB_BLKC_H
54 #ifndef CATACOMB_CMAC_H
58 #ifndef CATACOMB_CMAC_DEF_H
59 # include "cmac-def.h"
62 #ifndef CATACOMB_KEYSZ_H
66 #ifndef CATACOMB_PARANOIA_H
67 # include "paranoia.h"
70 #ifndef CATACOMB_RSVR_H
74 /*----- Macros ------------------------------------------------------------*/
76 /* --- @EAX_DEF@ --- *
78 * Arguments: @PRE@, @pre@ = prefixes for the underlying block cipher
80 * Use: Creates an implementation for the EAX authenticated-
84 #define EAX_DEF(PRE, pre) EAX_DEFX(PRE, pre, #pre, #pre)
86 #define EAX_DEFX(PRE, pre, name, fname) \
91 pre##_eaxnoncesz[] = { KSZ_ANY, PRE##_BLKSZ }, \
92 pre##_eaxtagsz[] = { KSZ_RANGE, PRE##_BLKSZ, 0, PRE##_BLKSZ, 1 }; \
94 /* --- @pre_eaxsetkey@ --- * \
96 * Arguments: @pre_eaxkey *key@ = pointer to key block to fill in \
97 * @const void *k@ = pointer to key material \
98 * @size_t ksz@ = size of key material \
102 * Use: Initializes an EAX key block. \
105 void pre##_eaxsetkey(pre##_eaxkey *key, const void *k, size_t ksz) \
107 uint32 t[PRE##_BLKSZ/4]; \
109 /* Initialize the block cipher. */ \
110 pre##_init(&key->ctx, k, ksz); \
112 /* Set up the OMAC masks. */ \
113 pre##_omacmasks(&key->ctx, key->m0, key->m1); \
115 /* Set up the OMAC tweaks. EAX tweaks its MAC by simply stitching \
116 * magic block-wide prefixes %$t_0$%, %$t_1$%, %$t_2$% (which are \
117 * simply the numbers 0, 1, 2) on the front of strings. We can \
118 * accelerate things by caching two values for each tweak: \
120 * * %$v_i = E_K(t_i)$% is the accumulator that results from \
121 * pushing the tweak through the blockcipher, which we'd \
122 * calculate if the original message was nonempty. \
124 * * %$z_i = E_K(t_0 \xor m_0)$% is the tweak with the `full final \
125 * buffer' mask applied, which is the final tag for a final empty \
128 BLKC_BSET(PRE, t, 0); pre##_eblk(&key->ctx, t, key->v0); \
129 BLKC_XMOVE(PRE, t, key->m0); pre##_eblk(&key->ctx, t, key->z0); \
130 BLKC_BSET(PRE, t, 1); pre##_eblk(&key->ctx, t, key->v1); \
131 BLKC_XMOVE(PRE, t, key->m0); pre##_eblk(&key->ctx, t, key->z1); \
132 BLKC_BSET(PRE, t, 2); pre##_eblk(&key->ctx, t, key->v2); \
133 BLKC_XMOVE(PRE, t, key->m0); pre##_eblk(&key->ctx, t, key->z2); \
136 /* --- @pre_eaxaadinit@ --- * \
138 * Arguments: @pre_eaxaadctx *aad@ = pointer to AAD context \
139 * @const pre_eaxkey *key@ = pointer to key block \
143 * Use: Initializes an EAX AAD (`additional authenticated \
144 * data') context associated with a given key. AAD \
145 * contexts can be copied and/or reused, saving time if \
146 * the AAD for a number of messages has a common prefix. \
148 * The @key@ doesn't need to be kept around, though \
149 * usually there'll at least be another copy in some EAX \
150 * operation context because the AAD on its own isn't much \
154 void pre##_eaxaadinit(pre##_eaxaadctx *aad, const pre##_eaxkey *key) \
155 { aad->k = *key; aad->off = 0; BLKC_MOVE(PRE, aad->a, key->v1); } \
157 /* --- @pre_eaxaadhash@ --- * \
159 * Arguments: @pre_eaxaadctx *aad@ = pointer to AAD context \
160 * @const void *p@ = pointer to AAD material \
161 * @size_t sz@ = length of AAD material \
165 * Use: Feeds AAD into the context. \
168 void pre##_eaxaadhash(pre##_eaxaadctx *aad, const void *p, size_t sz) \
173 rsvr_setup(&st, &pre##_omacpolicy, aad->b, &aad->off, p, sz); \
174 RSVR_DO(&st) while ((q = RSVR_NEXT(&st, PRE##_BLKSZ)) != 0) \
175 OMAC_BLOCK(PRE, pre, &aad->k.ctx, aad->a, q); \
178 /* --- @pre_eaxinit@ --- * \
180 * Arguments: @pre_eaxctx *ctx@ = pointer to EAX context \
181 * @const pre_eaxkey *key@ = pointer to key block \
182 * @const void *n@ = pointer to nonce \
183 * @size_t nsz@ = size of nonce \
187 * Use: Initialize an EAX operation context with a given key. \
189 * The original key needn't be kept around any more. \
192 void pre##_eaxinit(pre##_eaxctx *ctx, const pre##_eaxkey *k, \
193 const void *n, size_t nsz) \
194 { ctx->k = *k; pre##_eaxreinit(ctx, n, nsz); } \
196 /* --- @pre_eaxreinit@ --- * \
198 * Arguments: @pre_eaxctx *ctx@ = pointer to EAX context \
199 * @const void *n@ = pointer to nonce \
200 * @size_t nsz@ = size of nonce \
204 * Use: Reinitialize an EAX operation context, changing the \
208 void pre##_eaxreinit(pre##_eaxctx *ctx, const void *n, size_t nsz) \
210 octet b[PRE##_BLKSZ]; \
211 const octet *q = n; \
213 /* Initialize the OMAC context with the right tweak. */ \
214 BLKC_MOVE(PRE, ctx->a, ctx->k.v2); \
217 /* Calculate the initial counter from the nonce. This is OMAC again, \
218 * but this time we know that we're starting from a clean slate and \
219 * we have the whole input in one go, so we don't bother with the \
220 * full reservoir machinery. \
223 BLKC_MOVE(PRE, ctx->c0, ctx->k.z0); \
225 BLKC_MOVE(PRE, ctx->c0, ctx->k.v0); \
226 while (nsz > PRE##_BLKSZ) { \
227 OMAC_BLOCK(PRE, pre, &ctx->k.ctx, ctx->c0, q); \
228 q += PRE##_BLKSZ; nsz -= PRE##_BLKSZ; \
231 pre##_omacdone(&ctx->k.ctx, ctx->k.m0, ctx->k.m1, \
235 /* We must remember the initial counter for the final tag \
236 * calculation. (I conjecture that storing the final counter instead \
237 * would be just as secure, and require less state, but I've not \
238 * proven this, and anyway it wouldn't interoperate.) Copy it to \
239 * make the working counter. \
241 BLKC_MOVE(PRE, ctx->c, ctx->c0); \
244 /* --- @pre_eaxencrypt@ --- * \
246 * Arguments: @pre_eaxctx *ctx@ = pointer to EAX operation context \
247 * @const void *src@ = pointer to plaintext message chunk \
248 * @size_t sz@ = size of the plaintext \
249 * @buf *dst@ = a buffer to write the ciphertext to \
251 * Returns: Zero on success; @-1@ on failure. \
253 * Use: Encrypts a chunk of a plaintext message, writing a \
254 * chunk of ciphertext to the output buffer and updating \
255 * the operation state. \
257 * For EAX, we always write a ciphertext chunk the same \
258 * size as the plaintext. The messing about with @buf@ \
259 * objects makes the interface consistent with other AEAD \
260 * schemes which can't do this. \
263 int pre##_eaxencrypt(pre##_eaxctx *ctx, \
264 const void *src, size_t sz, buf *dst) \
267 uint32 t[PRE##_BLKSZ/4]; \
268 const octet *p = src; \
271 /* Allocate space for the ciphertext. */ \
272 if (sz) { q = buf_get(dst, sz); if (!q) return (-1); } \
275 /* Determine the buffering plan. Our buffer is going to do double- \
276 * duty here. The end portion is going to contain mask from the \
277 * encrypted counter which we mix into the plaintext to encrypt it; \
278 * the start portion, which originally mask bytes we've already used, \
279 * will hold the output ciphertext, which will eventually be \
280 * collected into the OMAC state. \
282 rsvr_mkplan(&plan, &pre##_omacpolicy, ctx->off, sz); \
284 /* Initial portion, fulfilled from the buffer. If the buffer is \
285 * empty, then that means that we haven't yet encrypted the current \
286 * counter, so we should do that and advance it. \
290 pre##_eblk(&ctx->k.ctx, ctx->c, t); BLKC_BSTEP(PRE, ctx->c); \
291 BLKC_STORE(PRE, ctx->b, t); \
293 r = ctx->b + ctx->off; ctx->off += plan.head; \
294 while (plan.head--) { y = *p++ ^ *r; *r++ = *q++ = y; } \
297 /* If we've filled up the buffer then we need to cycle the MAC and \
298 * reset the offset. \
300 if (plan.from_rsvr) { \
301 OMAC_BLOCK(PRE, pre, &ctx->k.ctx, ctx->a, ctx->b); \
305 /* Now to process the main body of the input. We sneakily open-code \
306 * the OMAC part of this. \
308 while (plan.from_input) { \
309 pre##_eblk(&ctx->k.ctx, ctx->c, t); BLKC_BSTEP(PRE, ctx->c); \
310 BLKC_XLOAD(PRE, t, p); p += PRE##_BLKSZ; \
311 BLKC_STORE(PRE, q, t); q += PRE##_BLKSZ; \
312 BLKC_XMOVE(PRE, ctx->a, t); pre##_eblk(&ctx->k.ctx, ctx->a, ctx->a); \
313 plan.from_input -= PRE##_BLKSZ; \
316 /* Finally, deal with any final portion. If there is one, we know \
317 * that the buffer is empty: we must have filled it above, or this \
318 * would all count as `initial' data. \
321 pre##_eblk(&ctx->k.ctx, ctx->c, t); BLKC_BSTEP(PRE, ctx->c); \
322 BLKC_STORE(PRE, ctx->b, t); \
323 r = ctx->b; ctx->off += plan.tail; \
324 while (plan.tail--) { y = *p++ ^ *r; *r++ = *q++ = y; } \
327 /* And we're done. */ \
331 /* --- @pre_eaxdecrypt@ --- * \
333 * Arguments: @pre_eaxctx *ctx@ = pointer to EAX operation context \
334 * @const void *src@ = pointer to ciphertext message chunk \
335 * @size_t sz@ = size of the ciphertext \
336 * @buf *dst@ = a buffer to write the plaintext to \
338 * Returns: Zero on success; @-1@ on failure. \
340 * Use: Decrypts a chunk of a ciphertext message, writing a \
341 * chunk of plaintext to the output buffer and updating \
342 * the operation state. \
344 * For EAX, we always write a plaintext chunk the same \
345 * size as the ciphertext. The messing about with @buf@ \
346 * objects makes the interface consistent with other AEAD \
347 * schemes which can't do this. \
350 int pre##_eaxdecrypt(pre##_eaxctx *ctx, \
351 const void *src, size_t sz, buf *dst) \
354 uint32 t[PRE##_BLKSZ/4], u[PRE##_BLKSZ]; \
355 const octet *p = src; \
358 /* Allocate space for the plaintext. */ \
359 if (sz) { q = buf_get(dst, sz); if (!q) return (-1); } \
362 /* Determine the buffering plan. Our buffer is going to do double- \
363 * duty here. The end portion is going to contain mask from the \
364 * encrypted counter which we mix into the plaintext to encrypt it; \
365 * the start portion, which originally mask bytes we've already used, \
366 * will hold the input ciphertext, which will eventually be \
367 * collected into the OMAC state. \
369 rsvr_mkplan(&plan, &pre##_omacpolicy, ctx->off, sz); \
371 /* Initial portion, fulfilled from the buffer. If the buffer is \
372 * empty, then that means that we haven't yet encrypted the current \
373 * counter, so we should do that and advance it. \
377 pre##_eblk(&ctx->k.ctx, ctx->c, t); BLKC_BSTEP(PRE, ctx->c); \
378 BLKC_STORE(PRE, ctx->b, t); \
380 r = ctx->b + ctx->off; ctx->off += plan.head; \
381 while (plan.head--) { y = *p++; *q++ = y ^ *r; *r++ = y; } \
384 /* If we've filled up the buffer then we need to cycle the MAC and \
385 * reset the offset. \
387 if (plan.from_rsvr) { \
388 OMAC_BLOCK(PRE, pre, &ctx->k.ctx, ctx->a, ctx->b); \
392 /* Now to process the main body of the input. We sneakily open-code \
393 * the OMAC part of this. \
395 while (plan.from_input) { \
396 pre##_eblk(&ctx->k.ctx, ctx->c, t); BLKC_BSTEP(PRE, ctx->c); \
397 BLKC_LOAD(PRE, u, p); p += PRE##_BLKSZ; \
398 BLKC_XSTORE(PRE, q, t, u); q += PRE##_BLKSZ; \
399 BLKC_XMOVE(PRE, ctx->a, u); pre##_eblk(&ctx->k.ctx, ctx->a, ctx->a); \
400 plan.from_input -= PRE##_BLKSZ; \
403 /* Finally, deal with any final portion. If there is one, we know \
404 * that the buffer is empty: we must have filled it above, or this \
405 * would all count as `initial' data. \
408 pre##_eblk(&ctx->k.ctx, ctx->c, t); BLKC_BSTEP(PRE, ctx->c); \
409 BLKC_STORE(PRE, ctx->b, t); \
410 r = ctx->b; ctx->off += plan.tail; \
411 while (plan.tail--) { y = *p++; *q++ = y ^ *r; *r++ = y; } \
414 /* And we're done. */ \
418 /* --- @pre_eaxtag@ --- * \
420 * Arguments: @pre_eaxctx *ctx@ = pointer to an EAX context \
421 * @const pre_eaxaadctx *aad@ = pointer to AAD context, or \
423 * @octet *t@ = where to write a (full-length) tag \
427 * Use: Finishes an EAX operation, by calculating the tag. \
430 static void pre##_eaxtag(pre##_eaxctx *ctx, \
431 const pre##_eaxaadctx *aad, octet *t) \
433 octet b[PRE##_BLKSZ]; \
434 uint32 u[PRE##_BLKSZ/4]; \
436 /* Finish tagging the ciphertext. (The buffer is empty if and only \
437 * if there was no message, since the OMAC reservoir policy leaves \
438 * the buffer full.) \
440 if (!ctx->off) BLKC_MOVE(PRE, ctx->a, ctx->k.z2); \
441 else pre##_omacdone(&ctx->k.ctx, ctx->k.m0, ctx->k.m1, \
442 ctx->a, ctx->b, ctx->off); \
444 /* If there's no AAD, because the pointer is null or no data was \
445 * supplied, then use the cached empty-header tag. Otherwise \
446 * calculate the tag for the AAD. Either way, mix the result into \
447 * ctx->A, and be careful not to modify the AAD context. (Again, the \
448 * buffer is empty if and only if there was no AAD.) \
450 if (!aad || !aad->off) BLKC_XMOVE(PRE, ctx->a, ctx->k.z1); \
452 BLKC_MOVE(PRE, u, aad->a); memcpy(b, aad->b, aad->off); \
453 pre##_omacdone(&ctx->k.ctx, ctx->k.m0, ctx->k.m1, u, b, aad->off); \
454 BLKC_XMOVE(PRE, ctx->a, u); \
457 /* Finally, mix in the initial counter value. */ \
458 BLKC_XMOVE(PRE, ctx->a, ctx->c0); \
461 BLKC_STORE(PRE, t, ctx->a); \
464 /* --- @pre_eaxencryptdone@ --- * \
466 * Arguments: @pre_eaxctx *ctx@ = pointer to an EAX context \
467 * @const pre_eaxaadctx *aad@ = pointer to AAD context, or \
469 * @buf *dst@ = buffer for remaining ciphertext \
470 * @void *tag@ = where to write the tag \
471 * @size_t tsz@ = length of tag to store \
473 * Returns: Zero on success; @-1@ on failure. \
475 * Use: Completes an EAX encryption operation. The @aad@ \
476 * pointer may be null if there is no additional \
477 * authenticated data. EAX doesn't buffer ciphertext, but \
478 * the output buffer is provided anyway for consistency \
479 * with other AEAD schemes which don't have this property; \
480 * the function will fail if the output buffer is broken. \
483 int pre##_eaxencryptdone(pre##_eaxctx *ctx, \
484 const pre##_eaxaadctx *aad, buf *dst, \
485 void *tag, size_t tsz) \
487 octet t[PRE##_BLKSZ]; \
489 if (tsz > PRE##_BLKSZ) return (-1); \
490 if (!BOK(dst)) return (-1); \
491 pre##_eaxtag(ctx, aad, t); memcpy(tag, t, tsz); \
495 /* --- @pre_eaxdecryptdone@ --- * \
497 * Arguments: @pre_eaxctx *ctx@ = pointer to an EAX context \
498 * @const pre_eaxaadctx *aad@ = pointer to AAD context, or \
500 * @buf *dst@ = buffer for remaining plaintext \
501 * @const void *tag@ = tag to verify \
502 * @size_t tsz@ = length of tag \
504 * Returns: @+1@ for complete success; @0@ if tag verification \
505 * failed; @-1@ for other kinds of errors. \
507 * Use: Completes an EAX decryption operation. The @aad@ \
508 * pointer may be null if there is no additional \
509 * authenticated data. EAX doesn't buffer plaintext, but \
510 * the output buffer is provided anyway for consistency \
511 * with other AEAD schemes which don't have this property; \
512 * the function will fail if the output buffer is broken. \
515 int pre##_eaxdecryptdone(pre##_eaxctx *ctx, \
516 const pre##_eaxaadctx *aad, buf *dst, \
517 const void *tag, size_t tsz) \
519 octet t[PRE##_BLKSZ]; \
521 if (tsz > PRE##_BLKSZ) return (-1); \
522 if (!BOK(dst)) return (-1); \
523 pre##_eaxtag(ctx, aad, t); \
524 if (!ct_memeq(tag, t, tsz)) return (0); \
528 /* --- Generic AEAD interface --- */ \
530 typedef struct gactx { \
532 pre##_eaxaadctx aad; \
536 static gaead_aad *gadup(const gaead_aad *a) \
537 { gactx *aad = S_CREATE(gactx); *aad = *(gactx *)a; return (&aad->a); } \
539 static void gahash(gaead_aad *a, const void *h, size_t hsz) \
540 { gactx *aad = (gactx *)a; pre##_eaxaadhash(&aad->aad, h, hsz); } \
542 static void gadestroy(gaead_aad *a) \
543 { gactx *aad = (gactx *)a; BURN(*aad); S_DESTROY(aad); } \
545 static const gaead_aadops gaops = \
546 { &pre##_eax, gadup, gahash, gadestroy }; \
548 static gaead_aad *gaad(const pre##_eaxkey *k) \
550 gactx *aad = S_CREATE(gactx); \
551 aad->a.ops = &gaops; \
552 pre##_eaxaadinit(&aad->aad, k); \
556 typedef struct gectx { \
561 static gaead_aad *geaad(gaead_enc *e) \
562 { gectx *enc = (gectx *)e; return (gaad(&enc->ctx.k)); } \
564 static int gereinit(gaead_enc *e, const void *n, size_t nsz, \
565 size_t hsz, size_t msz, size_t tsz) \
567 gectx *enc = (gectx *)e; \
569 if (tsz > PRE##_BLKSZ) return (-1); \
570 pre##_eaxreinit(&enc->ctx, n, nsz); \
574 static int geenc(gaead_enc *e, const void *m, size_t msz, buf *b) \
576 gectx *enc = (gectx *)e; \
577 return (pre##_eaxencrypt(&enc->ctx, m, msz, b)); \
580 static int gedone(gaead_enc *e, const gaead_aad *a, \
581 buf *b, void *t, size_t tsz) \
583 gectx *enc = (gectx *)e; gactx *aad = (gactx *)a; \
584 assert(!a || a->ops == &gaops); \
585 return (pre##_eaxencryptdone(&enc->ctx, a ? &aad->aad : 0, b, t, tsz)); \
588 static void gedestroy(gaead_enc *e) \
589 { gectx *enc = (gectx *)e; BURN(*enc); S_DESTROY(enc); } \
591 static const gaead_encops geops = \
592 { &pre##_eax, geaad, gereinit, geenc, gedone, gedestroy }; \
594 typedef struct gdctx { \
599 static gaead_aad *gdaad(gaead_dec *d) \
600 { gdctx *dec = (gdctx *)d; return (gaad(&dec->ctx.k)); } \
602 static int gdreinit(gaead_dec *d, const void *n, size_t nsz, \
603 size_t hsz, size_t csz, size_t tsz) \
605 gdctx *dec = (gdctx *)d; \
607 if (tsz > PRE##_BLKSZ) return (-1); \
608 pre##_eaxreinit(&dec->ctx, n, nsz); \
612 static int gddec(gaead_dec *d, const void *c, size_t csz, buf *b) \
614 gdctx *dec = (gdctx *)d; \
615 return (pre##_eaxdecrypt(&dec->ctx, c, csz, b)); \
618 static int gddone(gaead_dec *d, const gaead_aad *a, \
619 buf *b, const void *t, size_t tsz) \
621 gdctx *dec = (gdctx *)d; gactx *aad = (gactx *)a; \
622 assert(!a || a->ops == &gaops); \
623 return (pre##_eaxdecryptdone(&dec->ctx, a ? &aad->aad : 0, b, t, tsz)); \
626 static void gddestroy(gaead_dec *d) \
627 { gdctx *dec = (gdctx *)d; BURN(*dec); S_DESTROY(dec); } \
629 static const gaead_decops gdops = \
630 { &pre##_eax, gdaad, gdreinit, gddec, gddone, gddestroy }; \
632 typedef struct gkctx { \
637 static gaead_aad *gkaad(const gaead_key *k) \
638 { gkctx *key = (gkctx *)k; return (gaad(&key->key)); } \
640 static gaead_enc *gkenc(const gaead_key *k, const void *n, size_t nsz, \
641 size_t hsz, size_t msz, size_t tsz) \
643 gkctx *key = (gkctx *)k; \
646 if (tsz > PRE##_BLKSZ) return (0); \
647 enc = S_CREATE(gectx); enc->e.ops = &geops; \
648 pre##_eaxinit(&enc->ctx, &key->key, n, nsz); \
652 static gaead_dec *gkdec(const gaead_key *k, const void *n, size_t nsz, \
653 size_t hsz, size_t csz, size_t tsz) \
655 gkctx *key = (gkctx *)k; \
658 if (tsz > PRE##_BLKSZ) return (0); \
659 dec = S_CREATE(gdctx); dec->d.ops = &gdops; \
660 pre##_eaxinit(&dec->ctx, &key->key, n, nsz); \
664 static void gkdestroy(gaead_key *k) \
665 { gkctx *key = (gkctx *)k; BURN(*key); S_DESTROY(key); } \
667 static const gaead_keyops gkops = \
668 { &pre##_eax, gkaad, gkenc, gkdec, gkdestroy }; \
670 static gaead_key *gckey(const void *k, size_t ksz) \
672 gkctx *key = S_CREATE(gkctx); \
673 key->k.ops = &gkops; \
674 pre##_eaxsetkey(&key->key, k, ksz); \
678 const gcaead pre##_eax = { \
680 pre##_keysz, pre##_eaxnoncesz, pre##_eaxtagsz, \
681 PRE##_BLKSZ, 0, 0, 0, \
685 EAX_TESTX(PRE, pre, name, fname)
687 /*----- Test rig ----------------------------------------------------------*/
689 #define EAX_TEST(PRE, pre) EAX_TESTX(PRE, pre, #pre, #pre)
691 /* --- @EAX_TEST@ --- *
693 * Arguments: @PRE, pre@ = prefixes for the underlying block cipher
695 * Use: Standard test rig for EAX functions.
702 #include <mLib/dstr.h>
703 #include <mLib/macros.h>
704 #include <mLib/quis.h>
705 #include <mLib/testrig.h>
707 #define EAX_TESTX(PRE, pre, name, fname) \
709 static int eaxverify(dstr *v) \
712 pre##_eaxaadctx aad; \
717 int szs[] = { 1, 7, 192, -1, 0 }, *ip; \
719 dstr d = DSTR_INIT, t = DSTR_INIT; \
722 dstr_ensure(&d, v[4].len > v[3].len ? v[4].len : v[3].len); \
723 dstr_ensure(&t, v[5].len); t.len = v[5].len; \
725 pre##_eaxsetkey(&key, v[0].buf, v[0].len); \
727 for (ip = szs; *ip; ip++) { \
729 pre##_eaxinit(&ctx, &key, (octet *)v[1].buf, v[1].len); \
733 if (i == -1) i = hsz; \
734 if (i > hsz) continue; \
735 p = (octet *)v[2].buf; \
736 pre##_eaxaadinit(&aad, &key); \
738 if (i > hsz) i = hsz; \
739 pre##_eaxaadhash(&aad, p, i); \
743 buf_init(&b, d.buf, d.sz); \
746 if (i == -1) i = msz; \
747 if (i > msz) continue; \
748 p = (octet *)v[3].buf; \
750 if (i > msz) i = msz; \
751 if (pre##_eaxencrypt(&ctx, p, i, &b)) { \
752 puts("!! eaxencrypt reports failure"); \
758 if (pre##_eaxencryptdone(&ctx, &aad, &b, (octet *)t.buf, t.len)) { \
759 puts("!! eaxencryptdone reports failure"); \
764 if (d.len != v[4].len || \
765 MEMCMP(d.buf, !=, v[4].buf, v[4].len) || \
766 MEMCMP(t.buf, !=, v[5].buf, v[5].len)) { \
768 printf("\nfail encrypt:\n\tstep = %i", *ip); \
769 fputs("\n\tkey = ", stdout); type_hex.dump(&v[0], stdout); \
770 fputs("\n\tnonce = ", stdout); type_hex.dump(&v[1], stdout); \
771 fputs("\n\theader = ", stdout); type_hex.dump(&v[2], stdout); \
772 fputs("\n\tmessage = ", stdout); type_hex.dump(&v[3], stdout); \
773 fputs("\n\texp ct = ", stdout); type_hex.dump(&v[4], stdout); \
774 fputs("\n\tcalc ct = ", stdout); type_hex.dump(&d, stdout); \
775 fputs("\n\texp tag = ", stdout); type_hex.dump(&v[5], stdout); \
776 fputs("\n\tcalc tag = ", stdout); type_hex.dump(&t, stdout); \
781 pre##_eaxinit(&ctx, &key, (octet *)v[1].buf, v[1].len); \
783 buf_init(&b, d.buf, d.sz); \
786 if (i == -1) i = msz; \
787 if (i > msz) continue; \
788 p = (octet *)v[4].buf; \
790 if (i > msz) i = msz; \
791 if (pre##_eaxdecrypt(&ctx, p, i, &b)) { \
792 puts("!! eaxdecrypt reports failure"); \
793 win = 0; goto fail_dec; \
798 win = pre##_eaxdecryptdone(&ctx, &aad, &b, \
799 (octet *)v[5].buf, v[5].len); \
801 puts("!! eaxdecryptdone reports failure"); \
806 if (d.len != v[3].len || !win || \
807 MEMCMP(d.buf, !=, v[3].buf, v[3].len)) { \
809 printf("\nfail decrypt:\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\tciphertext = ", stdout); type_hex.dump(&v[4], stdout); \
814 fputs("\n\texp pt = ", stdout); type_hex.dump(&v[3], stdout); \
815 fputs("\n\tcalc pt = ", stdout); type_hex.dump(&d, stdout); \
816 fputs("\n\ttag = ", stdout); type_hex.dump(&v[5], stdout); \
817 printf("\n\tverify %s", win ? "ok" : "FAILED"); \
823 dstr_destroy(&d); dstr_destroy(&t); \
827 static test_chunk aeaddefs[] = { \
828 { name "-eax", eaxverify, \
829 { &type_hex, &type_hex, &type_hex, &type_hex, \
830 &type_hex, &type_hex, 0 } }, \
834 int main(int argc, char *argv[]) \
837 test_run(argc, argv, aeaddefs, SRCDIR"/t/" fname); \
842 # define EAX_TESTX(PRE, pre, name, fname)
845 /*----- That's all, folks -------------------------------------------------*/