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; }