Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys Rework AES in kernel to finally address CVE-2005-1797.



details:   https://anonhg.NetBSD.org/src/rev/87f6060a97f3
branches:  trunk
changeset: 935300:87f6060a97f3
user:      riastradh <riastradh%NetBSD.org@localhost>
date:      Mon Jun 29 23:27:52 2020 +0000

description:
Rework AES in kernel to finally address CVE-2005-1797.

1. Rip out old variable-time reference implementation.
2. Replace it by BearSSL's constant-time 32-bit logic.
   => Obtained from commit dda1f8a0c46e15b4a235163470ff700b2f13dcc5.
   => We could conditionally adopt the 64-bit logic too, which would
      likely give a modest performance boost on 64-bit platforms
      without AES-NI, but that's a bit more trouble.
3. Select the AES implementation at boot-time; allow an MD override.
   => Use self-tests to verify basic correctness at boot.
   => The implementation selection policy is rather rudimentary at
      the moment but it is isolated to one place so it's easy to
      change later on.

This (a) plugs a host of timing attacks on, e.g., cgd, and (b) paves
the way to take advantage of CPU support for AES -- both things we
should've done a decade ago.  Downside: Computing AES takes 2-3x the
CPU time.  But that's what hardware support will be coming for.

Rudimentary measurement of performance impact done by:

mount -t tmpfs tmpfs /tmp
dd if=/dev/zero of=/tmp/disk bs=1m count=512
vnconfig -cv vnd0 /tmp/disk
cgdconfig -s cgd0 /dev/vnd0 aes-cbc 256 < /dev/zero
dd if=/dev/rcgd0d of=/dev/null bs=64k
dd if=/dev/zero of=/dev/rcgd0d bs=64k

The AES-CBC encryption performance impact is closer to 3x because it
is inherently sequential; the AES-CBC decryption impact is closer to
2x because the bitsliced AES logic can process two blocks at once.

Discussed on tech-kern:

https://mail-index.NetBSD.org/tech-kern/2020/06/18/msg026505.html

diffstat:

 sys/conf/files                         |     4 +-
 sys/crypto/aes/aes.h                   |   101 ++
 sys/crypto/aes/aes_bear.c              |   617 ++++++++++++++++
 sys/crypto/aes/aes_bear.h              |    50 +
 sys/crypto/aes/aes_ct.c                |   335 ++++++++
 sys/crypto/aes/aes_ct_dec.c            |   177 ++++
 sys/crypto/aes/aes_ct_enc.c            |   119 +++
 sys/crypto/aes/aes_impl.c              |   256 ++++++
 sys/crypto/aes/aes_rijndael.c          |   306 +++++++
 sys/crypto/aes/aes_selftest.c          |   387 ++++++++++
 sys/crypto/aes/files.aes               |    12 +
 sys/crypto/rijndael/files.rijndael     |     7 -
 sys/crypto/rijndael/rijndael-alg-fst.c |  1225 --------------------------------
 sys/crypto/rijndael/rijndael-api-fst.c |   430 -----------
 sys/crypto/rijndael/rijndael.c         |    57 -
 sys/crypto/rijndael/rijndael_local.h   |     7 -
 sys/rump/kern/lib/libcrypto/Makefile   |    16 +-
 17 files changed, 2373 insertions(+), 1733 deletions(-)

diffs (truncated from 4202 to 300 lines):

diff -r a132c220d177 -r 87f6060a97f3 sys/conf/files
--- a/sys/conf/files    Mon Jun 29 23:22:27 2020 +0000
+++ b/sys/conf/files    Mon Jun 29 23:27:52 2020 +0000
@@ -1,4 +1,4 @@
-#      $NetBSD: files,v 1.1268 2020/06/07 09:45:19 maxv Exp $
+#      $NetBSD: files,v 1.1269 2020/06/29 23:27:52 riastradh Exp $
 #      @(#)files.newconf       7.5 (Berkeley) 5/10/93
 
 version        20171118
@@ -200,10 +200,10 @@
 # use it.
 
 # Individual crypto transforms
+include "crypto/aes/files.aes"
 include "crypto/des/files.des"
 include "crypto/blowfish/files.blowfish"
 include "crypto/cast128/files.cast128"
-include "crypto/rijndael/files.rijndael"
 include "crypto/skipjack/files.skipjack"
 include "crypto/camellia/files.camellia"
 # General-purpose crypto processing framework.
diff -r a132c220d177 -r 87f6060a97f3 sys/crypto/aes/aes.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/crypto/aes/aes.h      Mon Jun 29 23:27:52 2020 +0000
@@ -0,0 +1,101 @@
+/*     $NetBSD: aes.h,v 1.1 2020/06/29 23:27:52 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.
+ */
+
+#ifndef        _CRYPTO_AES_AES_H
+#define        _CRYPTO_AES_AES_H
+
+#include <sys/types.h>
+#include <sys/cdefs.h>
+
+/*
+ * struct aes
+ *
+ *     Expanded round keys.
+ */
+struct aes {
+       uint32_t        aes_rk[60];
+} __aligned(16);
+
+#define        AES_128_NROUNDS 10
+#define        AES_192_NROUNDS 12
+#define        AES_256_NROUNDS 14
+
+struct aesenc {
+       struct aes      aese_aes;
+};
+
+struct aesdec {
+       struct aes      aesd_aes;
+};
+
+struct aes_impl {
+       const char *ai_name;
+       int     (*ai_probe)(void);
+       void    (*ai_setenckey)(struct aesenc *, const uint8_t *, uint32_t);
+       void    (*ai_setdeckey)(struct aesdec *, const uint8_t *, uint32_t);
+       void    (*ai_enc)(const struct aesenc *, const uint8_t[static 16],
+                   uint8_t[static 16], uint32_t);
+       void    (*ai_dec)(const struct aesdec *, const uint8_t[static 16],
+                   uint8_t[static 16], uint32_t);
+       void    (*ai_cbc_enc)(const struct aesenc *, const uint8_t[static 16],
+                   uint8_t[static 16], size_t, uint8_t[static 16], uint32_t);
+       void    (*ai_cbc_dec)(const struct aesdec *, const uint8_t[static 16],
+                   uint8_t[static 16], size_t, uint8_t[static 16], uint32_t);
+       void    (*ai_xts_enc)(const struct aesenc *, const uint8_t[static 16],
+                   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);
+};
+
+int    aes_selftest(const struct aes_impl *);
+
+uint32_t aes_setenckey128(struct aesenc *, const uint8_t[static 16]);
+uint32_t aes_setenckey192(struct aesenc *, const uint8_t[static 24]);
+uint32_t aes_setenckey256(struct aesenc *, const uint8_t[static 32]);
+uint32_t aes_setdeckey128(struct aesdec *, const uint8_t[static 16]);
+uint32_t aes_setdeckey192(struct aesdec *, const uint8_t[static 24]);
+uint32_t aes_setdeckey256(struct aesdec *, const uint8_t[static 32]);
+
+void   aes_enc(const struct aesenc *, const uint8_t[static 16],
+           uint8_t[static 16], uint32_t);
+void   aes_dec(const struct aesdec *, const uint8_t[static 16],
+           uint8_t[static 16], uint32_t);
+
+void   aes_cbc_enc(struct aesenc *, const uint8_t[static 16],
+           uint8_t[static 16], size_t, uint8_t[static 16], uint32_t);
+void   aes_cbc_dec(struct aesdec *, const uint8_t[static 16],
+           uint8_t[static 16], size_t, uint8_t[static 16], uint32_t);
+
+void   aes_xts_enc(struct aesenc *, const uint8_t[static 16],
+           uint8_t[static 16], size_t, uint8_t[static 16], uint32_t);
+void   aes_xts_dec(struct aesdec *, const uint8_t[static 16],
+           uint8_t[static 16], size_t, uint8_t[static 16], uint32_t);
+
+void   aes_md_init(const struct aes_impl *);
+
+#endif /* _CRYPTO_AES_AES_H */
diff -r a132c220d177 -r 87f6060a97f3 sys/crypto/aes/aes_bear.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/crypto/aes/aes_bear.c Mon Jun 29 23:27:52 2020 +0000
@@ -0,0 +1,617 @@
+/*     $NetBSD: aes_bear.c,v 1.1 2020/06/29 23:27:52 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.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(1, "$NetBSD: aes_bear.c,v 1.1 2020/06/29 23:27:52 riastradh Exp $");
+
+#include <sys/types.h>
+#include <sys/endian.h>
+#include <sys/systm.h>
+
+#include <crypto/aes/aes.h>
+#include <crypto/aes/aes_bear.h>
+
+static void
+aesbear_setkey(uint32_t rk[static 60], const void *key, uint32_t nrounds)
+{
+       size_t key_len;
+
+       switch (nrounds) {
+       case 10:
+               key_len = 16;
+               break;
+       case 12:
+               key_len = 24;
+               break;
+       case 14:
+               key_len = 32;
+               break;
+       default:
+               panic("invalid AES nrounds: %u", nrounds);
+       }
+
+       br_aes_ct_keysched(rk, key, key_len);
+}
+
+static void
+aesbear_setenckey(struct aesenc *enc, const uint8_t *key, uint32_t nrounds)
+{
+
+       aesbear_setkey(enc->aese_aes.aes_rk, key, nrounds);
+}
+
+static void
+aesbear_setdeckey(struct aesdec *dec, const uint8_t *key, uint32_t nrounds)
+{
+
+       /*
+        * BearSSL computes InvMixColumns on the fly -- no need for
+        * distinct decryption round keys.
+        */
+       aesbear_setkey(dec->aesd_aes.aes_rk, key, nrounds);
+}
+
+static void
+aesbear_enc(const struct aesenc *enc, const uint8_t in[static 16],
+    uint8_t out[static 16], uint32_t nrounds)
+{
+       uint32_t sk_exp[120];
+       uint32_t q[8];
+
+       /* Expand round keys for bitslicing.  */
+       br_aes_ct_skey_expand(sk_exp, nrounds, enc->aese_aes.aes_rk);
+
+       /* Load input block interleaved with garbage block.  */
+       q[2*0] = le32dec(in + 4*0);
+       q[2*1] = le32dec(in + 4*1);
+       q[2*2] = le32dec(in + 4*2);
+       q[2*3] = le32dec(in + 4*3);
+       q[1] = q[3] = q[5] = q[7] = 0;
+
+       /* Transform to bitslice, decrypt, transform from bitslice.  */
+       br_aes_ct_ortho(q);
+       br_aes_ct_bitslice_encrypt(nrounds, sk_exp, q);
+       br_aes_ct_ortho(q);
+
+       /* Store output block.  */
+       le32enc(out + 4*0, q[2*0]);
+       le32enc(out + 4*1, q[2*1]);
+       le32enc(out + 4*2, q[2*2]);
+       le32enc(out + 4*3, q[2*3]);
+
+       /* Paranoia: Zero temporary buffers.  */
+       explicit_memset(sk_exp, 0, sizeof sk_exp);
+       explicit_memset(q, 0, sizeof q);
+}
+
+static void
+aesbear_dec(const struct aesdec *dec, const uint8_t in[static 16],
+    uint8_t out[static 16], uint32_t nrounds)
+{
+       uint32_t sk_exp[120];
+       uint32_t q[8];
+
+       /* Expand round keys for bitslicing.  */
+       br_aes_ct_skey_expand(sk_exp, nrounds, dec->aesd_aes.aes_rk);
+
+       /* Load input block interleaved with garbage.  */
+       q[2*0] = le32dec(in + 4*0);
+       q[2*1] = le32dec(in + 4*1);
+       q[2*2] = le32dec(in + 4*2);
+       q[2*3] = le32dec(in + 4*3);
+       q[1] = q[3] = q[5] = q[7] = 0;
+
+       /* Transform to bitslice, decrypt, transform from bitslice.  */
+       br_aes_ct_ortho(q);
+       br_aes_ct_bitslice_decrypt(nrounds, sk_exp, q);
+       br_aes_ct_ortho(q);
+
+       /* Store output block.  */
+       le32enc(out + 4*0, q[2*0]);
+       le32enc(out + 4*1, q[2*1]);
+       le32enc(out + 4*2, q[2*2]);
+       le32enc(out + 4*3, q[2*3]);
+
+       /* Paranoia: Zero temporary buffers.  */
+       explicit_memset(sk_exp, 0, sizeof sk_exp);
+       explicit_memset(q, 0, sizeof q);
+}
+
+static void
+aesbear_cbc_enc(const struct aesenc *enc, const uint8_t in[static 16],
+    uint8_t out[static 16], size_t nbytes, uint8_t iv[static 16],
+    uint32_t nrounds)
+{
+       uint32_t sk_exp[120];
+       uint32_t q[8];
+       uint32_t cv0, cv1, cv2, cv3;
+
+       KASSERT(nbytes % 16 == 0);
+
+       /* Skip if there's nothing to do.  */
+       if (nbytes == 0)
+               return;
+
+       /* Expand round keys for bitslicing.  */
+       br_aes_ct_skey_expand(sk_exp, nrounds, enc->aese_aes.aes_rk);
+
+       /* Initialize garbage block.  */
+       q[1] = q[3] = q[5] = q[7] = 0;
+
+       /* Load IV.  */
+       cv0 = le32dec(iv + 4*0);
+       cv1 = le32dec(iv + 4*1);
+       cv2 = le32dec(iv + 4*2);
+       cv3 = le32dec(iv + 4*3);



Home | Main Index | Thread Index | Old Index