tech-crypto archive

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

AES XTS in cgd



Hi,

I'm attaching my work-in-progress patches that add XTS mode to cgd
for AES-128 and AES-256. They correspond to key sizes 256 and 512
in cgdconfig.

Because the existing code is designed for CBC mode, I had to
introduce a new cipher_prep function that converts blkno_buf to
XTS tweak or CBC IV. It's optional because I didn't want to touch
Blowfish and 3DES but I'd like to switch them to cipher_prep too.

Unit tests for XTS are already in the tree in tests/dev/cgd/t_cgd_aes.c.

Comments, suggestions and testing are very well welcome!

Alex
Index: sys/crypto/rijndael/rijndael-api-fst.h
===================================================================
RCS file: /cvsroot/src/sys/crypto/rijndael/rijndael-api-fst.h,v
retrieving revision 1.8
diff -p -u -u -r1.8 rijndael-api-fst.h
--- sys/crypto/rijndael/rijndael-api-fst.h	21 Jan 2007 23:00:08 -0000	1.8
+++ sys/crypto/rijndael/rijndael-api-fst.h	6 Nov 2016 16:22:47 -0000
@@ -48,6 +48,7 @@
 #define     MODE_ECB              1 /*  Are we ciphering in ECB mode?   */
 #define     MODE_CBC              2 /*  Are we ciphering in CBC mode?   */
 #define     MODE_CFB1             3 /*  Are we ciphering in 1-bit CFB mode? */
+#define     MODE_XTS              4 /*  Are we ciphering in XTS mode? */
 #define     TRUE                  1
 #define     FALSE                 0
 #define     BITSPERBLOCK        128 /* Default number of bits in a cipher block */
Index: sys/crypto/rijndael/rijndael-api-fst.c
===================================================================
RCS file: /cvsroot/src/sys/crypto/rijndael/rijndael-api-fst.c,v
retrieving revision 1.24
diff -p -u -u -r1.24 rijndael-api-fst.c
--- sys/crypto/rijndael/rijndael-api-fst.c	14 May 2011 16:46:55 -0000	1.24
+++ sys/crypto/rijndael/rijndael-api-fst.c	6 Nov 2016 16:22:47 -0000
@@ -62,6 +62,22 @@ static void xor16(uint8_t *d, const uint
 	}
 }
 
+static void
+xts_exponentiate(uint8_t *iv)
+{
+	unsigned int carry = 0;
+
+	for (size_t i = 0; i < 16; i++) {
+		unsigned int msb = iv[i] >> 7;
+
+		iv[i] = (iv[i] << 1) | carry;
+		carry = msb;
+	}
+
+	if (carry != 0)
+		iv[0] ^= 0x87;
+}
+
 int
 rijndael_makeKey(keyInstance *key, BYTE direction, int keyLen,
     const char *keyMaterial)
@@ -102,7 +118,8 @@ rijndael_makeKey(keyInstance *key, BYTE 
 int
 rijndael_cipherInit(cipherInstance *cipher, BYTE mode, const char *IV)
 {
-	if ((mode == MODE_ECB) || (mode == MODE_CBC) || (mode == MODE_CFB1)) {
+	if ((mode == MODE_ECB) || (mode == MODE_CBC) ||
+	    (mode == MODE_XTS) || (mode == MODE_CFB1)) {
 		cipher->mode = mode;
 	} else {
 		return BAD_CIPHER_MODE;
@@ -153,6 +170,18 @@ rijndael_blockEncrypt(cipherInstance *ci
 		}
 		break;
 
+	case MODE_XTS:
+		iv = (u_int8_t *)cipher->IV;
+		for (i = numBlocks; i > 0; i--) {
+			xor16(block, input, iv);
+			rijndaelEncrypt(key->rk, key->Nr, block, block);
+			xor16(outBuffer, block, iv);
+			xts_exponentiate(iv);
+			input += 16;
+			outBuffer += 16;
+		}
+		break;
+
 	case MODE_CFB1:
 		iv = (u_int8_t *)cipher->IV;
 		for (i = numBlocks; i > 0; i--) {
@@ -284,7 +313,19 @@ rijndael_blockDecrypt(cipherInstance *ci
 		}
 		break;
 
-    case MODE_CFB1:
+	case MODE_XTS:
+		iv = (u_int8_t *)cipher->IV;
+		for (i = numBlocks; i > 0; i--) {
+			xor16(block, input, iv);
+			rijndaelDecrypt(key->rk, key->Nr, block, block);
+			xor16(outBuffer, block, iv);
+			xts_exponentiate(iv);
+			input += 16;
+			outBuffer += 16;
+		}
+		break;
+
+	case MODE_CFB1:
 		iv = (u_int8_t *)cipher->IV;
 		for (i = numBlocks; i > 0; i--) {
 			memcpy(outBuffer, input, 16);
Index: sys/dev/cgd_crypto.h
===================================================================
RCS file: /cvsroot/src/sys/dev/cgd_crypto.h,v
retrieving revision 1.8
diff -p -u -u -r1.8 cgd_crypto.h
--- sys/dev/cgd_crypto.h	25 Apr 2015 12:55:04 -0000	1.8
+++ sys/dev/cgd_crypto.h	6 Nov 2016 16:26:49 -0000
@@ -40,12 +40,14 @@ typedef void *(cfunc_init)(size_t, const
 typedef void  (cfunc_destroy)(void *);
 typedef void  (cfunc_cipher)(void *, struct uio *, struct uio *, const void *,
 				int);
+typedef void  (cfunc_cipher_prep)(void *, char *, const char *, size_t, int);
 
 struct cryptfuncs {
-	const char	 *cf_name;	/* cipher name */
-	cfunc_init	 *cf_init;	/* Initialisation function */
-	cfunc_destroy	 *cf_destroy;	/* destruction function */
-	cfunc_cipher	 *cf_cipher;	/* the cipher itself */
+	const char		 *cf_name;	/* cipher name */
+	cfunc_init		 *cf_init;	/* Initialisation function */
+	cfunc_destroy		 *cf_destroy;	/* destruction function */
+	cfunc_cipher		 *cf_cipher;	/* the cipher itself */
+	cfunc_cipher_prep	 *cf_cipher_prep;
 };
 
 const struct cryptfuncs	*cryptfuncs_find(const char *);
Index: sys/dev/cgd_crypto.c
===================================================================
RCS file: /cvsroot/src/sys/dev/cgd_crypto.c,v
retrieving revision 1.13
diff -p -u -u -r1.13 cgd_crypto.c
--- sys/dev/cgd_crypto.c	25 Apr 2015 12:55:04 -0000	1.13
+++ sys/dev/cgd_crypto.c	6 Nov 2016 16:26:49 -0000
@@ -62,9 +62,15 @@ __KERNEL_RCSID(0, "$NetBSD: cgd_crypto.c
  * to check key size and block size.
  */
 
-static cfunc_init	cgd_cipher_aes_init;
-static cfunc_destroy	cgd_cipher_aes_destroy;
-static cfunc_cipher	cgd_cipher_aes_cbc;
+static cfunc_init		cgd_cipher_aes_cbc_init;
+static cfunc_destroy		cgd_cipher_aes_cbc_destroy;
+static cfunc_cipher		cgd_cipher_aes_cbc;
+static cfunc_cipher_prep	cgd_cipher_aes_cbc_prep;
+
+static cfunc_init		cgd_cipher_aes_xts_init;
+static cfunc_destroy		cgd_cipher_aes_xts_destroy;
+static cfunc_cipher		cgd_cipher_aes_xts;
+static cfunc_cipher_prep	cgd_cipher_aes_xts_prep;
 
 static cfunc_init	cgd_cipher_3des_init;
 static cfunc_destroy	cgd_cipher_3des_destroy;
@@ -76,22 +82,32 @@ static cfunc_cipher	cgd_cipher_bf_cbc;
 
 static const struct cryptfuncs cf[] = {
 	{
+		.cf_name	= "aes-xts",
+		.cf_init	= cgd_cipher_aes_xts_init,
+		.cf_destroy	= cgd_cipher_aes_xts_destroy,
+		.cf_cipher	= cgd_cipher_aes_xts,
+		.cf_cipher_prep	= cgd_cipher_aes_xts_prep,
+	},
+	{
 		.cf_name	= "aes-cbc",
-		.cf_init	= cgd_cipher_aes_init,
-		.cf_destroy	= cgd_cipher_aes_destroy,
+		.cf_init	= cgd_cipher_aes_cbc_init,
+		.cf_destroy	= cgd_cipher_aes_cbc_destroy,
 		.cf_cipher	= cgd_cipher_aes_cbc,
+		.cf_cipher_prep	= cgd_cipher_aes_cbc_prep,
 	},
 	{
 		.cf_name	= "3des-cbc",
 		.cf_init	= cgd_cipher_3des_init,
 		.cf_destroy	= cgd_cipher_3des_destroy,
 		.cf_cipher	= cgd_cipher_3des_cbc,
+		.cf_cipher_prep	= NULL,
 	},
 	{
 		.cf_name	= "blowfish-cbc",
 		.cf_init	= cgd_cipher_bf_init,
 		.cf_destroy	= cgd_cipher_bf_destroy,
 		.cf_cipher	= cgd_cipher_bf_cbc,
+		.cf_cipher_prep	= NULL,
 	},
 };
 const struct cryptfuncs *
@@ -108,11 +124,11 @@ cryptfuncs_find(const char *alg)
 typedef void	(*cipher_func)(void *, void *, const void *, size_t);
 
 static void
-cgd_cipher_uio_cbc(void *privdata, cipher_func cipher,
+cgd_cipher_uio(void *privdata, cipher_func cipher,
 	struct uio *dstuio, struct uio *srcuio);
 
 /*
- * cgd_cipher_uio_cbc takes a simple cbc cipher and iterates
+ * cgd_cipher_uio takes a simple cbc or xts cipher and iterates
  * it over two struct uio's.  It presumes that the cipher function
  * that is passed to it keeps the IV state between calls.
  *
@@ -123,7 +139,7 @@ cgd_cipher_uio_cbc(void *privdata, ciphe
  */
 
 static void
-cgd_cipher_uio_cbc(void *privdata, cipher_func cipher,
+cgd_cipher_uio(void *privdata, cipher_func cipher,
     struct uio *dstuio, struct uio *srcuio)
 {
 	const struct iovec	*dst;
@@ -185,7 +201,7 @@ struct aes_encdata {
 };
 
 static void *
-cgd_cipher_aes_init(size_t keylen, const void *key, size_t *blocksize)
+cgd_cipher_aes_cbc_init(size_t keylen, const void *key, size_t *blocksize)
 {
 	struct	aes_privdata *ap;
 
@@ -206,7 +222,7 @@ cgd_cipher_aes_init(size_t keylen, const
 }
 
 static void
-cgd_cipher_aes_destroy(void *data)
+cgd_cipher_aes_cbc_destroy(void *data)
 {
 	struct aes_privdata *apd = data;
 
@@ -215,12 +231,30 @@ cgd_cipher_aes_destroy(void *data)
 }
 
 static void
+cgd_cipher_aes_cbc_prep(void *privdata, char *iv,
+    const char *blkno_buf, size_t blocksize, int dir)
+{
+	struct aes_privdata	*apd = privdata;
+	cipherInstance		 cipher;
+	int			 cipher_ok __diagused;
+
+	cipher_ok = rijndael_cipherInit(&cipher, MODE_CBC, NULL);
+	KASSERT(cipher_ok > 0);
+	rijndael_blockEncrypt(&cipher, &apd->ap_enckey,
+	    blkno_buf, blocksize * 8, iv);
+	if (blocksize > 16)
+		memmove(iv, iv + blocksize - 16, 16);
+}
+
+static void
 aes_cbc_enc_int(void *privdata, void *dst, const void *src, size_t len)
 {
 	struct aes_encdata	*ae = privdata;
 	cipherInstance		 cipher;
+	int			 cipher_ok __diagused;
 
-	rijndael_cipherInit(&cipher, MODE_CBC, ae->ae_iv);
+	cipher_ok = rijndael_cipherInit(&cipher, MODE_CBC, ae->ae_iv);
+	KASSERT(cipher_ok > 0);
 	rijndael_blockEncrypt(&cipher, ae->ae_key, src, len * 8, dst);
 	(void)memcpy(ae->ae_iv, (u_int8_t *)dst + (len - 16), 16);
 }
@@ -230,8 +264,10 @@ aes_cbc_dec_int(void *privdata, void *ds
 {
 	struct aes_encdata	*ae = privdata;
 	cipherInstance		 cipher;
+	int			 cipher_ok __diagused;
 
-	rijndael_cipherInit(&cipher, MODE_CBC, ae->ae_iv);
+	cipher_ok = rijndael_cipherInit(&cipher, MODE_CBC, ae->ae_iv);
+	KASSERT(cipher_ok > 0);
 	rijndael_blockDecrypt(&cipher, ae->ae_key, src, len * 8, dst);
 	(void)memcpy(ae->ae_iv, (const u_int8_t *)src + (len - 16), 16);
 }
@@ -247,11 +283,111 @@ cgd_cipher_aes_cbc(void *privdata, struc
 	switch (dir) {
 	case CGD_CIPHER_ENCRYPT:
 		encd.ae_key = &apd->ap_enckey;
-		cgd_cipher_uio_cbc(&encd, aes_cbc_enc_int, dstuio, srcuio);
+		cgd_cipher_uio(&encd, aes_cbc_enc_int, dstuio, srcuio);
+		break;
+	case CGD_CIPHER_DECRYPT:
+		encd.ae_key = &apd->ap_deckey;
+		cgd_cipher_uio(&encd, aes_cbc_dec_int, dstuio, srcuio);
+		break;
+	default:
+		DIAGPANIC(("%s: unrecognised direction %d", __func__, dir));
+	}
+}
+
+static void *
+cgd_cipher_aes_xts_init(size_t keylen, const void *xtskey, size_t *blocksize)
+{
+	struct aes_privdata *ap;
+	const char *key, *key2; /* XTS key is made of two AES keys. */
+
+	if (!blocksize)
+		return NULL;
+	if (keylen != 256 && keylen != 512)
+		return NULL;
+	if (*blocksize == (size_t)-1)
+		*blocksize = 128;
+	if (*blocksize != 128)
+		return NULL;
+	ap = malloc(2 * sizeof(*ap), M_DEVBUF, 0);
+	if (!ap)
+		return NULL;
+
+	keylen /= 2;
+	key = xtskey;
+	key2 = key + keylen / CHAR_BIT;
+
+	rijndael_makeKey(&ap[0].ap_enckey, DIR_ENCRYPT, keylen, key);
+	rijndael_makeKey(&ap[0].ap_deckey, DIR_DECRYPT, keylen, key);
+	rijndael_makeKey(&ap[1].ap_enckey, DIR_ENCRYPT, keylen, key2);
+
+	return ap;
+}
+
+static void
+cgd_cipher_aes_xts_destroy(void *data)
+{
+	struct aes_privdata *apd = data;
+
+	explicit_memset(apd, 0, 2 * sizeof(*apd));
+	free(apd, M_DEVBUF);
+}
+
+static void
+cgd_cipher_aes_xts_prep(void *privdata, char *iv,
+    const char *blkno_buf, size_t blocksize, int dir)
+{
+	struct aes_privdata	*apd = privdata;
+	cipherInstance		 cipher;
+	int			 cipher_ok __diagused;
+
+	cipher_ok = rijndael_cipherInit(&cipher, MODE_ECB, NULL);
+	KASSERT(cipher_ok > 0);
+	rijndael_blockEncrypt(&cipher, &apd[1].ap_enckey,
+	    blkno_buf, blocksize * 8, iv);
+}
+
+static void
+aes_xts_enc_int(void *privdata, void *dst, const void *src, size_t len)
+{
+	struct aes_encdata	*ae = privdata;
+	cipherInstance		 cipher;
+	int			 cipher_ok __diagused;
+
+	cipher_ok = rijndael_cipherInit(&cipher, MODE_XTS, ae->ae_iv);
+	KASSERT(cipher_ok > 0);
+	rijndael_blockEncrypt(&cipher, ae->ae_key, src, len * 8, dst);
+	(void)memcpy(ae->ae_iv, cipher.IV, 16);
+}
+
+static void
+aes_xts_dec_int(void *privdata, void *dst, const void *src, size_t len)
+{
+	struct aes_encdata	*ae = privdata;
+	cipherInstance		 cipher;
+	int			 cipher_ok __diagused;
+
+	cipher_ok = rijndael_cipherInit(&cipher, MODE_XTS, ae->ae_iv);
+	KASSERT(cipher_ok > 0);
+	rijndael_blockDecrypt(&cipher, ae->ae_key, src, len * 8, dst);
+	(void)memcpy(ae->ae_iv, cipher.IV, 16);
+}
+
+static void
+cgd_cipher_aes_xts(void *privdata, struct uio *dstuio,
+    struct uio *srcuio, const void *iv, int dir)
+{
+	struct aes_privdata	*apd = privdata;
+	struct aes_encdata	 encd;
+
+	(void)memcpy(encd.ae_iv, iv, 16);
+	switch (dir) {
+	case CGD_CIPHER_ENCRYPT:
+		encd.ae_key = &apd->ap_enckey;
+		cgd_cipher_uio(&encd, aes_xts_enc_int, dstuio, srcuio);
 		break;
 	case CGD_CIPHER_DECRYPT:
 		encd.ae_key = &apd->ap_deckey;
-		cgd_cipher_uio_cbc(&encd, aes_cbc_dec_int, dstuio, srcuio);
+		cgd_cipher_uio(&encd, aes_xts_dec_int, dstuio, srcuio);
 		break;
 	default:
 		DIAGPANIC(("%s: unrecognised direction %d", __func__, dir));
@@ -345,10 +481,10 @@ cgd_cipher_3des_cbc(void *privdata, stru
 	ce.ce_key3 = &cp->cp_key3;
 	switch (dir) {
 	case CGD_CIPHER_ENCRYPT:
-		cgd_cipher_uio_cbc(&ce, c3des_cbc_enc_int, dstuio, srcuio);
+		cgd_cipher_uio(&ce, c3des_cbc_enc_int, dstuio, srcuio);
 		break;
 	case CGD_CIPHER_DECRYPT:
-		cgd_cipher_uio_cbc(&ce, c3des_cbc_dec_int, dstuio, srcuio);
+		cgd_cipher_uio(&ce, c3des_cbc_dec_int, dstuio, srcuio);
 		break;
 	default:
 		DIAGPANIC(("%s: unrecognised direction %d", __func__, dir));
@@ -426,10 +562,10 @@ cgd_cipher_bf_cbc(void *privdata, struct
 	be.be_key = &bp->bp_key;
 	switch (dir) {
 	case CGD_CIPHER_ENCRYPT:
-		cgd_cipher_uio_cbc(&be, bf_cbc_enc_int, dstuio, srcuio);
+		cgd_cipher_uio(&be, bf_cbc_enc_int, dstuio, srcuio);
 		break;
 	case CGD_CIPHER_DECRYPT:
-		cgd_cipher_uio_cbc(&be, bf_cbc_dec_int, dstuio, srcuio);
+		cgd_cipher_uio(&be, bf_cbc_dec_int, dstuio, srcuio);
 		break;
 	default:
 		DIAGPANIC(("%s: unrecognised direction %d", __func__, dir));
Index: sys/dev/cgd.c
===================================================================
RCS file: /cvsroot/src/sys/dev/cgd.c,v
retrieving revision 1.111
diff -p -u -u -r1.111 cgd.c
--- sys/dev/cgd.c	14 Sep 2016 23:16:30 -0000	1.111
+++ sys/dev/cgd.c	6 Nov 2016 16:26:49 -0000
@@ -59,6 +59,18 @@ __KERNEL_RCSID(0, "$NetBSD: cgd.c,v 1.11
 
 #include "ioconf.h"
 
+struct selftest_params {
+	const char *alg;
+	int blocksize;	/* number of bytes */
+	int secsize;
+	daddr_t blkno;
+	int keylen;	/* number of bits */
+	int txtlen;	/* number of bytes */
+	const uint8_t *key;
+	const uint8_t *ptxt;
+	const uint8_t *ctxt;
+};
+
 /* Entry Point Functions */
 
 static dev_type_open(cgdopen);
@@ -96,6 +108,101 @@ const struct cdevsw cgd_cdevsw = {
 	.d_flag = D_DISK
 };
 
+/*
+ * Vector 5 from IEEE 1619/D16 truncated to 64 bytes, blkno 1.
+ */
+static const uint8_t selftest_aes_xts_256_ptxt[64] = {
+	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,
+};
+
+static const uint8_t selftest_aes_xts_256_ctxt[512] = {
+	0x26, 0x4d, 0x3c, 0xa8, 0x51, 0x21, 0x94, 0xfe,
+	0xc3, 0x12, 0xc8, 0xc9, 0x89, 0x1f, 0x27, 0x9f,
+	0xef, 0xdd, 0x60, 0x8d, 0x0c, 0x02, 0x7b, 0x60,
+	0x48, 0x3a, 0x3f, 0xa8, 0x11, 0xd6, 0x5e, 0xe5,
+	0x9d, 0x52, 0xd9, 0xe4, 0x0e, 0xc5, 0x67, 0x2d,
+	0x81, 0x53, 0x2b, 0x38, 0xb6, 0xb0, 0x89, 0xce,
+	0x95, 0x1f, 0x0f, 0x9c, 0x35, 0x59, 0x0b, 0x8b,
+	0x97, 0x8d, 0x17, 0x52, 0x13, 0xf3, 0x29, 0xbb,
+};
+
+static const uint8_t selftest_aes_xts_256_key[33] = {
+	0x27, 0x18, 0x28, 0x18, 0x28, 0x45, 0x90, 0x45,
+	0x23, 0x53, 0x60, 0x28, 0x74, 0x71, 0x35, 0x26,
+	0x31, 0x41, 0x59, 0x26, 0x53, 0x58, 0x97, 0x93,
+	0x23, 0x84, 0x62, 0x64, 0x33, 0x83, 0x27, 0x95,
+	0
+};
+
+/*
+ * Vector 11 from IEEE 1619/D16 truncated to 64 bytes, blkno 0xffff.
+ */
+static const uint8_t selftest_aes_xts_512_ptxt[64] = {
+	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+	0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+	0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+	0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+	0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+};
+
+static const uint8_t selftest_aes_xts_512_ctxt[64] = {
+	0x77, 0xa3, 0x12, 0x51, 0x61, 0x8a, 0x15, 0xe6,
+	0xb9, 0x2d, 0x1d, 0x66, 0xdf, 0xfe, 0x7b, 0x50,
+	0xb5, 0x0b, 0xad, 0x55, 0x23, 0x05, 0xba, 0x02,
+	0x17, 0xa6, 0x10, 0x68, 0x8e, 0xff, 0x7e, 0x11,
+	0xe1, 0xd0, 0x22, 0x54, 0x38, 0xe0, 0x93, 0x24,
+	0x2d, 0x6d, 0xb2, 0x74, 0xfd, 0xe8, 0x01, 0xd4,
+	0xca, 0xe0, 0x6f, 0x20, 0x92, 0xc7, 0x28, 0xb2,
+	0x47, 0x85, 0x59, 0xdf, 0x58, 0xe8, 0x37, 0xc2,
+};
+
+static const uint8_t selftest_aes_xts_512_key[65] = {
+	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,
+	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,
+	0
+};
+
+const struct selftest_params selftests[] = {
+	{
+		.alg = "aes-xts",
+		.blocksize = 16,
+		.secsize = 512,
+		.blkno = 1,
+		.keylen = 256,
+		.txtlen = sizeof(selftest_aes_xts_256_ptxt),
+		.key  = selftest_aes_xts_256_key,
+		.ptxt = selftest_aes_xts_256_ptxt,
+		.ctxt = selftest_aes_xts_256_ctxt
+	},
+	{
+		.alg = "aes-xts",
+		.blocksize = 16,
+		.secsize = 512,
+		.blkno = 0xffff,
+		.keylen = 512,
+		.txtlen = sizeof(selftest_aes_xts_512_ptxt),
+		.key  = selftest_aes_xts_512_key,
+		.ptxt = selftest_aes_xts_512_ptxt,
+		.ctxt = selftest_aes_xts_512_ctxt
+	}
+};
+
 static int cgd_match(device_t, cfdata_t, void *);
 static void cgd_attach(device_t, device_t, void *);
 static int cgd_detach(device_t, int);
@@ -945,7 +1052,8 @@ cgd_cipher(struct cgd_softc *cs, void *d
     size_t len, daddr_t blkno, size_t secsize, int dir)
 {
 	char		*dst = dstv;
-	char 		*src = srcv;
+	char		*src = srcv;
+	cfunc_cipher_prep	*ciprep = cs->sc_cfuncs->cf_cipher_prep;
 	cfunc_cipher	*cipher = cs->sc_cfuncs->cf_cipher;
 	struct uio	dstuio;
 	struct uio	srcuio;
@@ -956,6 +1064,8 @@ cgd_cipher(struct cgd_softc *cs, void *d
 	char		sink[CGD_MAXBLOCKSIZE];
 	char		zero_iv[CGD_MAXBLOCKSIZE];
 	char		blkno_buf[CGD_MAXBLOCKSIZE];
+	char		*iv = ciprep != NULL ? sink : zero_iv;
+	size_t		last_iov = ciprep != NULL ? 0 : 1;
 
 	DPRINTF_FOLLOW(("cgd_cipher() dir=%d\n", dir));
 
@@ -966,30 +1076,39 @@ cgd_cipher(struct cgd_softc *cs, void *d
 	DIAGCONDPANIC(sizeof(daddr_t) > blocksize,
 	    ("cgd_cipher: sizeof(daddr_t) > blocksize"));
 
-	memset(zero_iv, 0x0, blocksize);
+	DIAGCONDPANIC(blocksize > CGD_MAXBLOCKSIZE,
+	    ("cgd_cipher: blocksize > CGD_MAXBLOCKSIZE"));
+
+	if (ciprep == NULL)
+		memset(zero_iv, 0x0, blocksize);
 
 	dstuio.uio_iov = dstiov;
-	dstuio.uio_iovcnt = 2;
+	dstuio.uio_iovcnt = last_iov + 1;
 
 	srcuio.uio_iov = srciov;
-	srcuio.uio_iovcnt = 2;
+	srcuio.uio_iovcnt = last_iov + 1;
 
-	dstiov[0].iov_base = sink;
-	dstiov[0].iov_len  = blocksize;
-	srciov[0].iov_base = blkno_buf;
-	srciov[0].iov_len  = blocksize;
+	if (last_iov > 0) {
+		dstiov[0].iov_base = sink;
+		dstiov[0].iov_len  = blocksize;
+		srciov[0].iov_base = blkno_buf;
+		srciov[0].iov_len  = blocksize;
+	}
 
 	for (; len > 0; len -= todo) {
 		todo = MIN(len, secsize);
 
-		dstiov[1].iov_base = dst;
-		srciov[1].iov_base = src;
-		dstiov[1].iov_len  = todo;
-		srciov[1].iov_len  = todo;
+		dstiov[last_iov].iov_base = dst;
+		srciov[last_iov].iov_base = src;
+		dstiov[last_iov].iov_len  = todo;
+		srciov[last_iov].iov_len  = todo;
 
 		memset(blkno_buf, 0x0, blocksize);
 		blkno2blkno_buf(blkno_buf, blkno);
-		if (dir == CGD_CIPHER_DECRYPT) {
+		if (ciprep != NULL) {
+			ciprep(cs->sc_cdata.cf_priv,
+			    iv, blkno_buf, blocksize, dir);
+		} else if (dir == CGD_CIPHER_DECRYPT) {
 			dstuio.uio_iovcnt = 1;
 			srcuio.uio_iovcnt = 1;
 			IFDEBUG(CGDB_CRYPTO, hexprint("step 0: blkno_buf",
@@ -997,13 +1116,13 @@ cgd_cipher(struct cgd_softc *cs, void *d
 			cipher(cs->sc_cdata.cf_priv, &dstuio, &srcuio,
 			    zero_iv, CGD_CIPHER_ENCRYPT);
 			memcpy(blkno_buf, sink, blocksize);
-			dstuio.uio_iovcnt = 2;
-			srcuio.uio_iovcnt = 2;
+			dstuio.uio_iovcnt = last_iov + 1;
+			srcuio.uio_iovcnt = last_iov + 1;
 		}
 
 		IFDEBUG(CGDB_CRYPTO, hexprint("step 1: blkno_buf",
 		    blkno_buf, blocksize));
-		cipher(cs->sc_cdata.cf_priv, &dstuio, &srcuio, zero_iv, dir);
+		cipher(cs->sc_cdata.cf_priv, &dstuio, &srcuio, iv, dir);
 		IFDEBUG(CGDB_CRYPTO, hexprint("step 2: sink",
 		    sink, blocksize));
 
@@ -1026,6 +1145,61 @@ hexprint(const char *start, void *buf, i
 }
 #endif
 
+static void
+selftest(void)
+{
+	struct cgd_softc cs;
+	void *buf;
+
+	printf("running cgd selftest ");
+
+	for (size_t i = 0; i < __arraycount(selftests); i++) {
+		const char *alg = selftests[i].alg;
+		const uint8_t *key = selftests[i].key;
+		int keylen = selftests[i].keylen;
+		int txtlen = selftests[i].txtlen;
+
+		printf("%s-%d ", alg, keylen);
+
+		memset(&cs, 0, sizeof(cs));
+
+		cs.sc_cfuncs = cryptfuncs_find(alg);
+		if (cs.sc_cfuncs == NULL)
+			panic("%s not implemented", alg);
+
+		cs.sc_cdata.cf_blocksize = 8 * selftests[i].blocksize;
+		cs.sc_cdata.cf_mode = CGD_CIPHER_CBC_ENCBLKNO1;
+		cs.sc_cdata.cf_keylen = keylen;
+
+		cs.sc_cdata.cf_priv = cs.sc_cfuncs->cf_init(keylen,
+		    key, &cs.sc_cdata.cf_blocksize);
+		if (cs.sc_cdata.cf_priv == NULL)
+			panic("cf_priv is NULL");
+		if (cs.sc_cdata.cf_blocksize > CGD_MAXBLOCKSIZE)
+			panic("bad block size %zu", cs.sc_cdata.cf_blocksize);
+
+		cs.sc_cdata.cf_blocksize /= 8;
+
+		buf = malloc(txtlen, M_DEVBUF, M_WAITOK);
+		memcpy(buf, selftests[i].ptxt, txtlen);
+
+		cgd_cipher(&cs, buf, buf, txtlen, selftests[i].blkno,
+				selftests[i].secsize, CGD_CIPHER_ENCRYPT);
+		if (memcmp(buf, selftests[i].ctxt, txtlen) != 0)
+			panic("encryption is broken");
+
+		cgd_cipher(&cs, buf, buf, txtlen, selftests[i].blkno,
+				selftests[i].secsize, CGD_CIPHER_DECRYPT);
+		if (memcmp(buf, selftests[i].ptxt, txtlen) != 0)
+			panic("decryption is broken");
+
+		free(buf, M_DEVBUF);
+		cs.sc_cfuncs->cf_destroy(cs.sc_cdata.cf_priv);
+	}
+
+	printf("done\n");
+}
+
 MODULE(MODULE_CLASS_DRIVER, cgd, "dk_subr");
 
 #ifdef _MODULE
@@ -1041,6 +1215,7 @@ cgd_modcmd(modcmd_t cmd, void *arg)
 
 	switch (cmd) {
 	case MODULE_CMD_INIT:
+		selftest();
 #ifdef _MODULE
 		error = config_cfdriver_attach(&cgd_cd);
 		if (error)
Index: sbin/cgdconfig/params.c
===================================================================
RCS file: /cvsroot/src/sbin/cgdconfig/params.c,v
retrieving revision 1.28
diff -p -u -u -r1.28 params.c
--- sbin/cgdconfig/params.c	24 Nov 2015 14:07:18 -0000	1.28
+++ sbin/cgdconfig/params.c	6 Nov 2016 16:43:03 -0000
@@ -70,6 +70,7 @@ static struct crypto_defaults {
 	int	keylen;
 } crypto_defaults[] = {
 	{ "aes-cbc",		128 },
+	{ "aes-xts",		256 },
 	{ "3des-cbc",		192 },
 	{ "blowfish-cbc",	128 }
 };


Home | Main Index | Thread Index | Old Index