Module Name:    src
Committed By:   riastradh
Date:           Sat Jun 13 22:17:03 UTC 2020

Modified Files:
        src/sys/dev: cgd.c

Log Message:
Fix encblkno8 legacy support.  Add a test vector while here.

What a crock!

This is deliberately _not_ neatly abstracted because the whole
configurable `iv method' mechanism is a mistake and should never be
used for anything new.


To generate a diff of this commit:
cvs rdiff -u -r1.133 -r1.134 src/sys/dev/cgd.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/dev/cgd.c
diff -u src/sys/dev/cgd.c:1.133 src/sys/dev/cgd.c:1.134
--- src/sys/dev/cgd.c:1.133	Sat Jun 13 22:15:57 2020
+++ src/sys/dev/cgd.c	Sat Jun 13 22:17:03 2020
@@ -1,4 +1,4 @@
-/* $NetBSD: cgd.c,v 1.133 2020/06/13 22:15:57 riastradh Exp $ */
+/* $NetBSD: cgd.c,v 1.134 2020/06/13 22:17:03 riastradh Exp $ */
 
 /*-
  * Copyright (c) 2002 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: cgd.c,v 1.133 2020/06/13 22:15:57 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: cgd.c,v 1.134 2020/06/13 22:17:03 riastradh Exp $");
 
 #include <sys/types.h>
 #include <sys/param.h>
@@ -64,6 +64,7 @@ __KERNEL_RCSID(0, "$NetBSD: cgd.c,v 1.13
 
 struct selftest_params {
 	const char *alg;
+	int encblkno8;
 	int blocksize;	/* number of bytes */
 	int secsize;
 	daddr_t blkno;
@@ -292,6 +293,18 @@ static const uint8_t selftest_bf_cbc_ctx
 	0xb8, 0xbf, 0x69, 0x17, 0x20, 0x0a, 0xf7, 0xda,
 };
 
+static const uint8_t selftest_aes_cbc_encblkno8_zero64[64];
+static const uint8_t selftest_aes_cbc_encblkno8_ctxt[64] = {
+	0xa2, 0x06, 0x26, 0x26, 0xac, 0xdc, 0xe7, 0xcf,
+	0x47, 0x68, 0x24, 0x0e, 0xfa, 0x40, 0x44, 0x83,
+	0x07, 0xe1, 0xf4, 0x5d, 0x53, 0x47, 0xa0, 0xfe,
+	0xc0, 0x6e, 0x4e, 0xf8, 0x9d, 0x98, 0x63, 0xb8,
+	0x2c, 0x27, 0xfa, 0x3a, 0xd5, 0x40, 0xda, 0xdb,
+	0xe6, 0xc3, 0xe4, 0xfb, 0x85, 0x53, 0xfb, 0x78,
+	0x5d, 0xbd, 0x8f, 0x4c, 0x1a, 0x04, 0x9c, 0x88,
+	0x85, 0xec, 0x3c, 0x56, 0x46, 0x1a, 0x6e, 0xf5,
+};
+
 const struct selftest_params selftests[] = {
 	{
 		.alg = "aes-xts",
@@ -359,6 +372,18 @@ const struct selftest_params selftests[]
 		.ptxt = selftest_bf_cbc_ptxt,
 		.ctxt = selftest_bf_cbc_ctxt,
 	},
+	{
+		.alg = "aes-cbc",
+		.encblkno8 = 1,
+		.blocksize = 16,
+		.secsize = 512,
+		.blkno = 0,
+		.keylen = 128,
+		.txtlen = sizeof(selftest_aes_cbc_encblkno8_zero64),
+		.key = selftest_aes_cbc_encblkno8_zero64,
+		.ptxt = selftest_aes_cbc_encblkno8_zero64,
+		.ctxt = selftest_aes_cbc_encblkno8_ctxt,
+	},
 };
 
 static int cgd_match(device_t, cfdata_t, void *);
@@ -1264,6 +1289,25 @@ cgd_ioctl_set(struct cgd_softc *sc, void
 
 	sc->sc_cdata.cf_blocksize = ci->ci_blocksize;
 	sc->sc_cdata.cf_mode = encblkno[i].v;
+
+	/*
+	 * Print a warning if the user selected the legacy encblkno8
+	 * mistake, and reject it altogether for ciphers that it
+	 * doesn't apply to.
+	 */
+	if (encblkno[i].v != CGD_CIPHER_CBC_ENCBLKNO1) {
+		if (strcmp(sc->sc_cfuncs->cf_name, "aes-cbc") &&
+		    strcmp(sc->sc_cfuncs->cf_name, "3des-cbc") &&
+		    strcmp(sc->sc_cfuncs->cf_name, "bf-cbc")) {
+			log(LOG_WARNING, "cgd: %s only makes sense for cbc,"
+			    " not for %s; ignoring\n",
+			    encblkno[i].n, sc->sc_cfuncs->cf_name);
+			sc->sc_cdata.cf_mode = CGD_CIPHER_CBC_ENCBLKNO1;
+		} else {
+			log(LOG_WARNING, "cgd: enabling legacy encblkno8\n");
+		}
+	}
+
 	sc->sc_cdata.cf_keylen = ci->ci_keylen;
 	sc->sc_cdata.cf_priv = sc->sc_cfuncs->cf_init(ci->ci_keylen, inbuf,
 	    &sc->sc_cdata.cf_blocksize);
@@ -1547,6 +1591,9 @@ cgd_cipher(struct cgd_softc *sc, void *d
 
 	DPRINTF_FOLLOW(("cgd_cipher() dir=%d\n", dir));
 
+	if (sc->sc_cdata.cf_mode == CGD_CIPHER_CBC_ENCBLKNO8)
+		blocksize /= 8;
+
 	KASSERT(len % blocksize == 0);
 	/* ensure that sizeof(daddr_t) <= blocksize (for encblkno IVing) */
 	KASSERT(sizeof(daddr_t) <= blocksize);
@@ -1560,6 +1607,32 @@ cgd_cipher(struct cgd_softc *sc, void *d
 		IFDEBUG(CGDB_CRYPTO, hexprint("step 1: blkno_buf",
 		    blkno_buf, blocksize));
 
+		/*
+		 * Handle bollocksed up encblkno8 mistake.  We used to
+		 * compute the encryption of a zero block with blkno as
+		 * the CBC IV -- except in an early mistake arising
+		 * from bit/byte confusion, we actually computed the
+		 * encryption of the last of _eight_ zero blocks under
+		 * CBC as the CBC IV.
+		 *
+		 * Encrypting the block number is handled inside the
+		 * cipher dispatch now (even though in practice, both
+		 * CBC and XTS will do the same thing), so we have to
+		 * simulate the block number that would yield the same
+		 * result.  So we encrypt _six_ zero blocks -- the
+		 * first one and the last one are handled inside the
+		 * cipher dispatch.
+		 */
+		if (sc->sc_cdata.cf_mode == CGD_CIPHER_CBC_ENCBLKNO8) {
+			static const uint8_t zero[CGD_MAXBLOCKSIZE];
+			uint8_t iv[CGD_MAXBLOCKSIZE];
+
+			memcpy(iv, blkno_buf, blocksize);
+			cipher(sc->sc_cdata.cf_priv, blkno_buf, zero,
+			    6*blocksize, iv, CGD_CIPHER_ENCRYPT);
+			memmove(blkno_buf, blkno_buf + 5*blocksize, blocksize);
+		}
+
 		cipher(sc->sc_cdata.cf_priv, dst, src, todo, blkno_buf, dir);
 
 		dst += todo;
@@ -1589,11 +1662,13 @@ cgd_selftest(void)
 
 	for (size_t i = 0; i < __arraycount(selftests); i++) {
 		const char *alg = selftests[i].alg;
+		int encblkno8 = selftests[i].encblkno8;
 		const uint8_t *key = selftests[i].key;
 		int keylen = selftests[i].keylen;
 		int txtlen = selftests[i].txtlen;
 
-		aprint_verbose("cgd: self-test %s-%d\n", alg, keylen);
+		aprint_verbose("cgd: self-test %s-%d%s\n", alg, keylen,
+		    encblkno8 ? " (encblkno8)" : "");
 
 		memset(&sc, 0, sizeof(sc));
 
@@ -1602,7 +1677,8 @@ cgd_selftest(void)
 			panic("%s not implemented", alg);
 
 		sc.sc_cdata.cf_blocksize = 8 * selftests[i].blocksize;
-		sc.sc_cdata.cf_mode = CGD_CIPHER_CBC_ENCBLKNO1;
+		sc.sc_cdata.cf_mode = encblkno8 ? CGD_CIPHER_CBC_ENCBLKNO8 :
+		    CGD_CIPHER_CBC_ENCBLKNO1;
 		sc.sc_cdata.cf_keylen = keylen;
 
 		sc.sc_cdata.cf_priv = sc.sc_cfuncs->cf_init(keylen,
@@ -1612,7 +1688,8 @@ cgd_selftest(void)
 		if (sc.sc_cdata.cf_blocksize > CGD_MAXBLOCKSIZE)
 			panic("bad block size %zu", sc.sc_cdata.cf_blocksize);
 
-		sc.sc_cdata.cf_blocksize /= 8;
+		if (!encblkno8)
+			sc.sc_cdata.cf_blocksize /= 8;
 
 		buf = kmem_alloc(txtlen, KM_SLEEP);
 		memcpy(buf, selftests[i].ptxt, txtlen);

Reply via email to