Module Name: src
Committed By: riastradh
Date: Mon Jun 29 23:27:52 UTC 2020
Modified Files:
src/sys/conf: files
src/sys/rump/kern/lib/libcrypto: Makefile
Added Files:
src/sys/crypto/aes: aes.h aes_bear.c aes_bear.h aes_ct.c aes_ct_dec.c
aes_ct_enc.c aes_impl.c aes_rijndael.c aes_selftest.c files.aes
Removed Files:
src/sys/crypto/rijndael: files.rijndael rijndael-alg-fst.c
rijndael-api-fst.c rijndael.c rijndael_local.h
Log Message:
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
To generate a diff of this commit:
cvs rdiff -u -r1.1268 -r1.1269 src/sys/conf/files
cvs rdiff -u -r0 -r1.1 src/sys/crypto/aes/aes.h src/sys/crypto/aes/aes_bear.c \
src/sys/crypto/aes/aes_bear.h src/sys/crypto/aes/aes_ct.c \
src/sys/crypto/aes/aes_ct_dec.c src/sys/crypto/aes/aes_ct_enc.c \
src/sys/crypto/aes/aes_impl.c src/sys/crypto/aes/aes_rijndael.c \
src/sys/crypto/aes/aes_selftest.c src/sys/crypto/aes/files.aes
cvs rdiff -u -r1.7 -r0 src/sys/crypto/rijndael/files.rijndael \
src/sys/crypto/rijndael/rijndael-alg-fst.c
cvs rdiff -u -r1.25 -r0 src/sys/crypto/rijndael/rijndael-api-fst.c
cvs rdiff -u -r1.8 -r0 src/sys/crypto/rijndael/rijndael.c
cvs rdiff -u -r1.6 -r0 src/sys/crypto/rijndael/rijndael_local.h
cvs rdiff -u -r1.6 -r1.7 src/sys/rump/kern/lib/libcrypto/Makefile
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/conf/files
diff -u src/sys/conf/files:1.1268 src/sys/conf/files:1.1269
--- src/sys/conf/files:1.1268 Sun Jun 7 09:45:19 2020
+++ src/sys/conf/files Mon Jun 29 23:27:52 2020
@@ -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 @@ defflag opt_machdep.h MACHDEP
# 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.
Index: src/sys/rump/kern/lib/libcrypto/Makefile
diff -u src/sys/rump/kern/lib/libcrypto/Makefile:1.6 src/sys/rump/kern/lib/libcrypto/Makefile:1.7
--- src/sys/rump/kern/lib/libcrypto/Makefile:1.6 Thu Dec 5 03:57:55 2019
+++ src/sys/rump/kern/lib/libcrypto/Makefile Mon Jun 29 23:27:52 2020
@@ -1,11 +1,11 @@
-# $NetBSD: Makefile,v 1.6 2019/12/05 03:57:55 riastradh Exp $
+# $NetBSD: Makefile,v 1.7 2020/06/29 23:27:52 riastradh Exp $
#
-.PATH: ${.CURDIR}/../../../../crypto/blowfish \
+.PATH: ${.CURDIR}/../../../../crypto/aes \
+ ${.CURDIR}/../../../../crypto/blowfish \
${.CURDIR}/../../../../crypto/camellia \
${.CURDIR}/../../../../crypto/cast128 \
${.CURDIR}/../../../../crypto/des \
- ${.CURDIR}/../../../../crypto/rijndael \
${.CURDIR}/../../../../crypto/skipjack
LIB= rumpkern_crypto
@@ -23,8 +23,14 @@ SRCS+= cast128.c
# DES
SRCS+= des_ecb.c des_setkey.c des_enc.c des_cbc.c des_module.c
-# rijndael
-SRCS+= rijndael-alg-fst.c rijndael-api-fst.c rijndael.c
+# AES
+SRCS+= aes_bear.c
+SRCS+= aes_ct.c
+SRCS+= aes_ct_dec.c
+SRCS+= aes_ct_enc.c
+SRCS+= aes_impl.c
+SRCS+= aes_rijndael.c
+SRCS+= aes_selftest.c
# skipjack
SRCS+= skipjack.c
Added files:
Index: src/sys/crypto/aes/aes.h
diff -u /dev/null src/sys/crypto/aes/aes.h:1.1
--- /dev/null Mon Jun 29 23:27:52 2020
+++ src/sys/crypto/aes/aes.h Mon Jun 29 23:27:52 2020
@@ -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 */
Index: src/sys/crypto/aes/aes_bear.c
diff -u /dev/null src/sys/crypto/aes/aes_bear.c:1.1
--- /dev/null Mon Jun 29 23:27:52 2020
+++ src/sys/crypto/aes/aes_bear.c Mon Jun 29 23:27:52 2020
@@ -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);
+
+ for (; nbytes; nbytes -= 16, in += 16, out += 16) {
+ /* Load input block and apply CV. */
+ q[2*0] = cv0 ^ le32dec(in + 4*0);
+ q[2*1] = cv1 ^ le32dec(in + 4*1);
+ q[2*2] = cv2 ^ le32dec(in + 4*2);
+ q[2*3] = cv3 ^ le32dec(in + 4*3);
+
+ /* Transform to bitslice, encrypt, transform from bitslice. */
+ br_aes_ct_ortho(q);
+ br_aes_ct_bitslice_encrypt(nrounds, sk_exp, q);
+ br_aes_ct_ortho(q);
+
+ /* Remember ciphertext as CV and store output block. */
+ cv0 = q[2*0];
+ cv1 = q[2*1];
+ cv2 = q[2*2];
+ cv3 = q[2*3];
+ le32enc(out + 4*0, cv0);
+ le32enc(out + 4*1, cv1);
+ le32enc(out + 4*2, cv2);
+ le32enc(out + 4*3, cv3);
+ }
+
+ /* Store updated IV. */
+ le32enc(iv + 4*0, cv0);
+ le32enc(iv + 4*1, cv1);
+ le32enc(iv + 4*2, cv2);
+ le32enc(iv + 4*3, cv3);
+
+ /* Paranoia: Zero temporary buffers. */
+ explicit_memset(sk_exp, 0, sizeof sk_exp);
+ explicit_memset(q, 0, sizeof q);
+}
+
+static void
+aesbear_cbc_dec(const struct aesdec *dec, 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, iv0, iv1, iv2, iv3;
+
+ 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, dec->aesd_aes.aes_rk);
+
+ /* Load the IV. */
+ iv0 = le32dec(iv + 4*0);
+ iv1 = le32dec(iv + 4*1);
+ iv2 = le32dec(iv + 4*2);
+ iv3 = le32dec(iv + 4*3);
+
+ /* Load the last cipher block. */
+ cv0 = le32dec(in + nbytes - 16 + 4*0);
+ cv1 = le32dec(in + nbytes - 16 + 4*1);
+ cv2 = le32dec(in + nbytes - 16 + 4*2);
+ cv3 = le32dec(in + nbytes - 16 + 4*3);
+
+ /* Store the updated IV. */
+ le32enc(iv + 4*0, cv0);
+ le32enc(iv + 4*1, cv1);
+ le32enc(iv + 4*2, cv2);
+ le32enc(iv + 4*3, cv3);
+
+ /* Handle the last cipher block separately if odd number. */
+ if (nbytes % 32) {
+ KASSERT(nbytes % 32 == 16);
+
+ /* Set up the last cipher block and a garbage block. */
+ q[2*0] = cv0;
+ q[2*1] = cv1;
+ q[2*2] = cv2;
+ q[2*3] = cv3;
+ q[1] = q[3] = q[5] = q[7] = 0;
+
+ /* Decrypt. */
+ br_aes_ct_ortho(q);
+ br_aes_ct_bitslice_decrypt(nrounds, sk_exp, q);
+ br_aes_ct_ortho(q);
+
+ /* If this was the only cipher block, we're done. */
+ nbytes -= 16;
+ if (nbytes == 0)
+ goto out;
+
+ /*
+ * Otherwise, load up the penultimate cipher block, and
+ * store the output block.
+ */
+ cv0 = le32dec(in + nbytes - 16 + 4*0);
+ cv1 = le32dec(in + nbytes - 16 + 4*1);
+ cv2 = le32dec(in + nbytes - 16 + 4*2);
+ cv3 = le32dec(in + nbytes - 16 + 4*3);
+ le32enc(out + nbytes + 4*0, cv0 ^ q[2*0]);
+ le32enc(out + nbytes + 4*1, cv1 ^ q[2*1]);
+ le32enc(out + nbytes + 4*2, cv2 ^ q[2*2]);
+ le32enc(out + nbytes + 4*3, cv3 ^ q[2*3]);
+ }
+
+ for (;;) {
+ KASSERT(nbytes >= 32);
+
+ /*
+ * 1. Set up upper cipher block from cvN.
+ * 2. Load lower cipher block into cvN and set it up.
+ * 3. Decrypt.
+ */
+ q[2*0 + 1] = cv0;
+ q[2*1 + 1] = cv1;
+ q[2*2 + 1] = cv2;
+ q[2*3 + 1] = cv3;
+ cv0 = q[2*0] = le32dec(in + nbytes - 32 + 4*0);
+ cv1 = q[2*1] = le32dec(in + nbytes - 32 + 4*1);
+ cv2 = q[2*2] = le32dec(in + nbytes - 32 + 4*2);
+ cv3 = q[2*3] = le32dec(in + nbytes - 32 + 4*3);
+
+ br_aes_ct_ortho(q);
+ br_aes_ct_bitslice_decrypt(nrounds, sk_exp, q);
+ br_aes_ct_ortho(q);
+
+ /* Store the upper output block. */
+ le32enc(out + nbytes - 16 + 4*0, q[2*0 + 1] ^ cv0);
+ le32enc(out + nbytes - 16 + 4*1, q[2*1 + 1] ^ cv1);
+ le32enc(out + nbytes - 16 + 4*2, q[2*2 + 1] ^ cv2);
+ le32enc(out + nbytes - 16 + 4*3, q[2*3 + 1] ^ cv3);
+
+ /* Stop if we've reached the first output block. */
+ nbytes -= 32;
+ if (nbytes == 0)
+ goto out;
+
+ /*
+ * Load the preceding cipher block, and apply it as the
+ * chaining value to this one.
+ */
+ cv0 = le32dec(in + nbytes - 16 + 4*0);
+ cv1 = le32dec(in + nbytes - 16 + 4*1);
+ cv2 = le32dec(in + nbytes - 16 + 4*2);
+ cv3 = le32dec(in + nbytes - 16 + 4*3);
+ le32enc(out + nbytes + 4*0, q[2*0] ^ cv0);
+ le32enc(out + nbytes + 4*1, q[2*1] ^ cv1);
+ le32enc(out + nbytes + 4*2, q[2*2] ^ cv2);
+ le32enc(out + nbytes + 4*3, q[2*3] ^ cv3);
+ }
+
+out: /* Store the first output block. */
+ le32enc(out + 4*0, q[2*0] ^ iv0);
+ le32enc(out + 4*1, q[2*1] ^ iv1);
+ le32enc(out + 4*2, q[2*2] ^ iv2);
+ le32enc(out + 4*3, q[2*3] ^ iv3);
+
+ /* Paranoia: Zero temporary buffers. */
+ explicit_memset(sk_exp, 0, sizeof sk_exp);
+ explicit_memset(q, 0, sizeof q);
+}
+
+static inline void
+aesbear_xts_update(uint32_t *t0, uint32_t *t1, uint32_t *t2, uint32_t *t3)
+{
+ uint32_t s0, s1, s2, s3;
+
+ s0 = *t0 >> 31;
+ s1 = *t1 >> 31;
+ s2 = *t2 >> 31;
+ s3 = *t3 >> 31;
+ *t0 = (*t0 << 1) ^ (-s3 & 0x87);
+ *t1 = (*t1 << 1) ^ s0;
+ *t2 = (*t2 << 1) ^ s1;
+ *t3 = (*t3 << 1) ^ s2;
+}
+
+static int
+aesbear_xts_update_selftest(void)
+{
+ static const struct {
+ uint32_t in[4], out[4];
+ } cases[] = {
+ { {1}, {2} },
+ { {0x80000000U,0,0,0}, {0,1,0,0} },
+ { {0,0x80000000U,0,0}, {0,0,1,0} },
+ { {0,0,0x80000000U,0}, {0,0,0,1} },
+ { {0,0,0,0x80000000U}, {0x87,0,0,0} },
+ { {0,0x80000000U,0,0x80000000U}, {0x87,0,1,0} },
+ };
+ unsigned i;
+ uint32_t t0, t1, t2, t3;
+
+ for (i = 0; i < sizeof(cases)/sizeof(cases[0]); i++) {
+ t0 = cases[i].in[0];
+ t1 = cases[i].in[1];
+ t2 = cases[i].in[2];
+ t3 = cases[i].in[3];
+ aesbear_xts_update(&t0, &t1, &t2, &t3);
+ if (t0 != cases[i].out[0] ||
+ t1 != cases[i].out[1] ||
+ t2 != cases[i].out[2] ||
+ t3 != cases[i].out[3])
+ return -1;
+ }
+
+ /* Success! */
+ return 0;
+}
+
+static void
+aesbear_xts_enc(const struct aesenc *enc, const uint8_t in[static 16],
+ uint8_t out[static 16], size_t nbytes, uint8_t tweak[static 16],
+ uint32_t nrounds)
+{
+ uint32_t sk_exp[120];
+ uint32_t q[8];
+ uint32_t t0, t1, t2, t3, u0, u1, u2, u3;
+
+ 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);
+
+ /* Load tweak. */
+ t0 = le32dec(tweak + 4*0);
+ t1 = le32dec(tweak + 4*1);
+ t2 = le32dec(tweak + 4*2);
+ t3 = le32dec(tweak + 4*3);
+
+ /* Handle the first block separately if odd number. */
+ if (nbytes % 32) {
+ KASSERT(nbytes % 32 == 16);
+
+ /* Load up the first block and a garbage block. */
+ q[2*0] = le32dec(in + 4*0) ^ t0;
+ q[2*1] = le32dec(in + 4*1) ^ t1;
+ q[2*2] = le32dec(in + 4*2) ^ t2;
+ q[2*3] = le32dec(in + 4*3) ^ t3;
+ q[1] = q[3] = q[5] = q[7] = 0;
+
+ /* Encrypt two blocks. */
+ br_aes_ct_ortho(q);
+ br_aes_ct_bitslice_encrypt(nrounds, sk_exp, q);
+ br_aes_ct_ortho(q);
+
+ /* Store the first cipher block. */
+ le32enc(out + 4*0, q[2*0] ^ t0);
+ le32enc(out + 4*1, q[2*1] ^ t1);
+ le32enc(out + 4*2, q[2*2] ^ t2);
+ le32enc(out + 4*3, q[2*3] ^ t3);
+
+ /* Advance to the next block. */
+ aesbear_xts_update(&t0, &t1, &t2, &t3);
+ if ((nbytes -= 16) == 0)
+ goto out;
+ in += 16;
+ out += 16;
+ }
+
+ do {
+ KASSERT(nbytes >= 32);
+
+ /* Compute the upper tweak. */
+ u0 = t0; u1 = t1; u2 = t2; u3 = t3;
+ aesbear_xts_update(&u0, &u1, &u2, &u3);
+
+ /* Load lower and upper blocks. */
+ q[2*0] = le32dec(in + 4*0) ^ t0;
+ q[2*1] = le32dec(in + 4*1) ^ t1;
+ q[2*2] = le32dec(in + 4*2) ^ t2;
+ q[2*3] = le32dec(in + 4*3) ^ t3;
+ q[2*0 + 1] = le32dec(in + 16 + 4*0) ^ u0;
+ q[2*1 + 1] = le32dec(in + 16 + 4*1) ^ u1;
+ q[2*2 + 1] = le32dec(in + 16 + 4*2) ^ u2;
+ q[2*3 + 1] = le32dec(in + 16 + 4*3) ^ u3;
+
+ /* Encrypt two blocks. */
+ br_aes_ct_ortho(q);
+ br_aes_ct_bitslice_encrypt(nrounds, sk_exp, q);
+ br_aes_ct_ortho(q);
+
+ /* Store lower and upper blocks. */
+ le32enc(out + 4*0, q[2*0] ^ t0);
+ le32enc(out + 4*1, q[2*1] ^ t1);
+ le32enc(out + 4*2, q[2*2] ^ t2);
+ le32enc(out + 4*3, q[2*3] ^ t3);
+ le32enc(out + 16 + 4*0, q[2*0 + 1] ^ u0);
+ le32enc(out + 16 + 4*1, q[2*1 + 1] ^ u1);
+ le32enc(out + 16 + 4*2, q[2*2 + 1] ^ u2);
+ le32enc(out + 16 + 4*3, q[2*3 + 1] ^ u3);
+
+ /* Advance to the next pair of blocks. */
+ t0 = u0; t1 = u1; t2 = u2; t3 = u3;
+ aesbear_xts_update(&t0, &t1, &t2, &t3);
+ in += 32;
+ out += 32;
+ } while (nbytes -= 32, nbytes);
+
+out: /* Store the updated tweak. */
+ le32enc(tweak + 4*0, t0);
+ le32enc(tweak + 4*1, t1);
+ le32enc(tweak + 4*2, t2);
+ le32enc(tweak + 4*3, t3);
+
+ /* Paranoia: Zero temporary buffers. */
+ explicit_memset(sk_exp, 0, sizeof sk_exp);
+ explicit_memset(q, 0, sizeof q);
+}
+
+static void
+aesbear_xts_dec(const struct aesdec *dec, const uint8_t in[static 16],
+ uint8_t out[static 16], size_t nbytes, uint8_t tweak[static 16],
+ uint32_t nrounds)
+{
+ uint32_t sk_exp[120];
+ uint32_t q[8];
+ uint32_t t0, t1, t2, t3, u0, u1, u2, u3;
+
+ 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, dec->aesd_aes.aes_rk);
+
+ /* Load tweak. */
+ t0 = le32dec(tweak + 4*0);
+ t1 = le32dec(tweak + 4*1);
+ t2 = le32dec(tweak + 4*2);
+ t3 = le32dec(tweak + 4*3);
+
+ /* Handle the first block separately if odd number. */
+ if (nbytes % 32) {
+ KASSERT(nbytes % 32 == 16);
+
+ /* Load up the first block and a garbage block. */
+ q[2*0] = le32dec(in + 4*0) ^ t0;
+ q[2*1] = le32dec(in + 4*1) ^ t1;
+ q[2*2] = le32dec(in + 4*2) ^ t2;
+ q[2*3] = le32dec(in + 4*3) ^ t3;
+ q[1] = q[3] = q[5] = q[7] = 0;
+
+ /* Decrypt two blocks. */
+ br_aes_ct_ortho(q);
+ br_aes_ct_bitslice_decrypt(nrounds, sk_exp, q);
+ br_aes_ct_ortho(q);
+
+ /* Store the first cipher block. */
+ le32enc(out + 4*0, q[2*0] ^ t0);
+ le32enc(out + 4*1, q[2*1] ^ t1);
+ le32enc(out + 4*2, q[2*2] ^ t2);
+ le32enc(out + 4*3, q[2*3] ^ t3);
+
+ /* Advance to the next block. */
+ aesbear_xts_update(&t0, &t1, &t2, &t3);
+ if ((nbytes -= 16) == 0)
+ goto out;
+ in += 16;
+ out += 16;
+ }
+
+ do {
+ KASSERT(nbytes >= 32);
+
+ /* Compute the upper tweak. */
+ u0 = t0; u1 = t1; u2 = t2; u3 = t3;
+ aesbear_xts_update(&u0, &u1, &u2, &u3);
+
+ /* Load lower and upper blocks. */
+ q[2*0] = le32dec(in + 4*0) ^ t0;
+ q[2*1] = le32dec(in + 4*1) ^ t1;
+ q[2*2] = le32dec(in + 4*2) ^ t2;
+ q[2*3] = le32dec(in + 4*3) ^ t3;
+ q[2*0 + 1] = le32dec(in + 16 + 4*0) ^ u0;
+ q[2*1 + 1] = le32dec(in + 16 + 4*1) ^ u1;
+ q[2*2 + 1] = le32dec(in + 16 + 4*2) ^ u2;
+ q[2*3 + 1] = le32dec(in + 16 + 4*3) ^ u3;
+
+ /* Encrypt two blocks. */
+ br_aes_ct_ortho(q);
+ br_aes_ct_bitslice_decrypt(nrounds, sk_exp, q);
+ br_aes_ct_ortho(q);
+
+ /* Store lower and upper blocks. */
+ le32enc(out + 4*0, q[2*0] ^ t0);
+ le32enc(out + 4*1, q[2*1] ^ t1);
+ le32enc(out + 4*2, q[2*2] ^ t2);
+ le32enc(out + 4*3, q[2*3] ^ t3);
+ le32enc(out + 16 + 4*0, q[2*0 + 1] ^ u0);
+ le32enc(out + 16 + 4*1, q[2*1 + 1] ^ u1);
+ le32enc(out + 16 + 4*2, q[2*2 + 1] ^ u2);
+ le32enc(out + 16 + 4*3, q[2*3 + 1] ^ u3);
+
+ /* Advance to the next pair of blocks. */
+ t0 = u0; t1 = u1; t2 = u2; t3 = u3;
+ aesbear_xts_update(&t0, &t1, &t2, &t3);
+ in += 32;
+ out += 32;
+ } while (nbytes -= 32, nbytes);
+
+out: /* Store the updated tweak. */
+ le32enc(tweak + 4*0, t0);
+ le32enc(tweak + 4*1, t1);
+ le32enc(tweak + 4*2, t2);
+ le32enc(tweak + 4*3, t3);
+
+ /* Paranoia: Zero temporary buffers. */
+ explicit_memset(sk_exp, 0, sizeof sk_exp);
+ explicit_memset(q, 0, sizeof q);
+}
+
+static int
+aesbear_probe(void)
+{
+
+ if (aesbear_xts_update_selftest())
+ return -1;
+
+ /* XXX test br_aes_ct_bitslice_decrypt */
+ /* XXX test br_aes_ct_bitslice_encrypt */
+ /* XXX test br_aes_ct_keysched */
+ /* XXX test br_aes_ct_ortho */
+ /* XXX test br_aes_ct_skey_expand */
+
+ return 0;
+}
+
+struct aes_impl aes_bear_impl = {
+ .ai_name = "BearSSL aes_ct",
+ .ai_probe = aesbear_probe,
+ .ai_setenckey = aesbear_setenckey,
+ .ai_setdeckey = aesbear_setdeckey,
+ .ai_enc = aesbear_enc,
+ .ai_dec = aesbear_dec,
+ .ai_cbc_enc = aesbear_cbc_enc,
+ .ai_cbc_dec = aesbear_cbc_dec,
+ .ai_xts_enc = aesbear_xts_enc,
+ .ai_xts_dec = aesbear_xts_dec,
+};
Index: src/sys/crypto/aes/aes_bear.h
diff -u /dev/null src/sys/crypto/aes/aes_bear.h:1.1
--- /dev/null Mon Jun 29 23:27:52 2020
+++ src/sys/crypto/aes/aes_bear.h Mon Jun 29 23:27:52 2020
@@ -0,0 +1,50 @@
+/* $NetBSD: aes_bear.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_BEAR_H
+#define _CRYPTO_AES_AES_BEAR_H
+
+#include <sys/types.h>
+#include <sys/endian.h>
+
+#include <crypto/aes/aes.h>
+
+#define br_dec32le le32dec
+#define br_enc32le le32enc
+
+void br_aes_ct_bitslice_Sbox(uint32_t *);
+void br_aes_ct_bitslice_invSbox(uint32_t *);
+void br_aes_ct_ortho(uint32_t *);
+u_int br_aes_ct_keysched(uint32_t *, const void *, size_t);
+void br_aes_ct_skey_expand(uint32_t *, unsigned, const uint32_t *);
+void br_aes_ct_bitslice_encrypt(unsigned, const uint32_t *, uint32_t *);
+void br_aes_ct_bitslice_decrypt(unsigned, const uint32_t *, uint32_t *);
+
+extern struct aes_impl aes_bear_impl;
+
+#endif /* _CRYPTO_AES_AES_BEAR_H */
Index: src/sys/crypto/aes/aes_ct.c
diff -u /dev/null src/sys/crypto/aes/aes_ct.c:1.1
--- /dev/null Mon Jun 29 23:27:52 2020
+++ src/sys/crypto/aes/aes_ct.c Mon Jun 29 23:27:52 2020
@@ -0,0 +1,335 @@
+/* $NetBSD: aes_ct.c,v 1.1 2020/06/29 23:27:52 riastradh Exp $ */
+
+/*
+ * Copyright (c) 2016 Thomas Pornin <[email protected]>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(1, "$NetBSD: aes_ct.c,v 1.1 2020/06/29 23:27:52 riastradh Exp $");
+
+#include <sys/types.h>
+
+#include <crypto/aes/aes_bear.h>
+
+/* see inner.h */
+void
+br_aes_ct_bitslice_Sbox(uint32_t *q)
+{
+ /*
+ * This S-box implementation is a straightforward translation of
+ * the circuit described by Boyar and Peralta in "A new
+ * combinational logic minimization technique with applications
+ * to cryptology" (https://eprint.iacr.org/2009/191.pdf).
+ *
+ * Note that variables x* (input) and s* (output) are numbered
+ * in "reverse" order (x0 is the high bit, x7 is the low bit).
+ */
+
+ uint32_t x0, x1, x2, x3, x4, x5, x6, x7;
+ uint32_t y1, y2, y3, y4, y5, y6, y7, y8, y9;
+ uint32_t y10, y11, y12, y13, y14, y15, y16, y17, y18, y19;
+ uint32_t y20, y21;
+ uint32_t z0, z1, z2, z3, z4, z5, z6, z7, z8, z9;
+ uint32_t z10, z11, z12, z13, z14, z15, z16, z17;
+ uint32_t t0, t1, t2, t3, t4, t5, t6, t7, t8, t9;
+ uint32_t t10, t11, t12, t13, t14, t15, t16, t17, t18, t19;
+ uint32_t t20, t21, t22, t23, t24, t25, t26, t27, t28, t29;
+ uint32_t t30, t31, t32, t33, t34, t35, t36, t37, t38, t39;
+ uint32_t t40, t41, t42, t43, t44, t45, t46, t47, t48, t49;
+ uint32_t t50, t51, t52, t53, t54, t55, t56, t57, t58, t59;
+ uint32_t t60, t61, t62, t63, t64, t65, t66, t67;
+ uint32_t s0, s1, s2, s3, s4, s5, s6, s7;
+
+ x0 = q[7];
+ x1 = q[6];
+ x2 = q[5];
+ x3 = q[4];
+ x4 = q[3];
+ x5 = q[2];
+ x6 = q[1];
+ x7 = q[0];
+
+ /*
+ * Top linear transformation.
+ */
+ y14 = x3 ^ x5;
+ y13 = x0 ^ x6;
+ y9 = x0 ^ x3;
+ y8 = x0 ^ x5;
+ t0 = x1 ^ x2;
+ y1 = t0 ^ x7;
+ y4 = y1 ^ x3;
+ y12 = y13 ^ y14;
+ y2 = y1 ^ x0;
+ y5 = y1 ^ x6;
+ y3 = y5 ^ y8;
+ t1 = x4 ^ y12;
+ y15 = t1 ^ x5;
+ y20 = t1 ^ x1;
+ y6 = y15 ^ x7;
+ y10 = y15 ^ t0;
+ y11 = y20 ^ y9;
+ y7 = x7 ^ y11;
+ y17 = y10 ^ y11;
+ y19 = y10 ^ y8;
+ y16 = t0 ^ y11;
+ y21 = y13 ^ y16;
+ y18 = x0 ^ y16;
+
+ /*
+ * Non-linear section.
+ */
+ t2 = y12 & y15;
+ t3 = y3 & y6;
+ t4 = t3 ^ t2;
+ t5 = y4 & x7;
+ t6 = t5 ^ t2;
+ t7 = y13 & y16;
+ t8 = y5 & y1;
+ t9 = t8 ^ t7;
+ t10 = y2 & y7;
+ t11 = t10 ^ t7;
+ t12 = y9 & y11;
+ t13 = y14 & y17;
+ t14 = t13 ^ t12;
+ t15 = y8 & y10;
+ t16 = t15 ^ t12;
+ t17 = t4 ^ t14;
+ t18 = t6 ^ t16;
+ t19 = t9 ^ t14;
+ t20 = t11 ^ t16;
+ t21 = t17 ^ y20;
+ t22 = t18 ^ y19;
+ t23 = t19 ^ y21;
+ t24 = t20 ^ y18;
+
+ t25 = t21 ^ t22;
+ t26 = t21 & t23;
+ t27 = t24 ^ t26;
+ t28 = t25 & t27;
+ t29 = t28 ^ t22;
+ t30 = t23 ^ t24;
+ t31 = t22 ^ t26;
+ t32 = t31 & t30;
+ t33 = t32 ^ t24;
+ t34 = t23 ^ t33;
+ t35 = t27 ^ t33;
+ t36 = t24 & t35;
+ t37 = t36 ^ t34;
+ t38 = t27 ^ t36;
+ t39 = t29 & t38;
+ t40 = t25 ^ t39;
+
+ t41 = t40 ^ t37;
+ t42 = t29 ^ t33;
+ t43 = t29 ^ t40;
+ t44 = t33 ^ t37;
+ t45 = t42 ^ t41;
+ z0 = t44 & y15;
+ z1 = t37 & y6;
+ z2 = t33 & x7;
+ z3 = t43 & y16;
+ z4 = t40 & y1;
+ z5 = t29 & y7;
+ z6 = t42 & y11;
+ z7 = t45 & y17;
+ z8 = t41 & y10;
+ z9 = t44 & y12;
+ z10 = t37 & y3;
+ z11 = t33 & y4;
+ z12 = t43 & y13;
+ z13 = t40 & y5;
+ z14 = t29 & y2;
+ z15 = t42 & y9;
+ z16 = t45 & y14;
+ z17 = t41 & y8;
+
+ /*
+ * Bottom linear transformation.
+ */
+ t46 = z15 ^ z16;
+ t47 = z10 ^ z11;
+ t48 = z5 ^ z13;
+ t49 = z9 ^ z10;
+ t50 = z2 ^ z12;
+ t51 = z2 ^ z5;
+ t52 = z7 ^ z8;
+ t53 = z0 ^ z3;
+ t54 = z6 ^ z7;
+ t55 = z16 ^ z17;
+ t56 = z12 ^ t48;
+ t57 = t50 ^ t53;
+ t58 = z4 ^ t46;
+ t59 = z3 ^ t54;
+ t60 = t46 ^ t57;
+ t61 = z14 ^ t57;
+ t62 = t52 ^ t58;
+ t63 = t49 ^ t58;
+ t64 = z4 ^ t59;
+ t65 = t61 ^ t62;
+ t66 = z1 ^ t63;
+ s0 = t59 ^ t63;
+ s6 = t56 ^ ~t62;
+ s7 = t48 ^ ~t60;
+ t67 = t64 ^ t65;
+ s3 = t53 ^ t66;
+ s4 = t51 ^ t66;
+ s5 = t47 ^ t65;
+ s1 = t64 ^ ~s3;
+ s2 = t55 ^ ~t67;
+
+ q[7] = s0;
+ q[6] = s1;
+ q[5] = s2;
+ q[4] = s3;
+ q[3] = s4;
+ q[2] = s5;
+ q[1] = s6;
+ q[0] = s7;
+}
+
+/* see inner.h */
+void
+br_aes_ct_ortho(uint32_t *q)
+{
+#define SWAPN(cl, ch, s, x, y) do { \
+ uint32_t a, b; \
+ a = (x); \
+ b = (y); \
+ (x) = (a & (uint32_t)cl) | ((b & (uint32_t)cl) << (s)); \
+ (y) = ((a & (uint32_t)ch) >> (s)) | (b & (uint32_t)ch); \
+ } while (0)
+
+#define SWAP2(x, y) SWAPN(0x55555555, 0xAAAAAAAA, 1, x, y)
+#define SWAP4(x, y) SWAPN(0x33333333, 0xCCCCCCCC, 2, x, y)
+#define SWAP8(x, y) SWAPN(0x0F0F0F0F, 0xF0F0F0F0, 4, x, y)
+
+ SWAP2(q[0], q[1]);
+ SWAP2(q[2], q[3]);
+ SWAP2(q[4], q[5]);
+ SWAP2(q[6], q[7]);
+
+ SWAP4(q[0], q[2]);
+ SWAP4(q[1], q[3]);
+ SWAP4(q[4], q[6]);
+ SWAP4(q[5], q[7]);
+
+ SWAP8(q[0], q[4]);
+ SWAP8(q[1], q[5]);
+ SWAP8(q[2], q[6]);
+ SWAP8(q[3], q[7]);
+}
+
+static const unsigned char Rcon[] = {
+ 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1B, 0x36
+};
+
+static uint32_t
+sub_word(uint32_t x)
+{
+ uint32_t q[8];
+ int i;
+
+ for (i = 0; i < 8; i ++) {
+ q[i] = x;
+ }
+ br_aes_ct_ortho(q);
+ br_aes_ct_bitslice_Sbox(q);
+ br_aes_ct_ortho(q);
+ return q[0];
+}
+
+/* see inner.h */
+unsigned
+br_aes_ct_keysched(uint32_t *comp_skey, const void *key, size_t key_len)
+{
+ unsigned num_rounds;
+ int i, j, k, nk, nkf;
+ uint32_t tmp;
+ uint32_t skey[120];
+
+ switch (key_len) {
+ case 16:
+ num_rounds = 10;
+ break;
+ case 24:
+ num_rounds = 12;
+ break;
+ case 32:
+ num_rounds = 14;
+ break;
+ default:
+ /* abort(); */
+ return 0;
+ }
+ nk = (int)(key_len >> 2);
+ nkf = (int)((num_rounds + 1) << 2);
+ tmp = 0;
+ for (i = 0; i < nk; i ++) {
+ tmp = br_dec32le((const unsigned char *)key + (i << 2));
+ skey[(i << 1) + 0] = tmp;
+ skey[(i << 1) + 1] = tmp;
+ }
+ for (i = nk, j = 0, k = 0; i < nkf; i ++) {
+ if (j == 0) {
+ tmp = (tmp << 24) | (tmp >> 8);
+ tmp = sub_word(tmp) ^ Rcon[k];
+ } else if (nk > 6 && j == 4) {
+ tmp = sub_word(tmp);
+ }
+ tmp ^= skey[(i - nk) << 1];
+ skey[(i << 1) + 0] = tmp;
+ skey[(i << 1) + 1] = tmp;
+ if (++ j == nk) {
+ j = 0;
+ k ++;
+ }
+ }
+ for (i = 0; i < nkf; i += 4) {
+ br_aes_ct_ortho(skey + (i << 1));
+ }
+ for (i = 0, j = 0; i < nkf; i ++, j += 2) {
+ comp_skey[i] = (skey[j + 0] & 0x55555555)
+ | (skey[j + 1] & 0xAAAAAAAA);
+ }
+ return num_rounds;
+}
+
+/* see inner.h */
+void
+br_aes_ct_skey_expand(uint32_t *skey,
+ unsigned num_rounds, const uint32_t *comp_skey)
+{
+ unsigned u, v, n;
+
+ n = (num_rounds + 1) << 2;
+ for (u = 0, v = 0; u < n; u ++, v += 2) {
+ uint32_t x, y;
+
+ x = y = comp_skey[u];
+ x &= 0x55555555;
+ skey[v + 0] = x | (x << 1);
+ y &= 0xAAAAAAAA;
+ skey[v + 1] = y | (y >> 1);
+ }
+}
Index: src/sys/crypto/aes/aes_ct_dec.c
diff -u /dev/null src/sys/crypto/aes/aes_ct_dec.c:1.1
--- /dev/null Mon Jun 29 23:27:52 2020
+++ src/sys/crypto/aes/aes_ct_dec.c Mon Jun 29 23:27:52 2020
@@ -0,0 +1,177 @@
+/* $NetBSD: aes_ct_dec.c,v 1.1 2020/06/29 23:27:52 riastradh Exp $ */
+
+/*
+ * Copyright (c) 2016 Thomas Pornin <[email protected]>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(1, "$NetBSD: aes_ct_dec.c,v 1.1 2020/06/29 23:27:52 riastradh Exp $");
+
+#include <sys/types.h>
+
+#include <crypto/aes/aes_bear.h>
+
+/* see inner.h */
+void
+br_aes_ct_bitslice_invSbox(uint32_t *q)
+{
+ /*
+ * AES S-box is:
+ * S(x) = A(I(x)) ^ 0x63
+ * where I() is inversion in GF(256), and A() is a linear
+ * transform (0 is formally defined to be its own inverse).
+ * Since inversion is an involution, the inverse S-box can be
+ * computed from the S-box as:
+ * iS(x) = B(S(B(x ^ 0x63)) ^ 0x63)
+ * where B() is the inverse of A(). Indeed, for any y in GF(256):
+ * iS(S(y)) = B(A(I(B(A(I(y)) ^ 0x63 ^ 0x63))) ^ 0x63 ^ 0x63) = y
+ *
+ * Note: we reuse the implementation of the forward S-box,
+ * instead of duplicating it here, so that total code size is
+ * lower. By merging the B() transforms into the S-box circuit
+ * we could make faster CBC decryption, but CBC decryption is
+ * already quite faster than CBC encryption because we can
+ * process two blocks in parallel.
+ */
+ uint32_t q0, q1, q2, q3, q4, q5, q6, q7;
+
+ q0 = ~q[0];
+ q1 = ~q[1];
+ q2 = q[2];
+ q3 = q[3];
+ q4 = q[4];
+ q5 = ~q[5];
+ q6 = ~q[6];
+ q7 = q[7];
+ q[7] = q1 ^ q4 ^ q6;
+ q[6] = q0 ^ q3 ^ q5;
+ q[5] = q7 ^ q2 ^ q4;
+ q[4] = q6 ^ q1 ^ q3;
+ q[3] = q5 ^ q0 ^ q2;
+ q[2] = q4 ^ q7 ^ q1;
+ q[1] = q3 ^ q6 ^ q0;
+ q[0] = q2 ^ q5 ^ q7;
+
+ br_aes_ct_bitslice_Sbox(q);
+
+ q0 = ~q[0];
+ q1 = ~q[1];
+ q2 = q[2];
+ q3 = q[3];
+ q4 = q[4];
+ q5 = ~q[5];
+ q6 = ~q[6];
+ q7 = q[7];
+ q[7] = q1 ^ q4 ^ q6;
+ q[6] = q0 ^ q3 ^ q5;
+ q[5] = q7 ^ q2 ^ q4;
+ q[4] = q6 ^ q1 ^ q3;
+ q[3] = q5 ^ q0 ^ q2;
+ q[2] = q4 ^ q7 ^ q1;
+ q[1] = q3 ^ q6 ^ q0;
+ q[0] = q2 ^ q5 ^ q7;
+}
+
+static void
+add_round_key(uint32_t *q, const uint32_t *sk)
+{
+ int i;
+
+ for (i = 0; i < 8; i ++) {
+ q[i] ^= sk[i];
+ }
+}
+
+static void
+inv_shift_rows(uint32_t *q)
+{
+ int i;
+
+ for (i = 0; i < 8; i ++) {
+ uint32_t x;
+
+ x = q[i];
+ q[i] = (x & 0x000000FF)
+ | ((x & 0x00003F00) << 2) | ((x & 0x0000C000) >> 6)
+ | ((x & 0x000F0000) << 4) | ((x & 0x00F00000) >> 4)
+ | ((x & 0x03000000) << 6) | ((x & 0xFC000000) >> 2);
+ }
+}
+
+static inline uint32_t
+rotr16(uint32_t x)
+{
+ return (x << 16) | (x >> 16);
+}
+
+static void
+inv_mix_columns(uint32_t *q)
+{
+ uint32_t q0, q1, q2, q3, q4, q5, q6, q7;
+ uint32_t r0, r1, r2, r3, r4, r5, r6, r7;
+
+ q0 = q[0];
+ q1 = q[1];
+ q2 = q[2];
+ q3 = q[3];
+ q4 = q[4];
+ q5 = q[5];
+ q6 = q[6];
+ q7 = q[7];
+ r0 = (q0 >> 8) | (q0 << 24);
+ r1 = (q1 >> 8) | (q1 << 24);
+ r2 = (q2 >> 8) | (q2 << 24);
+ r3 = (q3 >> 8) | (q3 << 24);
+ r4 = (q4 >> 8) | (q4 << 24);
+ r5 = (q5 >> 8) | (q5 << 24);
+ r6 = (q6 >> 8) | (q6 << 24);
+ r7 = (q7 >> 8) | (q7 << 24);
+
+ q[0] = q5 ^ q6 ^ q7 ^ r0 ^ r5 ^ r7 ^ rotr16(q0 ^ q5 ^ q6 ^ r0 ^ r5);
+ q[1] = q0 ^ q5 ^ r0 ^ r1 ^ r5 ^ r6 ^ r7 ^ rotr16(q1 ^ q5 ^ q7 ^ r1 ^ r5 ^ r6);
+ q[2] = q0 ^ q1 ^ q6 ^ r1 ^ r2 ^ r6 ^ r7 ^ rotr16(q0 ^ q2 ^ q6 ^ r2 ^ r6 ^ r7);
+ q[3] = q0 ^ q1 ^ q2 ^ q5 ^ q6 ^ r0 ^ r2 ^ r3 ^ r5 ^ rotr16(q0 ^ q1 ^ q3 ^ q5 ^ q6 ^ q7 ^ r0 ^ r3 ^ r5 ^ r7);
+ q[4] = q1 ^ q2 ^ q3 ^ q5 ^ r1 ^ r3 ^ r4 ^ r5 ^ r6 ^ r7 ^ rotr16(q1 ^ q2 ^ q4 ^ q5 ^ q7 ^ r1 ^ r4 ^ r5 ^ r6);
+ q[5] = q2 ^ q3 ^ q4 ^ q6 ^ r2 ^ r4 ^ r5 ^ r6 ^ r7 ^ rotr16(q2 ^ q3 ^ q5 ^ q6 ^ r2 ^ r5 ^ r6 ^ r7);
+ q[6] = q3 ^ q4 ^ q5 ^ q7 ^ r3 ^ r5 ^ r6 ^ r7 ^ rotr16(q3 ^ q4 ^ q6 ^ q7 ^ r3 ^ r6 ^ r7);
+ q[7] = q4 ^ q5 ^ q6 ^ r4 ^ r6 ^ r7 ^ rotr16(q4 ^ q5 ^ q7 ^ r4 ^ r7);
+}
+
+/* see inner.h */
+void
+br_aes_ct_bitslice_decrypt(unsigned num_rounds,
+ const uint32_t *skey, uint32_t *q)
+{
+ unsigned u;
+
+ add_round_key(q, skey + (num_rounds << 3));
+ for (u = num_rounds - 1; u > 0; u --) {
+ inv_shift_rows(q);
+ br_aes_ct_bitslice_invSbox(q);
+ add_round_key(q, skey + (u << 3));
+ inv_mix_columns(q);
+ }
+ inv_shift_rows(q);
+ br_aes_ct_bitslice_invSbox(q);
+ add_round_key(q, skey);
+}
Index: src/sys/crypto/aes/aes_ct_enc.c
diff -u /dev/null src/sys/crypto/aes/aes_ct_enc.c:1.1
--- /dev/null Mon Jun 29 23:27:52 2020
+++ src/sys/crypto/aes/aes_ct_enc.c Mon Jun 29 23:27:52 2020
@@ -0,0 +1,119 @@
+/* $NetBSD: aes_ct_enc.c,v 1.1 2020/06/29 23:27:52 riastradh Exp $ */
+
+/*
+ * Copyright (c) 2016 Thomas Pornin <[email protected]>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(1, "$NetBSD: aes_ct_enc.c,v 1.1 2020/06/29 23:27:52 riastradh Exp $");
+
+#include <sys/types.h>
+
+#include <crypto/aes/aes_bear.h>
+
+static inline void
+add_round_key(uint32_t *q, const uint32_t *sk)
+{
+ q[0] ^= sk[0];
+ q[1] ^= sk[1];
+ q[2] ^= sk[2];
+ q[3] ^= sk[3];
+ q[4] ^= sk[4];
+ q[5] ^= sk[5];
+ q[6] ^= sk[6];
+ q[7] ^= sk[7];
+}
+
+static inline void
+shift_rows(uint32_t *q)
+{
+ int i;
+
+ for (i = 0; i < 8; i ++) {
+ uint32_t x;
+
+ x = q[i];
+ q[i] = (x & 0x000000FF)
+ | ((x & 0x0000FC00) >> 2) | ((x & 0x00000300) << 6)
+ | ((x & 0x00F00000) >> 4) | ((x & 0x000F0000) << 4)
+ | ((x & 0xC0000000) >> 6) | ((x & 0x3F000000) << 2);
+ }
+}
+
+static inline uint32_t
+rotr16(uint32_t x)
+{
+ return (x << 16) | (x >> 16);
+}
+
+static inline void
+mix_columns(uint32_t *q)
+{
+ uint32_t q0, q1, q2, q3, q4, q5, q6, q7;
+ uint32_t r0, r1, r2, r3, r4, r5, r6, r7;
+
+ q0 = q[0];
+ q1 = q[1];
+ q2 = q[2];
+ q3 = q[3];
+ q4 = q[4];
+ q5 = q[5];
+ q6 = q[6];
+ q7 = q[7];
+ r0 = (q0 >> 8) | (q0 << 24);
+ r1 = (q1 >> 8) | (q1 << 24);
+ r2 = (q2 >> 8) | (q2 << 24);
+ r3 = (q3 >> 8) | (q3 << 24);
+ r4 = (q4 >> 8) | (q4 << 24);
+ r5 = (q5 >> 8) | (q5 << 24);
+ r6 = (q6 >> 8) | (q6 << 24);
+ r7 = (q7 >> 8) | (q7 << 24);
+
+ q[0] = q7 ^ r7 ^ r0 ^ rotr16(q0 ^ r0);
+ q[1] = q0 ^ r0 ^ q7 ^ r7 ^ r1 ^ rotr16(q1 ^ r1);
+ q[2] = q1 ^ r1 ^ r2 ^ rotr16(q2 ^ r2);
+ q[3] = q2 ^ r2 ^ q7 ^ r7 ^ r3 ^ rotr16(q3 ^ r3);
+ q[4] = q3 ^ r3 ^ q7 ^ r7 ^ r4 ^ rotr16(q4 ^ r4);
+ q[5] = q4 ^ r4 ^ r5 ^ rotr16(q5 ^ r5);
+ q[6] = q5 ^ r5 ^ r6 ^ rotr16(q6 ^ r6);
+ q[7] = q6 ^ r6 ^ r7 ^ rotr16(q7 ^ r7);
+}
+
+/* see inner.h */
+void
+br_aes_ct_bitslice_encrypt(unsigned num_rounds,
+ const uint32_t *skey, uint32_t *q)
+{
+ unsigned u;
+
+ add_round_key(q, skey);
+ for (u = 1; u < num_rounds; u ++) {
+ br_aes_ct_bitslice_Sbox(q);
+ shift_rows(q);
+ mix_columns(q);
+ add_round_key(q, skey + (u << 3));
+ }
+ br_aes_ct_bitslice_Sbox(q);
+ shift_rows(q);
+ add_round_key(q, skey + (num_rounds << 3));
+}
Index: src/sys/crypto/aes/aes_impl.c
diff -u /dev/null src/sys/crypto/aes/aes_impl.c:1.1
--- /dev/null Mon Jun 29 23:27:52 2020
+++ src/sys/crypto/aes/aes_impl.c Mon Jun 29 23:27:52 2020
@@ -0,0 +1,256 @@
+/* $NetBSD: aes_impl.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_impl.c,v 1.1 2020/06/29 23:27:52 riastradh Exp $");
+
+#include <sys/types.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/once.h>
+#include <sys/systm.h>
+
+#include <crypto/aes/aes.h>
+#include <crypto/aes/aes_bear.h> /* default implementation */
+
+static const struct aes_impl *aes_md_impl __read_mostly;
+static const struct aes_impl *aes_impl __read_mostly;
+
+/*
+ * The timing of AES implementation selection is finicky:
+ *
+ * 1. It has to be done _after_ cpu_attach for implementations,
+ * such as AES-NI, that rely on fpu initialization done by
+ * fpu_attach.
+ *
+ * 2. It has to be done _before_ the cgd self-tests or anything
+ * else that might call AES.
+ *
+ * For the moment, doing it in module init works. However, if a
+ * driver-class module depended on the aes module, that would break.
+ */
+
+static int
+aes_select(void)
+{
+
+ KASSERT(aes_impl == NULL);
+
+ if (aes_md_impl) {
+ if (aes_selftest(aes_md_impl))
+ aprint_error("aes: self-test failed: %s\n",
+ aes_md_impl->ai_name);
+ else
+ aes_impl = aes_md_impl;
+ }
+ if (aes_impl == NULL) {
+ if (aes_selftest(&aes_bear_impl))
+ aprint_error("aes: self-test failed: %s\n",
+ aes_bear_impl.ai_name);
+ else
+ aes_impl = &aes_bear_impl;
+ }
+ if (aes_impl == NULL)
+ panic("AES self-tests failed");
+
+ aprint_normal("aes: %s\n", aes_impl->ai_name);
+ return 0;
+}
+
+MODULE(MODULE_CLASS_MISC, aes, NULL);
+
+static int
+aes_modcmd(modcmd_t cmd, void *opaque)
+{
+
+ switch (cmd) {
+ case MODULE_CMD_INIT:
+ return aes_select();
+ case MODULE_CMD_FINI:
+ return 0;
+ default:
+ return ENOTTY;
+ }
+}
+
+static void
+aes_guarantee_selected(void)
+{
+#if 0
+ static once_t once;
+ int error;
+
+ error = RUN_ONCE(&once, aes_select);
+ KASSERT(error == 0);
+#endif
+}
+
+void
+aes_md_init(const struct aes_impl *impl)
+{
+
+ KASSERT(cold);
+ KASSERTMSG(aes_impl == NULL,
+ "AES implementation `%s' already chosen, can't offer `%s'",
+ aes_impl->ai_name, impl->ai_name);
+ KASSERTMSG(aes_md_impl == NULL,
+ "AES implementation `%s' already offered, can't offer `%s'",
+ aes_md_impl->ai_name, impl->ai_name);
+
+ aes_md_impl = impl;
+}
+
+static void
+aes_setenckey(struct aesenc *enc, const uint8_t key[static 16],
+ uint32_t nrounds)
+{
+
+ aes_guarantee_selected();
+ aes_impl->ai_setenckey(enc, key, nrounds);
+}
+
+uint32_t
+aes_setenckey128(struct aesenc *enc, const uint8_t key[static 16])
+{
+ uint32_t nrounds = AES_128_NROUNDS;
+
+ aes_setenckey(enc, key, nrounds);
+ return nrounds;
+}
+
+uint32_t
+aes_setenckey192(struct aesenc *enc, const uint8_t key[static 24])
+{
+ uint32_t nrounds = AES_192_NROUNDS;
+
+ aes_setenckey(enc, key, nrounds);
+ return nrounds;
+}
+
+uint32_t
+aes_setenckey256(struct aesenc *enc, const uint8_t key[static 32])
+{
+ uint32_t nrounds = AES_256_NROUNDS;
+
+ aes_setenckey(enc, key, nrounds);
+ return nrounds;
+}
+
+static void
+aes_setdeckey(struct aesdec *dec, const uint8_t key[static 16],
+ uint32_t nrounds)
+{
+
+ aes_guarantee_selected();
+ aes_impl->ai_setdeckey(dec, key, nrounds);
+}
+
+uint32_t
+aes_setdeckey128(struct aesdec *dec, const uint8_t key[static 16])
+{
+ uint32_t nrounds = AES_128_NROUNDS;
+
+ aes_setdeckey(dec, key, nrounds);
+ return nrounds;
+}
+
+uint32_t
+aes_setdeckey192(struct aesdec *dec, const uint8_t key[static 24])
+{
+ uint32_t nrounds = AES_192_NROUNDS;
+
+ aes_setdeckey(dec, key, nrounds);
+ return nrounds;
+}
+
+uint32_t
+aes_setdeckey256(struct aesdec *dec, const uint8_t key[static 32])
+{
+ uint32_t nrounds = AES_256_NROUNDS;
+
+ aes_setdeckey(dec, key, nrounds);
+ return nrounds;
+}
+
+void
+aes_enc(const struct aesenc *enc, const uint8_t in[static 16],
+ uint8_t out[static 16], uint32_t nrounds)
+{
+
+ aes_guarantee_selected();
+ aes_impl->ai_enc(enc, in, out, nrounds);
+}
+
+void
+aes_dec(const struct aesdec *dec, const uint8_t in[static 16],
+ uint8_t out[static 16], uint32_t nrounds)
+{
+
+ aes_guarantee_selected();
+ aes_impl->ai_dec(dec, in, out, nrounds);
+}
+
+void
+aes_cbc_enc(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)
+{
+
+ aes_guarantee_selected();
+ aes_impl->ai_cbc_enc(enc, in, out, nbytes, iv, nrounds);
+}
+
+void
+aes_cbc_dec(struct aesdec *dec, const uint8_t in[static 16],
+ uint8_t out[static 16], size_t nbytes, uint8_t iv[static 16],
+ uint32_t nrounds)
+{
+
+ aes_guarantee_selected();
+ aes_impl->ai_cbc_dec(dec, in, out, nbytes, iv, nrounds);
+}
+
+void
+aes_xts_enc(struct aesenc *enc, const uint8_t in[static 16],
+ uint8_t out[static 16], size_t nbytes, uint8_t tweak[static 16],
+ uint32_t nrounds)
+{
+
+ aes_guarantee_selected();
+ aes_impl->ai_xts_enc(enc, in, out, nbytes, tweak, nrounds);
+}
+
+void
+aes_xts_dec(struct aesdec *dec, const uint8_t in[static 16],
+ uint8_t out[static 16], size_t nbytes, uint8_t tweak[static 16],
+ uint32_t nrounds)
+{
+
+ aes_guarantee_selected();
+ aes_impl->ai_xts_dec(dec, in, out, nbytes, tweak, nrounds);
+}
Index: src/sys/crypto/aes/aes_rijndael.c
diff -u /dev/null src/sys/crypto/aes/aes_rijndael.c:1.1
--- /dev/null Mon Jun 29 23:27:52 2020
+++ src/sys/crypto/aes/aes_rijndael.c Mon Jun 29 23:27:52 2020
@@ -0,0 +1,306 @@
+/* $NetBSD: aes_rijndael.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.
+ */
+
+/*
+ * Legacy `Rijndael' API
+ *
+ * rijndael_set_key
+ * rijndael_encrypt
+ * rijndael_decrypt
+ *
+ * rijndaelKeySetupEnc
+ * rijndaelKeySetupDec
+ * rijndaelEncrypt
+ * rijndaelDecrypt
+ * rijndael_makeKey
+ * rijndael_cipherInit
+ * rijndael_blockEncrypt
+ * rijndael_blockDecrypt
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(1, "$NetBSD: aes_rijndael.c,v 1.1 2020/06/29 23:27:52 riastradh Exp $");
+
+#include <sys/types.h>
+#include <sys/systm.h>
+
+#include <crypto/aes/aes.h>
+#include <crypto/rijndael/rijndael.h>
+#include <crypto/rijndael/rijndael-alg-fst.h>
+#include <crypto/rijndael/rijndael-api-fst.h>
+
+void
+rijndael_set_key(rijndael_ctx *ctx, const uint8_t *key, int keybits)
+{
+
+ ctx->Nr = rijndaelKeySetupEnc(ctx->ek, key, keybits);
+ rijndaelKeySetupDec(ctx->dk, key, keybits);
+}
+
+void
+rijndael_encrypt(const rijndael_ctx *ctx, const uint8_t *in, uint8_t *out)
+{
+
+ rijndaelEncrypt(ctx->ek, ctx->Nr, in, out);
+}
+
+void
+rijndael_decrypt(const rijndael_ctx *ctx, const u_char *in, uint8_t *out)
+{
+
+ rijndaelDecrypt(ctx->dk, ctx->Nr, in, out);
+}
+
+int
+rijndaelKeySetupEnc(uint32_t *rk, const uint8_t *key, int keybits)
+{
+ struct aesenc enc;
+ unsigned nrounds;
+
+ switch (keybits) {
+ case 128:
+ nrounds = aes_setenckey128(&enc, key);
+ break;
+ case 192:
+ nrounds = aes_setenckey192(&enc, key);
+ break;
+ case 256:
+ nrounds = aes_setenckey256(&enc, key);
+ break;
+ default:
+ panic("invalid AES key bits: %d", keybits);
+ }
+
+ memcpy(rk, enc.aese_aes.aes_rk, 4*(nrounds + 1)*sizeof(rk[0]));
+ explicit_memset(&enc, 0, sizeof enc);
+
+ return nrounds;
+}
+
+int
+rijndaelKeySetupDec(uint32_t *rk, const uint8_t *key, int keybits)
+{
+ struct aesdec dec;
+ unsigned nrounds;
+
+ switch (keybits) {
+ case 128:
+ nrounds = aes_setdeckey128(&dec, key);
+ break;
+ case 192:
+ nrounds = aes_setdeckey192(&dec, key);
+ break;
+ case 256:
+ nrounds = aes_setdeckey256(&dec, key);
+ break;
+ default:
+ panic("invalid AES key bits: %d", keybits);
+ }
+
+ memcpy(rk, dec.aesd_aes.aes_rk, 4*(nrounds + 1)*sizeof(rk[0]));
+ explicit_memset(&dec, 0, sizeof dec);
+
+ return nrounds;
+}
+
+void
+rijndaelEncrypt(const uint32_t *rk, int nrounds, const uint8_t in[16],
+ uint8_t out[16])
+{
+ struct aesenc enc;
+
+ memcpy(enc.aese_aes.aes_rk, rk, 4*(nrounds + 1)*sizeof(rk[0]));
+ aes_enc(&enc, in, out, nrounds);
+ explicit_memset(&enc, 0, sizeof enc);
+}
+
+void
+rijndaelDecrypt(const uint32_t *rk, int nrounds, const uint8_t in[16],
+ uint8_t out[16])
+{
+ struct aesdec dec;
+
+ memcpy(dec.aesd_aes.aes_rk, rk, 4*(nrounds + 1)*sizeof(rk[0]));
+ aes_dec(&dec, in, out, nrounds);
+ explicit_memset(&dec, 0, sizeof dec);
+}
+
+int
+rijndael_makeKey(keyInstance *key, BYTE direction, int keybits,
+ const char *keyp)
+{
+
+ if (key == NULL)
+ return BAD_KEY_INSTANCE;
+
+ memset(key, 0x1a, sizeof(*key));
+
+ switch (direction) {
+ case DIR_ENCRYPT:
+ case DIR_DECRYPT:
+ key->direction = direction;
+ break;
+ default:
+ return BAD_KEY_DIR;
+ }
+
+ switch (keybits) {
+ case 128:
+ case 192:
+ case 256:
+ key->keyLen = keybits;
+ break;
+ default:
+ return BAD_KEY_MAT;
+ }
+
+ if (keyp)
+ memcpy(key->keyMaterial, keyp, keybits/8);
+
+ switch (direction) {
+ case DIR_ENCRYPT:
+ key->Nr = rijndaelKeySetupEnc(key->rk,
+ (const uint8_t *)key->keyMaterial, keybits);
+ break;
+ case DIR_DECRYPT:
+ key->Nr = rijndaelKeySetupDec(key->rk,
+ (const uint8_t *)key->keyMaterial, keybits);
+ break;
+ default:
+ panic("unknown encryption direction %d", direction);
+ }
+ rijndaelKeySetupEnc(key->ek, (const uint8_t *)key->keyMaterial,
+ keybits);
+
+ return 1;
+}
+
+int
+rijndael_cipherInit(cipherInstance *cipher, BYTE mode, const char *iv)
+{
+
+ switch (mode) {
+ case MODE_ECB: /* used only for encrypting one block */
+ case MODE_CBC:
+ case MODE_XTS:
+ cipher->mode = mode;
+ break;
+ case MODE_CFB1: /* unused */
+ default:
+ return BAD_CIPHER_MODE;
+ }
+
+ if (iv)
+ memcpy(cipher->IV, iv, RIJNDAEL_MAX_IV_SIZE);
+ else
+ memset(cipher->IV, 0, RIJNDAEL_MAX_IV_SIZE);
+
+ return 1;
+}
+
+int
+rijndael_blockEncrypt(cipherInstance *cipher, keyInstance *key,
+ const BYTE *in, int nbits, BYTE *out)
+{
+ struct aesenc enc;
+
+ if (cipher == NULL)
+ return BAD_CIPHER_STATE;
+ if (key == NULL)
+ return BAD_CIPHER_STATE;
+ if (key->direction != DIR_ENCRYPT)
+ return BAD_CIPHER_STATE;
+
+ if (in == NULL || nbits <= 0)
+ return 0;
+
+ memcpy(enc.aese_aes.aes_rk, key->rk,
+ 4*(key->Nr + 1)*sizeof(key->rk[0]));
+ switch (cipher->mode) {
+ case MODE_ECB:
+ KASSERT(nbits == 128);
+ aes_enc(&enc, in, out, key->Nr);
+ break;
+ case MODE_CBC:
+ KASSERT(nbits % 128 == 0);
+ aes_cbc_enc(&enc, in, out, nbits/8, (uint8_t *)cipher->IV,
+ key->Nr);
+ break;
+ case MODE_XTS:
+ KASSERT(nbits % 128 == 0);
+ aes_xts_enc(&enc, in, out, nbits/8, (uint8_t *)cipher->IV,
+ key->Nr);
+ break;
+ default:
+ panic("invalid AES mode: %d", cipher->mode);
+ }
+ explicit_memset(&enc, 0, sizeof enc);
+
+ return nbits;
+}
+
+int
+rijndael_blockDecrypt(cipherInstance *cipher, keyInstance *key,
+ const BYTE *in, int nbits, BYTE *out)
+{
+ struct aesdec dec;
+
+ if (cipher == NULL)
+ return BAD_CIPHER_STATE;
+ if (key == NULL)
+ return BAD_CIPHER_STATE;
+ if (key->direction != DIR_DECRYPT)
+ return BAD_CIPHER_STATE;
+
+ if (in == NULL || nbits <= 0)
+ return 0;
+
+ memcpy(dec.aesd_aes.aes_rk, key->rk,
+ 4*(key->Nr + 1)*sizeof(key->rk[0]));
+ switch (cipher->mode) {
+ case MODE_ECB:
+ KASSERT(nbits == 128);
+ aes_dec(&dec, in, out, key->Nr);
+ break;
+ case MODE_CBC:
+ KASSERT(nbits % 128 == 0);
+ aes_cbc_dec(&dec, in, out, nbits/8, (uint8_t *)cipher->IV,
+ key->Nr);
+ break;
+ case MODE_XTS:
+ KASSERT(nbits % 128 == 0);
+ aes_xts_dec(&dec, in, out, nbits/8, (uint8_t *)cipher->IV,
+ key->Nr);
+ break;
+ default:
+ panic("invalid AES mode: %d", cipher->mode);
+ }
+ explicit_memset(&dec, 0, sizeof dec);
+
+ return nbits;
+}
Index: src/sys/crypto/aes/aes_selftest.c
diff -u /dev/null src/sys/crypto/aes/aes_selftest.c:1.1
--- /dev/null Mon Jun 29 23:27:52 2020
+++ src/sys/crypto/aes/aes_selftest.c Mon Jun 29 23:27:52 2020
@@ -0,0 +1,387 @@
+/* $NetBSD: aes_selftest.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_selftest.c,v 1.1 2020/06/29 23:27:52 riastradh Exp $");
+
+#include <sys/types.h>
+#include <sys/systm.h>
+
+#include <lib/libkern/libkern.h>
+
+#include <crypto/aes/aes.h>
+
+static const unsigned aes_keybytes[] __unused = { 16, 24, 32 };
+static const unsigned aes_keybits[] __unused = { 128, 192, 256 };
+static const unsigned aes_nrounds[] = { 10, 12, 14 };
+
+#define aes_selftest_fail(impl, actual, expected, nbytes, fmt, args...) \
+({ \
+ printf("%s "fmt": self-test failed\n", (impl)->ai_name, ##args); \
+ hexdump(printf, "was", (actual), (nbytes)); \
+ hexdump(printf, "expected", (expected), (nbytes)); \
+ -1; \
+})
+
+static int
+aes_selftest_encdec(const struct aes_impl *impl)
+{
+ /*
+ * head -c 16 < /dev/zero | openssl enc -aes-{128,192,256}-ecb
+ * -nopad -K 000102030405060708090a0b0c0d... | hexdump -C
+ */
+ static const uint8_t expected[3][16] = {
+ [0] = {
+ 0xc6,0xa1,0x3b,0x37,0x87,0x8f,0x5b,0x82,
+ 0x6f,0x4f,0x81,0x62,0xa1,0xc8,0xd8,0x79,
+ },
+ [1] = {
+ 0x91,0x62,0x51,0x82,0x1c,0x73,0xa5,0x22,
+ 0xc3,0x96,0xd6,0x27,0x38,0x01,0x96,0x07,
+ },
+ [2] = {
+ 0xf2,0x90,0x00,0xb6,0x2a,0x49,0x9f,0xd0,
+ 0xa9,0xf3,0x9a,0x6a,0xdd,0x2e,0x77,0x80,
+ },
+ };
+ struct aesenc enc;
+ struct aesdec dec;
+ uint8_t key[32];
+ uint8_t in[16];
+ uint8_t outbuf[18] = { [0] = 0x1a, [17] = 0x1a }, *out = outbuf + 1;
+ unsigned i;
+
+ for (i = 0; i < 32; i++)
+ key[i] = i;
+ for (i = 0; i < 16; i++)
+ in[i] = 0;
+
+ for (i = 0; i < 3; i++) {
+ impl->ai_setenckey(&enc, key, aes_nrounds[i]);
+ impl->ai_setdeckey(&dec, key, aes_nrounds[i]);
+ impl->ai_enc(&enc, in, out, aes_nrounds[i]);
+ if (memcmp(out, expected[i], 16))
+ return aes_selftest_fail(impl, out, expected[i], 16,
+ "AES-%u enc", aes_keybits[i]);
+ impl->ai_dec(&dec, out, out, aes_nrounds[i]);
+ if (memcmp(out, in, 16))
+ return aes_selftest_fail(impl, out, in, 16,
+ "AES-%u dec", aes_keybits[i]);
+ }
+
+ if (outbuf[0] != 0x1a)
+ return aes_selftest_fail(impl, outbuf,
+ (const uint8_t[1]){0x1a}, 1,
+ "AES overrun preceding");
+ if (outbuf[17] != 0x1a)
+ return aes_selftest_fail(impl, outbuf + 17,
+ (const uint8_t[1]){0x1a}, 1,
+ "AES overrun folllowing");
+
+ /* Success! */
+ return 0;
+}
+
+static int
+aes_selftest_encdec_cbc(const struct aes_impl *impl)
+{
+ static const uint8_t expected[3][144] = {
+ [0] = {
+ 0xfe,0xf1,0xa8,0xb6,0x25,0xf0,0xc4,0x3a,
+ 0x71,0x08,0xb6,0x23,0xa6,0xfb,0x90,0xca,
+ 0x9e,0x64,0x6d,0x95,0xb5,0xf5,0x41,0x24,
+ 0xd2,0xe6,0x60,0xda,0x6c,0x69,0xc4,0xa0,
+ 0x4d,0xaa,0x94,0xf6,0x66,0x1e,0xaa,0x85,
+ 0x68,0xc5,0x6b,0x2e,0x77,0x7a,0x68,0xff,
+ 0x45,0x15,0x45,0xc5,0x9c,0xbb,0x3a,0x23,
+ 0x08,0x3a,0x06,0xdd,0xc0,0x52,0xd2,0xb7,
+ 0x47,0xaa,0x1c,0xc7,0xb5,0xa9,0x7d,0x04,
+ 0x60,0x67,0x78,0xf6,0xb9,0xba,0x26,0x84,
+ 0x45,0x72,0x44,0xed,0xa3,0xd3,0xa0,0x3f,
+ 0x19,0xee,0x3f,0x94,0x59,0x52,0x4b,0x13,
+ 0xfd,0x81,0xcc,0xf9,0xf2,0x29,0xd7,0xec,
+ 0xde,0x03,0x56,0x01,0x4a,0x19,0x86,0xc0,
+ 0x87,0xce,0xe1,0xcc,0x13,0xf1,0x2e,0xda,
+ 0x3f,0xfe,0xa4,0x64,0xe7,0x48,0xb4,0x7b,
+ 0x73,0x62,0x5a,0x80,0x5e,0x01,0x20,0xa5,
+ 0x0a,0xd7,0x98,0xa7,0xd9,0x8b,0xff,0xc2,
+ },
+ [1] = {
+ 0xa6,0x87,0xf0,0x92,0x68,0xc8,0xd6,0x42,
+ 0xa8,0x83,0x1c,0x92,0x65,0x8c,0xd9,0xfe,
+ 0x0b,0x1a,0xc6,0x96,0x27,0x44,0xd4,0x14,
+ 0xfc,0xe7,0x85,0xb2,0x71,0xc7,0x11,0x39,
+ 0xed,0x36,0xd3,0x5c,0xa7,0xf7,0x3d,0xc9,
+ 0xa2,0x54,0x8b,0xb4,0xfa,0xe8,0x21,0xf9,
+ 0xfd,0x6a,0x42,0x85,0xde,0x66,0xd4,0xc0,
+ 0xa7,0xd3,0x5b,0xe1,0xe6,0xac,0xea,0xf9,
+ 0xa3,0x15,0x68,0xf4,0x66,0x4c,0x23,0x75,
+ 0x58,0xba,0x7f,0xca,0xbf,0x40,0x56,0x79,
+ 0x2f,0xbf,0xdf,0x5f,0x56,0xcb,0xa0,0xe4,
+ 0x22,0x65,0x6a,0x8f,0x4f,0xff,0x11,0x6b,
+ 0x57,0xeb,0x45,0xeb,0x9d,0x7f,0xfe,0x9c,
+ 0x8b,0x30,0xa8,0xb0,0x7e,0x27,0xf8,0xbc,
+ 0x1f,0xf8,0x15,0x34,0x36,0x4f,0x46,0x73,
+ 0x81,0x90,0x4b,0x4b,0x46,0x4d,0x01,0x45,
+ 0xa1,0xc3,0x0b,0xa8,0x5a,0xab,0xc1,0x88,
+ 0x66,0xc8,0x1a,0x94,0x17,0x64,0x6f,0xf4,
+ },
+ [2] = {
+ 0x22,0x4c,0x27,0xf4,0xba,0x37,0x8b,0x27,
+ 0xd3,0xd6,0x88,0x8a,0xdc,0xed,0x64,0x42,
+ 0x19,0x60,0x31,0x09,0xf3,0x72,0xd2,0xc2,
+ 0xd3,0xe3,0xff,0xce,0xc5,0x03,0x9f,0xce,
+ 0x99,0x49,0x8a,0xf2,0xe1,0xba,0xe2,0xa8,
+ 0xd7,0x32,0x07,0x2d,0xb0,0xb3,0xbc,0x67,
+ 0x32,0x9a,0x3e,0x7d,0x16,0x23,0xe7,0x24,
+ 0x84,0xe1,0x15,0x03,0x9c,0xa2,0x7a,0x95,
+ 0x34,0xa8,0x04,0x4e,0x79,0x31,0x50,0x26,
+ 0x76,0xd1,0x10,0xce,0xec,0x13,0xf7,0xfb,
+ 0x94,0x6b,0x76,0x50,0x5f,0xb2,0x3e,0x7c,
+ 0xbe,0x97,0xe7,0x13,0x06,0x9e,0x2d,0xc4,
+ 0x46,0x65,0xa7,0x69,0x37,0x07,0x25,0x37,
+ 0xe5,0x48,0x51,0xa8,0x58,0xe8,0x4d,0x7c,
+ 0xb5,0xbe,0x25,0x13,0xbc,0x11,0xc2,0xde,
+ 0xdb,0x00,0xef,0x1c,0x1d,0xeb,0xe3,0x49,
+ 0x1c,0xc0,0x78,0x29,0x76,0xc0,0xde,0x3a,
+ 0x0e,0x96,0x8f,0xea,0xd7,0x42,0x4e,0xb4,
+ },
+ };
+ struct aesenc enc;
+ struct aesdec dec;
+ uint8_t key[32];
+ uint8_t in[144];
+ uint8_t outbuf[146] = { [0] = 0x1a, [145] = 0x1a }, *out = outbuf + 1;
+ uint8_t iv0[16], iv[16];
+ unsigned i;
+
+ for (i = 0; i < 32; i++)
+ key[i] = i;
+ for (i = 0; i < 16; i++)
+ iv0[i] = 0x20 ^ i;
+ for (i = 0; i < 144; i++)
+ in[i] = 0x80 ^ i;
+
+ for (i = 0; i < 3; i++) {
+ impl->ai_setenckey(&enc, key, aes_nrounds[i]);
+ impl->ai_setdeckey(&dec, key, aes_nrounds[i]);
+
+ /* Try one swell foop. */
+ memcpy(iv, iv0, 16);
+ impl->ai_cbc_enc(&enc, in, out, 144, iv, aes_nrounds[i]);
+ if (memcmp(out, expected[i], 144))
+ return aes_selftest_fail(impl, out, expected[i], 144,
+ "AES-%u-CBC enc", aes_keybits[i]);
+
+ memcpy(iv, iv0, 16);
+ impl->ai_cbc_dec(&dec, out, out, 144, iv, aes_nrounds[i]);
+ if (memcmp(out, in, 144))
+ return aes_selftest_fail(impl, out, in, 144,
+ "AES-%u-CBC dec", aes_keybits[i]);
+
+ /* Try incrementally, with IV update. */
+ memcpy(iv, iv0, 16);
+ impl->ai_cbc_enc(&enc, in, out, 16, iv, aes_nrounds[i]);
+ impl->ai_cbc_enc(&enc, in + 16, out + 16, 128, iv,
+ aes_nrounds[i]);
+ if (memcmp(out, expected[i], 144))
+ return aes_selftest_fail(impl, out, expected[i], 144,
+ "AES-%u-CBC enc incremental", aes_keybits[i]);
+
+ memcpy(iv, iv0, 16);
+ impl->ai_cbc_dec(&dec, out, out, 128, iv, aes_nrounds[i]);
+ impl->ai_cbc_dec(&dec, out + 128, out + 128, 16, iv,
+ aes_nrounds[i]);
+ if (memcmp(out, in, 144))
+ return aes_selftest_fail(impl, out, in, 144,
+ "AES-%u-CBC dec incremental", aes_keybits[i]);
+ }
+
+ if (outbuf[0] != 0x1a)
+ return aes_selftest_fail(impl, outbuf,
+ (const uint8_t[1]){0x1a}, 1,
+ "AES-CBC overrun preceding");
+ if (outbuf[145] != 0x1a)
+ return aes_selftest_fail(impl, outbuf + 145,
+ (const uint8_t[1]){0x1a}, 1,
+ "AES-CBC overrun following");
+
+ /* Success! */
+ return 0;
+}
+
+static int
+aes_selftest_encdec_xts(const struct aes_impl *impl)
+{
+ uint64_t blkno[3] = { 0, 1, 0xff };
+ static const uint8_t expected[3][144] = {
+ [0] = {
+ /* IEEE P1619-D16, XTS-AES-128, Vector 4, truncated */
+ 0x27,0xa7,0x47,0x9b,0xef,0xa1,0xd4,0x76,
+ 0x48,0x9f,0x30,0x8c,0xd4,0xcf,0xa6,0xe2,
+ 0xa9,0x6e,0x4b,0xbe,0x32,0x08,0xff,0x25,
+ 0x28,0x7d,0xd3,0x81,0x96,0x16,0xe8,0x9c,
+ 0xc7,0x8c,0xf7,0xf5,0xe5,0x43,0x44,0x5f,
+ 0x83,0x33,0xd8,0xfa,0x7f,0x56,0x00,0x00,
+ 0x05,0x27,0x9f,0xa5,0xd8,0xb5,0xe4,0xad,
+ 0x40,0xe7,0x36,0xdd,0xb4,0xd3,0x54,0x12,
+ 0x32,0x80,0x63,0xfd,0x2a,0xab,0x53,0xe5,
+ 0xea,0x1e,0x0a,0x9f,0x33,0x25,0x00,0xa5,
+ 0xdf,0x94,0x87,0xd0,0x7a,0x5c,0x92,0xcc,
+ 0x51,0x2c,0x88,0x66,0xc7,0xe8,0x60,0xce,
+ 0x93,0xfd,0xf1,0x66,0xa2,0x49,0x12,0xb4,
+ 0x22,0x97,0x61,0x46,0xae,0x20,0xce,0x84,
+ 0x6b,0xb7,0xdc,0x9b,0xa9,0x4a,0x76,0x7a,
+ 0xae,0xf2,0x0c,0x0d,0x61,0xad,0x02,0x65,
+ 0x5e,0xa9,0x2d,0xc4,0xc4,0xe4,0x1a,0x89,
+ 0x52,0xc6,0x51,0xd3,0x31,0x74,0xbe,0x51,
+ },
+ [1] = {
+ },
+ [2] = {
+ /* IEEE P1619-D16, XTS-AES-256, Vector 10, truncated */
+ 0x1c,0x3b,0x3a,0x10,0x2f,0x77,0x03,0x86,
+ 0xe4,0x83,0x6c,0x99,0xe3,0x70,0xcf,0x9b,
+ 0xea,0x00,0x80,0x3f,0x5e,0x48,0x23,0x57,
+ 0xa4,0xae,0x12,0xd4,0x14,0xa3,0xe6,0x3b,
+ 0x5d,0x31,0xe2,0x76,0xf8,0xfe,0x4a,0x8d,
+ 0x66,0xb3,0x17,0xf9,0xac,0x68,0x3f,0x44,
+ 0x68,0x0a,0x86,0xac,0x35,0xad,0xfc,0x33,
+ 0x45,0xbe,0xfe,0xcb,0x4b,0xb1,0x88,0xfd,
+ 0x57,0x76,0x92,0x6c,0x49,0xa3,0x09,0x5e,
+ 0xb1,0x08,0xfd,0x10,0x98,0xba,0xec,0x70,
+ 0xaa,0xa6,0x69,0x99,0xa7,0x2a,0x82,0xf2,
+ 0x7d,0x84,0x8b,0x21,0xd4,0xa7,0x41,0xb0,
+ 0xc5,0xcd,0x4d,0x5f,0xff,0x9d,0xac,0x89,
+ 0xae,0xba,0x12,0x29,0x61,0xd0,0x3a,0x75,
+ 0x71,0x23,0xe9,0x87,0x0f,0x8a,0xcf,0x10,
+ 0x00,0x02,0x08,0x87,0x89,0x14,0x29,0xca,
+ 0x2a,0x3e,0x7a,0x7d,0x7d,0xf7,0xb1,0x03,
+ 0x55,0x16,0x5c,0x8b,0x9a,0x6d,0x0a,0x7d,
+ },
+ };
+ static const uint8_t key1[32] = {
+ 0x27,0x18,0x28,0x18,0x28,0x45,0x90,0x45,
+ 0x23,0x53,0x60,0x28,0x74,0x71,0x35,0x26,
+ 0x62,0x49,0x77,0x57,0x24,0x70,0x93,0x69,
+ 0x99,0x59,0x57,0x49,0x66,0x96,0x76,0x27,
+ };
+ static const uint8_t key2[32] = {
+ 0x31,0x41,0x59,0x26,0x53,0x58,0x97,0x93,
+ 0x23,0x84,0x62,0x64,0x33,0x83,0x27,0x95,
+ 0x02,0x88,0x41,0x97,0x16,0x93,0x99,0x37,
+ 0x51,0x05,0x82,0x09,0x74,0x94,0x45,0x92,
+ };
+ struct aesenc enc;
+ struct aesdec dec;
+ uint8_t in[144];
+ uint8_t outbuf[146] = { [0] = 0x1a, [145] = 0x1a }, *out = outbuf + 1;
+ uint8_t blkno_buf[16];
+ uint8_t iv0[16], iv[16];
+ unsigned i;
+
+ for (i = 0; i < 144; i++)
+ in[i] = i;
+
+ for (i = 0; i < 3; i++) {
+ if (i == 1) /* XXX missing AES-192 test vector */
+ continue;
+
+ /* Format the data unit sequence number. */
+ memset(blkno_buf, 0, sizeof blkno_buf);
+ le64enc(blkno_buf, blkno[i]);
+
+ /* Generate the tweak. */
+ impl->ai_setenckey(&enc, key2, aes_nrounds[i]);
+ impl->ai_enc(&enc, blkno_buf, iv0, aes_nrounds[i]);
+
+ /* Load the data encryption key. */
+ impl->ai_setenckey(&enc, key1, aes_nrounds[i]);
+ impl->ai_setdeckey(&dec, key1, aes_nrounds[i]);
+
+ /* Try one swell foop. */
+ memcpy(iv, iv0, 16);
+ impl->ai_xts_enc(&enc, in, out, 144, iv, aes_nrounds[i]);
+ if (memcmp(out, expected[i], 144))
+ return aes_selftest_fail(impl, out, expected[i], 144,
+ "AES-%u-XTS enc", aes_keybits[i]);
+
+ memcpy(iv, iv0, 16);
+ impl->ai_xts_dec(&dec, out, out, 144, iv, aes_nrounds[i]);
+ if (memcmp(out, in, 144))
+ return aes_selftest_fail(impl, out, in, 144,
+ "AES-%u-XTS dec", aes_keybits[i]);
+
+ /* Try incrementally, with IV update. */
+ memcpy(iv, iv0, 16);
+ impl->ai_xts_enc(&enc, in, out, 16, iv, aes_nrounds[i]);
+ impl->ai_xts_enc(&enc, in + 16, out + 16, 128, iv,
+ aes_nrounds[i]);
+ if (memcmp(out, expected[i], 144))
+ return aes_selftest_fail(impl, out, expected[i], 144,
+ "AES-%u-XTS enc incremental", aes_keybits[i]);
+
+ memcpy(iv, iv0, 16);
+ impl->ai_xts_dec(&dec, out, out, 128, iv, aes_nrounds[i]);
+ impl->ai_xts_dec(&dec, out + 128, out + 128, 16, iv,
+ aes_nrounds[i]);
+ if (memcmp(out, in, 144))
+ return aes_selftest_fail(impl, out, in, 144,
+ "AES-%u-XTS dec incremental", aes_keybits[i]);
+ }
+
+ if (outbuf[0] != 0x1a)
+ return aes_selftest_fail(impl, outbuf,
+ (const uint8_t[1]){0x1a}, 1,
+ "AES-XTS overrun preceding");
+ if (outbuf[145] != 0x1a)
+ return aes_selftest_fail(impl, outbuf + 145,
+ (const uint8_t[1]){0x1a}, 1,
+ "AES-XTS overrun following");
+
+ /* Success! */
+ return 0;
+}
+
+int
+aes_selftest(const struct aes_impl *impl)
+{
+ int result = 0;
+
+ if (impl->ai_probe())
+ return -1;
+
+ if (aes_selftest_encdec(impl))
+ result = -1;
+ if (aes_selftest_encdec_cbc(impl))
+ result = -1;
+ if (aes_selftest_encdec_xts(impl))
+ result = -1;
+
+ return result;
+}
Index: src/sys/crypto/aes/files.aes
diff -u /dev/null src/sys/crypto/aes/files.aes:1.1
--- /dev/null Mon Jun 29 23:27:52 2020
+++ src/sys/crypto/aes/files.aes Mon Jun 29 23:27:52 2020
@@ -0,0 +1,12 @@
+# $NetBSD: files.aes,v 1.1 2020/06/29 23:27:52 riastradh Exp $
+
+define aes
+define rijndael: aes # legacy Rijndael API
+
+file crypto/aes/aes_bear.c aes
+file crypto/aes/aes_ct.c aes
+file crypto/aes/aes_ct_dec.c aes
+file crypto/aes/aes_ct_enc.c aes
+file crypto/aes/aes_impl.c aes
+file crypto/aes/aes_rijndael.c rijndael
+file crypto/aes/aes_selftest.c aes