aes_ccm.c revision 1.3 1 1.3 riastrad /* $NetBSD: aes_ccm.c,v 1.3 2020/07/26 04:44:47 riastradh Exp $ */
2 1.1 riastrad
3 1.1 riastrad /*-
4 1.1 riastrad * Copyright (c) 2020 The NetBSD Foundation, Inc.
5 1.1 riastrad * All rights reserved.
6 1.1 riastrad *
7 1.1 riastrad * Redistribution and use in source and binary forms, with or without
8 1.1 riastrad * modification, are permitted provided that the following conditions
9 1.1 riastrad * are met:
10 1.1 riastrad * 1. Redistributions of source code must retain the above copyright
11 1.1 riastrad * notice, this list of conditions and the following disclaimer.
12 1.1 riastrad * 2. Redistributions in binary form must reproduce the above copyright
13 1.1 riastrad * notice, this list of conditions and the following disclaimer in the
14 1.1 riastrad * documentation and/or other materials provided with the distribution.
15 1.1 riastrad *
16 1.1 riastrad * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17 1.1 riastrad * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18 1.1 riastrad * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 1.1 riastrad * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20 1.1 riastrad * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 1.1 riastrad * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 1.1 riastrad * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 1.1 riastrad * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 1.1 riastrad * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 1.1 riastrad * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 1.1 riastrad * POSSIBILITY OF SUCH DAMAGE.
27 1.1 riastrad */
28 1.1 riastrad
29 1.1 riastrad /*
30 1.1 riastrad * AES-CCM, as defined in:
31 1.1 riastrad *
32 1.1 riastrad * D. Whiting, R. Housley, and N. Ferguson, `Counter with CBC-MAC
33 1.1 riastrad * (CCM)', IETF RFC 3610, September 2003.
34 1.1 riastrad * https://tools.ietf.org/html/rfc3610
35 1.1 riastrad */
36 1.1 riastrad
37 1.1 riastrad #include <sys/cdefs.h>
38 1.3 riastrad __KERNEL_RCSID(1, "$NetBSD: aes_ccm.c,v 1.3 2020/07/26 04:44:47 riastradh Exp $");
39 1.1 riastrad
40 1.1 riastrad #include <sys/types.h>
41 1.1 riastrad #include <sys/param.h>
42 1.1 riastrad #include <sys/systm.h>
43 1.1 riastrad
44 1.1 riastrad #include <lib/libkern/libkern.h>
45 1.1 riastrad
46 1.1 riastrad #include <crypto/aes/aes.h>
47 1.1 riastrad #include <crypto/aes/aes_ccm.h>
48 1.2 riastrad #include <crypto/aes/aes_impl.h>
49 1.1 riastrad
50 1.1 riastrad static inline void
51 1.1 riastrad xor(uint8_t *x, const uint8_t *a, const uint8_t *b, size_t n)
52 1.1 riastrad {
53 1.1 riastrad
54 1.1 riastrad while (n --> 0)
55 1.1 riastrad *x++ = *a++ ^ *b++;
56 1.1 riastrad }
57 1.1 riastrad
58 1.1 riastrad /* RFC 3610, 2.2 Authentication */
59 1.1 riastrad #define CCM_AFLAGS_ADATA __BIT(6)
60 1.1 riastrad #define CCM_AFLAGS_M __BITS(5,3)
61 1.1 riastrad #define CCM_AFLAGS_L __BITS(2,0)
62 1.1 riastrad
63 1.1 riastrad /* RFC 3610, 2.3 Encryption */
64 1.1 riastrad #define CCM_EFLAGS_L __BITS(2,0)
65 1.1 riastrad
66 1.1 riastrad static void
67 1.1 riastrad aes_ccm_inc(struct aes_ccm *C)
68 1.1 riastrad {
69 1.1 riastrad
70 1.1 riastrad KASSERT(C->L == 2);
71 1.1 riastrad if (++C->in[15] == 0 && ++C->in[14] == 0)
72 1.1 riastrad panic("AES-CCM overflow");
73 1.1 riastrad }
74 1.1 riastrad
75 1.1 riastrad static void
76 1.1 riastrad aes_ccm_zero_ctr(struct aes_ccm *C)
77 1.1 riastrad {
78 1.1 riastrad
79 1.1 riastrad KASSERT(C->L == 2);
80 1.1 riastrad C->in[14] = C->in[15] = 0;
81 1.1 riastrad }
82 1.1 riastrad
83 1.1 riastrad void
84 1.1 riastrad aes_ccm_init(struct aes_ccm *C, unsigned nr, const struct aesenc *enc,
85 1.1 riastrad unsigned L, unsigned M,
86 1.1 riastrad const uint8_t *nonce, unsigned noncelen, const void *ad, size_t adlen,
87 1.1 riastrad size_t mlen)
88 1.1 riastrad {
89 1.1 riastrad const uint8_t *adp = ad;
90 1.1 riastrad unsigned i;
91 1.1 riastrad
92 1.1 riastrad KASSERT(L == 2);
93 1.1 riastrad KASSERT(M % 2 == 0);
94 1.1 riastrad KASSERT(M >= 4);
95 1.1 riastrad KASSERT(M <= 16);
96 1.1 riastrad KASSERT(noncelen == 15 - L);
97 1.1 riastrad
98 1.1 riastrad C->enc = enc;
99 1.1 riastrad C->nr = nr;
100 1.1 riastrad C->L = L;
101 1.1 riastrad C->M = M;
102 1.1 riastrad C->mlen = C->mleft = mlen;
103 1.1 riastrad
104 1.1 riastrad /* Encode B0, the initial authenticated data block. */
105 1.1 riastrad C->auth[0] = __SHIFTIN(adlen == 0 ? 0 : 1, CCM_AFLAGS_ADATA);
106 1.1 riastrad C->auth[0] |= __SHIFTIN((M - 2)/2, CCM_AFLAGS_M);
107 1.1 riastrad C->auth[0] |= __SHIFTIN(L - 1, CCM_AFLAGS_L);
108 1.1 riastrad memcpy(C->auth + 1, nonce, noncelen);
109 1.1 riastrad for (i = 0; i < L; i++, mlen >>= 8) {
110 1.1 riastrad KASSERT(i < 16 - 1 - noncelen);
111 1.1 riastrad C->auth[16 - i - 1] = mlen & 0xff;
112 1.1 riastrad }
113 1.1 riastrad aes_enc(enc, C->auth, C->auth, C->nr);
114 1.1 riastrad
115 1.1 riastrad /* Process additional authenticated data, if any. */
116 1.1 riastrad if (adlen) {
117 1.1 riastrad /* Encode the length according to the table on p. 4. */
118 1.1 riastrad if (adlen < 0xff00) {
119 1.1 riastrad C->auth[0] ^= adlen >> 8;
120 1.1 riastrad C->auth[1] ^= adlen;
121 1.1 riastrad i = 2;
122 1.1 riastrad } else if (adlen < 0xffffffff) {
123 1.1 riastrad C->auth[0] ^= 0xff;
124 1.1 riastrad C->auth[1] ^= 0xfe;
125 1.1 riastrad C->auth[2] ^= adlen >> 24;
126 1.1 riastrad C->auth[3] ^= adlen >> 16;
127 1.1 riastrad C->auth[4] ^= adlen >> 8;
128 1.1 riastrad C->auth[5] ^= adlen;
129 1.1 riastrad i = 6;
130 1.1 riastrad #if SIZE_MAX > 0xffffffffU
131 1.1 riastrad } else {
132 1.1 riastrad CTASSERT(SIZE_MAX <= 0xffffffffffffffff);
133 1.1 riastrad C->auth[0] ^= 0xff;
134 1.1 riastrad C->auth[1] ^= 0xff;
135 1.1 riastrad C->auth[2] ^= adlen >> 56;
136 1.1 riastrad C->auth[3] ^= adlen >> 48;
137 1.1 riastrad C->auth[4] ^= adlen >> 40;
138 1.1 riastrad C->auth[5] ^= adlen >> 32;
139 1.1 riastrad C->auth[6] ^= adlen >> 24;
140 1.1 riastrad C->auth[7] ^= adlen >> 16;
141 1.1 riastrad C->auth[8] ^= adlen >> 8;
142 1.1 riastrad C->auth[9] ^= adlen;
143 1.1 riastrad i = 10;
144 1.1 riastrad #endif
145 1.1 riastrad }
146 1.1 riastrad
147 1.1 riastrad /* Fill out the partial block if we can, and encrypt. */
148 1.1 riastrad xor(C->auth + i, C->auth + i, adp, MIN(adlen, 16 - i));
149 1.1 riastrad adp += MIN(adlen, 16 - i);
150 1.1 riastrad adlen -= MIN(adlen, 16 - i);
151 1.1 riastrad aes_enc(enc, C->auth, C->auth, C->nr);
152 1.1 riastrad
153 1.1 riastrad /* If there was anything more, process 16 bytes at a time. */
154 1.2 riastrad if (adlen - (adlen % 16)) {
155 1.2 riastrad aes_cbcmac_update1(enc, adp, adlen - (adlen % 16),
156 1.2 riastrad C->auth, C->nr);
157 1.2 riastrad adlen %= 16;
158 1.1 riastrad }
159 1.1 riastrad
160 1.1 riastrad /*
161 1.1 riastrad * If there's anything at the end, enter it in (padded
162 1.1 riastrad * with zeros, which is a no-op) and process it.
163 1.1 riastrad */
164 1.1 riastrad if (adlen) {
165 1.1 riastrad xor(C->auth, C->auth, adp, adlen);
166 1.1 riastrad aes_enc(enc, C->auth, C->auth, C->nr);
167 1.1 riastrad }
168 1.1 riastrad }
169 1.1 riastrad
170 1.1 riastrad /* Set up the AES input for AES-CTR encryption. */
171 1.1 riastrad C->in[0] = __SHIFTIN(L - 1, CCM_EFLAGS_L);
172 1.1 riastrad memcpy(C->in + 1, nonce, noncelen);
173 1.1 riastrad memset(C->in + 1 + noncelen, 0, 16 - 1 - noncelen);
174 1.1 riastrad
175 1.1 riastrad /* Start on a block boundary. */
176 1.1 riastrad C->i = 0;
177 1.1 riastrad }
178 1.1 riastrad
179 1.1 riastrad void
180 1.1 riastrad aes_ccm_enc(struct aes_ccm *C, const void *in, void *out, size_t nbytes)
181 1.1 riastrad {
182 1.1 riastrad const uint8_t *p = in;
183 1.1 riastrad uint8_t *q = out;
184 1.1 riastrad
185 1.1 riastrad KASSERTMSG(C->i != ~0u,
186 1.1 riastrad "%s not allowed after message complete", __func__);
187 1.1 riastrad KASSERTMSG(nbytes <= C->mleft,
188 1.1 riastrad "message too long: promised %zu bytes, processing >=%zu",
189 1.1 riastrad C->mlen, C->mlen - C->mleft + nbytes);
190 1.1 riastrad C->mleft -= nbytes;
191 1.1 riastrad
192 1.1 riastrad /* Finish a partial block if it was already started. */
193 1.1 riastrad if (C->i) {
194 1.1 riastrad unsigned m = MIN(16 - C->i, nbytes);
195 1.1 riastrad
196 1.1 riastrad xor(C->auth + C->i, C->auth + C->i, p, m);
197 1.1 riastrad xor(q, C->out + C->i, p, m);
198 1.1 riastrad C->i += m;
199 1.1 riastrad p += m;
200 1.1 riastrad q += m;
201 1.1 riastrad nbytes -= m;
202 1.1 riastrad
203 1.1 riastrad if (C->i == 16) {
204 1.1 riastrad /* Finished a block; authenticate it. */
205 1.1 riastrad aes_enc(C->enc, C->auth, C->auth, C->nr);
206 1.1 riastrad C->i = 0;
207 1.1 riastrad } else {
208 1.1 riastrad /* Didn't finish block, must be done with input. */
209 1.1 riastrad KASSERT(nbytes == 0);
210 1.1 riastrad return;
211 1.1 riastrad }
212 1.1 riastrad }
213 1.1 riastrad
214 1.1 riastrad /* Process 16 bytes at a time. */
215 1.2 riastrad if (nbytes - (nbytes % 16)) {
216 1.2 riastrad aes_ccm_enc1(C->enc, p, q, nbytes - (nbytes % 16), C->auth,
217 1.2 riastrad C->nr);
218 1.2 riastrad p += nbytes - (nbytes % 16);
219 1.2 riastrad q += nbytes - (nbytes % 16);
220 1.2 riastrad nbytes %= 16;
221 1.1 riastrad }
222 1.1 riastrad
223 1.1 riastrad /* Incorporate any <16-byte unit as a partial block. */
224 1.1 riastrad if (nbytes) {
225 1.1 riastrad /* authenticate */
226 1.1 riastrad xor(C->auth, C->auth, p, nbytes);
227 1.1 riastrad
228 1.1 riastrad /* encrypt */
229 1.1 riastrad aes_ccm_inc(C);
230 1.1 riastrad aes_enc(C->enc, C->in, C->out, C->nr);
231 1.1 riastrad xor(q, C->out, p, nbytes);
232 1.1 riastrad
233 1.1 riastrad C->i = nbytes;
234 1.1 riastrad }
235 1.1 riastrad }
236 1.1 riastrad
237 1.1 riastrad void
238 1.1 riastrad aes_ccm_dec(struct aes_ccm *C, const void *in, void *out, size_t nbytes)
239 1.1 riastrad {
240 1.1 riastrad const uint8_t *p = in;
241 1.1 riastrad uint8_t *q = out;
242 1.1 riastrad
243 1.1 riastrad KASSERTMSG(C->i != ~0u,
244 1.1 riastrad "%s not allowed after message complete", __func__);
245 1.1 riastrad KASSERTMSG(nbytes <= C->mleft,
246 1.1 riastrad "message too long: promised %zu bytes, processing >=%zu",
247 1.1 riastrad C->mlen, C->mlen - C->mleft + nbytes);
248 1.1 riastrad C->mleft -= nbytes;
249 1.1 riastrad
250 1.1 riastrad /* Finish a partial block if it was already started. */
251 1.1 riastrad if (C->i) {
252 1.1 riastrad unsigned m = MIN(16 - C->i, nbytes);
253 1.1 riastrad
254 1.1 riastrad xor(q, C->out + C->i, p, m);
255 1.1 riastrad xor(C->auth + C->i, C->auth + C->i, q, m);
256 1.1 riastrad C->i += m;
257 1.1 riastrad p += m;
258 1.1 riastrad q += m;
259 1.1 riastrad nbytes -= m;
260 1.1 riastrad
261 1.1 riastrad if (C->i == 16) {
262 1.1 riastrad /* Finished a block; authenticate it. */
263 1.1 riastrad aes_enc(C->enc, C->auth, C->auth, C->nr);
264 1.1 riastrad C->i = 0;
265 1.1 riastrad } else {
266 1.1 riastrad /* Didn't finish block, must be done with input. */
267 1.1 riastrad KASSERT(nbytes == 0);
268 1.1 riastrad return;
269 1.1 riastrad }
270 1.1 riastrad }
271 1.1 riastrad
272 1.1 riastrad /* Process 16 bytes at a time. */
273 1.2 riastrad if (nbytes - (nbytes % 16)) {
274 1.2 riastrad aes_ccm_dec1(C->enc, p, q, nbytes - (nbytes % 16), C->auth,
275 1.2 riastrad C->nr);
276 1.2 riastrad p += nbytes - (nbytes % 16);
277 1.2 riastrad q += nbytes - (nbytes % 16);
278 1.2 riastrad nbytes %= 16;
279 1.1 riastrad }
280 1.1 riastrad
281 1.1 riastrad /* Incorporate any <16-byte unit as a partial block. */
282 1.1 riastrad if (nbytes) {
283 1.1 riastrad /* decrypt */
284 1.1 riastrad aes_ccm_inc(C);
285 1.1 riastrad aes_enc(C->enc, C->in, C->out, C->nr);
286 1.1 riastrad xor(q, C->out, p, nbytes);
287 1.1 riastrad
288 1.1 riastrad /* authenticate */
289 1.1 riastrad xor(C->auth, C->auth, q, nbytes);
290 1.1 riastrad
291 1.1 riastrad C->i = nbytes;
292 1.1 riastrad }
293 1.1 riastrad }
294 1.1 riastrad
295 1.1 riastrad void
296 1.1 riastrad aes_ccm_tag(struct aes_ccm *C, void *out)
297 1.1 riastrad {
298 1.1 riastrad
299 1.1 riastrad KASSERTMSG(C->mleft == 0,
300 1.1 riastrad "message too short: promised %zu bytes, processed %zu",
301 1.1 riastrad C->mlen, C->mlen - C->mleft);
302 1.1 riastrad
303 1.1 riastrad /* Zero-pad and munch up a partial block, if any. */
304 1.1 riastrad if (C->i)
305 1.1 riastrad aes_enc(C->enc, C->auth, C->auth, C->nr);
306 1.1 riastrad
307 1.1 riastrad /* Zero the counter and generate a pad for the tag. */
308 1.1 riastrad aes_ccm_zero_ctr(C);
309 1.1 riastrad aes_enc(C->enc, C->in, C->out, C->nr);
310 1.1 riastrad
311 1.1 riastrad /* Copy out as many bytes as requested. */
312 1.1 riastrad xor(out, C->out, C->auth, C->M);
313 1.1 riastrad
314 1.1 riastrad C->i = ~0u; /* paranoia: prevent future misuse */
315 1.1 riastrad }
316 1.1 riastrad
317 1.1 riastrad int
318 1.1 riastrad aes_ccm_verify(struct aes_ccm *C, const void *tag)
319 1.1 riastrad {
320 1.1 riastrad uint8_t expected[16];
321 1.1 riastrad int result;
322 1.1 riastrad
323 1.1 riastrad aes_ccm_tag(C, expected);
324 1.1 riastrad result = consttime_memequal(tag, expected, C->M);
325 1.1 riastrad explicit_memset(expected, 0, sizeof expected);
326 1.1 riastrad
327 1.1 riastrad return result;
328 1.1 riastrad }
329 1.1 riastrad
330 1.1 riastrad /* RFC 3610, 8 */
331 1.1 riastrad
332 1.1 riastrad static const uint8_t keyC[16] = {
333 1.1 riastrad 0xc0,0xc1,0xc2,0xc3, 0xc4,0xc5,0xc6,0xc7,
334 1.1 riastrad 0xc8,0xc9,0xca,0xcb, 0xcc,0xcd,0xce,0xcf,
335 1.1 riastrad };
336 1.1 riastrad
337 1.1 riastrad static const uint8_t keyD[16] = {
338 1.1 riastrad 0xd7,0x82,0x8d,0x13, 0xb2,0xb0,0xbd,0xc3,
339 1.1 riastrad 0x25,0xa7,0x62,0x36, 0xdf,0x93,0xcc,0x6b,
340 1.1 riastrad };
341 1.1 riastrad
342 1.1 riastrad static const uint8_t ptxt_seq[] = {
343 1.1 riastrad 0x00,0x01,0x02,0x03, 0x04,0x05,0x06,0x07,
344 1.1 riastrad 0x08,0x09,0x0a,0x0b, 0x0c,0x0d,0x0e,0x0f,
345 1.1 riastrad 0x10,0x11,0x12,0x13, 0x14,0x15,0x16,0x17,
346 1.1 riastrad 0x18,0x19,0x1a,0x1b, 0x1c,0x1d,0x1e,0x1f,
347 1.1 riastrad 0x20,
348 1.1 riastrad };
349 1.1 riastrad
350 1.1 riastrad static const uint8_t ptxt_rand[] = {
351 1.1 riastrad 0x6e,0x37,0xa6,0xef, 0x54,0x6d,0x95,0x5d,
352 1.1 riastrad 0x34,0xab,0x60,0x59, 0xab,0xf2,0x1c,0x0b,
353 1.1 riastrad 0x02,0xfe,0xb8,0x8f, 0x85,0x6d,0xf4,0xa3,
354 1.1 riastrad 0x73,0x81,0xbc,0xe3, 0xcc,0x12,0x85,0x17,
355 1.1 riastrad 0xd4,
356 1.1 riastrad };
357 1.1 riastrad
358 1.1 riastrad static const struct {
359 1.1 riastrad const uint8_t *key;
360 1.1 riastrad size_t noncelen;
361 1.1 riastrad const uint8_t nonce[13];
362 1.1 riastrad size_t adlen;
363 1.1 riastrad const uint8_t *ad;
364 1.1 riastrad size_t mlen;
365 1.1 riastrad const uint8_t *ptxt;
366 1.1 riastrad unsigned M;
367 1.1 riastrad const uint8_t tag[16];
368 1.1 riastrad const uint8_t *ctxt;
369 1.1 riastrad } T[] = {
370 1.1 riastrad [0] = { /* Packet Vector #1, p. 11 */
371 1.1 riastrad .key = keyC,
372 1.1 riastrad .nonce = {
373 1.1 riastrad 0x00,0x00,0x00,0x03, 0x02,0x01,0x00,0xa0,
374 1.1 riastrad 0xa1,0xa2,0xa3,0xa4, 0xa5,
375 1.1 riastrad },
376 1.1 riastrad .adlen = 8,
377 1.1 riastrad .ad = ptxt_seq,
378 1.1 riastrad .mlen = 23,
379 1.1 riastrad .ptxt = ptxt_seq + 8,
380 1.1 riastrad .M = 8,
381 1.1 riastrad .tag = {0x17,0xe8,0xd1,0x2c,0xfd, 0xf9,0x26,0xe0},
382 1.1 riastrad .ctxt = (const uint8_t[23]) {
383 1.1 riastrad 0x58,0x8c,0x97,0x9a, 0x61,0xc6,0x63,0xd2,
384 1.1 riastrad 0xf0,0x66,0xd0,0xc2, 0xc0,0xf9,0x89,0x80,
385 1.1 riastrad 0x6d,0x5f,0x6b,0x61, 0xda,0xc3,0x84,
386 1.1 riastrad },
387 1.1 riastrad },
388 1.1 riastrad [1] = { /* Packet Vector #2, p. 11 */
389 1.1 riastrad .key = keyC,
390 1.1 riastrad .nonce = {
391 1.1 riastrad 0x00,0x00,0x00,0x04, 0x03,0x02,0x01,0xa0,
392 1.1 riastrad 0xa1,0xa2,0xa3,0xa4, 0xa5,
393 1.1 riastrad },
394 1.1 riastrad .adlen = 8,
395 1.1 riastrad .ad = ptxt_seq,
396 1.1 riastrad .mlen = 24,
397 1.1 riastrad .ptxt = ptxt_seq + 8,
398 1.1 riastrad .M = 8,
399 1.1 riastrad .tag = {0xa0,0x91,0xd5,0x6e, 0x10,0x40,0x09,0x16},
400 1.1 riastrad .ctxt = (const uint8_t[24]) {
401 1.1 riastrad 0x72,0xc9,0x1a,0x36, 0xe1,0x35,0xf8,0xcf,
402 1.1 riastrad 0x29,0x1c,0xa8,0x94, 0x08,0x5c,0x87,0xe3,
403 1.1 riastrad 0xcc,0x15,0xc4,0x39, 0xc9,0xe4,0x3a,0x3b,
404 1.1 riastrad },
405 1.1 riastrad },
406 1.1 riastrad [2] = { /* Packet Vector #3, p. 12 */
407 1.1 riastrad .key = keyC,
408 1.1 riastrad .nonce = {
409 1.1 riastrad 0x00,0x00,0x00,0x05, 0x04,0x03,0x02,0xa0,
410 1.1 riastrad 0xa1,0xa2,0xa3,0xa4, 0xa5,
411 1.1 riastrad },
412 1.1 riastrad .adlen = 8,
413 1.1 riastrad .ad = ptxt_seq,
414 1.1 riastrad .mlen = 25,
415 1.1 riastrad .ptxt = ptxt_seq + 8,
416 1.1 riastrad .M = 8,
417 1.1 riastrad .tag = {0x4a,0xda,0xa7,0x6f, 0xbd,0x9f,0xb0,0xc5},
418 1.1 riastrad .ctxt = (const uint8_t[25]) {
419 1.1 riastrad 0x51,0xb1,0xe5,0xf4, 0x4a,0x19,0x7d,0x1d,
420 1.1 riastrad 0xa4,0x6b,0x0f,0x8e, 0x2d,0x28,0x2a,0xe8,
421 1.1 riastrad 0x71,0xe8,0x38,0xbb, 0x64,0xda,0x85,0x96,
422 1.1 riastrad 0x57,
423 1.1 riastrad },
424 1.1 riastrad },
425 1.1 riastrad [3] = { /* Packet Vector #4, p. 13 */
426 1.1 riastrad .key = keyC,
427 1.1 riastrad .nonce = {
428 1.1 riastrad 0x00,0x00,0x00,0x06, 0x05,0x04,0x03,0xa0,
429 1.1 riastrad 0xa1,0xa2,0xa3,0xa4, 0xa5,
430 1.1 riastrad },
431 1.1 riastrad .adlen = 12,
432 1.1 riastrad .ad = ptxt_seq,
433 1.1 riastrad .mlen = 19,
434 1.1 riastrad .ptxt = ptxt_seq + 12,
435 1.1 riastrad .M = 8,
436 1.1 riastrad .tag = {0x96,0xc8,0x61,0xb9, 0xc9,0xe6,0x1e,0xf1},
437 1.1 riastrad .ctxt = (const uint8_t[19]) {
438 1.1 riastrad 0xa2,0x8c,0x68,0x65, 0x93,0x9a,0x9a,0x79,
439 1.1 riastrad 0xfa,0xaa,0x5c,0x4c, 0x2a,0x9d,0x4a,0x91,
440 1.1 riastrad 0xcd,0xac,0x8c,
441 1.1 riastrad },
442 1.1 riastrad },
443 1.1 riastrad [4] = { /* Packet Vector #5, p. 13 */
444 1.1 riastrad .key = keyC,
445 1.1 riastrad .nonce = {
446 1.1 riastrad 0x00,0x00,0x00,0x07, 0x06,0x05,0x04,0xa0,
447 1.1 riastrad 0xa1,0xa2,0xa3,0xa4, 0xa5,
448 1.1 riastrad },
449 1.1 riastrad .adlen = 12,
450 1.1 riastrad .ad = ptxt_seq,
451 1.1 riastrad .mlen = 20,
452 1.1 riastrad .ptxt = ptxt_seq + 12,
453 1.1 riastrad .M = 8,
454 1.1 riastrad .tag = {0x51,0xe8,0x3f,0x07, 0x7d,0x9c,0x2d,0x93},
455 1.1 riastrad .ctxt = (const uint8_t[20]) {
456 1.1 riastrad 0xdc,0xf1,0xfb,0x7b, 0x5d,0x9e,0x23,0xfb,
457 1.1 riastrad 0x9d,0x4e,0x13,0x12, 0x53,0x65,0x8a,0xd8,
458 1.1 riastrad 0x6e,0xbd,0xca,0x3e,
459 1.1 riastrad },
460 1.1 riastrad },
461 1.1 riastrad [5] = { /* Packet Vector #6, p. 13 */
462 1.1 riastrad .key = keyC,
463 1.1 riastrad .nonce = {
464 1.1 riastrad 0x00,0x00,0x00,0x08, 0x07,0x06,0x05,0xa0,
465 1.1 riastrad 0xa1,0xa2,0xa3,0xa4, 0xa5,
466 1.1 riastrad },
467 1.1 riastrad .adlen = 12,
468 1.1 riastrad .ad = ptxt_seq,
469 1.1 riastrad .mlen = 21,
470 1.1 riastrad .ptxt = ptxt_seq + 12,
471 1.1 riastrad .M = 8,
472 1.1 riastrad .tag = {0x40,0x5a,0x04,0x43, 0xac,0x91,0xcb,0x94},
473 1.1 riastrad .ctxt = (const uint8_t[21]) {
474 1.1 riastrad 0x6f,0xc1,0xb0,0x11, 0xf0,0x06,0x56,0x8b,
475 1.1 riastrad 0x51,0x71,0xa4,0x2d, 0x95,0x3d,0x46,0x9b,
476 1.1 riastrad 0x25,0x70,0xa4,0xbd, 0x87,
477 1.1 riastrad },
478 1.1 riastrad },
479 1.1 riastrad [6] = { /* Packet Vector #24 */
480 1.1 riastrad .key = keyD,
481 1.1 riastrad .nonce = {
482 1.1 riastrad 0x00,0x8d,0x49,0x3b, 0x30,0xae,0x8b,0x3c,
483 1.1 riastrad 0x96,0x96,0x76,0x6c, 0xfa,
484 1.1 riastrad },
485 1.1 riastrad .adlen = 12,
486 1.1 riastrad .ad = ptxt_rand,
487 1.1 riastrad .mlen = 21,
488 1.1 riastrad .ptxt = ptxt_rand + 12,
489 1.1 riastrad .M = 10,
490 1.1 riastrad .tag = {0x6d,0xce,0x9e,0x82, 0xef,0xa1,0x6d,0xa6, 0x20,0x59},
491 1.1 riastrad .ctxt = (const uint8_t[21]) {
492 1.1 riastrad 0xf3,0x29,0x05,0xb8, 0x8a,0x64,0x1b,0x04,
493 1.1 riastrad 0xb9,0xc9,0xff,0xb5, 0x8c,0xc3,0x90,0x90,
494 1.1 riastrad 0x0f,0x3d,0xa1,0x2a, 0xb1,
495 1.1 riastrad },
496 1.1 riastrad },
497 1.1 riastrad };
498 1.1 riastrad
499 1.1 riastrad int
500 1.1 riastrad aes_ccm_selftest(void)
501 1.1 riastrad {
502 1.1 riastrad const unsigned L = 2;
503 1.1 riastrad const unsigned noncelen = 13;
504 1.1 riastrad struct aesenc enc, *AE = &enc;
505 1.1 riastrad struct aes_ccm ccm, *C = &ccm;
506 1.1 riastrad uint8_t buf[33 + 2], *bufp = buf + 1;
507 1.1 riastrad uint8_t tag[16 + 2], *tagp = tag + 1;
508 1.1 riastrad unsigned i;
509 1.1 riastrad int result = 0;
510 1.1 riastrad
511 1.1 riastrad bufp[-1] = bufp[33] = 0x1a;
512 1.1 riastrad tagp[-1] = tagp[16] = 0x53;
513 1.1 riastrad
514 1.1 riastrad for (i = 0; i < __arraycount(T); i++) {
515 1.1 riastrad const unsigned nr = aes_setenckey128(AE, T[i].key);
516 1.1 riastrad
517 1.1 riastrad /* encrypt and authenticate */
518 1.1 riastrad aes_ccm_init(C, nr, AE, L, T[i].M, T[i].nonce, noncelen,
519 1.1 riastrad T[i].ad, T[i].adlen, T[i].mlen);
520 1.1 riastrad aes_ccm_enc(C, T[i].ptxt, bufp, 1);
521 1.1 riastrad aes_ccm_enc(C, T[i].ptxt + 1, bufp + 1, 2);
522 1.1 riastrad aes_ccm_enc(C, T[i].ptxt + 3, bufp + 3, T[i].mlen - 4);
523 1.1 riastrad aes_ccm_enc(C, T[i].ptxt + T[i].mlen - 1,
524 1.1 riastrad bufp + T[i].mlen - 1, 1);
525 1.1 riastrad aes_ccm_tag(C, tagp);
526 1.1 riastrad if (memcmp(bufp, T[i].ctxt, T[i].mlen)) {
527 1.1 riastrad char name[32];
528 1.1 riastrad snprintf(name, sizeof name, "%s: ctxt %u", __func__,
529 1.1 riastrad i);
530 1.1 riastrad hexdump(printf, name, bufp, T[i].mlen);
531 1.1 riastrad result = -1;
532 1.1 riastrad }
533 1.1 riastrad if (memcmp(tagp, T[i].tag, T[i].M)) {
534 1.1 riastrad char name[32];
535 1.1 riastrad snprintf(name, sizeof name, "%s: tag %u", __func__, i);
536 1.1 riastrad hexdump(printf, name, tagp, T[i].M);
537 1.1 riastrad result = -1;
538 1.1 riastrad }
539 1.1 riastrad
540 1.1 riastrad /* decrypt and verify */
541 1.1 riastrad aes_ccm_init(C, nr, AE, L, T[i].M, T[i].nonce, noncelen,
542 1.1 riastrad T[i].ad, T[i].adlen, T[i].mlen);
543 1.1 riastrad aes_ccm_dec(C, T[i].ctxt, bufp, 1);
544 1.1 riastrad aes_ccm_dec(C, T[i].ctxt + 1, bufp + 1, 2);
545 1.1 riastrad aes_ccm_dec(C, T[i].ctxt + 3, bufp + 3, T[i].mlen - 4);
546 1.1 riastrad aes_ccm_dec(C, T[i].ctxt + T[i].mlen - 1,
547 1.1 riastrad bufp + T[i].mlen - 1, 1);
548 1.1 riastrad if (!aes_ccm_verify(C, T[i].tag)) {
549 1.1 riastrad printf("%s: verify %u failed\n", __func__, i);
550 1.1 riastrad result = -1;
551 1.1 riastrad }
552 1.1 riastrad if (memcmp(bufp, T[i].ptxt, T[i].mlen)) {
553 1.1 riastrad char name[32];
554 1.1 riastrad snprintf(name, sizeof name, "%s: ptxt %u", __func__,
555 1.1 riastrad i);
556 1.1 riastrad hexdump(printf, name, bufp, T[i].mlen);
557 1.1 riastrad result = -1;
558 1.1 riastrad }
559 1.1 riastrad
560 1.1 riastrad /* decrypt and verify with a bit flipped */
561 1.1 riastrad memcpy(tagp, T[i].tag, T[i].M);
562 1.1 riastrad tagp[0] ^= 0x80;
563 1.1 riastrad aes_ccm_init(C, nr, AE, L, T[i].M, T[i].nonce, noncelen,
564 1.1 riastrad T[i].ad, T[i].adlen, T[i].mlen);
565 1.1 riastrad aes_ccm_dec(C, T[i].ctxt, bufp, 1);
566 1.1 riastrad aes_ccm_dec(C, T[i].ctxt + 1, bufp + 1, 2);
567 1.1 riastrad aes_ccm_dec(C, T[i].ctxt + 3, bufp + 3, T[i].mlen - 4);
568 1.1 riastrad aes_ccm_dec(C, T[i].ctxt + T[i].mlen - 1,
569 1.1 riastrad bufp + T[i].mlen - 1, 1);
570 1.1 riastrad if (aes_ccm_verify(C, tagp)) {
571 1.1 riastrad printf("%s: forgery %u succeeded\n", __func__, i);
572 1.1 riastrad result = -1;
573 1.1 riastrad }
574 1.1 riastrad }
575 1.1 riastrad
576 1.1 riastrad if (bufp[-1] != 0x1a || bufp[33] != 0x1a) {
577 1.1 riastrad printf("%s: buffer overrun\n", __func__);
578 1.1 riastrad result = -1;
579 1.1 riastrad }
580 1.1 riastrad if (tagp[-1] != 0x53 || tagp[16] != 0x53) {
581 1.1 riastrad printf("%s: tag overrun\n", __func__);
582 1.1 riastrad result = -1;
583 1.1 riastrad }
584 1.1 riastrad
585 1.1 riastrad return result;
586 1.1 riastrad }
587 1.1 riastrad
588 1.1 riastrad /* XXX provisional hack */
589 1.1 riastrad #include <sys/module.h>
590 1.1 riastrad
591 1.3 riastrad MODULE(MODULE_CLASS_MISC, aes_ccm, "aes");
592 1.1 riastrad
593 1.1 riastrad static int
594 1.1 riastrad aes_ccm_modcmd(modcmd_t cmd, void *opaque)
595 1.1 riastrad {
596 1.1 riastrad
597 1.1 riastrad switch (cmd) {
598 1.1 riastrad case MODULE_CMD_INIT:
599 1.1 riastrad if (aes_ccm_selftest())
600 1.1 riastrad return EIO;
601 1.1 riastrad aprint_verbose("aes_ccm: self-test passed\n");
602 1.1 riastrad return 0;
603 1.1 riastrad case MODULE_CMD_FINI:
604 1.1 riastrad return 0;
605 1.1 riastrad default:
606 1.1 riastrad return ENOTTY;
607 1.1 riastrad }
608 1.1 riastrad }
609