File Coverage

src/aead/ccm.c
Criterion Covered Total %
statement 0 132 0.0
branch 0 56 0.0
condition n/a
subroutine n/a
pod n/a
total 0 188 0.0


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             * The combined CTR + CBC-MAC functions can only handle full blocks,
32             * so some buffering is necessary.
33             *
34             * - 'ptr' contains a value from 0 to 15, which is the number of bytes
35             * accumulated in buf[] that still needs to be processed with the
36             * current CBC-MAC computation.
37             *
38             * - When processing the message itself, CTR encryption/decryption is
39             * also done at the same time. The first 'ptr' bytes of buf[] then
40             * contains the plaintext bytes, while the last '16 - ptr' bytes of
41             * buf[] are the remnants of the stream block, to be used against
42             * the next input bytes, when available. When 'ptr' is 0, the
43             * contents of buf[] are to be ignored.
44             *
45             * - The current counter and running CBC-MAC values are kept in 'ctr'
46             * and 'cbcmac', respectively.
47             */
48              
49             /* see bearssl_block.h */
50             void
51 0           br_ccm_init(br_ccm_context *ctx, const br_block_ctrcbc_class **bctx)
52             {
53 0           ctx->bctx = bctx;
54 0           }
55              
56             /* see bearssl_block.h */
57             int
58 0           br_ccm_reset(br_ccm_context *ctx, const void *nonce, size_t nonce_len,
59             uint64_t aad_len, uint64_t data_len, size_t tag_len)
60             {
61             unsigned char tmp[16];
62             unsigned u, q;
63              
64 0 0         if (nonce_len < 7 || nonce_len > 13) {
    0          
65 0           return 0;
66             }
67 0 0         if (tag_len < 4 || tag_len > 16 || (tag_len & 1) != 0) {
    0          
    0          
68 0           return 0;
69             }
70 0           q = 15 - (unsigned)nonce_len;
71 0           ctx->tag_len = tag_len;
72              
73             /*
74             * Block B0, to start CBC-MAC.
75             */
76 0           tmp[0] = (aad_len > 0 ? 0x40 : 0x00)
77 0 0         | (((unsigned)tag_len - 2) << 2)
78 0           | (q - 1);
79 0           memcpy(tmp + 1, nonce, nonce_len);
80 0 0         for (u = 0; u < q; u ++) {
81 0           tmp[15 - u] = (unsigned char)data_len;
82 0           data_len >>= 8;
83             }
84 0 0         if (data_len != 0) {
85             /*
86             * If the data length was not entirely consumed in the
87             * loop above, then it exceeds the maximum limit of
88             * q bytes (when encoded).
89             */
90 0           return 0;
91             }
92              
93             /*
94             * Start CBC-MAC.
95             */
96 0           memset(ctx->cbcmac, 0, sizeof ctx->cbcmac);
97 0           (*ctx->bctx)->mac(ctx->bctx, ctx->cbcmac, tmp, sizeof tmp);
98              
99             /*
100             * Assemble AAD length header.
101             */
102 0 0         if ((aad_len >> 32) != 0) {
103 0           ctx->buf[0] = 0xFF;
104 0           ctx->buf[1] = 0xFF;
105 0           br_enc64be(ctx->buf + 2, aad_len);
106 0           ctx->ptr = 10;
107 0 0         } else if (aad_len >= 0xFF00) {
108 0           ctx->buf[0] = 0xFF;
109 0           ctx->buf[1] = 0xFE;
110 0           br_enc32be(ctx->buf + 2, (uint32_t)aad_len);
111 0           ctx->ptr = 6;
112 0 0         } else if (aad_len > 0) {
113 0           br_enc16be(ctx->buf, (unsigned)aad_len);
114 0           ctx->ptr = 2;
115             } else {
116 0           ctx->ptr = 0;
117             }
118              
119             /*
120             * Make initial counter value and compute tag mask.
121             */
122 0           ctx->ctr[0] = q - 1;
123 0           memcpy(ctx->ctr + 1, nonce, nonce_len);
124 0           memset(ctx->ctr + 1 + nonce_len, 0, q);
125 0           memset(ctx->tagmask, 0, sizeof ctx->tagmask);
126 0           (*ctx->bctx)->ctr(ctx->bctx, ctx->ctr,
127 0           ctx->tagmask, sizeof ctx->tagmask);
128              
129 0           return 1;
130             }
131              
132             /* see bearssl_block.h */
133             void
134 0           br_ccm_aad_inject(br_ccm_context *ctx, const void *data, size_t len)
135             {
136             const unsigned char *dbuf;
137             size_t ptr;
138              
139 0           dbuf = data;
140              
141             /*
142             * Complete partial block, if needed.
143             */
144 0           ptr = ctx->ptr;
145 0 0         if (ptr != 0) {
146             size_t clen;
147              
148 0           clen = (sizeof ctx->buf) - ptr;
149 0 0         if (clen > len) {
150 0           memcpy(ctx->buf + ptr, dbuf, len);
151 0           ctx->ptr = ptr + len;
152 0           return;
153             }
154 0           memcpy(ctx->buf + ptr, dbuf, clen);
155 0           dbuf += clen;
156 0           len -= clen;
157 0           (*ctx->bctx)->mac(ctx->bctx, ctx->cbcmac,
158 0           ctx->buf, sizeof ctx->buf);
159             }
160              
161             /*
162             * Process complete blocks.
163             */
164 0           ptr = len & 15;
165 0           len -= ptr;
166 0           (*ctx->bctx)->mac(ctx->bctx, ctx->cbcmac, dbuf, len);
167 0           dbuf += len;
168              
169             /*
170             * Copy last partial block in the context buffer.
171             */
172 0           memcpy(ctx->buf, dbuf, ptr);
173 0           ctx->ptr = ptr;
174             }
175              
176             /* see bearssl_block.h */
177             void
178 0           br_ccm_flip(br_ccm_context *ctx)
179             {
180             size_t ptr;
181              
182             /*
183             * Complete AAD partial block with zeros, if necessary.
184             */
185 0           ptr = ctx->ptr;
186 0 0         if (ptr != 0) {
187 0           memset(ctx->buf + ptr, 0, (sizeof ctx->buf) - ptr);
188 0           (*ctx->bctx)->mac(ctx->bctx, ctx->cbcmac,
189 0           ctx->buf, sizeof ctx->buf);
190 0           ctx->ptr = 0;
191             }
192              
193             /*
194             * Counter was already set by br_ccm_reset().
195             */
196 0           }
197              
198             /* see bearssl_block.h */
199             void
200 0           br_ccm_run(br_ccm_context *ctx, int encrypt, void *data, size_t len)
201             {
202             unsigned char *dbuf;
203             size_t ptr;
204              
205 0           dbuf = data;
206              
207             /*
208             * Complete a partial block, if any: ctx->buf[] contains
209             * ctx->ptr plaintext bytes (already reported), and the other
210             * bytes are CTR stream output.
211             */
212 0           ptr = ctx->ptr;
213 0 0         if (ptr != 0) {
214             size_t clen;
215             size_t u;
216              
217 0           clen = (sizeof ctx->buf) - ptr;
218 0 0         if (clen > len) {
219 0           clen = len;
220             }
221 0 0         if (encrypt) {
222 0 0         for (u = 0; u < clen; u ++) {
223             unsigned w, x;
224              
225 0           w = ctx->buf[ptr + u];
226 0           x = dbuf[u];
227 0           ctx->buf[ptr + u] = x;
228 0           dbuf[u] = w ^ x;
229             }
230             } else {
231 0 0         for (u = 0; u < clen; u ++) {
232             unsigned w;
233              
234 0           w = ctx->buf[ptr + u] ^ dbuf[u];
235 0           dbuf[u] = w;
236 0           ctx->buf[ptr + u] = w;
237             }
238             }
239 0           dbuf += clen;
240 0           len -= clen;
241 0           ptr += clen;
242 0 0         if (ptr < sizeof ctx->buf) {
243 0           ctx->ptr = ptr;
244 0           return;
245             }
246 0           (*ctx->bctx)->mac(ctx->bctx,
247 0           ctx->cbcmac, ctx->buf, sizeof ctx->buf);
248             }
249              
250             /*
251             * Process all complete blocks. Note that the ctrcbc API is for
252             * encrypt-then-MAC (CBC-MAC is computed over the encrypted
253             * blocks) while CCM uses MAC-and-encrypt (CBC-MAC is computed
254             * over the plaintext blocks). Therefore, we need to use the
255             * _decryption_ function for encryption, and the encryption
256             * function for decryption (this works because CTR encryption
257             * and decryption are identical, so the choice really is about
258             * computing the CBC-MAC before or after XORing with the CTR
259             * stream).
260             */
261 0           ptr = len & 15;
262 0           len -= ptr;
263 0 0         if (encrypt) {
264 0           (*ctx->bctx)->decrypt(ctx->bctx, ctx->ctr, ctx->cbcmac,
265             dbuf, len);
266             } else {
267 0           (*ctx->bctx)->encrypt(ctx->bctx, ctx->ctr, ctx->cbcmac,
268             dbuf, len);
269             }
270 0           dbuf += len;
271              
272             /*
273             * If there is some remaining data, then we need to compute an
274             * extra block of CTR stream.
275             */
276 0 0         if (ptr != 0) {
277             size_t u;
278              
279 0           memset(ctx->buf, 0, sizeof ctx->buf);
280 0           (*ctx->bctx)->ctr(ctx->bctx, ctx->ctr,
281 0           ctx->buf, sizeof ctx->buf);
282 0 0         if (encrypt) {
283 0 0         for (u = 0; u < ptr; u ++) {
284             unsigned w, x;
285              
286 0           w = ctx->buf[u];
287 0           x = dbuf[u];
288 0           ctx->buf[u] = x;
289 0           dbuf[u] = w ^ x;
290             }
291             } else {
292 0 0         for (u = 0; u < ptr; u ++) {
293             unsigned w;
294              
295 0           w = ctx->buf[u] ^ dbuf[u];
296 0           dbuf[u] = w;
297 0           ctx->buf[u] = w;
298             }
299             }
300             }
301 0           ctx->ptr = ptr;
302             }
303              
304             /* see bearssl_block.h */
305             size_t
306 0           br_ccm_get_tag(br_ccm_context *ctx, void *tag)
307             {
308             size_t ptr;
309             size_t u;
310              
311             /*
312             * If there is some buffered data, then we need to pad it with
313             * zeros and finish up CBC-MAC.
314             */
315 0           ptr = ctx->ptr;
316 0 0         if (ptr != 0) {
317 0           memset(ctx->buf + ptr, 0, (sizeof ctx->buf) - ptr);
318 0           (*ctx->bctx)->mac(ctx->bctx, ctx->cbcmac,
319 0           ctx->buf, sizeof ctx->buf);
320             }
321              
322             /*
323             * XOR the tag mask into the CBC-MAC output.
324             */
325 0 0         for (u = 0; u < ctx->tag_len; u ++) {
326 0           ctx->cbcmac[u] ^= ctx->tagmask[u];
327             }
328 0           memcpy(tag, ctx->cbcmac, ctx->tag_len);
329 0           return ctx->tag_len;
330             }
331              
332             /* see bearssl_block.h */
333             uint32_t
334 0           br_ccm_check_tag(br_ccm_context *ctx, const void *tag)
335             {
336             unsigned char tmp[16];
337             size_t u, tag_len;
338             uint32_t z;
339              
340 0           tag_len = br_ccm_get_tag(ctx, tmp);
341 0           z = 0;
342 0 0         for (u = 0; u < tag_len; u ++) {
343 0           z |= tmp[u] ^ ((const unsigned char *)tag)[u];
344             }
345 0           return EQ0(z);
346             }