Module Name: src Committed By: alnsn Date: Sun Dec 11 00:20:49 UTC 2016
Modified Files: src/sys/dev: cgd.c cgd_crypto.c cgd_crypto.h Log Message: Add XTS mode to cgd(4). To generate a diff of this commit: cvs rdiff -u -r1.111 -r1.112 src/sys/dev/cgd.c cvs rdiff -u -r1.13 -r1.14 src/sys/dev/cgd_crypto.c cvs rdiff -u -r1.8 -r1.9 src/sys/dev/cgd_crypto.h 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.111 src/sys/dev/cgd.c:1.112 --- src/sys/dev/cgd.c:1.111 Wed Sep 14 23:16:30 2016 +++ src/sys/dev/cgd.c Sun Dec 11 00:20:49 2016 @@ -1,4 +1,4 @@ -/* $NetBSD: cgd.c,v 1.111 2016/09/14 23:16:30 mlelstv Exp $ */ +/* $NetBSD: cgd.c,v 1.112 2016/12/11 00:20:49 alnsn Exp $ */ /*- * Copyright (c) 2002 The NetBSD Foundation, Inc. @@ -30,7 +30,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: cgd.c,v 1.111 2016/09/14 23:16:30 mlelstv Exp $"); +__KERNEL_RCSID(0, "$NetBSD: cgd.c,v 1.112 2016/12/11 00:20:49 alnsn Exp $"); #include <sys/types.h> #include <sys/param.h> @@ -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); @@ -896,19 +1003,6 @@ bail: * We implement here the IV method ``encrypted block * number''. * - * For the encryption case, we accomplish this by setting - * up a struct uio where the first iovec of the source is - * the blocknumber and the first iovec of the dest is a - * sink. We then call the cipher with an IV of zero, and - * the right thing happens. - * - * For the decryption case, we use the same basic mechanism - * for symmetry, but we encrypt the block number in the - * first iovec. - * - * We mainly do this to avoid requiring the definition of - * an ECB mode. - * * XXXrcd: for now we rely on our own crypto framework defined * in dev/cgd_crypto.c. This will change when we * get a generic kernel crypto framework. @@ -945,7 +1039,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; @@ -953,9 +1048,7 @@ cgd_cipher(struct cgd_softc *cs, void *d struct iovec srciov[2]; size_t blocksize = cs->sc_cdata.cf_blocksize; size_t todo; - char sink[CGD_MAXBLOCKSIZE]; - char zero_iv[CGD_MAXBLOCKSIZE]; - char blkno_buf[CGD_MAXBLOCKSIZE]; + char blkno_buf[CGD_MAXBLOCKSIZE], *iv; DPRINTF_FOLLOW(("cgd_cipher() dir=%d\n", dir)); @@ -966,46 +1059,37 @@ 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")); dstuio.uio_iov = dstiov; - dstuio.uio_iovcnt = 2; + dstuio.uio_iovcnt = 1; srcuio.uio_iov = srciov; - srcuio.uio_iovcnt = 2; - - dstiov[0].iov_base = sink; - dstiov[0].iov_len = blocksize; - srciov[0].iov_base = blkno_buf; - srciov[0].iov_len = blocksize; + srcuio.uio_iovcnt = 1; 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[0].iov_base = dst; + srciov[0].iov_base = src; + dstiov[0].iov_len = todo; + srciov[0].iov_len = todo; memset(blkno_buf, 0x0, blocksize); blkno2blkno_buf(blkno_buf, blkno); - if (dir == CGD_CIPHER_DECRYPT) { - dstuio.uio_iovcnt = 1; - srcuio.uio_iovcnt = 1; - IFDEBUG(CGDB_CRYPTO, hexprint("step 0: blkno_buf", - blkno_buf, blocksize)); - 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; - } - IFDEBUG(CGDB_CRYPTO, hexprint("step 1: blkno_buf", blkno_buf, blocksize)); - cipher(cs->sc_cdata.cf_priv, &dstuio, &srcuio, zero_iv, dir); - IFDEBUG(CGDB_CRYPTO, hexprint("step 2: sink", - sink, blocksize)); + + /* + * Compute an initial IV. All ciphers + * can convert blkno_buf in-place. + */ + iv = blkno_buf; + ciprep(cs->sc_cdata.cf_priv, iv, blkno_buf, blocksize, dir); + IFDEBUG(CGDB_CRYPTO, hexprint("step 2: iv", iv, blocksize)); + + cipher(cs->sc_cdata.cf_priv, &dstuio, &srcuio, iv, dir); dst += todo; src += todo; @@ -1026,6 +1110,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 +1180,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: src/sys/dev/cgd_crypto.c diff -u src/sys/dev/cgd_crypto.c:1.13 src/sys/dev/cgd_crypto.c:1.14 --- src/sys/dev/cgd_crypto.c:1.13 Sat Apr 25 12:55:04 2015 +++ src/sys/dev/cgd_crypto.c Sun Dec 11 00:20:49 2016 @@ -1,4 +1,4 @@ -/* $NetBSD: cgd_crypto.c,v 1.13 2015/04/25 12:55:04 riastradh Exp $ */ +/* $NetBSD: cgd_crypto.c,v 1.14 2016/12/11 00:20:49 alnsn Exp $ */ /*- * Copyright (c) 2002 The NetBSD Foundation, Inc. @@ -37,7 +37,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: cgd_crypto.c,v 1.13 2015/04/25 12:55:04 riastradh Exp $"); +__KERNEL_RCSID(0, "$NetBSD: cgd_crypto.c,v 1.14 2016/12/11 00:20:49 alnsn Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -62,36 +62,54 @@ __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_3des_init; -static cfunc_destroy cgd_cipher_3des_destroy; -static cfunc_cipher cgd_cipher_3des_cbc; - -static cfunc_init cgd_cipher_bf_init; -static cfunc_destroy cgd_cipher_bf_destroy; -static cfunc_cipher cgd_cipher_bf_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; +static cfunc_cipher cgd_cipher_3des_cbc; +static cfunc_cipher_prep cgd_cipher_3des_cbc_prep; + +static cfunc_init cgd_cipher_bf_init; +static cfunc_destroy cgd_cipher_bf_destroy; +static cfunc_cipher cgd_cipher_bf_cbc; +static cfunc_cipher_prep cgd_cipher_bf_cbc_prep; 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 = cgd_cipher_3des_cbc_prep, }, { .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 = cgd_cipher_bf_cbc_prep, }, }; const struct cryptfuncs * @@ -108,11 +126,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 +141,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 +203,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 +224,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 +233,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) + (void)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 +266,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 +285,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_cbc(&encd, aes_cbc_dec_int, dstuio, srcuio); + 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(&encd, aes_xts_dec_int, dstuio, srcuio); break; default: DIAGPANIC(("%s: unrecognised direction %d", __func__, dir)); @@ -313,6 +451,20 @@ cgd_cipher_3des_destroy(void *data) } static void +cgd_cipher_3des_cbc_prep(void *privdata, char *iv, + const char *blkno_buf, size_t blocksize, int dir) +{ + struct c3des_privdata *cp = privdata; + char zero_iv[8]; + + memset(zero_iv, 0, sizeof(zero_iv)); + des_ede3_cbc_encrypt(blkno_buf, iv, blocksize, + cp->cp_key1, cp->cp_key2, cp->cp_key3, (des_cblock *)zero_iv, 1); + if (blocksize > 8) + (void)memmove(iv, iv + blocksize - 8, 8); +} + +static void c3des_cbc_enc_int(void *privdata, void *dst, const void *src, size_t len) { struct c3des_encdata *ce = privdata; @@ -345,10 +497,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)); @@ -398,6 +550,19 @@ cgd_cipher_bf_destroy(void *data) } static void +cgd_cipher_bf_cbc_prep(void *privdata, char *iv, + const char *blkno_buf, size_t blocksize, int dir) +{ + struct bf_privdata *bp = privdata; + char zero_iv[8]; + + memset(zero_iv, 0, sizeof(zero_iv)); + BF_cbc_encrypt(blkno_buf, iv, blocksize, &bp->bp_key, zero_iv, 1); + if (blocksize > 8) + (void)memmove(iv, iv + blocksize - 8, 8); +} + +static void bf_cbc_enc_int(void *privdata, void *dst, const void *src, size_t len) { struct bf_encdata *be = privdata; @@ -426,10 +591,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: src/sys/dev/cgd_crypto.h diff -u src/sys/dev/cgd_crypto.h:1.8 src/sys/dev/cgd_crypto.h:1.9 --- src/sys/dev/cgd_crypto.h:1.8 Sat Apr 25 12:55:04 2015 +++ src/sys/dev/cgd_crypto.h Sun Dec 11 00:20:49 2016 @@ -1,4 +1,4 @@ -/* $NetBSD: cgd_crypto.h,v 1.8 2015/04/25 12:55:04 riastradh Exp $ */ +/* $NetBSD: cgd_crypto.h,v 1.9 2016/12/11 00:20:49 alnsn Exp $ */ /*- * Copyright (c) 2002 The NetBSD Foundation, Inc. @@ -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; /* prepare to cipher */ }; const struct cryptfuncs *cryptfuncs_find(const char *);