Module Name:    src
Committed By:   riastradh
Date:           Sat Jul 25 22:15:55 UTC 2020

Modified Files:
        src/sys/crypto/aes: files.aes
Added Files:
        src/sys/crypto/aes: aes_ccm.c aes_ccm.h aes_ccm_mbuf.c aes_ccm_mbuf.h

Log Message:
New aes_ccm API.

Intended for use in net80211 for WPA2 CCMP.


To generate a diff of this commit:
cvs rdiff -u -r0 -r1.1 src/sys/crypto/aes/aes_ccm.c \
    src/sys/crypto/aes/aes_ccm.h src/sys/crypto/aes/aes_ccm_mbuf.c \
    src/sys/crypto/aes/aes_ccm_mbuf.h
cvs rdiff -u -r1.1 -r1.2 src/sys/crypto/aes/files.aes

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/crypto/aes/files.aes
diff -u src/sys/crypto/aes/files.aes:1.1 src/sys/crypto/aes/files.aes:1.2
--- src/sys/crypto/aes/files.aes:1.1	Mon Jun 29 23:27:52 2020
+++ src/sys/crypto/aes/files.aes	Sat Jul 25 22:15:55 2020
@@ -1,9 +1,11 @@
-#	$NetBSD: files.aes,v 1.1 2020/06/29 23:27:52 riastradh Exp $
+#	$NetBSD: files.aes,v 1.2 2020/07/25 22:15:55 riastradh Exp $
 
 define	aes
 define	rijndael: aes	# legacy Rijndael API
 
 file	crypto/aes/aes_bear.c			aes
+file	crypto/aes/aes_ccm.c			aes
+file	crypto/aes/aes_ccm_mbuf.c		aes
 file	crypto/aes/aes_ct.c			aes
 file	crypto/aes/aes_ct_dec.c			aes
 file	crypto/aes/aes_ct_enc.c			aes

Added files:

Index: src/sys/crypto/aes/aes_ccm.c
diff -u /dev/null src/sys/crypto/aes/aes_ccm.c:1.1
--- /dev/null	Sat Jul 25 22:15:55 2020
+++ src/sys/crypto/aes/aes_ccm.c	Sat Jul 25 22:15:55 2020
@@ -0,0 +1,619 @@
+/*	$NetBSD: aes_ccm.c,v 1.1 2020/07/25 22:15:55 riastradh Exp $	*/
+
+/*-
+ * Copyright (c) 2020 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * AES-CCM, as defined in:
+ *
+ *	D. Whiting, R. Housley, and N. Ferguson, `Counter with CBC-MAC
+ *	(CCM)', IETF RFC 3610, September 2003.
+ *	https://tools.ietf.org/html/rfc3610
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(1, "$NetBSD: aes_ccm.c,v 1.1 2020/07/25 22:15:55 riastradh Exp $");
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+
+#include <lib/libkern/libkern.h>
+
+#include <crypto/aes/aes.h>
+#include <crypto/aes/aes_ccm.h>
+
+static inline void
+xor(uint8_t *x, const uint8_t *a, const uint8_t *b, size_t n)
+{
+
+	while (n --> 0)
+		*x++ = *a++ ^ *b++;
+}
+
+static inline void
+xor16(uint8_t *x, const uint8_t *a, const uint8_t *b)
+{
+
+	xor(x, a, b, 16);
+}
+
+/* RFC 3610, §2.2 Authentication */
+#define	CCM_AFLAGS_ADATA	__BIT(6)
+#define	CCM_AFLAGS_M		__BITS(5,3)
+#define	CCM_AFLAGS_L		__BITS(2,0)
+
+/* RFC 3610, §2.3 Encryption */
+#define	CCM_EFLAGS_L		__BITS(2,0)
+
+static void
+aes_ccm_inc(struct aes_ccm *C)
+{
+
+	KASSERT(C->L == 2);
+	if (++C->in[15] == 0 && ++C->in[14] == 0)
+		panic("AES-CCM overflow");
+}
+
+static void
+aes_ccm_zero_ctr(struct aes_ccm *C)
+{
+
+	KASSERT(C->L == 2);
+	C->in[14] = C->in[15] = 0;
+}
+
+void
+aes_ccm_init(struct aes_ccm *C, unsigned nr, const struct aesenc *enc,
+    unsigned L, unsigned M,
+    const uint8_t *nonce, unsigned noncelen, const void *ad, size_t adlen,
+    size_t mlen)
+{
+	const uint8_t *adp = ad;
+	unsigned i;
+
+	KASSERT(L == 2);
+	KASSERT(M % 2 == 0);
+	KASSERT(M >= 4);
+	KASSERT(M <= 16);
+	KASSERT(noncelen == 15 - L);
+
+	C->enc = enc;
+	C->nr = nr;
+	C->L = L;
+	C->M = M;
+	C->mlen = C->mleft = mlen;
+
+	/* Encode B0, the initial authenticated data block.  */
+	C->auth[0] = __SHIFTIN(adlen == 0 ? 0 : 1, CCM_AFLAGS_ADATA);
+	C->auth[0] |= __SHIFTIN((M - 2)/2, CCM_AFLAGS_M);
+	C->auth[0] |= __SHIFTIN(L - 1, CCM_AFLAGS_L);
+	memcpy(C->auth + 1, nonce, noncelen);
+	for (i = 0; i < L; i++, mlen >>= 8) {
+		KASSERT(i < 16 - 1 - noncelen);
+		C->auth[16 - i - 1] = mlen & 0xff;
+	}
+	aes_enc(enc, C->auth, C->auth, C->nr);
+
+	/* Process additional authenticated data, if any.  */
+	if (adlen) {
+		/* Encode the length according to the table on p. 4.  */
+		if (adlen < 0xff00) {
+			C->auth[0] ^= adlen >> 8;
+			C->auth[1] ^= adlen;
+			i = 2;
+		} else if (adlen < 0xffffffff) {
+			C->auth[0] ^= 0xff;
+			C->auth[1] ^= 0xfe;
+			C->auth[2] ^= adlen >> 24;
+			C->auth[3] ^= adlen >> 16;
+			C->auth[4] ^= adlen >> 8;
+			C->auth[5] ^= adlen;
+			i = 6;
+#if SIZE_MAX > 0xffffffffU
+		} else {
+			CTASSERT(SIZE_MAX <= 0xffffffffffffffff);
+			C->auth[0] ^= 0xff;
+			C->auth[1] ^= 0xff;
+			C->auth[2] ^= adlen >> 56;
+			C->auth[3] ^= adlen >> 48;
+			C->auth[4] ^= adlen >> 40;
+			C->auth[5] ^= adlen >> 32;
+			C->auth[6] ^= adlen >> 24;
+			C->auth[7] ^= adlen >> 16;
+			C->auth[8] ^= adlen >> 8;
+			C->auth[9] ^= adlen;
+			i = 10;
+#endif
+		}
+
+		/* Fill out the partial block if we can, and encrypt.  */
+		xor(C->auth + i, C->auth + i, adp, MIN(adlen, 16 - i));
+		adp += MIN(adlen, 16 - i);
+		adlen -= MIN(adlen, 16 - i);
+		aes_enc(enc, C->auth, C->auth, C->nr);
+
+		/* If there was anything more, process 16 bytes at a time.  */
+		for (; adlen >= 16; adp += 16, adlen -= 16) {
+			xor16(C->auth, C->auth, adp);
+			aes_enc(enc, C->auth, C->auth, C->nr);
+		}
+
+		/*
+		 * If there's anything at the end, enter it in (padded
+		 * with zeros, which is a no-op) and process it.
+		 */
+		if (adlen) {
+			xor(C->auth, C->auth, adp, adlen);
+			aes_enc(enc, C->auth, C->auth, C->nr);
+		}
+	}
+
+	/* Set up the AES input for AES-CTR encryption.  */
+	C->in[0] = __SHIFTIN(L - 1, CCM_EFLAGS_L);
+	memcpy(C->in + 1, nonce, noncelen);
+	memset(C->in + 1 + noncelen, 0, 16 - 1 - noncelen);
+
+	/* Start on a block boundary.  */
+	C->i = 0;
+}
+
+void
+aes_ccm_enc(struct aes_ccm *C, const void *in, void *out, size_t nbytes)
+{
+	const uint8_t *p = in;
+	uint8_t *q = out;
+
+	KASSERTMSG(C->i != ~0u,
+	    "%s not allowed after message complete", __func__);
+	KASSERTMSG(nbytes <= C->mleft,
+	    "message too long: promised %zu bytes, processing >=%zu",
+	    C->mlen, C->mlen - C->mleft + nbytes);
+	C->mleft -= nbytes;
+
+	/* Finish a partial block if it was already started.  */
+	if (C->i) {
+		unsigned m = MIN(16 - C->i, nbytes);
+
+		xor(C->auth + C->i, C->auth + C->i, p, m);
+		xor(q, C->out + C->i, p, m);
+		C->i += m;
+		p += m;
+		q += m;
+		nbytes -= m;
+
+		if (C->i == 16) {
+			/* Finished a block; authenticate it.  */
+			aes_enc(C->enc, C->auth, C->auth, C->nr);
+			C->i = 0;
+		} else {
+			/* Didn't finish block, must be done with input. */
+			KASSERT(nbytes == 0);
+			return;
+		}
+	}
+
+	/* Process 16 bytes at a time.  */
+	for (; nbytes >= 16; p += 16, q += 16, nbytes -= 16) {
+		/* authenticate */
+		xor16(C->auth, C->auth, p);
+		aes_enc(C->enc, C->auth, C->auth, C->nr);
+
+		/* encrypt */
+		aes_ccm_inc(C);
+		aes_enc(C->enc, C->in, C->out, C->nr);
+		xor16(q, C->out, p);
+	}
+
+	/* Incorporate any <16-byte unit as a partial block.  */
+	if (nbytes) {
+		/* authenticate */
+		xor(C->auth, C->auth, p, nbytes);
+
+		/* encrypt */
+		aes_ccm_inc(C);
+		aes_enc(C->enc, C->in, C->out, C->nr);
+		xor(q, C->out, p, nbytes);
+
+		C->i = nbytes;
+	}
+}
+
+void
+aes_ccm_dec(struct aes_ccm *C, const void *in, void *out, size_t nbytes)
+{
+	const uint8_t *p = in;
+	uint8_t *q = out;
+
+	KASSERTMSG(C->i != ~0u,
+	    "%s not allowed after message complete", __func__);
+	KASSERTMSG(nbytes <= C->mleft,
+	    "message too long: promised %zu bytes, processing >=%zu",
+	    C->mlen, C->mlen - C->mleft + nbytes);
+	C->mleft -= nbytes;
+
+	/* Finish a partial block if it was already started.  */
+	if (C->i) {
+		unsigned m = MIN(16 - C->i, nbytes);
+
+		xor(q, C->out + C->i, p, m);
+		xor(C->auth + C->i, C->auth + C->i, q, m);
+		C->i += m;
+		p += m;
+		q += m;
+		nbytes -= m;
+
+		if (C->i == 16) {
+			/* Finished a block; authenticate it.  */
+			aes_enc(C->enc, C->auth, C->auth, C->nr);
+			C->i = 0;
+		} else {
+			/* Didn't finish block, must be done with input. */
+			KASSERT(nbytes == 0);
+			return;
+		}
+	}
+
+	/* Process 16 bytes at a time.  */
+	for (; nbytes >= 16; p += 16, q += 16, nbytes -= 16) {
+		/* decrypt */
+		aes_ccm_inc(C);
+		aes_enc(C->enc, C->in, C->out, C->nr);
+		xor16(q, C->out, p);
+
+		/* authenticate */
+		xor16(C->auth, C->auth, q);
+		aes_enc(C->enc, C->auth, C->auth, C->nr);
+	}
+
+	/* Incorporate any <16-byte unit as a partial block.  */
+	if (nbytes) {
+		/* decrypt */
+		aes_ccm_inc(C);
+		aes_enc(C->enc, C->in, C->out, C->nr);
+		xor(q, C->out, p, nbytes);
+
+		/* authenticate */
+		xor(C->auth, C->auth, q, nbytes);
+
+		C->i = nbytes;
+	}
+}
+
+void
+aes_ccm_tag(struct aes_ccm *C, void *out)
+{
+
+	KASSERTMSG(C->mleft == 0,
+	    "message too short: promised %zu bytes, processed %zu",
+	    C->mlen, C->mlen - C->mleft);
+
+	/* Zero-pad and munch up a partial block, if any.  */
+	if (C->i)
+		aes_enc(C->enc, C->auth, C->auth, C->nr);
+
+	/* Zero the counter and generate a pad for the tag.  */
+	aes_ccm_zero_ctr(C);
+	aes_enc(C->enc, C->in, C->out, C->nr);
+
+	/* Copy out as many bytes as requested.  */
+	xor(out, C->out, C->auth, C->M);
+
+	C->i = ~0u;		/* paranoia: prevent future misuse */
+}
+
+int
+aes_ccm_verify(struct aes_ccm *C, const void *tag)
+{
+	uint8_t expected[16];
+	int result;
+
+	aes_ccm_tag(C, expected);
+	result = consttime_memequal(tag, expected, C->M);
+	explicit_memset(expected, 0, sizeof expected);
+
+	return result;
+}
+
+/* RFC 3610, §8 */
+
+static const uint8_t keyC[16] = {
+	0xc0,0xc1,0xc2,0xc3, 0xc4,0xc5,0xc6,0xc7,
+	0xc8,0xc9,0xca,0xcb, 0xcc,0xcd,0xce,0xcf,
+};
+
+static const uint8_t keyD[16] = {
+	0xd7,0x82,0x8d,0x13, 0xb2,0xb0,0xbd,0xc3,
+	0x25,0xa7,0x62,0x36, 0xdf,0x93,0xcc,0x6b,
+};
+
+static const uint8_t ptxt_seq[] = {
+	0x00,0x01,0x02,0x03, 0x04,0x05,0x06,0x07,
+	0x08,0x09,0x0a,0x0b, 0x0c,0x0d,0x0e,0x0f,
+	0x10,0x11,0x12,0x13, 0x14,0x15,0x16,0x17,
+	0x18,0x19,0x1a,0x1b, 0x1c,0x1d,0x1e,0x1f,
+	0x20,
+};
+
+static const uint8_t ptxt_rand[] = {
+	0x6e,0x37,0xa6,0xef, 0x54,0x6d,0x95,0x5d,
+	0x34,0xab,0x60,0x59, 0xab,0xf2,0x1c,0x0b,
+	0x02,0xfe,0xb8,0x8f, 0x85,0x6d,0xf4,0xa3,
+	0x73,0x81,0xbc,0xe3, 0xcc,0x12,0x85,0x17,
+	0xd4,
+};
+
+static const struct {
+	const uint8_t *key;
+	size_t noncelen;
+	const uint8_t nonce[13];
+	size_t adlen;
+	const uint8_t *ad;
+	size_t mlen;
+	const uint8_t *ptxt;
+	unsigned M;
+	const uint8_t tag[16];
+	const uint8_t *ctxt;
+} T[] = {
+	[0] = {		/* Packet Vector #1, p. 11 */
+		.key = keyC,
+		.nonce = {
+			0x00,0x00,0x00,0x03, 0x02,0x01,0x00,0xa0,
+			0xa1,0xa2,0xa3,0xa4, 0xa5,
+		},
+		.adlen = 8,
+		.ad = ptxt_seq,
+		.mlen = 23,
+		.ptxt = ptxt_seq + 8,
+		.M = 8,
+		.tag = {0x17,0xe8,0xd1,0x2c,0xfd, 0xf9,0x26,0xe0},
+		.ctxt = (const uint8_t[23]) {
+			0x58,0x8c,0x97,0x9a, 0x61,0xc6,0x63,0xd2,
+			0xf0,0x66,0xd0,0xc2, 0xc0,0xf9,0x89,0x80,
+			0x6d,0x5f,0x6b,0x61, 0xda,0xc3,0x84,
+		},
+	},
+	[1] = {			/* Packet Vector #2, p. 11 */
+		.key = keyC,
+		.nonce = {
+			0x00,0x00,0x00,0x04, 0x03,0x02,0x01,0xa0,
+			0xa1,0xa2,0xa3,0xa4, 0xa5,
+		},
+		.adlen = 8,
+		.ad = ptxt_seq,
+		.mlen = 24,
+		.ptxt = ptxt_seq + 8,
+		.M = 8,
+		.tag = {0xa0,0x91,0xd5,0x6e, 0x10,0x40,0x09,0x16},
+		.ctxt = (const uint8_t[24]) {
+			0x72,0xc9,0x1a,0x36, 0xe1,0x35,0xf8,0xcf,
+			0x29,0x1c,0xa8,0x94, 0x08,0x5c,0x87,0xe3,
+			0xcc,0x15,0xc4,0x39, 0xc9,0xe4,0x3a,0x3b,
+		},
+	},
+	[2] = {			/* Packet Vector #3, p. 12 */
+		.key = keyC,
+		.nonce = {
+			0x00,0x00,0x00,0x05, 0x04,0x03,0x02,0xa0,
+			0xa1,0xa2,0xa3,0xa4, 0xa5,
+		},
+		.adlen = 8,
+		.ad = ptxt_seq,
+		.mlen = 25,
+		.ptxt = ptxt_seq + 8,
+		.M = 8,
+		.tag = {0x4a,0xda,0xa7,0x6f, 0xbd,0x9f,0xb0,0xc5},
+		.ctxt = (const uint8_t[25]) {
+			0x51,0xb1,0xe5,0xf4, 0x4a,0x19,0x7d,0x1d,
+			0xa4,0x6b,0x0f,0x8e, 0x2d,0x28,0x2a,0xe8,
+			0x71,0xe8,0x38,0xbb, 0x64,0xda,0x85,0x96,
+			0x57,
+		},
+	},
+	[3] = {			/* Packet Vector #4, p. 13 */
+		.key = keyC,
+		.nonce = {
+			0x00,0x00,0x00,0x06, 0x05,0x04,0x03,0xa0,
+			0xa1,0xa2,0xa3,0xa4, 0xa5,
+		},
+		.adlen = 12,
+		.ad = ptxt_seq,
+		.mlen = 19,
+		.ptxt = ptxt_seq + 12,
+		.M = 8,
+		.tag = {0x96,0xc8,0x61,0xb9, 0xc9,0xe6,0x1e,0xf1},
+		.ctxt = (const uint8_t[19]) {
+			0xa2,0x8c,0x68,0x65, 0x93,0x9a,0x9a,0x79,
+			0xfa,0xaa,0x5c,0x4c, 0x2a,0x9d,0x4a,0x91,
+			0xcd,0xac,0x8c,
+		},
+	},
+	[4] = {			/* Packet Vector #5, p. 13 */
+		.key = keyC,
+		.nonce = {
+			0x00,0x00,0x00,0x07, 0x06,0x05,0x04,0xa0,
+			0xa1,0xa2,0xa3,0xa4, 0xa5,
+		},
+		.adlen = 12,
+		.ad = ptxt_seq,
+		.mlen = 20,
+		.ptxt = ptxt_seq + 12,
+		.M = 8,
+		.tag = {0x51,0xe8,0x3f,0x07, 0x7d,0x9c,0x2d,0x93},
+		.ctxt = (const uint8_t[20]) {
+			0xdc,0xf1,0xfb,0x7b, 0x5d,0x9e,0x23,0xfb,
+			0x9d,0x4e,0x13,0x12, 0x53,0x65,0x8a,0xd8,
+			0x6e,0xbd,0xca,0x3e,
+		},
+	},
+	[5] = {			/* Packet Vector #6, p. 13 */
+		.key = keyC,
+		.nonce = {
+			0x00,0x00,0x00,0x08, 0x07,0x06,0x05,0xa0,
+			0xa1,0xa2,0xa3,0xa4, 0xa5,
+		},
+		.adlen = 12,
+		.ad = ptxt_seq,
+		.mlen = 21,
+		.ptxt = ptxt_seq + 12,
+		.M = 8,
+		.tag = {0x40,0x5a,0x04,0x43, 0xac,0x91,0xcb,0x94},
+		.ctxt = (const uint8_t[21]) {
+			0x6f,0xc1,0xb0,0x11, 0xf0,0x06,0x56,0x8b,
+			0x51,0x71,0xa4,0x2d, 0x95,0x3d,0x46,0x9b,
+			0x25,0x70,0xa4,0xbd, 0x87,
+		},
+	},
+	[6] = {			/* Packet Vector #24 */
+		.key = keyD,
+		.nonce = {
+			0x00,0x8d,0x49,0x3b, 0x30,0xae,0x8b,0x3c,
+			0x96,0x96,0x76,0x6c, 0xfa,
+		},
+		.adlen = 12,
+		.ad = ptxt_rand,
+		.mlen = 21,
+		.ptxt = ptxt_rand + 12,
+		.M = 10,
+		.tag = {0x6d,0xce,0x9e,0x82, 0xef,0xa1,0x6d,0xa6, 0x20,0x59},
+		.ctxt = (const uint8_t[21]) {
+			0xf3,0x29,0x05,0xb8, 0x8a,0x64,0x1b,0x04,
+			0xb9,0xc9,0xff,0xb5, 0x8c,0xc3,0x90,0x90,
+			0x0f,0x3d,0xa1,0x2a, 0xb1,
+		},
+	},
+};
+
+int
+aes_ccm_selftest(void)
+{
+	const unsigned L = 2;
+	const unsigned noncelen = 13;
+	struct aesenc enc, *AE = &enc;
+	struct aes_ccm ccm, *C = &ccm;
+	uint8_t buf[33 + 2], *bufp = buf + 1;
+	uint8_t tag[16 + 2], *tagp = tag + 1;
+	unsigned i;
+	int result = 0;
+
+	bufp[-1] = bufp[33] = 0x1a;
+	tagp[-1] = tagp[16] = 0x53;
+
+	for (i = 0; i < __arraycount(T); i++) {
+		const unsigned nr = aes_setenckey128(AE, T[i].key);
+
+		/* encrypt and authenticate */
+		aes_ccm_init(C, nr, AE, L, T[i].M, T[i].nonce, noncelen,
+		    T[i].ad, T[i].adlen, T[i].mlen);
+		aes_ccm_enc(C, T[i].ptxt, bufp, 1);
+		aes_ccm_enc(C, T[i].ptxt + 1, bufp + 1, 2);
+		aes_ccm_enc(C, T[i].ptxt + 3, bufp + 3, T[i].mlen - 4);
+		aes_ccm_enc(C, T[i].ptxt + T[i].mlen - 1,
+		    bufp + T[i].mlen - 1, 1);
+		aes_ccm_tag(C, tagp);
+		if (memcmp(bufp, T[i].ctxt, T[i].mlen)) {
+			char name[32];
+			snprintf(name, sizeof name, "%s: ctxt %u", __func__,
+			    i);
+			hexdump(printf, name, bufp, T[i].mlen);
+			result = -1;
+		}
+		if (memcmp(tagp, T[i].tag, T[i].M)) {
+			char name[32];
+			snprintf(name, sizeof name, "%s: tag %u", __func__, i);
+			hexdump(printf, name, tagp, T[i].M);
+			result = -1;
+		}
+
+		/* decrypt and verify */
+		aes_ccm_init(C, nr, AE, L, T[i].M, T[i].nonce, noncelen,
+		    T[i].ad, T[i].adlen, T[i].mlen);
+		aes_ccm_dec(C, T[i].ctxt, bufp, 1);
+		aes_ccm_dec(C, T[i].ctxt + 1, bufp + 1, 2);
+		aes_ccm_dec(C, T[i].ctxt + 3, bufp + 3, T[i].mlen - 4);
+		aes_ccm_dec(C, T[i].ctxt + T[i].mlen - 1,
+		    bufp + T[i].mlen - 1, 1);
+		if (!aes_ccm_verify(C, T[i].tag)) {
+			printf("%s: verify %u failed\n", __func__, i);
+			result = -1;
+		}
+		if (memcmp(bufp, T[i].ptxt, T[i].mlen)) {
+			char name[32];
+			snprintf(name, sizeof name, "%s: ptxt %u", __func__,
+			    i);
+			hexdump(printf, name, bufp, T[i].mlen);
+			result = -1;
+		}
+
+		/* decrypt and verify with a bit flipped */
+		memcpy(tagp, T[i].tag, T[i].M);
+		tagp[0] ^= 0x80;
+		aes_ccm_init(C, nr, AE, L, T[i].M, T[i].nonce, noncelen,
+		    T[i].ad, T[i].adlen, T[i].mlen);
+		aes_ccm_dec(C, T[i].ctxt, bufp, 1);
+		aes_ccm_dec(C, T[i].ctxt + 1, bufp + 1, 2);
+		aes_ccm_dec(C, T[i].ctxt + 3, bufp + 3, T[i].mlen - 4);
+		aes_ccm_dec(C, T[i].ctxt + T[i].mlen - 1,
+		    bufp + T[i].mlen - 1, 1);
+		if (aes_ccm_verify(C, tagp)) {
+			printf("%s: forgery %u succeeded\n", __func__, i);
+			result = -1;
+		}
+	}
+
+	if (bufp[-1] != 0x1a || bufp[33] != 0x1a) {
+		printf("%s: buffer overrun\n", __func__);
+		result = -1;
+	}
+	if (tagp[-1] != 0x53 || tagp[16] != 0x53) {
+		printf("%s: tag overrun\n", __func__);
+		result = -1;
+	}
+
+	return result;
+}
+
+/* XXX provisional hack */
+#include <sys/module.h>
+
+MODULE(MODULE_CLASS_MISC, aes_ccm, NULL);
+
+static int
+aes_ccm_modcmd(modcmd_t cmd, void *opaque)
+{
+
+	switch (cmd) {
+	case MODULE_CMD_INIT:
+		if (aes_ccm_selftest())
+			return EIO;
+		aprint_verbose("aes_ccm: self-test passed\n");
+		return 0;
+	case MODULE_CMD_FINI:
+		return 0;
+	default:
+		return ENOTTY;
+	}
+}
Index: src/sys/crypto/aes/aes_ccm.h
diff -u /dev/null src/sys/crypto/aes/aes_ccm.h:1.1
--- /dev/null	Sat Jul 25 22:15:55 2020
+++ src/sys/crypto/aes/aes_ccm.h	Sat Jul 25 22:15:55 2020
@@ -0,0 +1,55 @@
+/*	$NetBSD: aes_ccm.h,v 1.1 2020/07/25 22:15:55 riastradh Exp $	*/
+
+/*-
+ * Copyright (c) 2020 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef	_CRYPTO_AES_AES_CCM_H
+#define	_CRYPTO_AES_AES_CCM_H
+
+#include <sys/types.h>
+
+struct aesenc;
+
+struct aes_ccm {
+	const struct aesenc	*enc;
+	uint8_t			auth[16];
+	uint8_t			in[16];		/* AES input block */
+	uint8_t			out[16];	/* AES output block */
+	size_t			mlen, mleft;
+	unsigned		i, nr, L, M;
+};
+
+void aes_ccm_init(struct aes_ccm *, unsigned, const struct aesenc *,
+    unsigned, unsigned, const uint8_t *, unsigned, const void *, size_t,
+    size_t);
+void aes_ccm_enc(struct aes_ccm *, const void *, void *, size_t);
+void aes_ccm_dec(struct aes_ccm *, const void *, void *, size_t);
+void aes_ccm_tag(struct aes_ccm *, void *);
+int aes_ccm_verify(struct aes_ccm *, const void *);
+
+int aes_ccm_selftest(void);
+
+#endif	/* _CRYPTO_AES_AES_CCM_H */
Index: src/sys/crypto/aes/aes_ccm_mbuf.c
diff -u /dev/null src/sys/crypto/aes/aes_ccm_mbuf.c:1.1
--- /dev/null	Sat Jul 25 22:15:55 2020
+++ src/sys/crypto/aes/aes_ccm_mbuf.c	Sat Jul 25 22:15:55 2020
@@ -0,0 +1,105 @@
+/*	$NetBSD: aes_ccm_mbuf.c,v 1.1 2020/07/25 22:15:55 riastradh Exp $	*/
+
+/*-
+ * Copyright (c) 2020 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(1, "$NetBSD: aes_ccm_mbuf.c,v 1.1 2020/07/25 22:15:55 riastradh Exp $");
+
+#include <sys/types.h>
+
+#include <sys/mbuf.h>
+
+#include <lib/libkern/libkern.h>
+
+#include <crypto/aes/aes_ccm.h>
+#include <crypto/aes/aes_ccm_mbuf.h>
+
+void
+aes_ccm_enc_mbuf(struct aes_ccm *C, struct mbuf *m, size_t off, size_t len,
+    void *tag)
+{
+	uint8_t *p;
+	size_t seglen;
+
+	while (off >= m->m_len) {
+		KASSERT(m->m_next);
+		m = m->m_next;
+		off -= m->m_len;
+	}
+
+	for (; len > 0; m = m->m_next, off = 0, len -= seglen) {
+		KASSERT(m->m_len >= off);
+		p = mtod(m, uint8_t *) + off;
+		seglen = MIN(m->m_len - off, len);
+		aes_ccm_enc(C, p, p, seglen);
+	}
+
+	aes_ccm_tag(C, tag);
+}
+
+int
+aes_ccm_dec_mbuf(struct aes_ccm *C, struct mbuf *m0, size_t off0, size_t len0,
+    const void *tag)
+{
+	struct mbuf *m;
+	size_t off, len;
+	uint8_t *p;
+	size_t seglen;
+
+	while (off0 >= m0->m_len) {
+		KASSERT(m0->m_next);
+		m0 = m0->m_next;
+		off0 -= m0->m_len;
+	}
+
+	for (m = m0, off = off0, len = len0;
+	     len > 0;
+	     m = m->m_next, off = 0, len -= seglen) {
+		KASSERT(m->m_len >= off);
+		p = mtod(m, uint8_t *) + off;
+		seglen = MIN(m->m_len - off, len);
+		aes_ccm_dec(C, p, p, seglen);
+	}
+
+	if (aes_ccm_verify(C, tag))
+		return 1;
+
+	/*
+	 * Verification failed.  Zero the mbuf so we don't accidentally
+	 * leak anything about it.
+	 */
+	for (m = m0, off = off0, len = len0;
+	     len > 0;
+	     m = m->m_next, off = 0, len -= seglen) {
+		KASSERT(m->m_len >= off);
+		p = mtod(m, uint8_t *) + off;
+		seglen = MIN(m->m_len - off, len);
+		memset(p, 0, seglen);
+	}
+
+	return 0;
+}
Index: src/sys/crypto/aes/aes_ccm_mbuf.h
diff -u /dev/null src/sys/crypto/aes/aes_ccm_mbuf.h:1.1
--- /dev/null	Sat Jul 25 22:15:55 2020
+++ src/sys/crypto/aes/aes_ccm_mbuf.h	Sat Jul 25 22:15:55 2020
@@ -0,0 +1,40 @@
+/*	$NetBSD: aes_ccm_mbuf.h,v 1.1 2020/07/25 22:15:55 riastradh Exp $	*/
+
+/*-
+ * Copyright (c) 2020 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef	_CRYPTO_AES_AES_CCM_MBUF_H
+#define	_CRYPTO_AES_AES_CCM_MBUF_H
+
+#include <sys/types.h>
+
+struct aes_ccm;
+
+void aes_ccm_enc_mbuf(struct aes_ccm *, struct mbuf *, size_t, size_t, void *);
+int aes_ccm_dec_mbuf(struct aes_ccm *, struct mbuf *, size_t, size_t,
+    const void *);
+
+#endif	/* _CRYPTO_AES_AES_CCM_MBUF_H */

Reply via email to