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