-/* $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>
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;
}
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;
}
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);