/src/BearSSL/src/aead/gcm.c
Line | Count | Source |
1 | | /* |
2 | | * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org> |
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 | | br_gcm_init(br_gcm_context *ctx, const br_block_ctr_class **bctx, br_ghash gh) |
56 | 1.53k | { |
57 | 1.53k | unsigned char iv[12]; |
58 | | |
59 | 1.53k | ctx->vtable = &br_gcm_vtable; |
60 | 1.53k | ctx->bctx = bctx; |
61 | 1.53k | 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 | 1.53k | memset(ctx->h, 0, sizeof ctx->h); |
70 | 1.53k | memset(iv, 0, sizeof iv); |
71 | 1.53k | (*bctx)->run(bctx, iv, 0, ctx->h, sizeof ctx->h); |
72 | 1.53k | } |
73 | | |
74 | | /* see bearssl_aead.h */ |
75 | | void |
76 | | br_gcm_reset(br_gcm_context *ctx, const void *iv, size_t len) |
77 | 1.53k | { |
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 | 1.53k | if (len == 12) { |
88 | 101 | memcpy(ctx->j0_1, iv, 12); |
89 | 101 | ctx->j0_2 = 1; |
90 | 1.43k | } else { |
91 | 1.43k | unsigned char ty[16], tmp[16]; |
92 | | |
93 | 1.43k | memset(ty, 0, sizeof ty); |
94 | 1.43k | ctx->gh(ty, ctx->h, iv, len); |
95 | 1.43k | memset(tmp, 0, 8); |
96 | 1.43k | br_enc64be(tmp + 8, (uint64_t)len << 3); |
97 | 1.43k | ctx->gh(ty, ctx->h, tmp, 16); |
98 | 1.43k | memcpy(ctx->j0_1, ty, 12); |
99 | 1.43k | ctx->j0_2 = br_dec32be(ty + 12); |
100 | 1.43k | } |
101 | 1.53k | ctx->jc = ctx->j0_2 + 1; |
102 | 1.53k | memset(ctx->y, 0, sizeof ctx->y); |
103 | 1.53k | ctx->count_aad = 0; |
104 | 1.53k | ctx->count_ctr = 0; |
105 | 1.53k | } |
106 | | |
107 | | /* see bearssl_aead.h */ |
108 | | void |
109 | | br_gcm_aad_inject(br_gcm_context *ctx, const void *data, size_t len) |
110 | 2.12k | { |
111 | 2.12k | size_t ptr, dlen; |
112 | | |
113 | 2.12k | ptr = (size_t)ctx->count_aad & (size_t)15; |
114 | 2.12k | if (ptr != 0) { |
115 | | /* |
116 | | * If there is a partial block, then we first try to |
117 | | * complete it. |
118 | | */ |
119 | 798 | size_t clen; |
120 | | |
121 | 798 | clen = 16 - ptr; |
122 | 798 | if (len < clen) { |
123 | 676 | memcpy(ctx->buf + ptr, data, len); |
124 | 676 | ctx->count_aad += (uint64_t)len; |
125 | 676 | return; |
126 | 676 | } |
127 | 122 | memcpy(ctx->buf + ptr, data, clen); |
128 | 122 | ctx->gh(ctx->y, ctx->h, ctx->buf, 16); |
129 | 122 | data = (const unsigned char *)data + clen; |
130 | 122 | len -= clen; |
131 | 122 | ctx->count_aad += (uint64_t)clen; |
132 | 122 | } |
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 | 1.45k | dlen = len & ~(size_t)15; |
140 | 1.45k | ctx->gh(ctx->y, ctx->h, data, dlen); |
141 | 1.45k | memcpy(ctx->buf, (const unsigned char *)data + dlen, len - dlen); |
142 | 1.45k | ctx->count_aad += (uint64_t)len; |
143 | 1.45k | } |
144 | | |
145 | | /* see bearssl_aead.h */ |
146 | | void |
147 | | br_gcm_flip(br_gcm_context *ctx) |
148 | 1.53k | { |
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 | 1.53k | size_t ptr; |
155 | | |
156 | 1.53k | ptr = (size_t)ctx->count_aad & (size_t)15; |
157 | 1.53k | if (ptr != 0) { |
158 | 281 | ctx->gh(ctx->y, ctx->h, ctx->buf, ptr); |
159 | 281 | } |
160 | 1.53k | } |
161 | | |
162 | | /* see bearssl_aead.h */ |
163 | | void |
164 | | br_gcm_run(br_gcm_context *ctx, int encrypt, void *data, size_t len) |
165 | 19.0k | { |
166 | 19.0k | unsigned char *buf; |
167 | 19.0k | size_t ptr, dlen; |
168 | | |
169 | 19.0k | buf = data; |
170 | 19.0k | ptr = (size_t)ctx->count_ctr & (size_t)15; |
171 | 19.0k | if (ptr != 0) { |
172 | | /* |
173 | | * If we have a partial block, then we try to complete it. |
174 | | */ |
175 | 12.5k | size_t u, clen; |
176 | | |
177 | 12.5k | clen = 16 - ptr; |
178 | 12.5k | if (len < clen) { |
179 | 11.9k | clen = len; |
180 | 11.9k | } |
181 | 17.5k | for (u = 0; u < clen; u ++) { |
182 | 4.97k | unsigned x, y; |
183 | | |
184 | 4.97k | x = buf[u]; |
185 | 4.97k | y = x ^ ctx->buf[ptr + u]; |
186 | 4.97k | ctx->buf[ptr + u] = encrypt ? y : x; |
187 | 4.97k | buf[u] = y; |
188 | 4.97k | } |
189 | 12.5k | ctx->count_ctr += (uint64_t)clen; |
190 | 12.5k | buf += clen; |
191 | 12.5k | len -= clen; |
192 | 12.5k | if (ptr + clen < 16) { |
193 | 11.9k | return; |
194 | 11.9k | } |
195 | 565 | ctx->gh(ctx->y, ctx->h, ctx->buf, 16); |
196 | 565 | } |
197 | | |
198 | | /* |
199 | | * Process full blocks. |
200 | | */ |
201 | 7.09k | dlen = len & ~(size_t)15; |
202 | 7.09k | if (!encrypt) { |
203 | 1.38k | ctx->gh(ctx->y, ctx->h, buf, dlen); |
204 | 1.38k | } |
205 | 7.09k | ctx->jc = (*ctx->bctx)->run(ctx->bctx, ctx->j0_1, ctx->jc, buf, dlen); |
206 | 7.09k | if (encrypt) { |
207 | 5.70k | ctx->gh(ctx->y, ctx->h, buf, dlen); |
208 | 5.70k | } |
209 | 7.09k | buf += dlen; |
210 | 7.09k | len -= dlen; |
211 | 7.09k | ctx->count_ctr += (uint64_t)dlen; |
212 | | |
213 | 7.09k | if (len > 0) { |
214 | | /* |
215 | | * There is a partial block. |
216 | | */ |
217 | 1.70k | size_t u; |
218 | | |
219 | 1.70k | memset(ctx->buf, 0, sizeof ctx->buf); |
220 | 1.70k | ctx->jc = (*ctx->bctx)->run(ctx->bctx, ctx->j0_1, |
221 | 1.70k | ctx->jc, ctx->buf, 16); |
222 | 9.06k | for (u = 0; u < len; u ++) { |
223 | 7.35k | unsigned x, y; |
224 | | |
225 | 7.35k | x = buf[u]; |
226 | 7.35k | y = x ^ ctx->buf[u]; |
227 | 7.35k | ctx->buf[u] = encrypt ? y : x; |
228 | 7.35k | buf[u] = y; |
229 | 7.35k | } |
230 | 1.70k | ctx->count_ctr += (uint64_t)len; |
231 | 1.70k | } |
232 | 7.09k | } |
233 | | |
234 | | /* see bearssl_aead.h */ |
235 | | void |
236 | | br_gcm_get_tag(br_gcm_context *ctx, void *tag) |
237 | 588 | { |
238 | 588 | size_t ptr; |
239 | 588 | unsigned char tmp[16]; |
240 | | |
241 | 588 | ptr = (size_t)ctx->count_ctr & (size_t)15; |
242 | 588 | 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 | 435 | ctx->gh(ctx->y, ctx->h, ctx->buf, ptr); |
249 | 435 | } |
250 | | |
251 | | /* |
252 | | * Final block for GHASH: the AAD and plaintext lengths (in bits). |
253 | | */ |
254 | 588 | br_enc64be(tmp, ctx->count_aad << 3); |
255 | 588 | br_enc64be(tmp + 8, ctx->count_ctr << 3); |
256 | 588 | 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 | 588 | memcpy(tag, ctx->y, 16); |
263 | 588 | (*ctx->bctx)->run(ctx->bctx, ctx->j0_1, ctx->j0_2, tag, 16); |
264 | 588 | } |
265 | | |
266 | | /* see bearssl_aead.h */ |
267 | | void |
268 | | br_gcm_get_tag_trunc(br_gcm_context *ctx, void *tag, size_t len) |
269 | 0 | { |
270 | 0 | 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 | | br_gcm_check_tag_trunc(br_gcm_context *ctx, const void *tag, size_t len) |
279 | 303 | { |
280 | 303 | unsigned char tmp[16]; |
281 | 303 | size_t u; |
282 | 303 | int x; |
283 | | |
284 | 303 | br_gcm_get_tag(ctx, tmp); |
285 | 303 | x = 0; |
286 | 5.15k | for (u = 0; u < len; u ++) { |
287 | 4.84k | x |= tmp[u] ^ ((const unsigned char *)tag)[u]; |
288 | 4.84k | } |
289 | 303 | return EQ0(x); |
290 | 303 | } |
291 | | |
292 | | /* see bearssl_aead.h */ |
293 | | uint32_t |
294 | | br_gcm_check_tag(br_gcm_context *ctx, const void *tag) |
295 | 303 | { |
296 | 303 | return br_gcm_check_tag_trunc(ctx, tag, 16); |
297 | 303 | } |
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 | | }; |