Module Name:    src
Committed By:   riastradh
Date:           Sat Jul 25 22:27:53 UTC 2020

Modified Files:
        src/sys/crypto/aes: aes_ccm.c aes_impl.c aes_impl.h aes_selftest.c

Log Message:
Push CBC-MAC and CCM block updates into the aes_impl API.

This should help reduce the setup and teardown overhead (enabling and
disabling fpu, or expanding bitsliced keys) for CCM, as used in
802.11 WPA2 CCMP.  But all the fiddly formatting details remain in
aes_ccm.c to reduce the effort of implementing it -- at the cost of a
handful additional setups and teardowns per message.

Not yet implemented by any of the aes_impls, so leave a fallback that
just calls aes_enc for now.  This should be removed when all of the
aes_impls provide CBC-MAC and CCM block updates.


To generate a diff of this commit:
cvs rdiff -u -r1.1 -r1.2 src/sys/crypto/aes/aes_ccm.c \
    src/sys/crypto/aes/aes_impl.h
cvs rdiff -u -r1.5 -r1.6 src/sys/crypto/aes/aes_impl.c
cvs rdiff -u -r1.3 -r1.4 src/sys/crypto/aes/aes_selftest.c

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/aes_ccm.c
diff -u src/sys/crypto/aes/aes_ccm.c:1.1 src/sys/crypto/aes/aes_ccm.c:1.2
--- src/sys/crypto/aes/aes_ccm.c:1.1	Sat Jul 25 22:15:55 2020
+++ src/sys/crypto/aes/aes_ccm.c	Sat Jul 25 22:27:53 2020
@@ -1,4 +1,4 @@
-/*	$NetBSD: aes_ccm.c,v 1.1 2020/07/25 22:15:55 riastradh Exp $	*/
+/*	$NetBSD: aes_ccm.c,v 1.2 2020/07/25 22:27:53 riastradh Exp $	*/
 
 /*-
  * Copyright (c) 2020 The NetBSD Foundation, Inc.
@@ -35,7 +35,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(1, "$NetBSD: aes_ccm.c,v 1.1 2020/07/25 22:15:55 riastradh Exp $");
+__KERNEL_RCSID(1, "$NetBSD: aes_ccm.c,v 1.2 2020/07/25 22:27:53 riastradh Exp $");
 
 #include <sys/types.h>
 #include <sys/param.h>
@@ -45,6 +45,7 @@ __KERNEL_RCSID(1, "$NetBSD: aes_ccm.c,v 
 
 #include <crypto/aes/aes.h>
 #include <crypto/aes/aes_ccm.h>
+#include <crypto/aes/aes_impl.h>
 
 static inline void
 xor(uint8_t *x, const uint8_t *a, const uint8_t *b, size_t n)
@@ -54,13 +55,6 @@ xor(uint8_t *x, const uint8_t *a, const 
 		*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)
@@ -157,9 +151,10 @@ aes_ccm_init(struct aes_ccm *C, unsigned
 		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 (adlen - (adlen % 16)) {
+			aes_cbcmac_update1(enc, adp, adlen - (adlen % 16),
+			    C->auth, C->nr);
+			adlen %= 16;
 		}
 
 		/*
@@ -217,15 +212,12 @@ aes_ccm_enc(struct aes_ccm *C, const voi
 	}
 
 	/* 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);
+	if (nbytes - (nbytes % 16)) {
+		aes_ccm_enc1(C->enc, p, q, nbytes - (nbytes % 16), C->auth,
+		    C->nr);
+		p += nbytes - (nbytes % 16);
+		q += nbytes - (nbytes % 16);
+		nbytes %= 16;
 	}
 
 	/* Incorporate any <16-byte unit as a partial block.  */
@@ -278,15 +270,12 @@ aes_ccm_dec(struct aes_ccm *C, const voi
 	}
 
 	/* 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);
+	if (nbytes - (nbytes % 16)) {
+		aes_ccm_dec1(C->enc, p, q, nbytes - (nbytes % 16), C->auth,
+		    C->nr);
+		p += nbytes - (nbytes % 16);
+		q += nbytes - (nbytes % 16);
+		nbytes %= 16;
 	}
 
 	/* Incorporate any <16-byte unit as a partial block.  */
Index: src/sys/crypto/aes/aes_impl.h
diff -u src/sys/crypto/aes/aes_impl.h:1.1 src/sys/crypto/aes/aes_impl.h:1.2
--- src/sys/crypto/aes/aes_impl.h:1.1	Sat Jul 25 22:12:57 2020
+++ src/sys/crypto/aes/aes_impl.h	Sat Jul 25 22:27:53 2020
@@ -1,4 +1,4 @@
-/*	$NetBSD: aes_impl.h,v 1.1 2020/07/25 22:12:57 riastradh Exp $	*/
+/*	$NetBSD: aes_impl.h,v 1.2 2020/07/25 22:27:53 riastradh Exp $	*/
 
 /*-
  * Copyright (c) 2020 The NetBSD Foundation, Inc.
@@ -51,10 +51,27 @@ struct aes_impl {
 		    uint8_t[static 16], size_t, uint8_t[static 16], uint32_t);
 	void	(*ai_xts_dec)(const struct aesdec *, const uint8_t[static 16],
 		    uint8_t[static 16], size_t, uint8_t[static 16], uint32_t);
+	void	(*ai_cbcmac_update1)(const struct aesenc *,
+		    const uint8_t[static 16], size_t, uint8_t[static 16],
+		    uint32_t);
+	void	(*ai_ccm_enc1)(const struct aesenc *,
+		    const uint8_t[static 16], uint8_t[static 16],
+		    size_t, uint8_t[static 32], uint32_t);
+	void	(*ai_ccm_dec1)(const struct aesenc *,
+		    const uint8_t[static 16], uint8_t[static 16],
+		    size_t, uint8_t[static 32], uint32_t);
 };
 
 void	aes_md_init(const struct aes_impl *);
 
 int	aes_selftest(const struct aes_impl *);
 
+/* Internal subroutines dispatched to implementation for AES-CCM.  */
+void	aes_cbcmac_update1(const struct aesenc *, const uint8_t[static 16],
+	    size_t, uint8_t[static 16], uint32_t);
+void	aes_ccm_enc1(const struct aesenc *, const uint8_t[static 16],
+	    uint8_t[static 16], size_t, uint8_t[static 32], uint32_t);
+void	aes_ccm_dec1(const struct aesenc *, const uint8_t[static 16],
+	    uint8_t[static 16], size_t, uint8_t[static 32], uint32_t);
+
 #endif	/* _CRYPTO_AES_AES_IMPL_H */

Index: src/sys/crypto/aes/aes_impl.c
diff -u src/sys/crypto/aes/aes_impl.c:1.5 src/sys/crypto/aes/aes_impl.c:1.6
--- src/sys/crypto/aes/aes_impl.c:1.5	Sat Jul 25 22:14:35 2020
+++ src/sys/crypto/aes/aes_impl.c	Sat Jul 25 22:27:53 2020
@@ -1,4 +1,4 @@
-/*	$NetBSD: aes_impl.c,v 1.5 2020/07/25 22:14:35 riastradh Exp $	*/
+/*	$NetBSD: aes_impl.c,v 1.6 2020/07/25 22:27:53 riastradh Exp $	*/
 
 /*-
  * Copyright (c) 2020 The NetBSD Foundation, Inc.
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(1, "$NetBSD: aes_impl.c,v 1.5 2020/07/25 22:14:35 riastradh Exp $");
+__KERNEL_RCSID(1, "$NetBSD: aes_impl.c,v 1.6 2020/07/25 22:27:53 riastradh Exp $");
 
 #include <sys/types.h>
 #include <sys/kernel.h>
@@ -288,6 +288,90 @@ aes_xts_dec(struct aesdec *dec, const ui
 	aes_impl->ai_xts_dec(dec, in, out, nbytes, tweak, nrounds);
 }
 
+static void
+xor16(uint8_t *x, const uint8_t *a, const uint8_t *b)
+{
+
+	le32enc(x + 4*0, le32dec(a + 4*0) ^ le32dec(b + 4*0));
+	le32enc(x + 4*1, le32dec(a + 4*1) ^ le32dec(b + 4*1));
+	le32enc(x + 4*2, le32dec(a + 4*2) ^ le32dec(b + 4*2));
+	le32enc(x + 4*3, le32dec(a + 4*3) ^ le32dec(b + 4*3));
+}
+
+void
+aes_cbcmac_update1(const struct aesenc *enc, const uint8_t in[static 16],
+    size_t nbytes, uint8_t auth[static 16], uint32_t nrounds)
+{
+
+	KASSERT(nbytes);
+	KASSERT(nbytes % 16 == 0);
+
+	aes_guarantee_selected();
+	if (aes_impl->ai_cbcmac_update1) {
+		aes_impl->ai_cbcmac_update1(enc, in, nbytes, auth, nrounds);
+		return;
+	}
+
+	for (; nbytes; in += 16, nbytes -= 16) {
+		xor16(auth, auth, in);
+		aes_enc(enc, auth, auth, nrounds);
+	}
+}
+
+void
+aes_ccm_enc1(const struct aesenc *enc, const uint8_t in[static 16],
+    uint8_t out[static 16], size_t nbytes, uint8_t authctr[static 32],
+    uint32_t nrounds)
+{
+	uint8_t *auth = authctr;
+	uint8_t *ctr = authctr + 16;
+
+	KASSERT(nbytes);
+	KASSERT(nbytes % 16 == 0);
+
+	aes_guarantee_selected();
+	if (aes_impl->ai_ccm_enc1) {
+		aes_impl->ai_ccm_enc1(enc, in, out, nbytes, auth, nrounds);
+		return;
+	}
+
+	for (; nbytes; in += 16, out += 16, nbytes -= 16) {
+		xor16(auth, auth, in);
+		aes_enc(enc, auth, auth, nrounds);
+
+		be32enc(ctr + 12, 1 + be32dec(ctr + 12));
+		aes_enc(enc, ctr, out, nrounds);
+		xor16(out, out, in);
+	}
+}
+
+void
+aes_ccm_dec1(const struct aesenc *enc, const uint8_t in[static 16],
+    uint8_t out[static 16], size_t nbytes, uint8_t authctr[static 32],
+    uint32_t nrounds)
+{
+	uint8_t *auth = authctr;
+	uint8_t *ctr = authctr + 16;
+
+	KASSERT(nbytes);
+	KASSERT(nbytes % 16 == 0);
+
+	aes_guarantee_selected();
+	if (aes_impl->ai_ccm_dec1) {
+		aes_impl->ai_ccm_dec1(enc, in, out, nbytes, auth, nrounds);
+		return;
+	}
+
+	for (; nbytes >= 16; in += 16, out += 16, nbytes -= 16) {
+		be32enc(ctr + 12, 1 + be32dec(ctr + 12));
+		aes_enc(enc, ctr, out, nrounds);
+		xor16(out, out, in);
+
+		xor16(auth, auth, out);
+		aes_enc(enc, auth, auth, nrounds);
+	}
+}
+
 /*
  * Known-answer self-tests for the standard key schedule.
  */

Index: src/sys/crypto/aes/aes_selftest.c
diff -u src/sys/crypto/aes/aes_selftest.c:1.3 src/sys/crypto/aes/aes_selftest.c:1.4
--- src/sys/crypto/aes/aes_selftest.c:1.3	Sat Jul 25 22:12:57 2020
+++ src/sys/crypto/aes/aes_selftest.c	Sat Jul 25 22:27:53 2020
@@ -1,4 +1,4 @@
-/*	$NetBSD: aes_selftest.c,v 1.3 2020/07/25 22:12:57 riastradh Exp $	*/
+/*	$NetBSD: aes_selftest.c,v 1.4 2020/07/25 22:27:53 riastradh Exp $	*/
 
 /*-
  * Copyright (c) 2020 The NetBSD Foundation, Inc.
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(1, "$NetBSD: aes_selftest.c,v 1.3 2020/07/25 22:12:57 riastradh Exp $");
+__KERNEL_RCSID(1, "$NetBSD: aes_selftest.c,v 1.4 2020/07/25 22:27:53 riastradh Exp $");
 
 #ifdef _KERNEL
 
@@ -400,6 +400,149 @@ aes_selftest_encdec_xts(const struct aes
 	return 0;
 }
 
+static int
+aes_selftest_cbcmac(const struct aes_impl *impl)
+{
+	static const uint8_t m[48] = {
+		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,0x21,0x22,0x23, 0x24,0x25,0x26,0x27,
+		0x28,0x29,0x2a,0x2b, 0x2c,0x2d,0x2e,0x2f,
+	};
+	static uint8_t auth16[16] = {
+		0x7a,0xca,0x0f,0xd9, 0xbc,0xd6,0xec,0x7c,
+		0x9f,0x97,0x46,0x66, 0x16,0xe6,0xa2,0x82,
+	};
+	static uint8_t auth48[16] = {
+		0x26,0x9a,0xe5,0xfc, 0x8c,0x53,0x0f,0xf7,
+		0x6b,0xd9,0xec,0x05, 0x40,0xf7,0x35,0x13,
+	};
+	static const uint8_t key[16];
+	struct aesenc enc;
+	uint8_t auth[16];
+	const unsigned nr = AES_128_NROUNDS;
+
+	if (impl->ai_cbcmac_update1 == NULL)
+		return 0;
+
+	memset(auth, 0, sizeof auth);
+
+	impl->ai_setenckey(&enc, key, nr);
+	impl->ai_cbcmac_update1(&enc, m, 16, auth, nr);
+	if (memcmp(auth, auth16, 16))
+		return aes_selftest_fail(impl, auth, auth16, 16,
+		    "AES-128 CBC-MAC (16)");
+	impl->ai_cbcmac_update1(&enc, m + 16, 32, auth, nr);
+	if (memcmp(auth, auth48, 16))
+		return aes_selftest_fail(impl, auth, auth48, 16,
+		    "AES-128 CBC-MAC (48)");
+
+	return 0;
+}
+
+static int
+aes_selftest_ccm(const struct aes_impl *impl)
+{
+	static const uint8_t ptxt[48] = {
+		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,0x21,0x22,0x23, 0x24,0x25,0x26,0x27,
+		0x28,0x29,0x2a,0x2b, 0x2c,0x2d,0x2e,0x2f,
+	};
+	static uint8_t ctr0[16] = {
+		/* L - 1, #octets in counter */
+		[0] = 0x01,
+		/* nonce */
+		[1] = 0,1,2,3,4,5,6,7,8,9,10,11,12,
+		[14] = 0,
+		[15] = 254,
+	};
+	static uint8_t authctr16[32] = {
+		/* authentication tag */
+		0x7a,0xca,0x0f,0xd9, 0xbc,0xd6,0xec,0x7c,
+		0x9f,0x97,0x46,0x66, 0x16,0xe6,0xa2,0x82,
+
+		/* L - 1, #octets in counter */
+		[16 + 0] = 0x01,
+		/* nonce */
+		[16 + 1] = 0,1,2,3,4,5,6,7,8,9,10,11,12,
+		[16 + 14] = 0,
+		[16 + 15] = 255,
+	};
+	static uint8_t authctr48[32] = {
+		/* authentication tag */
+		0x26,0x9a,0xe5,0xfc, 0x8c,0x53,0x0f,0xf7,
+		0x6b,0xd9,0xec,0x05, 0x40,0xf7,0x35,0x13,
+
+		/* L - 1, #octets in counter */
+		[16 + 0] = 0x01,
+		/* nonce */
+		[16 + 1] = 0,1,2,3,4,5,6,7,8,9,10,11,12,
+		[16 + 14] = 1,
+		[16 + 15] = 1,
+	};
+	static uint8_t ctxt[48] = {
+		0xa4,0x35,0x07,0x5c, 0xdf,0x2d,0x67,0xd3,
+		0xbf,0x1f,0x36,0x93, 0xe4,0x43,0xcb,0x1e,
+		0xa0,0x82,0x9c,0x2a, 0x0b,0x66,0x46,0x05,
+		0x80,0x17,0x71,0xa1, 0x7b,0x09,0xa7,0xd5,
+		0x91,0x0b,0xb3,0x96, 0xd1,0x5e,0x29,0x3e,
+		0x74,0x94,0x74,0x6d, 0x6b,0x25,0x43,0x8c,
+	};
+	static const uint8_t key[16];
+	struct aesenc enc;
+	uint8_t authctr[32];
+	uint8_t buf[48];
+	const unsigned nr = AES_128_NROUNDS;
+	int result = 0;
+
+	if (impl->ai_ccm_enc1 == NULL)
+		return 0;
+
+	impl->ai_setenckey(&enc, key, nr);
+
+	memset(authctr, 0, 16);
+	memcpy(authctr + 16, ctr0, 16);
+
+	impl->ai_ccm_enc1(&enc, ptxt, buf, 16, authctr, nr);
+	if (memcmp(authctr, authctr16, 32))
+		result |= aes_selftest_fail(impl, authctr, authctr16, 32,
+		    "AES-128 CCM encrypt auth/ctr (16)");
+	impl->ai_ccm_enc1(&enc, ptxt + 16, buf + 16, 32, authctr, nr);
+	if (memcmp(authctr, authctr48, 32))
+		result |= aes_selftest_fail(impl, authctr, authctr48, 32,
+		    "AES-128 CCM encrypt auth/ctr (48)");
+
+	if (memcmp(buf, ctxt, 32))
+		result |= aes_selftest_fail(impl, buf, ctxt, 48,
+		    "AES-128 CCM ciphertext");
+
+	if (impl->ai_ccm_dec1 == NULL)
+		return result;
+
+	memset(authctr, 0, 16);
+	memcpy(authctr + 16, ctr0, 16);
+
+	impl->ai_ccm_dec1(&enc, ctxt, buf, 16, authctr, nr);
+	if (memcmp(authctr, authctr16, 32))
+		result |= aes_selftest_fail(impl, authctr, authctr16, 32,
+		    "AES-128 CCM decrypt auth/ctr (16)");
+	impl->ai_ccm_dec1(&enc, ctxt + 16, buf + 16, 32, authctr, nr);
+	if (memcmp(authctr, authctr48, 32))
+		result |= aes_selftest_fail(impl, authctr, authctr48, 32,
+		    "AES-128 CCM decrypt auth/ctr (48)");
+
+	if (memcmp(buf, ptxt, 32))
+		result |= aes_selftest_fail(impl, buf, ptxt, 48,
+		    "AES-128 CCM plaintext");
+
+	return result;
+}
+
 int
 aes_selftest(const struct aes_impl *impl)
 {
@@ -414,6 +557,10 @@ aes_selftest(const struct aes_impl *impl
 		result = -1;
 	if (aes_selftest_encdec_xts(impl))
 		result = -1;
+	if (aes_selftest_cbcmac(impl))
+		result = -1;
+	if (aes_selftest_ccm(impl))
+		result = -1;
 
 	return result;
 }

Reply via email to