1/*	$NetBSD: aes_ccm.c,v 1.6 2021/10/17 14:45:45 jmcneill 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.6 2021/10/17 14:45:45 jmcneill 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
50static inline void
51xor(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
66static void
67aes_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
76static void
77aes_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
85void
86aes_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
183void
184aes_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
243void
244aes_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
303void
304#if defined(__m68k__) && __GNUC_PREREQ__(8, 0)
305__attribute__((__optimize__("O0")))
306#endif
307aes_ccm_tag(struct aes_ccm *C, void *out)
308{
309	uint8_t *auth = C->authctr;
310	const uint8_t *ctr = C->authctr + 16;
311
312	KASSERTMSG(C->mleft == 0,
313	    "message too short: promised %zu bytes, processed %zu",
314	    C->mlen, C->mlen - C->mleft);
315
316	/* Zero-pad and munch up a partial block, if any.  */
317	if (C->i)
318		aes_enc(C->enc, auth, auth, C->nr);
319
320	/* Zero the counter and generate a pad for the tag.  */
321	aes_ccm_zero_ctr(C);
322	aes_enc(C->enc, ctr, C->out, C->nr);
323
324	/* Copy out as many bytes as requested.  */
325	xor(out, C->out, auth, C->M);
326
327	C->i = ~0u;		/* paranoia: prevent future misuse */
328}
329
330int
331aes_ccm_verify(struct aes_ccm *C, const void *tag)
332{
333	uint8_t expected[16];
334	int result;
335
336	aes_ccm_tag(C, expected);
337	result = consttime_memequal(tag, expected, C->M);
338	explicit_memset(expected, 0, sizeof expected);
339
340	return result;
341}
342
343/* RFC 3610, ��8 */
344
345static const uint8_t keyC[16] = {
346	0xc0,0xc1,0xc2,0xc3, 0xc4,0xc5,0xc6,0xc7,
347	0xc8,0xc9,0xca,0xcb, 0xcc,0xcd,0xce,0xcf,
348};
349
350static const uint8_t keyD[16] = {
351	0xd7,0x82,0x8d,0x13, 0xb2,0xb0,0xbd,0xc3,
352	0x25,0xa7,0x62,0x36, 0xdf,0x93,0xcc,0x6b,
353};
354
355static const uint8_t ptxt_seq[] = {
356	0x00,0x01,0x02,0x03, 0x04,0x05,0x06,0x07,
357	0x08,0x09,0x0a,0x0b, 0x0c,0x0d,0x0e,0x0f,
358	0x10,0x11,0x12,0x13, 0x14,0x15,0x16,0x17,
359	0x18,0x19,0x1a,0x1b, 0x1c,0x1d,0x1e,0x1f,
360	0x20,
361};
362
363static const uint8_t ptxt_rand[] = {
364	0x6e,0x37,0xa6,0xef, 0x54,0x6d,0x95,0x5d,
365	0x34,0xab,0x60,0x59, 0xab,0xf2,0x1c,0x0b,
366	0x02,0xfe,0xb8,0x8f, 0x85,0x6d,0xf4,0xa3,
367	0x73,0x81,0xbc,0xe3, 0xcc,0x12,0x85,0x17,
368	0xd4,
369};
370
371static const struct {
372	const uint8_t *key;
373	size_t noncelen;
374	const uint8_t nonce[13];
375	size_t adlen;
376	const uint8_t *ad;
377	size_t mlen;
378	const uint8_t *ptxt;
379	unsigned M;
380	const uint8_t tag[16];
381	const uint8_t *ctxt;
382} T[] = {
383	[0] = {		/* Packet Vector #1, p. 11 */
384		.key = keyC,
385		.nonce = {
386			0x00,0x00,0x00,0x03, 0x02,0x01,0x00,0xa0,
387			0xa1,0xa2,0xa3,0xa4, 0xa5,
388		},
389		.adlen = 8,
390		.ad = ptxt_seq,
391		.mlen = 23,
392		.ptxt = ptxt_seq + 8,
393		.M = 8,
394		.tag = {0x17,0xe8,0xd1,0x2c,0xfd, 0xf9,0x26,0xe0},
395		.ctxt = (const uint8_t[23]) {
396			0x58,0x8c,0x97,0x9a, 0x61,0xc6,0x63,0xd2,
397			0xf0,0x66,0xd0,0xc2, 0xc0,0xf9,0x89,0x80,
398			0x6d,0x5f,0x6b,0x61, 0xda,0xc3,0x84,
399		},
400	},
401	[1] = {			/* Packet Vector #2, p. 11 */
402		.key = keyC,
403		.nonce = {
404			0x00,0x00,0x00,0x04, 0x03,0x02,0x01,0xa0,
405			0xa1,0xa2,0xa3,0xa4, 0xa5,
406		},
407		.adlen = 8,
408		.ad = ptxt_seq,
409		.mlen = 24,
410		.ptxt = ptxt_seq + 8,
411		.M = 8,
412		.tag = {0xa0,0x91,0xd5,0x6e, 0x10,0x40,0x09,0x16},
413		.ctxt = (const uint8_t[24]) {
414			0x72,0xc9,0x1a,0x36, 0xe1,0x35,0xf8,0xcf,
415			0x29,0x1c,0xa8,0x94, 0x08,0x5c,0x87,0xe3,
416			0xcc,0x15,0xc4,0x39, 0xc9,0xe4,0x3a,0x3b,
417		},
418	},
419	[2] = {			/* Packet Vector #3, p. 12 */
420		.key = keyC,
421		.nonce = {
422			0x00,0x00,0x00,0x05, 0x04,0x03,0x02,0xa0,
423			0xa1,0xa2,0xa3,0xa4, 0xa5,
424		},
425		.adlen = 8,
426		.ad = ptxt_seq,
427		.mlen = 25,
428		.ptxt = ptxt_seq + 8,
429		.M = 8,
430		.tag = {0x4a,0xda,0xa7,0x6f, 0xbd,0x9f,0xb0,0xc5},
431		.ctxt = (const uint8_t[25]) {
432			0x51,0xb1,0xe5,0xf4, 0x4a,0x19,0x7d,0x1d,
433			0xa4,0x6b,0x0f,0x8e, 0x2d,0x28,0x2a,0xe8,
434			0x71,0xe8,0x38,0xbb, 0x64,0xda,0x85,0x96,
435			0x57,
436		},
437	},
438	[3] = {			/* Packet Vector #4, p. 13 */
439		.key = keyC,
440		.nonce = {
441			0x00,0x00,0x00,0x06, 0x05,0x04,0x03,0xa0,
442			0xa1,0xa2,0xa3,0xa4, 0xa5,
443		},
444		.adlen = 12,
445		.ad = ptxt_seq,
446		.mlen = 19,
447		.ptxt = ptxt_seq + 12,
448		.M = 8,
449		.tag = {0x96,0xc8,0x61,0xb9, 0xc9,0xe6,0x1e,0xf1},
450		.ctxt = (const uint8_t[19]) {
451			0xa2,0x8c,0x68,0x65, 0x93,0x9a,0x9a,0x79,
452			0xfa,0xaa,0x5c,0x4c, 0x2a,0x9d,0x4a,0x91,
453			0xcd,0xac,0x8c,
454		},
455	},
456	[4] = {			/* Packet Vector #5, p. 13 */
457		.key = keyC,
458		.nonce = {
459			0x00,0x00,0x00,0x07, 0x06,0x05,0x04,0xa0,
460			0xa1,0xa2,0xa3,0xa4, 0xa5,
461		},
462		.adlen = 12,
463		.ad = ptxt_seq,
464		.mlen = 20,
465		.ptxt = ptxt_seq + 12,
466		.M = 8,
467		.tag = {0x51,0xe8,0x3f,0x07, 0x7d,0x9c,0x2d,0x93},
468		.ctxt = (const uint8_t[20]) {
469			0xdc,0xf1,0xfb,0x7b, 0x5d,0x9e,0x23,0xfb,
470			0x9d,0x4e,0x13,0x12, 0x53,0x65,0x8a,0xd8,
471			0x6e,0xbd,0xca,0x3e,
472		},
473	},
474	[5] = {			/* Packet Vector #6, p. 13 */
475		.key = keyC,
476		.nonce = {
477			0x00,0x00,0x00,0x08, 0x07,0x06,0x05,0xa0,
478			0xa1,0xa2,0xa3,0xa4, 0xa5,
479		},
480		.adlen = 12,
481		.ad = ptxt_seq,
482		.mlen = 21,
483		.ptxt = ptxt_seq + 12,
484		.M = 8,
485		.tag = {0x40,0x5a,0x04,0x43, 0xac,0x91,0xcb,0x94},
486		.ctxt = (const uint8_t[21]) {
487			0x6f,0xc1,0xb0,0x11, 0xf0,0x06,0x56,0x8b,
488			0x51,0x71,0xa4,0x2d, 0x95,0x3d,0x46,0x9b,
489			0x25,0x70,0xa4,0xbd, 0x87,
490		},
491	},
492	[6] = {			/* Packet Vector #24 */
493		.key = keyD,
494		.nonce = {
495			0x00,0x8d,0x49,0x3b, 0x30,0xae,0x8b,0x3c,
496			0x96,0x96,0x76,0x6c, 0xfa,
497		},
498		.adlen = 12,
499		.ad = ptxt_rand,
500		.mlen = 21,
501		.ptxt = ptxt_rand + 12,
502		.M = 10,
503		.tag = {0x6d,0xce,0x9e,0x82, 0xef,0xa1,0x6d,0xa6, 0x20,0x59},
504		.ctxt = (const uint8_t[21]) {
505			0xf3,0x29,0x05,0xb8, 0x8a,0x64,0x1b,0x04,
506			0xb9,0xc9,0xff,0xb5, 0x8c,0xc3,0x90,0x90,
507			0x0f,0x3d,0xa1,0x2a, 0xb1,
508		},
509	},
510};
511
512int
513aes_ccm_selftest(void)
514{
515	const unsigned L = 2;
516	const unsigned noncelen = 13;
517	struct aesenc enc, *AE = &enc;
518	struct aes_ccm ccm, *C = &ccm;
519	uint8_t buf[33 + 2], *bufp = buf + 1;
520	uint8_t tag[16 + 2], *tagp = tag + 1;
521	unsigned i;
522	int result = 0;
523
524	bufp[-1] = bufp[33] = 0x1a;
525	tagp[-1] = tagp[16] = 0x53;
526
527	for (i = 0; i < __arraycount(T); i++) {
528		const unsigned nr = aes_setenckey128(AE, T[i].key);
529
530		/* encrypt and authenticate */
531		aes_ccm_init(C, nr, AE, L, T[i].M, T[i].nonce, noncelen,
532		    T[i].ad, T[i].adlen, T[i].mlen);
533		aes_ccm_enc(C, T[i].ptxt, bufp, 1);
534		aes_ccm_enc(C, T[i].ptxt + 1, bufp + 1, 2);
535		aes_ccm_enc(C, T[i].ptxt + 3, bufp + 3, T[i].mlen - 4);
536		aes_ccm_enc(C, T[i].ptxt + T[i].mlen - 1,
537		    bufp + T[i].mlen - 1, 1);
538		aes_ccm_tag(C, tagp);
539		if (memcmp(bufp, T[i].ctxt, T[i].mlen)) {
540			char name[32];
541			snprintf(name, sizeof name, "%s: ctxt %u", __func__,
542			    i);
543			hexdump(printf, name, bufp, T[i].mlen);
544			result = -1;
545		}
546		if (memcmp(tagp, T[i].tag, T[i].M)) {
547			char name[32];
548			snprintf(name, sizeof name, "%s: tag %u", __func__, i);
549			hexdump(printf, name, tagp, T[i].M);
550			result = -1;
551		}
552
553		/* decrypt and verify */
554		aes_ccm_init(C, nr, AE, L, T[i].M, T[i].nonce, noncelen,
555		    T[i].ad, T[i].adlen, T[i].mlen);
556		aes_ccm_dec(C, T[i].ctxt, bufp, 1);
557		aes_ccm_dec(C, T[i].ctxt + 1, bufp + 1, 2);
558		aes_ccm_dec(C, T[i].ctxt + 3, bufp + 3, T[i].mlen - 4);
559		aes_ccm_dec(C, T[i].ctxt + T[i].mlen - 1,
560		    bufp + T[i].mlen - 1, 1);
561		if (!aes_ccm_verify(C, T[i].tag)) {
562			printf("%s: verify %u failed\n", __func__, i);
563			result = -1;
564		}
565		if (memcmp(bufp, T[i].ptxt, T[i].mlen)) {
566			char name[32];
567			snprintf(name, sizeof name, "%s: ptxt %u", __func__,
568			    i);
569			hexdump(printf, name, bufp, T[i].mlen);
570			result = -1;
571		}
572
573		/* decrypt and verify with a bit flipped */
574		memcpy(tagp, T[i].tag, T[i].M);
575		tagp[0] ^= 0x80;
576		aes_ccm_init(C, nr, AE, L, T[i].M, T[i].nonce, noncelen,
577		    T[i].ad, T[i].adlen, T[i].mlen);
578		aes_ccm_dec(C, T[i].ctxt, bufp, 1);
579		aes_ccm_dec(C, T[i].ctxt + 1, bufp + 1, 2);
580		aes_ccm_dec(C, T[i].ctxt + 3, bufp + 3, T[i].mlen - 4);
581		aes_ccm_dec(C, T[i].ctxt + T[i].mlen - 1,
582		    bufp + T[i].mlen - 1, 1);
583		if (aes_ccm_verify(C, tagp)) {
584			printf("%s: forgery %u succeeded\n", __func__, i);
585			result = -1;
586		}
587	}
588
589	if (bufp[-1] != 0x1a || bufp[33] != 0x1a) {
590		printf("%s: buffer overrun\n", __func__);
591		result = -1;
592	}
593	if (tagp[-1] != 0x53 || tagp[16] != 0x53) {
594		printf("%s: tag overrun\n", __func__);
595		result = -1;
596	}
597
598	return result;
599}
600
601/* XXX provisional hack */
602#include <sys/module.h>
603
604MODULE(MODULE_CLASS_MISC, aes_ccm, "aes");
605
606static int
607aes_ccm_modcmd(modcmd_t cmd, void *opaque)
608{
609
610	switch (cmd) {
611	case MODULE_CMD_INIT:
612		if (aes_ccm_selftest())
613			return EIO;
614		aprint_debug("aes_ccm: self-test passed\n");
615		return 0;
616	case MODULE_CMD_FINI:
617		return 0;
618	default:
619		return ENOTTY;
620	}
621}
622