File Coverage

src/aead/gcm.c
Criterion Covered Total %
statement 77 105 73.3
branch 20 32 62.5
condition n/a
subroutine n/a
pod n/a
total 97 137 70.8


line stmt bran cond sub pod time code
1             /*
2             * Copyright (c) 2017 Thomas Pornin
3             *
4             * Permission is hereby granted, free of charge, to any person obtaining
5             * a copy of this software and associated documentation files (the
6             * "Software"), to deal in the Software without restriction, including
7             * without limitation the rights to use, copy, modify, merge, publish,
8             * distribute, sublicense, and/or sell copies of the Software, and to
9             * permit persons to whom the Software is furnished to do so, subject to
10             * the following conditions:
11             *
12             * The above copyright notice and this permission notice shall be
13             * included in all copies or substantial portions of the Software.
14             *
15             * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16             * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17             * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18             * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
19             * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20             * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21             * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22             * SOFTWARE.
23             */
24              
25             #include "inner.h"
26              
27             /*
28             * Implementation Notes
29             * ====================
30             *
31             * Since CTR and GHASH implementations can handle only full blocks, a
32             * 16-byte buffer (buf[]) is maintained in the context:
33             *
34             * - When processing AAD, buf[] contains the 0-15 unprocessed bytes.
35             *
36             * - When doing CTR encryption / decryption, buf[] contains the AES output
37             * for the last partial block, to be used with the next few bytes of
38             * data, as well as the already encrypted bytes. For instance, if the
39             * processed data length so far is 21 bytes, then buf[0..4] contains
40             * the five last encrypted bytes, and buf[5..15] contains the next 11
41             * AES output bytes to be XORed with the next 11 bytes of input.
42             *
43             * The recorded AES output bytes are used to complete the block when
44             * the corresponding bytes are obtained. Note that buf[] always
45             * contains the _encrypted_ bytes, whether we apply encryption or
46             * decryption: these bytes are used as input to GHASH when the block
47             * is complete.
48             *
49             * In both cases, the low bits of the data length counters (count_aad,
50             * count_ctr) are used to work out the current situation.
51             */
52              
53             /* see bearssl_aead.h */
54             void
55 8           br_gcm_init(br_gcm_context *ctx, const br_block_ctr_class **bctx, br_ghash gh)
56             {
57             unsigned char iv[12];
58              
59 8           ctx->vtable = &br_gcm_vtable;
60 8           ctx->bctx = bctx;
61 8           ctx->gh = gh;
62              
63             /*
64             * The GHASH key h[] is the raw encryption of the all-zero
65             * block. Since we only have a CTR implementation, we use it
66             * with an all-zero IV and a zero counter, to CTR-encrypt an
67             * all-zero block.
68             */
69 8           memset(ctx->h, 0, sizeof ctx->h);
70 8           memset(iv, 0, sizeof iv);
71 8           (*bctx)->run(bctx, iv, 0, ctx->h, sizeof ctx->h);
72 8           }
73              
74             /* see bearssl_aead.h */
75             void
76 16           br_gcm_reset(br_gcm_context *ctx, const void *iv, size_t len)
77             {
78             /*
79             * If the provided nonce is 12 bytes, then this is the initial
80             * IV for CTR mode; it will be used with a counter that starts
81             * at 2 (value 1 is for encrypting the GHASH output into the tag).
82             *
83             * If the provided nonce has any other length, then it is hashed
84             * (with GHASH) into a 16-byte value that will be the IV for CTR
85             * (both 12-byte IV and 32-bit counter).
86             */
87 16 100         if (len == 12) {
88 12           memcpy(ctx->j0_1, iv, 12);
89 12           ctx->j0_2 = 1;
90             } else {
91             unsigned char ty[16], tmp[16];
92              
93 4           memset(ty, 0, sizeof ty);
94 4           ctx->gh(ty, ctx->h, iv, len);
95 4           memset(tmp, 0, 8);
96 4           br_enc64be(tmp + 8, (uint64_t)len << 3);
97 4           ctx->gh(ty, ctx->h, tmp, 16);
98 4           memcpy(ctx->j0_1, ty, 12);
99 4           ctx->j0_2 = br_dec32be(ty + 12);
100             }
101 16           ctx->jc = ctx->j0_2 + 1;
102 16           memset(ctx->y, 0, sizeof ctx->y);
103 16           ctx->count_aad = 0;
104 16           ctx->count_ctr = 0;
105 16           }
106              
107             /* see bearssl_aead.h */
108             void
109 16           br_gcm_aad_inject(br_gcm_context *ctx, const void *data, size_t len)
110             {
111             size_t ptr, dlen;
112              
113 16           ptr = (size_t)ctx->count_aad & (size_t)15;
114 16 50         if (ptr != 0) {
115             /*
116             * If there is a partial block, then we first try to
117             * complete it.
118             */
119             size_t clen;
120              
121 0           clen = 16 - ptr;
122 0 0         if (len < clen) {
123 0           memcpy(ctx->buf + ptr, data, len);
124 0           ctx->count_aad += (uint64_t)len;
125 0           return;
126             }
127 0           memcpy(ctx->buf + ptr, data, clen);
128 0           ctx->gh(ctx->y, ctx->h, ctx->buf, 16);
129 0           data = (const unsigned char *)data + clen;
130 0           len -= clen;
131 0           ctx->count_aad += (uint64_t)clen;
132             }
133              
134             /*
135             * Now AAD is aligned on a 16-byte block (with regards to GHASH).
136             * We process all complete blocks, and save the last partial
137             * block.
138             */
139 16           dlen = len & ~(size_t)15;
140 16           ctx->gh(ctx->y, ctx->h, data, dlen);
141 16           memcpy(ctx->buf, (const unsigned char *)data + dlen, len - dlen);
142 16           ctx->count_aad += (uint64_t)len;
143             }
144              
145             /* see bearssl_aead.h */
146             void
147 16           br_gcm_flip(br_gcm_context *ctx)
148             {
149             /*
150             * We complete the GHASH computation if there is a partial block.
151             * The GHASH implementation automatically applies padding with
152             * zeros.
153             */
154             size_t ptr;
155              
156 16           ptr = (size_t)ctx->count_aad & (size_t)15;
157 16 100         if (ptr != 0) {
158 6           ctx->gh(ctx->y, ctx->h, ctx->buf, ptr);
159             }
160 16           }
161              
162             /* see bearssl_aead.h */
163             void
164 16           br_gcm_run(br_gcm_context *ctx, int encrypt, void *data, size_t len)
165             {
166             unsigned char *buf;
167             size_t ptr, dlen;
168              
169 16           buf = data;
170 16           ptr = (size_t)ctx->count_ctr & (size_t)15;
171 16 50         if (ptr != 0) {
172             /*
173             * If we have a partial block, then we try to complete it.
174             */
175             size_t u, clen;
176              
177 0           clen = 16 - ptr;
178 0 0         if (len < clen) {
179 0           clen = len;
180             }
181 0 0         for (u = 0; u < clen; u ++) {
182             unsigned x, y;
183              
184 0           x = buf[u];
185 0           y = x ^ ctx->buf[ptr + u];
186 0 0         ctx->buf[ptr + u] = encrypt ? y : x;
187 0           buf[u] = y;
188             }
189 0           ctx->count_ctr += (uint64_t)clen;
190 0           buf += clen;
191 0           len -= clen;
192 0 0         if (ptr + clen < 16) {
193 0           return;
194             }
195 0           ctx->gh(ctx->y, ctx->h, ctx->buf, 16);
196             }
197              
198             /*
199             * Process full blocks.
200             */
201 16           dlen = len & ~(size_t)15;
202 16 100         if (!encrypt) {
203 8           ctx->gh(ctx->y, ctx->h, buf, dlen);
204             }
205 16           ctx->jc = (*ctx->bctx)->run(ctx->bctx, ctx->j0_1, ctx->jc, buf, dlen);
206 16 100         if (encrypt) {
207 8           ctx->gh(ctx->y, ctx->h, buf, dlen);
208             }
209 16           buf += dlen;
210 16           len -= dlen;
211 16           ctx->count_ctr += (uint64_t)dlen;
212              
213 16 100         if (len > 0) {
214             /*
215             * There is a partial block.
216             */
217             size_t u;
218              
219 6           memset(ctx->buf, 0, sizeof ctx->buf);
220 12           ctx->jc = (*ctx->bctx)->run(ctx->bctx, ctx->j0_1,
221 6           ctx->jc, ctx->buf, 16);
222 78 100         for (u = 0; u < len; u ++) {
223             unsigned x, y;
224              
225 72           x = buf[u];
226 72           y = x ^ ctx->buf[u];
227 72 100         ctx->buf[u] = encrypt ? y : x;
228 72           buf[u] = y;
229             }
230 6           ctx->count_ctr += (uint64_t)len;
231             }
232             }
233              
234             /* see bearssl_aead.h */
235             void
236 16           br_gcm_get_tag(br_gcm_context *ctx, void *tag)
237             {
238             size_t ptr;
239             unsigned char tmp[16];
240              
241 16           ptr = (size_t)ctx->count_ctr & (size_t)15;
242 16 100         if (ptr > 0) {
243             /*
244             * There is a partial block: encrypted/decrypted data has
245             * been produced, but the encrypted bytes must still be
246             * processed by GHASH.
247             */
248 6           ctx->gh(ctx->y, ctx->h, ctx->buf, ptr);
249             }
250              
251             /*
252             * Final block for GHASH: the AAD and plaintext lengths (in bits).
253             */
254 16           br_enc64be(tmp, ctx->count_aad << 3);
255 16           br_enc64be(tmp + 8, ctx->count_ctr << 3);
256 16           ctx->gh(ctx->y, ctx->h, tmp, 16);
257              
258             /*
259             * Tag is the GHASH output XORed with the encryption of the
260             * nonce with the initial counter value.
261             */
262 16           memcpy(tag, ctx->y, 16);
263 16           (*ctx->bctx)->run(ctx->bctx, ctx->j0_1, ctx->j0_2, tag, 16);
264 16           }
265              
266             /* see bearssl_aead.h */
267             void
268 0           br_gcm_get_tag_trunc(br_gcm_context *ctx, void *tag, size_t len)
269             {
270             unsigned char tmp[16];
271              
272 0           br_gcm_get_tag(ctx, tmp);
273 0           memcpy(tag, tmp, len);
274 0           }
275              
276             /* see bearssl_aead.h */
277             uint32_t
278 8           br_gcm_check_tag_trunc(br_gcm_context *ctx, const void *tag, size_t len)
279             {
280             unsigned char tmp[16];
281             size_t u;
282             int x;
283              
284 8           br_gcm_get_tag(ctx, tmp);
285 8           x = 0;
286 136 100         for (u = 0; u < len; u ++) {
287 128           x |= tmp[u] ^ ((const unsigned char *)tag)[u];
288             }
289 8           return EQ0(x);
290             }
291              
292             /* see bearssl_aead.h */
293             uint32_t
294 8           br_gcm_check_tag(br_gcm_context *ctx, const void *tag)
295             {
296 8           return br_gcm_check_tag_trunc(ctx, tag, 16);
297             }
298              
299             /* see bearssl_aead.h */
300             const br_aead_class br_gcm_vtable = {
301             16,
302             (void (*)(const br_aead_class **, const void *, size_t))
303             &br_gcm_reset,
304             (void (*)(const br_aead_class **, const void *, size_t))
305             &br_gcm_aad_inject,
306             (void (*)(const br_aead_class **))
307             &br_gcm_flip,
308             (void (*)(const br_aead_class **, int, void *, size_t))
309             &br_gcm_run,
310             (void (*)(const br_aead_class **, void *))
311             &br_gcm_get_tag,
312             (uint32_t (*)(const br_aead_class **, const void *))
313             &br_gcm_check_tag,
314             (void (*)(const br_aead_class **, void *, size_t))
315             &br_gcm_get_tag_trunc,
316             (uint32_t (*)(const br_aead_class **, const void *, size_t))
317             &br_gcm_check_tag_trunc
318             };