xref: /freebsd/contrib/bearssl/src/aead/eax.c (revision 2aaf9152a852aba9eb2036b95f4948ee77988826)
1*0957b409SSimon J. Gerraty /*
2*0957b409SSimon J. Gerraty  * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
3*0957b409SSimon J. Gerraty  *
4*0957b409SSimon J. Gerraty  * Permission is hereby granted, free of charge, to any person obtaining
5*0957b409SSimon J. Gerraty  * a copy of this software and associated documentation files (the
6*0957b409SSimon J. Gerraty  * "Software"), to deal in the Software without restriction, including
7*0957b409SSimon J. Gerraty  * without limitation the rights to use, copy, modify, merge, publish,
8*0957b409SSimon J. Gerraty  * distribute, sublicense, and/or sell copies of the Software, and to
9*0957b409SSimon J. Gerraty  * permit persons to whom the Software is furnished to do so, subject to
10*0957b409SSimon J. Gerraty  * the following conditions:
11*0957b409SSimon J. Gerraty  *
12*0957b409SSimon J. Gerraty  * The above copyright notice and this permission notice shall be
13*0957b409SSimon J. Gerraty  * included in all copies or substantial portions of the Software.
14*0957b409SSimon J. Gerraty  *
15*0957b409SSimon J. Gerraty  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16*0957b409SSimon J. Gerraty  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17*0957b409SSimon J. Gerraty  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18*0957b409SSimon J. Gerraty  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
19*0957b409SSimon J. Gerraty  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20*0957b409SSimon J. Gerraty  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21*0957b409SSimon J. Gerraty  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22*0957b409SSimon J. Gerraty  * SOFTWARE.
23*0957b409SSimon J. Gerraty  */
24*0957b409SSimon J. Gerraty 
25*0957b409SSimon J. Gerraty #include "inner.h"
26*0957b409SSimon J. Gerraty 
27*0957b409SSimon J. Gerraty /*
28*0957b409SSimon J. Gerraty  * Implementation Notes
29*0957b409SSimon J. Gerraty  * ====================
30*0957b409SSimon J. Gerraty  *
31*0957b409SSimon J. Gerraty  * The combined CTR + CBC-MAC functions can only handle full blocks,
32*0957b409SSimon J. Gerraty  * so some buffering is necessary. Moreover, EAX has a special padding
33*0957b409SSimon J. Gerraty  * rule for CBC-MAC, which implies that we cannot compute the MAC over
34*0957b409SSimon J. Gerraty  * the last received full block until we know whether we are at the
35*0957b409SSimon J. Gerraty  * end of the data or not.
36*0957b409SSimon J. Gerraty  *
37*0957b409SSimon J. Gerraty  *  - 'ptr' contains a value from 1 to 16, which is the number of bytes
38*0957b409SSimon J. Gerraty  *    accumulated in buf[] that still needs to be processed with the
39*0957b409SSimon J. Gerraty  *    current OMAC computation. Beware that this can go to 16: a
40*0957b409SSimon J. Gerraty  *    complete block cannot be processed until it is known whether it
41*0957b409SSimon J. Gerraty  *    is the last block or not. However, it can never be 0, because
42*0957b409SSimon J. Gerraty  *    OMAC^t works on an input that is at least one-block long.
43*0957b409SSimon J. Gerraty  *
44*0957b409SSimon J. Gerraty  *  - When processing the message itself, CTR encryption/decryption is
45*0957b409SSimon J. Gerraty  *    also done at the same time. The first 'ptr' bytes of buf[] then
46*0957b409SSimon J. Gerraty  *    contains the encrypted bytes, while the last '16 - ptr' bytes of
47*0957b409SSimon J. Gerraty  *    buf[] are the remnants of the stream block, to be used against
48*0957b409SSimon J. Gerraty  *    the next input bytes, when available.
49*0957b409SSimon J. Gerraty  *
50*0957b409SSimon J. Gerraty  *  - The current counter and running CBC-MAC values are kept in 'ctr'
51*0957b409SSimon J. Gerraty  *    and 'cbcmac', respectively.
52*0957b409SSimon J. Gerraty  *
53*0957b409SSimon J. Gerraty  *  - The derived keys for padding are kept in L2 and L4 (double and
54*0957b409SSimon J. Gerraty  *    quadruple of Enc_K(0^n), in GF(2^128), respectively).
55*0957b409SSimon J. Gerraty  */
56*0957b409SSimon J. Gerraty 
57*0957b409SSimon J. Gerraty /*
58*0957b409SSimon J. Gerraty  * Start an OMAC computation; the first block is the big-endian
59*0957b409SSimon J. Gerraty  * representation of the provided value ('val' must fit on one byte).
60*0957b409SSimon J. Gerraty  * We make it a delayed block because it may also be the last one,
61*0957b409SSimon J. Gerraty  */
62*0957b409SSimon J. Gerraty static void
omac_start(br_eax_context * ctx,unsigned val)63*0957b409SSimon J. Gerraty omac_start(br_eax_context *ctx, unsigned val)
64*0957b409SSimon J. Gerraty {
65*0957b409SSimon J. Gerraty 	memset(ctx->cbcmac, 0, sizeof ctx->cbcmac);
66*0957b409SSimon J. Gerraty 	memset(ctx->buf, 0, sizeof ctx->buf);
67*0957b409SSimon J. Gerraty 	ctx->buf[15] = val;
68*0957b409SSimon J. Gerraty 	ctx->ptr = 16;
69*0957b409SSimon J. Gerraty }
70*0957b409SSimon J. Gerraty 
71*0957b409SSimon J. Gerraty /*
72*0957b409SSimon J. Gerraty  * Double a value in finite field GF(2^128), defined with modulus
73*0957b409SSimon J. Gerraty  * X^128+X^7+X^2+X+1.
74*0957b409SSimon J. Gerraty  */
75*0957b409SSimon J. Gerraty static void
double_gf128(unsigned char * dst,const unsigned char * src)76*0957b409SSimon J. Gerraty double_gf128(unsigned char *dst, const unsigned char *src)
77*0957b409SSimon J. Gerraty {
78*0957b409SSimon J. Gerraty 	unsigned cc;
79*0957b409SSimon J. Gerraty 	int i;
80*0957b409SSimon J. Gerraty 
81*0957b409SSimon J. Gerraty 	cc = 0x87 & -((unsigned)src[0] >> 7);
82*0957b409SSimon J. Gerraty 	for (i = 15; i >= 0; i --) {
83*0957b409SSimon J. Gerraty 		unsigned z;
84*0957b409SSimon J. Gerraty 
85*0957b409SSimon J. Gerraty 		z = (src[i] << 1) ^ cc;
86*0957b409SSimon J. Gerraty 		cc = z >> 8;
87*0957b409SSimon J. Gerraty 		dst[i] = (unsigned char)z;
88*0957b409SSimon J. Gerraty 	}
89*0957b409SSimon J. Gerraty }
90*0957b409SSimon J. Gerraty 
91*0957b409SSimon J. Gerraty /*
92*0957b409SSimon J. Gerraty  * Apply padding to the last block, currently in ctx->buf (with
93*0957b409SSimon J. Gerraty  * ctx->ptr bytes), and finalize OMAC computation.
94*0957b409SSimon J. Gerraty  */
95*0957b409SSimon J. Gerraty static void
do_pad(br_eax_context * ctx)96*0957b409SSimon J. Gerraty do_pad(br_eax_context *ctx)
97*0957b409SSimon J. Gerraty {
98*0957b409SSimon J. Gerraty 	unsigned char *pad;
99*0957b409SSimon J. Gerraty 	size_t ptr, u;
100*0957b409SSimon J. Gerraty 
101*0957b409SSimon J. Gerraty 	ptr = ctx->ptr;
102*0957b409SSimon J. Gerraty 	if (ptr == 16) {
103*0957b409SSimon J. Gerraty 		pad = ctx->L2;
104*0957b409SSimon J. Gerraty 	} else {
105*0957b409SSimon J. Gerraty 		ctx->buf[ptr ++] = 0x80;
106*0957b409SSimon J. Gerraty 		memset(ctx->buf + ptr, 0x00, 16 - ptr);
107*0957b409SSimon J. Gerraty 		pad = ctx->L4;
108*0957b409SSimon J. Gerraty 	}
109*0957b409SSimon J. Gerraty 	for (u = 0; u < sizeof ctx->buf; u ++) {
110*0957b409SSimon J. Gerraty 		ctx->buf[u] ^= pad[u];
111*0957b409SSimon J. Gerraty 	}
112*0957b409SSimon J. Gerraty 	(*ctx->bctx)->mac(ctx->bctx, ctx->cbcmac, ctx->buf, sizeof ctx->buf);
113*0957b409SSimon J. Gerraty }
114*0957b409SSimon J. Gerraty 
115*0957b409SSimon J. Gerraty /*
116*0957b409SSimon J. Gerraty  * Apply CBC-MAC on the provided data, with buffering management.
117*0957b409SSimon J. Gerraty  *
118*0957b409SSimon J. Gerraty  * Upon entry, two situations are acceptable:
119*0957b409SSimon J. Gerraty  *
120*0957b409SSimon J. Gerraty  *   ctx->ptr == 0: there is no data to process in ctx->buf
121*0957b409SSimon J. Gerraty  *   ctx->ptr == 16: there is a full block of unprocessed data in ctx->buf
122*0957b409SSimon J. Gerraty  *
123*0957b409SSimon J. Gerraty  * Upon exit, ctx->ptr may be zero only if it was already zero on entry,
124*0957b409SSimon J. Gerraty  * and len == 0. In all other situations, ctx->ptr will be non-zero on
125*0957b409SSimon J. Gerraty  * exit (and may have value 16).
126*0957b409SSimon J. Gerraty  */
127*0957b409SSimon J. Gerraty static void
do_cbcmac_chunk(br_eax_context * ctx,const void * data,size_t len)128*0957b409SSimon J. Gerraty do_cbcmac_chunk(br_eax_context *ctx, const void *data, size_t len)
129*0957b409SSimon J. Gerraty {
130*0957b409SSimon J. Gerraty 	size_t ptr;
131*0957b409SSimon J. Gerraty 
132*0957b409SSimon J. Gerraty 	if (len == 0) {
133*0957b409SSimon J. Gerraty 		return;
134*0957b409SSimon J. Gerraty 	}
135*0957b409SSimon J. Gerraty 	ptr = len & (size_t)15;
136*0957b409SSimon J. Gerraty 	if (ptr == 0) {
137*0957b409SSimon J. Gerraty 		len -= 16;
138*0957b409SSimon J. Gerraty 		ptr = 16;
139*0957b409SSimon J. Gerraty 	} else {
140*0957b409SSimon J. Gerraty 		len -= ptr;
141*0957b409SSimon J. Gerraty 	}
142*0957b409SSimon J. Gerraty 	if (ctx->ptr == 16) {
143*0957b409SSimon J. Gerraty 		(*ctx->bctx)->mac(ctx->bctx, ctx->cbcmac,
144*0957b409SSimon J. Gerraty 			ctx->buf, sizeof ctx->buf);
145*0957b409SSimon J. Gerraty 	}
146*0957b409SSimon J. Gerraty 	(*ctx->bctx)->mac(ctx->bctx, ctx->cbcmac, data, len);
147*0957b409SSimon J. Gerraty 	memcpy(ctx->buf, (const unsigned char *)data + len, ptr);
148*0957b409SSimon J. Gerraty 	ctx->ptr = ptr;
149*0957b409SSimon J. Gerraty }
150*0957b409SSimon J. Gerraty 
151*0957b409SSimon J. Gerraty /* see bearssl_aead.h */
152*0957b409SSimon J. Gerraty void
br_eax_init(br_eax_context * ctx,const br_block_ctrcbc_class ** bctx)153*0957b409SSimon J. Gerraty br_eax_init(br_eax_context *ctx, const br_block_ctrcbc_class **bctx)
154*0957b409SSimon J. Gerraty {
155*0957b409SSimon J. Gerraty 	unsigned char tmp[16], iv[16];
156*0957b409SSimon J. Gerraty 
157*0957b409SSimon J. Gerraty 	ctx->vtable = &br_eax_vtable;
158*0957b409SSimon J. Gerraty 	ctx->bctx = bctx;
159*0957b409SSimon J. Gerraty 
160*0957b409SSimon J. Gerraty 	/*
161*0957b409SSimon J. Gerraty 	 * Encrypt a whole-zero block to compute L2 and L4.
162*0957b409SSimon J. Gerraty 	 */
163*0957b409SSimon J. Gerraty 	memset(tmp, 0, sizeof tmp);
164*0957b409SSimon J. Gerraty 	memset(iv, 0, sizeof iv);
165*0957b409SSimon J. Gerraty 	(*bctx)->ctr(bctx, iv, tmp, sizeof tmp);
166*0957b409SSimon J. Gerraty 	double_gf128(ctx->L2, tmp);
167*0957b409SSimon J. Gerraty 	double_gf128(ctx->L4, ctx->L2);
168*0957b409SSimon J. Gerraty }
169*0957b409SSimon J. Gerraty 
170*0957b409SSimon J. Gerraty /* see bearssl_aead.h */
171*0957b409SSimon J. Gerraty void
br_eax_capture(const br_eax_context * ctx,br_eax_state * st)172*0957b409SSimon J. Gerraty br_eax_capture(const br_eax_context *ctx, br_eax_state *st)
173*0957b409SSimon J. Gerraty {
174*0957b409SSimon J. Gerraty 	/*
175*0957b409SSimon J. Gerraty 	 * We capture the three OMAC* states _after_ processing the
176*0957b409SSimon J. Gerraty 	 * initial block (assuming that nonce, message and AAD are
177*0957b409SSimon J. Gerraty 	 * all non-empty).
178*0957b409SSimon J. Gerraty 	 */
179*0957b409SSimon J. Gerraty 	int i;
180*0957b409SSimon J. Gerraty 
181*0957b409SSimon J. Gerraty 	memset(st->st, 0, sizeof st->st);
182*0957b409SSimon J. Gerraty 	for (i = 0; i < 3; i ++) {
183*0957b409SSimon J. Gerraty 		unsigned char tmp[16];
184*0957b409SSimon J. Gerraty 
185*0957b409SSimon J. Gerraty 		memset(tmp, 0, sizeof tmp);
186*0957b409SSimon J. Gerraty 		tmp[15] = (unsigned char)i;
187*0957b409SSimon J. Gerraty 		(*ctx->bctx)->mac(ctx->bctx, st->st[i], tmp, sizeof tmp);
188*0957b409SSimon J. Gerraty 	}
189*0957b409SSimon J. Gerraty }
190*0957b409SSimon J. Gerraty 
191*0957b409SSimon J. Gerraty /* see bearssl_aead.h */
192*0957b409SSimon J. Gerraty void
br_eax_reset(br_eax_context * ctx,const void * nonce,size_t len)193*0957b409SSimon J. Gerraty br_eax_reset(br_eax_context *ctx, const void *nonce, size_t len)
194*0957b409SSimon J. Gerraty {
195*0957b409SSimon J. Gerraty 	/*
196*0957b409SSimon J. Gerraty 	 * Process nonce with OMAC^0.
197*0957b409SSimon J. Gerraty 	 */
198*0957b409SSimon J. Gerraty 	omac_start(ctx, 0);
199*0957b409SSimon J. Gerraty 	do_cbcmac_chunk(ctx, nonce, len);
200*0957b409SSimon J. Gerraty 	do_pad(ctx);
201*0957b409SSimon J. Gerraty 	memcpy(ctx->nonce, ctx->cbcmac, sizeof ctx->cbcmac);
202*0957b409SSimon J. Gerraty 
203*0957b409SSimon J. Gerraty 	/*
204*0957b409SSimon J. Gerraty 	 * Start OMAC^1 for the AAD ("header" in the EAX specification).
205*0957b409SSimon J. Gerraty 	 */
206*0957b409SSimon J. Gerraty 	omac_start(ctx, 1);
207*0957b409SSimon J. Gerraty 
208*0957b409SSimon J. Gerraty 	/*
209*0957b409SSimon J. Gerraty 	 * We use ctx->head[0] as temporary flag to mark that we are
210*0957b409SSimon J. Gerraty 	 * using a "normal" reset().
211*0957b409SSimon J. Gerraty 	 */
212*0957b409SSimon J. Gerraty 	ctx->head[0] = 0;
213*0957b409SSimon J. Gerraty }
214*0957b409SSimon J. Gerraty 
215*0957b409SSimon J. Gerraty /* see bearssl_aead.h */
216*0957b409SSimon J. Gerraty void
br_eax_reset_pre_aad(br_eax_context * ctx,const br_eax_state * st,const void * nonce,size_t len)217*0957b409SSimon J. Gerraty br_eax_reset_pre_aad(br_eax_context *ctx, const br_eax_state *st,
218*0957b409SSimon J. Gerraty 	const void *nonce, size_t len)
219*0957b409SSimon J. Gerraty {
220*0957b409SSimon J. Gerraty 	if (len == 0) {
221*0957b409SSimon J. Gerraty 		omac_start(ctx, 0);
222*0957b409SSimon J. Gerraty 	} else {
223*0957b409SSimon J. Gerraty 		memcpy(ctx->cbcmac, st->st[0], sizeof ctx->cbcmac);
224*0957b409SSimon J. Gerraty 		ctx->ptr = 0;
225*0957b409SSimon J. Gerraty 		do_cbcmac_chunk(ctx, nonce, len);
226*0957b409SSimon J. Gerraty 	}
227*0957b409SSimon J. Gerraty 	do_pad(ctx);
228*0957b409SSimon J. Gerraty 	memcpy(ctx->nonce, ctx->cbcmac, sizeof ctx->cbcmac);
229*0957b409SSimon J. Gerraty 
230*0957b409SSimon J. Gerraty 	memcpy(ctx->cbcmac, st->st[1], sizeof ctx->cbcmac);
231*0957b409SSimon J. Gerraty 	ctx->ptr = 0;
232*0957b409SSimon J. Gerraty 
233*0957b409SSimon J. Gerraty 	memcpy(ctx->ctr, st->st[2], sizeof ctx->ctr);
234*0957b409SSimon J. Gerraty 
235*0957b409SSimon J. Gerraty 	/*
236*0957b409SSimon J. Gerraty 	 * We use ctx->head[0] as a flag to indicate that we use a
237*0957b409SSimon J. Gerraty 	 * a recorded state, with ctx->ctr containing the preprocessed
238*0957b409SSimon J. Gerraty 	 * first block for OMAC^2.
239*0957b409SSimon J. Gerraty 	 */
240*0957b409SSimon J. Gerraty 	ctx->head[0] = 1;
241*0957b409SSimon J. Gerraty }
242*0957b409SSimon J. Gerraty 
243*0957b409SSimon J. Gerraty /* see bearssl_aead.h */
244*0957b409SSimon J. Gerraty void
br_eax_reset_post_aad(br_eax_context * ctx,const br_eax_state * st,const void * nonce,size_t len)245*0957b409SSimon J. Gerraty br_eax_reset_post_aad(br_eax_context *ctx, const br_eax_state *st,
246*0957b409SSimon J. Gerraty 	const void *nonce, size_t len)
247*0957b409SSimon J. Gerraty {
248*0957b409SSimon J. Gerraty 	if (len == 0) {
249*0957b409SSimon J. Gerraty 		omac_start(ctx, 0);
250*0957b409SSimon J. Gerraty 	} else {
251*0957b409SSimon J. Gerraty 		memcpy(ctx->cbcmac, st->st[0], sizeof ctx->cbcmac);
252*0957b409SSimon J. Gerraty 		ctx->ptr = 0;
253*0957b409SSimon J. Gerraty 		do_cbcmac_chunk(ctx, nonce, len);
254*0957b409SSimon J. Gerraty 	}
255*0957b409SSimon J. Gerraty 	do_pad(ctx);
256*0957b409SSimon J. Gerraty 	memcpy(ctx->nonce, ctx->cbcmac, sizeof ctx->cbcmac);
257*0957b409SSimon J. Gerraty 	memcpy(ctx->ctr, ctx->nonce, sizeof ctx->nonce);
258*0957b409SSimon J. Gerraty 
259*0957b409SSimon J. Gerraty 	memcpy(ctx->head, st->st[1], sizeof ctx->head);
260*0957b409SSimon J. Gerraty 
261*0957b409SSimon J. Gerraty 	memcpy(ctx->cbcmac, st->st[2], sizeof ctx->cbcmac);
262*0957b409SSimon J. Gerraty 	ctx->ptr = 0;
263*0957b409SSimon J. Gerraty }
264*0957b409SSimon J. Gerraty 
265*0957b409SSimon J. Gerraty /* see bearssl_aead.h */
266*0957b409SSimon J. Gerraty void
br_eax_aad_inject(br_eax_context * ctx,const void * data,size_t len)267*0957b409SSimon J. Gerraty br_eax_aad_inject(br_eax_context *ctx, const void *data, size_t len)
268*0957b409SSimon J. Gerraty {
269*0957b409SSimon J. Gerraty 	size_t ptr;
270*0957b409SSimon J. Gerraty 
271*0957b409SSimon J. Gerraty 	ptr = ctx->ptr;
272*0957b409SSimon J. Gerraty 
273*0957b409SSimon J. Gerraty 	/*
274*0957b409SSimon J. Gerraty 	 * If there is a partial block, first complete it.
275*0957b409SSimon J. Gerraty 	 */
276*0957b409SSimon J. Gerraty 	if (ptr < 16) {
277*0957b409SSimon J. Gerraty 		size_t clen;
278*0957b409SSimon J. Gerraty 
279*0957b409SSimon J. Gerraty 		clen = 16 - ptr;
280*0957b409SSimon J. Gerraty 		if (len <= clen) {
281*0957b409SSimon J. Gerraty 			memcpy(ctx->buf + ptr, data, len);
282*0957b409SSimon J. Gerraty 			ctx->ptr = ptr + len;
283*0957b409SSimon J. Gerraty 			return;
284*0957b409SSimon J. Gerraty 		}
285*0957b409SSimon J. Gerraty 		memcpy(ctx->buf + ptr, data, clen);
286*0957b409SSimon J. Gerraty 		data = (const unsigned char *)data + clen;
287*0957b409SSimon J. Gerraty 		len -= clen;
288*0957b409SSimon J. Gerraty 	}
289*0957b409SSimon J. Gerraty 
290*0957b409SSimon J. Gerraty 	/*
291*0957b409SSimon J. Gerraty 	 * We now have a full block in buf[], and this is not the last
292*0957b409SSimon J. Gerraty 	 * block.
293*0957b409SSimon J. Gerraty 	 */
294*0957b409SSimon J. Gerraty 	do_cbcmac_chunk(ctx, data, len);
295*0957b409SSimon J. Gerraty }
296*0957b409SSimon J. Gerraty 
297*0957b409SSimon J. Gerraty /* see bearssl_aead.h */
298*0957b409SSimon J. Gerraty void
br_eax_flip(br_eax_context * ctx)299*0957b409SSimon J. Gerraty br_eax_flip(br_eax_context *ctx)
300*0957b409SSimon J. Gerraty {
301*0957b409SSimon J. Gerraty 	int from_capture;
302*0957b409SSimon J. Gerraty 
303*0957b409SSimon J. Gerraty 	/*
304*0957b409SSimon J. Gerraty 	 * ctx->head[0] may be non-zero if the context was reset with
305*0957b409SSimon J. Gerraty 	 * a pre-AAD captured state. In that case, ctx->ctr[] contains
306*0957b409SSimon J. Gerraty 	 * the state for OMAC^2 _after_ processing the first block.
307*0957b409SSimon J. Gerraty 	 */
308*0957b409SSimon J. Gerraty 	from_capture = ctx->head[0];
309*0957b409SSimon J. Gerraty 
310*0957b409SSimon J. Gerraty 	/*
311*0957b409SSimon J. Gerraty 	 * Complete the OMAC computation on the AAD.
312*0957b409SSimon J. Gerraty 	 */
313*0957b409SSimon J. Gerraty 	do_pad(ctx);
314*0957b409SSimon J. Gerraty 	memcpy(ctx->head, ctx->cbcmac, sizeof ctx->cbcmac);
315*0957b409SSimon J. Gerraty 
316*0957b409SSimon J. Gerraty 	/*
317*0957b409SSimon J. Gerraty 	 * Start OMAC^2 for the encrypted data.
318*0957b409SSimon J. Gerraty 	 * If the context was initialized from a captured state, then
319*0957b409SSimon J. Gerraty 	 * the OMAC^2 value is in the ctr[] array.
320*0957b409SSimon J. Gerraty 	 */
321*0957b409SSimon J. Gerraty 	if (from_capture) {
322*0957b409SSimon J. Gerraty 		memcpy(ctx->cbcmac, ctx->ctr, sizeof ctx->cbcmac);
323*0957b409SSimon J. Gerraty 		ctx->ptr = 0;
324*0957b409SSimon J. Gerraty 	} else {
325*0957b409SSimon J. Gerraty 		omac_start(ctx, 2);
326*0957b409SSimon J. Gerraty 	}
327*0957b409SSimon J. Gerraty 
328*0957b409SSimon J. Gerraty 	/*
329*0957b409SSimon J. Gerraty 	 * Initial counter value for CTR is the processed nonce.
330*0957b409SSimon J. Gerraty 	 */
331*0957b409SSimon J. Gerraty 	memcpy(ctx->ctr, ctx->nonce, sizeof ctx->nonce);
332*0957b409SSimon J. Gerraty }
333*0957b409SSimon J. Gerraty 
334*0957b409SSimon J. Gerraty /* see bearssl_aead.h */
335*0957b409SSimon J. Gerraty void
br_eax_run(br_eax_context * ctx,int encrypt,void * data,size_t len)336*0957b409SSimon J. Gerraty br_eax_run(br_eax_context *ctx, int encrypt, void *data, size_t len)
337*0957b409SSimon J. Gerraty {
338*0957b409SSimon J. Gerraty 	unsigned char *dbuf;
339*0957b409SSimon J. Gerraty 	size_t ptr;
340*0957b409SSimon J. Gerraty 
341*0957b409SSimon J. Gerraty 	/*
342*0957b409SSimon J. Gerraty 	 * Ensure that there is actual data to process.
343*0957b409SSimon J. Gerraty 	 */
344*0957b409SSimon J. Gerraty 	if (len == 0) {
345*0957b409SSimon J. Gerraty 		return;
346*0957b409SSimon J. Gerraty 	}
347*0957b409SSimon J. Gerraty 
348*0957b409SSimon J. Gerraty 	dbuf = data;
349*0957b409SSimon J. Gerraty 	ptr = ctx->ptr;
350*0957b409SSimon J. Gerraty 
351*0957b409SSimon J. Gerraty 	/*
352*0957b409SSimon J. Gerraty 	 * We may have ptr == 0 here if we initialized from a captured
353*0957b409SSimon J. Gerraty 	 * state. In that case, there is no partially consumed block
354*0957b409SSimon J. Gerraty 	 * or unprocessed data.
355*0957b409SSimon J. Gerraty 	 */
356*0957b409SSimon J. Gerraty 	if (ptr != 0 && ptr != 16) {
357*0957b409SSimon J. Gerraty 		/*
358*0957b409SSimon J. Gerraty 		 * We have a partially consumed block.
359*0957b409SSimon J. Gerraty 		 */
360*0957b409SSimon J. Gerraty 		size_t u, clen;
361*0957b409SSimon J. Gerraty 
362*0957b409SSimon J. Gerraty 		clen = 16 - ptr;
363*0957b409SSimon J. Gerraty 		if (len <= clen) {
364*0957b409SSimon J. Gerraty 			clen = len;
365*0957b409SSimon J. Gerraty 		}
366*0957b409SSimon J. Gerraty 		if (encrypt) {
367*0957b409SSimon J. Gerraty 			for (u = 0; u < clen; u ++) {
368*0957b409SSimon J. Gerraty 				ctx->buf[ptr + u] ^= dbuf[u];
369*0957b409SSimon J. Gerraty 			}
370*0957b409SSimon J. Gerraty 			memcpy(dbuf, ctx->buf + ptr, clen);
371*0957b409SSimon J. Gerraty 		} else {
372*0957b409SSimon J. Gerraty 			for (u = 0; u < clen; u ++) {
373*0957b409SSimon J. Gerraty 				unsigned dx, sx;
374*0957b409SSimon J. Gerraty 
375*0957b409SSimon J. Gerraty 				sx = ctx->buf[ptr + u];
376*0957b409SSimon J. Gerraty 				dx = dbuf[u];
377*0957b409SSimon J. Gerraty 				ctx->buf[ptr + u] = dx;
378*0957b409SSimon J. Gerraty 				dbuf[u] = sx ^ dx;
379*0957b409SSimon J. Gerraty 			}
380*0957b409SSimon J. Gerraty 		}
381*0957b409SSimon J. Gerraty 
382*0957b409SSimon J. Gerraty 		if (len <= clen) {
383*0957b409SSimon J. Gerraty 			ctx->ptr = ptr + clen;
384*0957b409SSimon J. Gerraty 			return;
385*0957b409SSimon J. Gerraty 		}
386*0957b409SSimon J. Gerraty 		dbuf += clen;
387*0957b409SSimon J. Gerraty 		len -= clen;
388*0957b409SSimon J. Gerraty 	}
389*0957b409SSimon J. Gerraty 
390*0957b409SSimon J. Gerraty 	/*
391*0957b409SSimon J. Gerraty 	 * We now have a complete encrypted block in buf[] that must still
392*0957b409SSimon J. Gerraty 	 * be processed with OMAC, and this is not the final buf.
393*0957b409SSimon J. Gerraty 	 * Exception: when ptr == 0, no block has been produced yet.
394*0957b409SSimon J. Gerraty 	 */
395*0957b409SSimon J. Gerraty 	if (ptr != 0) {
396*0957b409SSimon J. Gerraty 		(*ctx->bctx)->mac(ctx->bctx, ctx->cbcmac,
397*0957b409SSimon J. Gerraty 			ctx->buf, sizeof ctx->buf);
398*0957b409SSimon J. Gerraty 	}
399*0957b409SSimon J. Gerraty 
400*0957b409SSimon J. Gerraty 	/*
401*0957b409SSimon J. Gerraty 	 * Do CTR encryption or decryption and CBC-MAC for all full blocks
402*0957b409SSimon J. Gerraty 	 * except the last.
403*0957b409SSimon J. Gerraty 	 */
404*0957b409SSimon J. Gerraty 	ptr = len & (size_t)15;
405*0957b409SSimon J. Gerraty 	if (ptr == 0) {
406*0957b409SSimon J. Gerraty 		len -= 16;
407*0957b409SSimon J. Gerraty 		ptr = 16;
408*0957b409SSimon J. Gerraty 	} else {
409*0957b409SSimon J. Gerraty 		len -= ptr;
410*0957b409SSimon J. Gerraty 	}
411*0957b409SSimon J. Gerraty 	if (encrypt) {
412*0957b409SSimon J. Gerraty 		(*ctx->bctx)->encrypt(ctx->bctx, ctx->ctr, ctx->cbcmac,
413*0957b409SSimon J. Gerraty 			dbuf, len);
414*0957b409SSimon J. Gerraty 	} else {
415*0957b409SSimon J. Gerraty 		(*ctx->bctx)->decrypt(ctx->bctx, ctx->ctr, ctx->cbcmac,
416*0957b409SSimon J. Gerraty 			dbuf, len);
417*0957b409SSimon J. Gerraty 	}
418*0957b409SSimon J. Gerraty 	dbuf += len;
419*0957b409SSimon J. Gerraty 
420*0957b409SSimon J. Gerraty 	/*
421*0957b409SSimon J. Gerraty 	 * Compute next block of CTR stream, and use it to finish
422*0957b409SSimon J. Gerraty 	 * encrypting or decrypting the data.
423*0957b409SSimon J. Gerraty 	 */
424*0957b409SSimon J. Gerraty 	memset(ctx->buf, 0, sizeof ctx->buf);
425*0957b409SSimon J. Gerraty 	(*ctx->bctx)->ctr(ctx->bctx, ctx->ctr, ctx->buf, sizeof ctx->buf);
426*0957b409SSimon J. Gerraty 	if (encrypt) {
427*0957b409SSimon J. Gerraty 		size_t u;
428*0957b409SSimon J. Gerraty 
429*0957b409SSimon J. Gerraty 		for (u = 0; u < ptr; u ++) {
430*0957b409SSimon J. Gerraty 			ctx->buf[u] ^= dbuf[u];
431*0957b409SSimon J. Gerraty 		}
432*0957b409SSimon J. Gerraty 		memcpy(dbuf, ctx->buf, ptr);
433*0957b409SSimon J. Gerraty 	} else {
434*0957b409SSimon J. Gerraty 		size_t u;
435*0957b409SSimon J. Gerraty 
436*0957b409SSimon J. Gerraty 		for (u = 0; u < ptr; u ++) {
437*0957b409SSimon J. Gerraty 			unsigned dx, sx;
438*0957b409SSimon J. Gerraty 
439*0957b409SSimon J. Gerraty 			sx = ctx->buf[u];
440*0957b409SSimon J. Gerraty 			dx = dbuf[u];
441*0957b409SSimon J. Gerraty 			ctx->buf[u] = dx;
442*0957b409SSimon J. Gerraty 			dbuf[u] = sx ^ dx;
443*0957b409SSimon J. Gerraty 		}
444*0957b409SSimon J. Gerraty 	}
445*0957b409SSimon J. Gerraty 	ctx->ptr = ptr;
446*0957b409SSimon J. Gerraty }
447*0957b409SSimon J. Gerraty 
448*0957b409SSimon J. Gerraty /*
449*0957b409SSimon J. Gerraty  * Complete tag computation. The final tag is written in ctx->cbcmac.
450*0957b409SSimon J. Gerraty  */
451*0957b409SSimon J. Gerraty static void
do_final(br_eax_context * ctx)452*0957b409SSimon J. Gerraty do_final(br_eax_context *ctx)
453*0957b409SSimon J. Gerraty {
454*0957b409SSimon J. Gerraty 	size_t u;
455*0957b409SSimon J. Gerraty 
456*0957b409SSimon J. Gerraty 	do_pad(ctx);
457*0957b409SSimon J. Gerraty 
458*0957b409SSimon J. Gerraty 	/*
459*0957b409SSimon J. Gerraty 	 * Authentication tag is the XOR of the three OMAC outputs for
460*0957b409SSimon J. Gerraty 	 * the nonce, AAD and encrypted data.
461*0957b409SSimon J. Gerraty 	 */
462*0957b409SSimon J. Gerraty 	for (u = 0; u < 16; u ++) {
463*0957b409SSimon J. Gerraty 		ctx->cbcmac[u] ^= ctx->nonce[u] ^ ctx->head[u];
464*0957b409SSimon J. Gerraty 	}
465*0957b409SSimon J. Gerraty }
466*0957b409SSimon J. Gerraty 
467*0957b409SSimon J. Gerraty /* see bearssl_aead.h */
468*0957b409SSimon J. Gerraty void
br_eax_get_tag(br_eax_context * ctx,void * tag)469*0957b409SSimon J. Gerraty br_eax_get_tag(br_eax_context *ctx, void *tag)
470*0957b409SSimon J. Gerraty {
471*0957b409SSimon J. Gerraty 	do_final(ctx);
472*0957b409SSimon J. Gerraty 	memcpy(tag, ctx->cbcmac, sizeof ctx->cbcmac);
473*0957b409SSimon J. Gerraty }
474*0957b409SSimon J. Gerraty 
475*0957b409SSimon J. Gerraty /* see bearssl_aead.h */
476*0957b409SSimon J. Gerraty void
br_eax_get_tag_trunc(br_eax_context * ctx,void * tag,size_t len)477*0957b409SSimon J. Gerraty br_eax_get_tag_trunc(br_eax_context *ctx, void *tag, size_t len)
478*0957b409SSimon J. Gerraty {
479*0957b409SSimon J. Gerraty 	do_final(ctx);
480*0957b409SSimon J. Gerraty 	memcpy(tag, ctx->cbcmac, len);
481*0957b409SSimon J. Gerraty }
482*0957b409SSimon J. Gerraty 
483*0957b409SSimon J. Gerraty /* see bearssl_aead.h */
484*0957b409SSimon J. Gerraty uint32_t
br_eax_check_tag_trunc(br_eax_context * ctx,const void * tag,size_t len)485*0957b409SSimon J. Gerraty br_eax_check_tag_trunc(br_eax_context *ctx, const void *tag, size_t len)
486*0957b409SSimon J. Gerraty {
487*0957b409SSimon J. Gerraty 	unsigned char tmp[16];
488*0957b409SSimon J. Gerraty 	size_t u;
489*0957b409SSimon J. Gerraty 	int x;
490*0957b409SSimon J. Gerraty 
491*0957b409SSimon J. Gerraty 	br_eax_get_tag(ctx, tmp);
492*0957b409SSimon J. Gerraty 	x = 0;
493*0957b409SSimon J. Gerraty 	for (u = 0; u < len; u ++) {
494*0957b409SSimon J. Gerraty 		x |= tmp[u] ^ ((const unsigned char *)tag)[u];
495*0957b409SSimon J. Gerraty 	}
496*0957b409SSimon J. Gerraty 	return EQ0(x);
497*0957b409SSimon J. Gerraty }
498*0957b409SSimon J. Gerraty 
499*0957b409SSimon J. Gerraty /* see bearssl_aead.h */
500*0957b409SSimon J. Gerraty uint32_t
br_eax_check_tag(br_eax_context * ctx,const void * tag)501*0957b409SSimon J. Gerraty br_eax_check_tag(br_eax_context *ctx, const void *tag)
502*0957b409SSimon J. Gerraty {
503*0957b409SSimon J. Gerraty 	return br_eax_check_tag_trunc(ctx, tag, 16);
504*0957b409SSimon J. Gerraty }
505*0957b409SSimon J. Gerraty 
506*0957b409SSimon J. Gerraty /* see bearssl_aead.h */
507*0957b409SSimon J. Gerraty const br_aead_class br_eax_vtable = {
508*0957b409SSimon J. Gerraty 	16,
509*0957b409SSimon J. Gerraty 	(void (*)(const br_aead_class **, const void *, size_t))
510*0957b409SSimon J. Gerraty 		&br_eax_reset,
511*0957b409SSimon J. Gerraty 	(void (*)(const br_aead_class **, const void *, size_t))
512*0957b409SSimon J. Gerraty 		&br_eax_aad_inject,
513*0957b409SSimon J. Gerraty 	(void (*)(const br_aead_class **))
514*0957b409SSimon J. Gerraty 		&br_eax_flip,
515*0957b409SSimon J. Gerraty 	(void (*)(const br_aead_class **, int, void *, size_t))
516*0957b409SSimon J. Gerraty 		&br_eax_run,
517*0957b409SSimon J. Gerraty 	(void (*)(const br_aead_class **, void *))
518*0957b409SSimon J. Gerraty 		&br_eax_get_tag,
519*0957b409SSimon J. Gerraty 	(uint32_t (*)(const br_aead_class **, const void *))
520*0957b409SSimon J. Gerraty 		&br_eax_check_tag,
521*0957b409SSimon J. Gerraty 	(void (*)(const br_aead_class **, void *, size_t))
522*0957b409SSimon J. Gerraty 		&br_eax_get_tag_trunc,
523*0957b409SSimon J. Gerraty 	(uint32_t (*)(const br_aead_class **, const void *, size_t))
524*0957b409SSimon J. Gerraty 		&br_eax_check_tag_trunc
525*0957b409SSimon J. Gerraty };
526