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 * Since CTR and GHASH implementations can handle only full blocks, a
32*0957b409SSimon J. Gerraty * 16-byte buffer (buf[]) is maintained in the context:
33*0957b409SSimon J. Gerraty *
34*0957b409SSimon J. Gerraty * - When processing AAD, buf[] contains the 0-15 unprocessed bytes.
35*0957b409SSimon J. Gerraty *
36*0957b409SSimon J. Gerraty * - When doing CTR encryption / decryption, buf[] contains the AES output
37*0957b409SSimon J. Gerraty * for the last partial block, to be used with the next few bytes of
38*0957b409SSimon J. Gerraty * data, as well as the already encrypted bytes. For instance, if the
39*0957b409SSimon J. Gerraty * processed data length so far is 21 bytes, then buf[0..4] contains
40*0957b409SSimon J. Gerraty * the five last encrypted bytes, and buf[5..15] contains the next 11
41*0957b409SSimon J. Gerraty * AES output bytes to be XORed with the next 11 bytes of input.
42*0957b409SSimon J. Gerraty *
43*0957b409SSimon J. Gerraty * The recorded AES output bytes are used to complete the block when
44*0957b409SSimon J. Gerraty * the corresponding bytes are obtained. Note that buf[] always
45*0957b409SSimon J. Gerraty * contains the _encrypted_ bytes, whether we apply encryption or
46*0957b409SSimon J. Gerraty * decryption: these bytes are used as input to GHASH when the block
47*0957b409SSimon J. Gerraty * is complete.
48*0957b409SSimon J. Gerraty *
49*0957b409SSimon J. Gerraty * In both cases, the low bits of the data length counters (count_aad,
50*0957b409SSimon J. Gerraty * count_ctr) are used to work out the current situation.
51*0957b409SSimon J. Gerraty */
52*0957b409SSimon J. Gerraty
53*0957b409SSimon J. Gerraty /* see bearssl_aead.h */
54*0957b409SSimon J. Gerraty void
br_gcm_init(br_gcm_context * ctx,const br_block_ctr_class ** bctx,br_ghash gh)55*0957b409SSimon J. Gerraty br_gcm_init(br_gcm_context *ctx, const br_block_ctr_class **bctx, br_ghash gh)
56*0957b409SSimon J. Gerraty {
57*0957b409SSimon J. Gerraty unsigned char iv[12];
58*0957b409SSimon J. Gerraty
59*0957b409SSimon J. Gerraty ctx->vtable = &br_gcm_vtable;
60*0957b409SSimon J. Gerraty ctx->bctx = bctx;
61*0957b409SSimon J. Gerraty ctx->gh = gh;
62*0957b409SSimon J. Gerraty
63*0957b409SSimon J. Gerraty /*
64*0957b409SSimon J. Gerraty * The GHASH key h[] is the raw encryption of the all-zero
65*0957b409SSimon J. Gerraty * block. Since we only have a CTR implementation, we use it
66*0957b409SSimon J. Gerraty * with an all-zero IV and a zero counter, to CTR-encrypt an
67*0957b409SSimon J. Gerraty * all-zero block.
68*0957b409SSimon J. Gerraty */
69*0957b409SSimon J. Gerraty memset(ctx->h, 0, sizeof ctx->h);
70*0957b409SSimon J. Gerraty memset(iv, 0, sizeof iv);
71*0957b409SSimon J. Gerraty (*bctx)->run(bctx, iv, 0, ctx->h, sizeof ctx->h);
72*0957b409SSimon J. Gerraty }
73*0957b409SSimon J. Gerraty
74*0957b409SSimon J. Gerraty /* see bearssl_aead.h */
75*0957b409SSimon J. Gerraty void
br_gcm_reset(br_gcm_context * ctx,const void * iv,size_t len)76*0957b409SSimon J. Gerraty br_gcm_reset(br_gcm_context *ctx, const void *iv, size_t len)
77*0957b409SSimon J. Gerraty {
78*0957b409SSimon J. Gerraty /*
79*0957b409SSimon J. Gerraty * If the provided nonce is 12 bytes, then this is the initial
80*0957b409SSimon J. Gerraty * IV for CTR mode; it will be used with a counter that starts
81*0957b409SSimon J. Gerraty * at 2 (value 1 is for encrypting the GHASH output into the tag).
82*0957b409SSimon J. Gerraty *
83*0957b409SSimon J. Gerraty * If the provided nonce has any other length, then it is hashed
84*0957b409SSimon J. Gerraty * (with GHASH) into a 16-byte value that will be the IV for CTR
85*0957b409SSimon J. Gerraty * (both 12-byte IV and 32-bit counter).
86*0957b409SSimon J. Gerraty */
87*0957b409SSimon J. Gerraty if (len == 12) {
88*0957b409SSimon J. Gerraty memcpy(ctx->j0_1, iv, 12);
89*0957b409SSimon J. Gerraty ctx->j0_2 = 1;
90*0957b409SSimon J. Gerraty } else {
91*0957b409SSimon J. Gerraty unsigned char ty[16], tmp[16];
92*0957b409SSimon J. Gerraty
93*0957b409SSimon J. Gerraty memset(ty, 0, sizeof ty);
94*0957b409SSimon J. Gerraty ctx->gh(ty, ctx->h, iv, len);
95*0957b409SSimon J. Gerraty memset(tmp, 0, 8);
96*0957b409SSimon J. Gerraty br_enc64be(tmp + 8, (uint64_t)len << 3);
97*0957b409SSimon J. Gerraty ctx->gh(ty, ctx->h, tmp, 16);
98*0957b409SSimon J. Gerraty memcpy(ctx->j0_1, ty, 12);
99*0957b409SSimon J. Gerraty ctx->j0_2 = br_dec32be(ty + 12);
100*0957b409SSimon J. Gerraty }
101*0957b409SSimon J. Gerraty ctx->jc = ctx->j0_2 + 1;
102*0957b409SSimon J. Gerraty memset(ctx->y, 0, sizeof ctx->y);
103*0957b409SSimon J. Gerraty ctx->count_aad = 0;
104*0957b409SSimon J. Gerraty ctx->count_ctr = 0;
105*0957b409SSimon J. Gerraty }
106*0957b409SSimon J. Gerraty
107*0957b409SSimon J. Gerraty /* see bearssl_aead.h */
108*0957b409SSimon J. Gerraty void
br_gcm_aad_inject(br_gcm_context * ctx,const void * data,size_t len)109*0957b409SSimon J. Gerraty br_gcm_aad_inject(br_gcm_context *ctx, const void *data, size_t len)
110*0957b409SSimon J. Gerraty {
111*0957b409SSimon J. Gerraty size_t ptr, dlen;
112*0957b409SSimon J. Gerraty
113*0957b409SSimon J. Gerraty ptr = (size_t)ctx->count_aad & (size_t)15;
114*0957b409SSimon J. Gerraty if (ptr != 0) {
115*0957b409SSimon J. Gerraty /*
116*0957b409SSimon J. Gerraty * If there is a partial block, then we first try to
117*0957b409SSimon J. Gerraty * complete it.
118*0957b409SSimon J. Gerraty */
119*0957b409SSimon J. Gerraty size_t clen;
120*0957b409SSimon J. Gerraty
121*0957b409SSimon J. Gerraty clen = 16 - ptr;
122*0957b409SSimon J. Gerraty if (len < clen) {
123*0957b409SSimon J. Gerraty memcpy(ctx->buf + ptr, data, len);
124*0957b409SSimon J. Gerraty ctx->count_aad += (uint64_t)len;
125*0957b409SSimon J. Gerraty return;
126*0957b409SSimon J. Gerraty }
127*0957b409SSimon J. Gerraty memcpy(ctx->buf + ptr, data, clen);
128*0957b409SSimon J. Gerraty ctx->gh(ctx->y, ctx->h, ctx->buf, 16);
129*0957b409SSimon J. Gerraty data = (const unsigned char *)data + clen;
130*0957b409SSimon J. Gerraty len -= clen;
131*0957b409SSimon J. Gerraty ctx->count_aad += (uint64_t)clen;
132*0957b409SSimon J. Gerraty }
133*0957b409SSimon J. Gerraty
134*0957b409SSimon J. Gerraty /*
135*0957b409SSimon J. Gerraty * Now AAD is aligned on a 16-byte block (with regards to GHASH).
136*0957b409SSimon J. Gerraty * We process all complete blocks, and save the last partial
137*0957b409SSimon J. Gerraty * block.
138*0957b409SSimon J. Gerraty */
139*0957b409SSimon J. Gerraty dlen = len & ~(size_t)15;
140*0957b409SSimon J. Gerraty ctx->gh(ctx->y, ctx->h, data, dlen);
141*0957b409SSimon J. Gerraty memcpy(ctx->buf, (const unsigned char *)data + dlen, len - dlen);
142*0957b409SSimon J. Gerraty ctx->count_aad += (uint64_t)len;
143*0957b409SSimon J. Gerraty }
144*0957b409SSimon J. Gerraty
145*0957b409SSimon J. Gerraty /* see bearssl_aead.h */
146*0957b409SSimon J. Gerraty void
br_gcm_flip(br_gcm_context * ctx)147*0957b409SSimon J. Gerraty br_gcm_flip(br_gcm_context *ctx)
148*0957b409SSimon J. Gerraty {
149*0957b409SSimon J. Gerraty /*
150*0957b409SSimon J. Gerraty * We complete the GHASH computation if there is a partial block.
151*0957b409SSimon J. Gerraty * The GHASH implementation automatically applies padding with
152*0957b409SSimon J. Gerraty * zeros.
153*0957b409SSimon J. Gerraty */
154*0957b409SSimon J. Gerraty size_t ptr;
155*0957b409SSimon J. Gerraty
156*0957b409SSimon J. Gerraty ptr = (size_t)ctx->count_aad & (size_t)15;
157*0957b409SSimon J. Gerraty if (ptr != 0) {
158*0957b409SSimon J. Gerraty ctx->gh(ctx->y, ctx->h, ctx->buf, ptr);
159*0957b409SSimon J. Gerraty }
160*0957b409SSimon J. Gerraty }
161*0957b409SSimon J. Gerraty
162*0957b409SSimon J. Gerraty /* see bearssl_aead.h */
163*0957b409SSimon J. Gerraty void
br_gcm_run(br_gcm_context * ctx,int encrypt,void * data,size_t len)164*0957b409SSimon J. Gerraty br_gcm_run(br_gcm_context *ctx, int encrypt, void *data, size_t len)
165*0957b409SSimon J. Gerraty {
166*0957b409SSimon J. Gerraty unsigned char *buf;
167*0957b409SSimon J. Gerraty size_t ptr, dlen;
168*0957b409SSimon J. Gerraty
169*0957b409SSimon J. Gerraty buf = data;
170*0957b409SSimon J. Gerraty ptr = (size_t)ctx->count_ctr & (size_t)15;
171*0957b409SSimon J. Gerraty if (ptr != 0) {
172*0957b409SSimon J. Gerraty /*
173*0957b409SSimon J. Gerraty * If we have a partial block, then we try to complete it.
174*0957b409SSimon J. Gerraty */
175*0957b409SSimon J. Gerraty size_t u, clen;
176*0957b409SSimon J. Gerraty
177*0957b409SSimon J. Gerraty clen = 16 - ptr;
178*0957b409SSimon J. Gerraty if (len < clen) {
179*0957b409SSimon J. Gerraty clen = len;
180*0957b409SSimon J. Gerraty }
181*0957b409SSimon J. Gerraty for (u = 0; u < clen; u ++) {
182*0957b409SSimon J. Gerraty unsigned x, y;
183*0957b409SSimon J. Gerraty
184*0957b409SSimon J. Gerraty x = buf[u];
185*0957b409SSimon J. Gerraty y = x ^ ctx->buf[ptr + u];
186*0957b409SSimon J. Gerraty ctx->buf[ptr + u] = encrypt ? y : x;
187*0957b409SSimon J. Gerraty buf[u] = y;
188*0957b409SSimon J. Gerraty }
189*0957b409SSimon J. Gerraty ctx->count_ctr += (uint64_t)clen;
190*0957b409SSimon J. Gerraty buf += clen;
191*0957b409SSimon J. Gerraty len -= clen;
192*0957b409SSimon J. Gerraty if (ptr + clen < 16) {
193*0957b409SSimon J. Gerraty return;
194*0957b409SSimon J. Gerraty }
195*0957b409SSimon J. Gerraty ctx->gh(ctx->y, ctx->h, ctx->buf, 16);
196*0957b409SSimon J. Gerraty }
197*0957b409SSimon J. Gerraty
198*0957b409SSimon J. Gerraty /*
199*0957b409SSimon J. Gerraty * Process full blocks.
200*0957b409SSimon J. Gerraty */
201*0957b409SSimon J. Gerraty dlen = len & ~(size_t)15;
202*0957b409SSimon J. Gerraty if (!encrypt) {
203*0957b409SSimon J. Gerraty ctx->gh(ctx->y, ctx->h, buf, dlen);
204*0957b409SSimon J. Gerraty }
205*0957b409SSimon J. Gerraty ctx->jc = (*ctx->bctx)->run(ctx->bctx, ctx->j0_1, ctx->jc, buf, dlen);
206*0957b409SSimon J. Gerraty if (encrypt) {
207*0957b409SSimon J. Gerraty ctx->gh(ctx->y, ctx->h, buf, dlen);
208*0957b409SSimon J. Gerraty }
209*0957b409SSimon J. Gerraty buf += dlen;
210*0957b409SSimon J. Gerraty len -= dlen;
211*0957b409SSimon J. Gerraty ctx->count_ctr += (uint64_t)dlen;
212*0957b409SSimon J. Gerraty
213*0957b409SSimon J. Gerraty if (len > 0) {
214*0957b409SSimon J. Gerraty /*
215*0957b409SSimon J. Gerraty * There is a partial block.
216*0957b409SSimon J. Gerraty */
217*0957b409SSimon J. Gerraty size_t u;
218*0957b409SSimon J. Gerraty
219*0957b409SSimon J. Gerraty memset(ctx->buf, 0, sizeof ctx->buf);
220*0957b409SSimon J. Gerraty ctx->jc = (*ctx->bctx)->run(ctx->bctx, ctx->j0_1,
221*0957b409SSimon J. Gerraty ctx->jc, ctx->buf, 16);
222*0957b409SSimon J. Gerraty for (u = 0; u < len; u ++) {
223*0957b409SSimon J. Gerraty unsigned x, y;
224*0957b409SSimon J. Gerraty
225*0957b409SSimon J. Gerraty x = buf[u];
226*0957b409SSimon J. Gerraty y = x ^ ctx->buf[u];
227*0957b409SSimon J. Gerraty ctx->buf[u] = encrypt ? y : x;
228*0957b409SSimon J. Gerraty buf[u] = y;
229*0957b409SSimon J. Gerraty }
230*0957b409SSimon J. Gerraty ctx->count_ctr += (uint64_t)len;
231*0957b409SSimon J. Gerraty }
232*0957b409SSimon J. Gerraty }
233*0957b409SSimon J. Gerraty
234*0957b409SSimon J. Gerraty /* see bearssl_aead.h */
235*0957b409SSimon J. Gerraty void
br_gcm_get_tag(br_gcm_context * ctx,void * tag)236*0957b409SSimon J. Gerraty br_gcm_get_tag(br_gcm_context *ctx, void *tag)
237*0957b409SSimon J. Gerraty {
238*0957b409SSimon J. Gerraty size_t ptr;
239*0957b409SSimon J. Gerraty unsigned char tmp[16];
240*0957b409SSimon J. Gerraty
241*0957b409SSimon J. Gerraty ptr = (size_t)ctx->count_ctr & (size_t)15;
242*0957b409SSimon J. Gerraty if (ptr > 0) {
243*0957b409SSimon J. Gerraty /*
244*0957b409SSimon J. Gerraty * There is a partial block: encrypted/decrypted data has
245*0957b409SSimon J. Gerraty * been produced, but the encrypted bytes must still be
246*0957b409SSimon J. Gerraty * processed by GHASH.
247*0957b409SSimon J. Gerraty */
248*0957b409SSimon J. Gerraty ctx->gh(ctx->y, ctx->h, ctx->buf, ptr);
249*0957b409SSimon J. Gerraty }
250*0957b409SSimon J. Gerraty
251*0957b409SSimon J. Gerraty /*
252*0957b409SSimon J. Gerraty * Final block for GHASH: the AAD and plaintext lengths (in bits).
253*0957b409SSimon J. Gerraty */
254*0957b409SSimon J. Gerraty br_enc64be(tmp, ctx->count_aad << 3);
255*0957b409SSimon J. Gerraty br_enc64be(tmp + 8, ctx->count_ctr << 3);
256*0957b409SSimon J. Gerraty ctx->gh(ctx->y, ctx->h, tmp, 16);
257*0957b409SSimon J. Gerraty
258*0957b409SSimon J. Gerraty /*
259*0957b409SSimon J. Gerraty * Tag is the GHASH output XORed with the encryption of the
260*0957b409SSimon J. Gerraty * nonce with the initial counter value.
261*0957b409SSimon J. Gerraty */
262*0957b409SSimon J. Gerraty memcpy(tag, ctx->y, 16);
263*0957b409SSimon J. Gerraty (*ctx->bctx)->run(ctx->bctx, ctx->j0_1, ctx->j0_2, tag, 16);
264*0957b409SSimon J. Gerraty }
265*0957b409SSimon J. Gerraty
266*0957b409SSimon J. Gerraty /* see bearssl_aead.h */
267*0957b409SSimon J. Gerraty void
br_gcm_get_tag_trunc(br_gcm_context * ctx,void * tag,size_t len)268*0957b409SSimon J. Gerraty br_gcm_get_tag_trunc(br_gcm_context *ctx, void *tag, size_t len)
269*0957b409SSimon J. Gerraty {
270*0957b409SSimon J. Gerraty unsigned char tmp[16];
271*0957b409SSimon J. Gerraty
272*0957b409SSimon J. Gerraty br_gcm_get_tag(ctx, tmp);
273*0957b409SSimon J. Gerraty memcpy(tag, tmp, len);
274*0957b409SSimon J. Gerraty }
275*0957b409SSimon J. Gerraty
276*0957b409SSimon J. Gerraty /* see bearssl_aead.h */
277*0957b409SSimon J. Gerraty uint32_t
br_gcm_check_tag_trunc(br_gcm_context * ctx,const void * tag,size_t len)278*0957b409SSimon J. Gerraty br_gcm_check_tag_trunc(br_gcm_context *ctx, const void *tag, size_t len)
279*0957b409SSimon J. Gerraty {
280*0957b409SSimon J. Gerraty unsigned char tmp[16];
281*0957b409SSimon J. Gerraty size_t u;
282*0957b409SSimon J. Gerraty int x;
283*0957b409SSimon J. Gerraty
284*0957b409SSimon J. Gerraty br_gcm_get_tag(ctx, tmp);
285*0957b409SSimon J. Gerraty x = 0;
286*0957b409SSimon J. Gerraty for (u = 0; u < len; u ++) {
287*0957b409SSimon J. Gerraty x |= tmp[u] ^ ((const unsigned char *)tag)[u];
288*0957b409SSimon J. Gerraty }
289*0957b409SSimon J. Gerraty return EQ0(x);
290*0957b409SSimon J. Gerraty }
291*0957b409SSimon J. Gerraty
292*0957b409SSimon J. Gerraty /* see bearssl_aead.h */
293*0957b409SSimon J. Gerraty uint32_t
br_gcm_check_tag(br_gcm_context * ctx,const void * tag)294*0957b409SSimon J. Gerraty br_gcm_check_tag(br_gcm_context *ctx, const void *tag)
295*0957b409SSimon J. Gerraty {
296*0957b409SSimon J. Gerraty return br_gcm_check_tag_trunc(ctx, tag, 16);
297*0957b409SSimon J. Gerraty }
298*0957b409SSimon J. Gerraty
299*0957b409SSimon J. Gerraty /* see bearssl_aead.h */
300*0957b409SSimon J. Gerraty const br_aead_class br_gcm_vtable = {
301*0957b409SSimon J. Gerraty 16,
302*0957b409SSimon J. Gerraty (void (*)(const br_aead_class **, const void *, size_t))
303*0957b409SSimon J. Gerraty &br_gcm_reset,
304*0957b409SSimon J. Gerraty (void (*)(const br_aead_class **, const void *, size_t))
305*0957b409SSimon J. Gerraty &br_gcm_aad_inject,
306*0957b409SSimon J. Gerraty (void (*)(const br_aead_class **))
307*0957b409SSimon J. Gerraty &br_gcm_flip,
308*0957b409SSimon J. Gerraty (void (*)(const br_aead_class **, int, void *, size_t))
309*0957b409SSimon J. Gerraty &br_gcm_run,
310*0957b409SSimon J. Gerraty (void (*)(const br_aead_class **, void *))
311*0957b409SSimon J. Gerraty &br_gcm_get_tag,
312*0957b409SSimon J. Gerraty (uint32_t (*)(const br_aead_class **, const void *))
313*0957b409SSimon J. Gerraty &br_gcm_check_tag,
314*0957b409SSimon J. Gerraty (void (*)(const br_aead_class **, void *, size_t))
315*0957b409SSimon J. Gerraty &br_gcm_get_tag_trunc,
316*0957b409SSimon J. Gerraty (uint32_t (*)(const br_aead_class **, const void *, size_t))
317*0957b409SSimon J. Gerraty &br_gcm_check_tag_trunc
318*0957b409SSimon J. Gerraty };
319