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