diff options
Diffstat (limited to 'sys/lib')
-rw-r--r-- | sys/lib/libsa/softraid.c | 190 | ||||
-rw-r--r-- | sys/lib/libsa/softraid.h | 4 |
2 files changed, 122 insertions, 72 deletions
diff --git a/sys/lib/libsa/softraid.c b/sys/lib/libsa/softraid.c index 84824038de7..41e964f879e 100644 --- a/sys/lib/libsa/softraid.c +++ b/sys/lib/libsa/softraid.c @@ -1,4 +1,4 @@ -/* $OpenBSD: softraid.c,v 1.3 2017/11/10 16:50:59 sunil Exp $ */ +/* $OpenBSD: softraid.c,v 1.4 2018/08/10 16:41:35 jsing Exp $ */ /* * Copyright (c) 2012 Joel Sing <jsing@openbsd.org> @@ -107,66 +107,54 @@ sr_crypto_calculate_check_hmac_sha1(u_int8_t *maskkey, int maskkey_size, explicit_bzero(&shactx, sizeof(shactx)); } -int -sr_crypto_decrypt_keys(struct sr_boot_volume *bv) +static int +sr_crypto_decrypt_keys(struct sr_meta_crypto *cm, + struct sr_crypto_kdfinfo *kdfinfo, u_int8_t *kp) { - struct sr_meta_crypto *cm; - struct sr_boot_keydisk *kd; - struct sr_meta_opt_item *omi; - struct sr_crypto_pbkdf *kdfhint; - struct sr_crypto_kdfinfo kdfinfo; - char passphrase[PASSPHRASE_LENGTH]; u_int8_t digest[SHA1_DIGEST_LENGTH]; - u_int8_t *keys = NULL; - u_int8_t *kp, *cp; rijndael_ctx ctx; - u_int32_t type; + u_int8_t *cp; int rv = -1; - int c, i; + int i; - SLIST_FOREACH(omi, &bv->sbv_meta_opt, omi_link) - if (omi->omi_som->som_type == SR_OPT_CRYPTO) - break; - - if (omi == NULL) { - printf("Crypto metadata not found!\n"); + if (rijndael_set_key(&ctx, kdfinfo->maskkey, 256) != 0) goto done; - } - cm = (struct sr_meta_crypto *)omi->omi_som; - kdfhint = (struct sr_crypto_pbkdf *)&cm->scm_kdfhint; + cp = (u_int8_t *)cm->scm_key; + for (i = 0; i < SR_CRYPTO_KEYBLOCK_BYTES; i += RIJNDAEL128_BLOCK_LEN) + rijndael_decrypt(&ctx, (u_char *)(cp + i), (u_char *)(kp + i)); - switch (cm->scm_mask_alg) { - case SR_CRYPTOM_AES_ECB_256: - break; - default: - printf("unsupported encryption algorithm %u\n", - cm->scm_mask_alg); - goto done; - } + /* Check that the key decrypted properly. */ + sr_crypto_calculate_check_hmac_sha1(kdfinfo->maskkey, + sizeof(kdfinfo->maskkey), kp, SR_CRYPTO_KEYBLOCK_BYTES, digest); - SLIST_FOREACH(kd, &sr_keydisks, kd_link) { - if (bcmp(&kd->kd_uuid, &bv->sbv_uuid, sizeof(kd->kd_uuid)) == 0) - break; - } - if (kd) { - bcopy(&kd->kd_key, &kdfinfo.maskkey, sizeof(kdfinfo.maskkey)); - } else if (kdfhint->generic.type == SR_CRYPTOKDFT_KEYDISK) { - printf("keydisk not found\n"); - goto done; - } else { - if (kdfhint->generic.type != SR_CRYPTOKDFT_PKCS5_PBKDF2 && - kdfhint->generic.type != SR_CRYPTOKDFT_BCRYPT_PBKDF) { - printf("unknown KDF type %u\n", kdfhint->generic.type); - goto done; - } + if (bcmp(digest, cm->chk_hmac_sha1.sch_mac, sizeof(digest)) == 0) + rv = 0; + + done: + explicit_bzero(digest, sizeof(digest)); + + return rv; +} + +static int +sr_crypto_passphrase_decrypt(struct sr_meta_crypto *cm, + struct sr_crypto_kdfinfo *kdfinfo, u_int8_t *kp) +{ + char passphrase[PASSPHRASE_LENGTH]; + struct sr_crypto_pbkdf *kdfhint; + int rv = -1; + int c, i; + kdfhint = (struct sr_crypto_pbkdf *)&cm->scm_kdfhint; + + for (;;) { printf("Passphrase: "); for (i = 0; i < PASSPHRASE_LENGTH - 1; i++) { c = cngetc(); - if (c == '\r' || c == '\n') + if (c == '\r' || c == '\n') { break; - else if (c == '\b') { + } else if (c == '\b') { i = i > 0 ? i - 2 : -1; continue; } @@ -175,54 +163,118 @@ sr_crypto_decrypt_keys(struct sr_boot_volume *bv) passphrase[i] = 0; printf("\n"); + /* Abort on an empty passphrase. */ + if (i == 0) { + printf("aborting...\n"); + goto done; + } + #ifdef DEBUG printf("Got passphrase: %s with len %d\n", passphrase, strlen(passphrase)); #endif - type = kdfhint->generic.type; - if (type == SR_CRYPTOKDFT_PKCS5_PBKDF2) { + switch (kdfhint->generic.type) { + case SR_CRYPTOKDFT_PKCS5_PBKDF2: if (pkcs5_pbkdf2(passphrase, strlen(passphrase), kdfhint->salt, sizeof(kdfhint->salt), - kdfinfo.maskkey, sizeof(kdfinfo.maskkey), + kdfinfo->maskkey, sizeof(kdfinfo->maskkey), kdfhint->rounds) != 0) { printf("pkcs5_pbkdf2 failed\n"); goto done; } - } else if (type == SR_CRYPTOKDFT_BCRYPT_PBKDF) { + break; + + case SR_CRYPTOKDFT_BCRYPT_PBKDF: if (bcrypt_pbkdf(passphrase, strlen(passphrase), kdfhint->salt, sizeof(kdfhint->salt), - kdfinfo.maskkey, sizeof(kdfinfo.maskkey), + kdfinfo->maskkey, sizeof(kdfinfo->maskkey), kdfhint->rounds) != 0) { printf("bcrypt_pbkdf failed\n"); goto done; } - } else { + break; + + default: printf("unknown KDF type %u\n", kdfhint->generic.type); goto done; } + + if (sr_crypto_decrypt_keys(cm, kdfinfo, kp) == 0) { + rv = 0; + goto done; + } + + printf("incorrect passphrase\n"); } - /* kdfinfo->maskkey now has key. */ + done: + explicit_bzero(passphrase, PASSPHRASE_LENGTH); - /* Decrypt disk keys. */ - keys = alloc(SR_CRYPTO_KEYBLOCK_BYTES); - bzero(keys, SR_CRYPTO_KEYBLOCK_BYTES); + return rv; +} + +int +sr_crypto_unlock_volume(struct sr_boot_volume *bv) +{ + struct sr_meta_crypto *cm; + struct sr_boot_keydisk *kd; + struct sr_meta_opt_item *omi; + struct sr_crypto_pbkdf *kdfhint; + struct sr_crypto_kdfinfo kdfinfo; + u_int8_t *keys = NULL; + int rv = -1; + + SLIST_FOREACH(omi, &bv->sbv_meta_opt, omi_link) + if (omi->omi_som->som_type == SR_OPT_CRYPTO) + break; - if (rijndael_set_key(&ctx, kdfinfo.maskkey, 256) != 0) + if (omi == NULL) { + printf("crypto metadata not found!\n"); goto done; + } - cp = (u_int8_t *)cm->scm_key; - kp = keys; - for (i = 0; i < SR_CRYPTO_KEYBLOCK_BYTES; i += RIJNDAEL128_BLOCK_LEN) - rijndael_decrypt(&ctx, (u_char *)(cp + i), (u_char *)(kp + i)); + cm = (struct sr_meta_crypto *)omi->omi_som; + kdfhint = (struct sr_crypto_pbkdf *)&cm->scm_kdfhint; - /* Check that the key decrypted properly. */ - sr_crypto_calculate_check_hmac_sha1(kdfinfo.maskkey, - sizeof(kdfinfo.maskkey), keys, SR_CRYPTO_KEYBLOCK_BYTES, digest); + switch (cm->scm_mask_alg) { + case SR_CRYPTOM_AES_ECB_256: + break; + default: + printf("unsupported encryption algorithm %u\n", + cm->scm_mask_alg); + goto done; + } - if (bcmp(digest, cm->chk_hmac_sha1.sch_mac, sizeof(digest))) { - printf("incorrect passphrase or keydisk\n"); + keys = alloc(SR_CRYPTO_KEYBLOCK_BYTES); + bzero(keys, SR_CRYPTO_KEYBLOCK_BYTES); + + switch (kdfhint->generic.type) { + case SR_CRYPTOKDFT_KEYDISK: + SLIST_FOREACH(kd, &sr_keydisks, kd_link) { + if (bcmp(&kd->kd_uuid, &bv->sbv_uuid, + sizeof(kd->kd_uuid)) == 0) + break; + } + if (kd == NULL) { + printf("keydisk not found\n"); + goto done; + } + bcopy(&kd->kd_key, &kdfinfo.maskkey, sizeof(kdfinfo.maskkey)); + if (sr_crypto_decrypt_keys(cm, &kdfinfo, keys) != 0) { + printf("incorrect keydisk\n"); + goto done; + } + break; + + case SR_CRYPTOKDFT_BCRYPT_PBKDF: + case SR_CRYPTOKDFT_PKCS5_PBKDF2: + if (sr_crypto_passphrase_decrypt(cm, &kdfinfo, keys) != 0) + goto done; + break; + + default: + printf("unknown KDF type %u\n", kdfhint->generic.type); goto done; } @@ -233,10 +285,8 @@ sr_crypto_decrypt_keys(struct sr_boot_volume *bv) rv = 0; -done: - explicit_bzero(passphrase, PASSPHRASE_LENGTH); + done: explicit_bzero(&kdfinfo, sizeof(kdfinfo)); - explicit_bzero(digest, sizeof(digest)); if (keys != NULL && rv != 0) { explicit_bzero(keys, SR_CRYPTO_KEYBLOCK_BYTES); diff --git a/sys/lib/libsa/softraid.h b/sys/lib/libsa/softraid.h index fc02f18b04d..f4f7efe99fc 100644 --- a/sys/lib/libsa/softraid.h +++ b/sys/lib/libsa/softraid.h @@ -1,4 +1,4 @@ -/* $OpenBSD: softraid.h,v 1.1 2016/09/11 17:49:36 jsing Exp $ */ +/* $OpenBSD: softraid.h,v 1.2 2018/08/10 16:41:35 jsing Exp $ */ /* * Copyright (c) 2012 Joel Sing <jsing@openbsd.org> @@ -34,6 +34,6 @@ extern struct sr_boot_volume_head sr_volumes; extern struct sr_boot_keydisk_head sr_keydisks; void sr_clear_keys(void); -int sr_crypto_decrypt_keys(struct sr_boot_volume *); +int sr_crypto_unlock_volume(struct sr_boot_volume *); #endif /* _SOFTRAID_H */ |