Index: bioctl.c =================================================================== RCS file: /cvs/src/sbin/bioctl/bioctl.c,v retrieving revision 1.126 diff -u -p -r1.126 bioctl.c --- bioctl.c 11 May 2015 12:14:22 -0000 1.126 +++ bioctl.c 24 May 2015 12:39:27 -0000 @@ -31,6 +31,7 @@ #include <sys/ioctl.h> #include <sys/dkio.h> #include <sys/stat.h> +#include <dev/softraid_luks.h> #include <dev/softraidvar.h> #include <dev/biovar.h> @@ -60,6 +61,8 @@ int bio_parse_devlist(char *, dev_t *) void bio_kdf_derive(struct sr_crypto_kdfinfo *, struct sr_crypto_kdf_pbkdf2 *, char *, int); void bio_kdf_generate(struct sr_crypto_kdfinfo *); +void luks_kdf_derive(u_int8_t **, size_t *, + struct luks_user_pbkdf2 *); void derive_key_pkcs(int, u_int8_t *, size_t, u_int8_t *, size_t, char *, int); @@ -765,6 +768,8 @@ bio_createraid(u_int16_t level, char *de struct sr_crypto_kdfinfo kdfinfo; struct sr_crypto_kdf_pbkdf2 kdfhint; struct stat sb; + u_int8_t *response = NULL; + size_t resplen; int rv, no_dev, fd; dev_t *dt; u_int16_t min_disks = 0; @@ -788,6 +793,7 @@ bio_createraid(u_int16_t level, char *de case 5: min_disks = 3; break; + case 'L': case 'C': min_disks = 1; break; @@ -813,7 +819,36 @@ bio_createraid(u_int16_t level, char *de create.bc_flags = BIOC_SCDEVT | cflags; create.bc_key_disk = NODEV; - if (level == 'C' && key_disk == NULL) { + if (level == 'L') { + + struct luks_user_pbkdf2 hint; + + memset(&hint, 0, sizeof hint); + + create.bc_flags |= BIOC_SCNOAUTOASSEMBLE; + + create.bc_opaque = &hint; + create.bc_opaque_size = sizeof hint; + create.bc_opaque_flags = BIOC_SOOUT; + + if (ioctl(devh, BIOCCREATERAID, &create)) + err(1, "ioctl"); + + bio_status(&create.bc_bio.bio_status); + + if (create.bc_opaque_status == BIOC_SOINOUT_OK) { + luks_kdf_derive(&response, &resplen, &hint); + memset(&hint, 0, sizeof hint); + } else { + errx(1, "creating LUKS not supported yet"); + } + + create.bc_opaque = response; + create.bc_opaque_size = resplen; + create.bc_opaque_flags = BIOC_SOIN; + + } + else if (level == 'C' && key_disk == NULL) { memset(&kdfinfo, 0, sizeof(kdfinfo)); memset(&kdfhint, 0, sizeof(kdfhint)); @@ -870,6 +905,10 @@ bio_createraid(u_int16_t level, char *de rv = ioctl(devh, BIOCCREATERAID, &create); explicit_bzero(&kdfinfo, sizeof(kdfinfo)); + if (response != NULL) { + explicit_bzero(response, resplen); + free(response); + } if (rv == -1) err(1, "BIOCCREATERAID"); @@ -921,6 +960,47 @@ bio_kdf_generate(struct sr_crypto_kdfinf kdfinfo->maskkey, sizeof(kdfinfo->maskkey), kdfinfo->pbkdf2.salt, sizeof(kdfinfo->pbkdf2.salt), "New passphrase: ", 1); +} + +void +luks_kdf_derive(u_int8_t **respp, size_t *resplenp, struct luks_user_pbkdf2 *h) +{ + char passphrase[1024]; + u_int8_t *ret; + int i; + + if (readpassphrase("LUKS Passphrase: ", passphrase, sizeof(passphrase), + rpp_flag) == NULL) + errx(1, "unable to read passphrase"); + + /* This will be leaked, but this is a one-shot program anyway. */ + ret = reallocarray(NULL, h->key_bytes, LUKS_NUM_KEYS); + if (ret == NULL) { + explicit_bzero(passphrase, sizeof(passphrase)); + errx(1, "out of memory, need %u\n", h->key_bytes); + } + + for (i = 0; i < LUKS_NUM_KEYS; ++i) { + u_int8_t *digest = ret + (i * h->key_bytes); + + if ((h->have_keys & (1 << i)) == 0) + continue; + + /* derive key from passphrase */ + if (pkcs5_pbkdf2(passphrase, strlen(passphrase), + h->keys[i].salt, LUKS_SALT_LEN, + digest, h->key_bytes, h->keys[i].iterations) != 0) + goto fail; + } + explicit_bzero(passphrase, sizeof(passphrase)); + + *respp = ret; + *resplenp = h->key_bytes * LUKS_NUM_KEYS; + return; + fail: + explicit_bzero(passphrase, sizeof(passphrase)); + explicit_bzero(ret, h->key_bytes * LUKS_NUM_KEYS); + errx(1, "pbkdf2 failed"); } int