diff --git a/lib/fvault2/fvault2.c b/lib/fvault2/fvault2.c index cc30956c..343c77a5 100644 --- a/lib/fvault2/fvault2.c +++ b/lib/fvault2/fvault2.c @@ -755,6 +755,54 @@ out: return r; } +/** + * Activate device. + * @param[in] cd crypt_device struct passed into FVAULT2_activate_by_* + * @param[in] name name of the mapped device + * @param[in] vol_key the pre-derived AES-XTS volume key + * @param[in] params logical volume decryption parameters + * @param[in] flags flags assigned to the crypt_dm_active_device struct + */ +static int _activate( + struct crypt_device *cd, + const char *name, + struct volume_key *vol_key, + const struct fvault2_params *params, + uint32_t flags) +{ + int r = 0; + char *cipher = NULL; + struct crypt_dm_active_device dm_dev = { + .flags = flags, + .size = params->log_vol_size / SECTOR_SIZE + }; + + r = device_block_adjust(cd, crypt_data_device(cd), DEV_EXCL, + crypt_get_data_offset(cd), &dm_dev.size, &dm_dev.flags); + if (r) + goto out; + + if (asprintf(&cipher, "%s-%s", params->cipher, params->cipher_mode) < 0) + return r; + + r = dm_crypt_target_set(&dm_dev.segment, 0, dm_dev.size, + crypt_data_device(cd), vol_key, cipher, + crypt_get_iv_offset(cd), crypt_get_data_offset(cd), + crypt_get_integrity(cd), crypt_get_integrity_tag_size(cd), + crypt_get_sector_size(cd)); + if (r != 0) + goto out; + + r = dm_create_device(cd, name, CRYPT_FVAULT2, &dm_dev); + if (r < 0) + goto out; + +out: + dm_targets_free(cd, &dm_dev); + free(cipher); + return r; +} + int FVAULT2_read_metadata( struct crypt_device *cd, struct fvault2_params *params) @@ -917,7 +965,22 @@ int FVAULT2_activate_by_passphrase( const struct fvault2_params *params, uint32_t flags) { - return -ENOTSUP; + int r = 0; + struct volume_key *vol_key = NULL; + + r = FVAULT2_get_volume_key(cd, passphr, passphr_len, params, + &vol_key); + if (r < 0) + goto out; + + if (name == NULL) + goto out; + + r = _activate(cd, name, vol_key, params, flags); + +out: + crypt_free_volume_key(vol_key); + return r; } int FVAULT2_activate_by_volume_key( @@ -928,5 +991,18 @@ int FVAULT2_activate_by_volume_key( const struct fvault2_params *params, uint32_t flags) { - return -ENOTSUP; + int r = 0; + struct volume_key *vol_key = NULL; + + if (key_size != FVAULT2_XTS_KEY_SIZE) + return -ENOMEM; + + vol_key = crypt_alloc_volume_key(FVAULT2_XTS_KEY_SIZE, key); + if (vol_key == NULL) + return -ENOMEM; + + r = _activate(cd, name, vol_key, params, flags); + + crypt_free_volume_key(vol_key); + return r; } diff --git a/lib/setup.c b/lib/setup.c index bb867b52..7247ddbc 100644 --- a/lib/setup.c +++ b/lib/setup.c @@ -4324,6 +4324,10 @@ static int _activate_by_passphrase(struct crypt_device *cd, r = BITLK_activate_by_passphrase(cd, name, passphrase, passphrase_size, &cd->u.bitlk.params, flags); keyslot = 0; + } else if (isFVAULT2(cd->type)) { + r = FVAULT2_activate_by_passphrase(cd, name, passphrase, passphrase_size, + &cd->u.fvault2.params, flags); + keyslot = 0; } else { log_err(cd, _("Device type is not properly initialized.")); r = -EINVAL; @@ -5557,6 +5561,9 @@ uint64_t crypt_get_data_offset(struct crypt_device *cd) if (isBITLK(cd->type)) return cd->u.bitlk.params.volume_header_size / SECTOR_SIZE; + if (isFVAULT2(cd->type)) + return cd->u.fvault2.params.log_vol_off / SECTOR_SIZE; + return cd->data_offset; } diff --git a/src/cryptsetup.c b/src/cryptsetup.c index 0b7d46ca..68604c70 100644 --- a/src/cryptsetup.c +++ b/src/cryptsetup.c @@ -719,6 +719,67 @@ out: return r; } +static int action_open_fvault2(void) +{ + struct crypt_device *cd = NULL; + const char *activated_name; + uint32_t activate_flags = 0; + int r, tries, keysize; + char *password = NULL; + char *key = NULL; + size_t passwordLen; + + activated_name = ARG_SET(OPT_TEST_PASSPHRASE_ID) ? NULL : action_argv[1]; + + if ((r = crypt_init(&cd, action_argv[0]))) + goto out; + + r = crypt_load(cd, CRYPT_FVAULT2, NULL); + if (r < 0) { + log_err(_("Device %s is not a valid FVAULT2 device."), action_argv[0]); + goto out; + } + set_activation_flags(&activate_flags); + + if (ARG_SET(OPT_VOLUME_KEY_FILE_ID)) { + keysize = crypt_get_volume_key_size(cd); + if (!keysize && !ARG_SET(OPT_KEY_SIZE_ID)) { + log_err(_("Cannot determine volume key size for FVAULT2, please use --key-size option.")); + r = -EINVAL; + goto out; + } else if (!keysize) + keysize = ARG_UINT32(OPT_KEY_SIZE_ID) / 8; + + r = tools_read_vk(ARG_STR(OPT_VOLUME_KEY_FILE_ID), &key, keysize); + if (r < 0) + goto out; + r = crypt_activate_by_volume_key(cd, activated_name, key, keysize, + activate_flags); + } else { + tries = set_tries_tty(); + do { + r = tools_get_key(NULL, &password, &passwordLen, + ARG_UINT64(OPT_KEYFILE_OFFSET_ID), ARG_UINT32(OPT_KEYFILE_SIZE_ID), + ARG_STR(OPT_KEY_FILE_ID), ARG_UINT32(OPT_TIMEOUT_ID), + verify_passphrase(0), 0, cd); + if (r < 0) + goto out; + + r = crypt_activate_by_passphrase(cd, activated_name, CRYPT_ANY_SLOT, + password, passwordLen, activate_flags); + tools_passphrase_msg(r); + check_signal(&r); + crypt_safe_free(password); + password = NULL; + } while ((r == -EPERM || r == -ERANGE) && (--tries > 0)); + } +out: + crypt_safe_free(password); + crypt_safe_free(key); + crypt_free(cd); + return r; +} + static int action_close(void) { struct crypt_device *cd = NULL; @@ -2558,6 +2619,10 @@ static int action_open(void) if (action_argc < 2 && !ARG_SET(OPT_TEST_PASSPHRASE_ID)) goto out; return action_open_bitlk(); + } else if (!strcmp(device_type, "fvault2")) { + if (action_argc < 2 && !ARG_SET(OPT_TEST_PASSPHRASE_ID)) + goto out; + return action_open_fvault2(); } else r = -ENOENT; out: