Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/crypto/aes New aes_ccm API.
details: https://anonhg.NetBSD.org/src/rev/5db88794a62e
branches: trunk
changeset: 1012175:5db88794a62e
user: riastradh <riastradh%NetBSD.org@localhost>
date: Sat Jul 25 22:15:55 2020 +0000
description:
New aes_ccm API.
Intended for use in net80211 for WPA2 CCMP.
diffstat:
sys/crypto/aes/aes_ccm.c | 619 ++++++++++++++++++++++++++++++++++++++++++
sys/crypto/aes/aes_ccm.h | 55 +++
sys/crypto/aes/aes_ccm_mbuf.c | 105 +++++++
sys/crypto/aes/aes_ccm_mbuf.h | 40 ++
sys/crypto/aes/files.aes | 4 +-
5 files changed, 822 insertions(+), 1 deletions(-)
diffs (truncated from 851 to 300 lines):
diff -r 5b0545c9479d -r 5db88794a62e sys/crypto/aes/aes_ccm.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/crypto/aes/aes_ccm.c Sat Jul 25 22:15:55 2020 +0000
@@ -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);
Home |
Main Index |
Thread Index |
Old Index