diff --git a/sys/crypto/aes/aes_ccm.c b/sys/crypto/aes/aes_ccm.c index 245fcd625ca2..3928dd07ba5f 100644 --- a/sys/crypto/aes/aes_ccm.c +++ b/sys/crypto/aes/aes_ccm.c @@ -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 -__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 #include @@ -45,6 +45,7 @@ __KERNEL_RCSID(1, "$NetBSD: aes_ccm.c,v 1.1 2020/07/25 22:15:55 riastradh Exp $" #include #include +#include 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 uint8_t *b, size_t n) *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 nr, const struct aesenc *enc, 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 void *in, void *out, size_t nbytes) } /* 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 void *in, void *out, size_t nbytes) } /* 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. */ diff --git a/sys/crypto/aes/aes_impl.c b/sys/crypto/aes/aes_impl.c index a72d0114de80..fb7b987a0c00 100644 --- a/sys/crypto/aes/aes_impl.c +++ b/sys/crypto/aes/aes_impl.c @@ -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 -__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 #include @@ -288,6 +288,90 @@ aes_xts_dec(struct aesdec *dec, const uint8_t in[static 16], 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. */ diff --git a/sys/crypto/aes/aes_impl.h b/sys/crypto/aes/aes_impl.h index 6bbda2c07723..e36f3e3df405 100644 --- a/sys/crypto/aes/aes_impl.h +++ b/sys/crypto/aes/aes_impl.h @@ -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 */ diff --git a/sys/crypto/aes/aes_selftest.c b/sys/crypto/aes/aes_selftest.c index b644954710cd..4de1210fc967 100644 --- a/sys/crypto/aes/aes_selftest.c +++ b/sys/crypto/aes/aes_selftest.c @@ -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 -__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_impl *impl) 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; }