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/8a4d04f16575
branches:  trunk
changeset: 936306:8a4d04f16575
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 eaa816805f24 -r 8a4d04f16575 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