diff --git a/lib/libcryptsetup.h b/lib/libcryptsetup.h index 22d74cac..df854f00 100644 --- a/lib/libcryptsetup.h +++ b/lib/libcryptsetup.h @@ -2034,6 +2034,19 @@ uint64_t crypt_get_iv_offset(struct crypt_device *cd); */ int crypt_get_volume_key_size(struct crypt_device *cd); +/** + * Get size (in bytes) of old volume key for LUKS2 device in reencryption. + * + * @param cd crypt LUKS2 device handle + * + * @return old volume key size when device is in reencryption state + * + * @note For LUKS2, this function can be used only if there is at least + * one keyslot assigned to old data segment. Also with reencryption + * mode 'encrypt' there's no old volume key. + */ +int crypt_get_old_volume_key_size(struct crypt_device *cd); + /** * Get size (in bytes) of encryption sector for crypt device. * diff --git a/lib/libcryptsetup.sym b/lib/libcryptsetup.sym index a8752507..b33d5d39 100644 --- a/lib/libcryptsetup.sym +++ b/lib/libcryptsetup.sym @@ -192,4 +192,5 @@ CRYPTSETUP_2.8 { crypt_keyslot_context_init_by_keyring; crypt_keyslot_context_init_by_vk_in_keyring; crypt_reencrypt_init_by_keyslot_context; + crypt_get_old_volume_key_size; } CRYPTSETUP_2.7; diff --git a/lib/luks2/luks2.h b/lib/luks2/luks2.h index 1675f32b..30568dbb 100644 --- a/lib/luks2/luks2.h +++ b/lib/luks2/luks2.h @@ -411,6 +411,7 @@ const char *LUKS2_get_integrity(struct luks2_hdr *hdr, int segment); int LUKS2_get_integrity_key_size(struct luks2_hdr *hdr, int segment); int LUKS2_keyslot_params_default(struct crypt_device *cd, struct luks2_hdr *hdr, struct luks2_keyslot_params *params); +int LUKS2_get_old_volume_key_size(struct luks2_hdr *hdr); int LUKS2_get_volume_key_size(struct luks2_hdr *hdr, int segment); int LUKS2_get_keyslot_stored_key_size(struct luks2_hdr *hdr, int keyslot); const char *LUKS2_get_keyslot_cipher(struct luks2_hdr *hdr, int keyslot, size_t *key_size); diff --git a/lib/luks2/luks2_json_metadata.c b/lib/luks2/luks2_json_metadata.c index 57822c27..20d5fd42 100644 --- a/lib/luks2/luks2_json_metadata.c +++ b/lib/luks2/luks2_json_metadata.c @@ -2461,6 +2461,19 @@ int LUKS2_get_volume_key_size(struct luks2_hdr *hdr, int segment) return -1; } +int LUKS2_get_old_volume_key_size(struct luks2_hdr *hdr) +{ + int old_segment; + + assert(hdr); + + old_segment = LUKS2_reencrypt_segment_old(hdr); + if (old_segment < 0) + return old_segment; + + return LUKS2_get_volume_key_size(hdr, old_segment); +} + uint32_t LUKS2_get_sector_size(struct luks2_hdr *hdr) { return json_segment_get_sector_size(LUKS2_get_segment_jobj(hdr, CRYPT_DEFAULT_SEGMENT)); diff --git a/lib/setup.c b/lib/setup.c index 26277a6a..301f7bb2 100644 --- a/lib/setup.c +++ b/lib/setup.c @@ -6413,6 +6413,19 @@ int crypt_get_volume_key_size(struct crypt_device *cd) return 0; } +int crypt_get_old_volume_key_size(struct crypt_device *cd) +{ + int r = _onlyLUKS2(cd, CRYPT_CD_QUIET, + CRYPT_REQUIREMENT_ONLINE_REENCRYPT | CRYPT_REQUIREMENT_OPAL); + + if (r < 0) + return 0; + + r = LUKS2_get_old_volume_key_size(&cd->u.luks2.hdr); + + return r < 0 ? 0 : r; +} + int crypt_get_hw_encryption_key_size(struct crypt_device *cd) { if (!cd || !isLUKS2(cd->type)) diff --git a/tests/api-test-2.c b/tests/api-test-2.c index 070ba820..cf6f864e 100644 --- a/tests/api-test-2.c +++ b/tests/api-test-2.c @@ -4201,6 +4201,7 @@ static void Luks2Reencryption(void) EQ_(getflags & CRYPT_REQUIREMENT_ONLINE_REENCRYPT, CRYPT_REQUIREMENT_ONLINE_REENCRYPT); /* some parameters are expected to change immediately after reencryption initialization */ + EQ_(crypt_get_old_volume_key_size(cd), 32); EQ_(crypt_get_volume_key_size(cd), 64); OK_(strcmp(crypt_get_cipher_mode(cd), "xts-plain64")); EQ_(crypt_get_sector_size(cd), 4096); @@ -4402,6 +4403,34 @@ static void Luks2Reencryption(void) CRYPT_FREE(cd); CRYPT_FREE(cd2); + /* same key size reencryption */ + OK_(crypt_init(&cd, DMDIR L_DEVICE_OK)); + OK_(crypt_format(cd, CRYPT_LUKS2, "aes", "cbc-essiv:sha256", NULL, NULL, 32, ¶ms2)); + OK_(crypt_set_pbkdf_type(cd, &pbkdf)); + EQ_(crypt_keyslot_add_by_volume_key(cd, 0, NULL, 32, PASSPHRASE, strlen(PASSPHRASE)), 0); + EQ_(crypt_keyslot_add_by_key(cd, 10, NULL, 32, PASSPHRASE, strlen(PASSPHRASE), CRYPT_VOLUME_KEY_NO_SEGMENT), 10); + rparams = (struct crypt_params_reencrypt) { + .mode = CRYPT_REENCRYPT_REENCRYPT, + .direction = CRYPT_REENCRYPT_FORWARD, + .resilience = "none", + .flags = CRYPT_REENCRYPT_INITIALIZE_ONLY + }; + rparams.luks2 = &(struct crypt_params_luks2){ .sector_size = 512 }; + NOTFAIL_(crypt_reencrypt_init_by_passphrase(cd, NULL, PASSPHRASE, strlen(PASSPHRASE), 0, 10, "aes", "xts-plain64", &rparams), "Failed to initialize reencryption"); + EQ_(crypt_get_volume_key_size(cd), 32); + EQ_(crypt_get_old_volume_key_size(cd), 32); + CRYPT_FREE(cd); + + /* same key reencryption */ + OK_(crypt_init(&cd, DMDIR L_DEVICE_OK)); + OK_(crypt_format(cd, CRYPT_LUKS2, "aes", "cbc-essiv:sha256", NULL, NULL, 32, ¶ms2)); + OK_(crypt_set_pbkdf_type(cd, &pbkdf)); + EQ_(crypt_keyslot_add_by_volume_key(cd, 0, NULL, 32, PASSPHRASE, strlen(PASSPHRASE)), 0); + NOTFAIL_(crypt_reencrypt_init_by_passphrase(cd, NULL, PASSPHRASE, strlen(PASSPHRASE), 0, 0, "aes", "xts-plain64", &rparams), "Failed to initialize reencryption"); + EQ_(crypt_get_volume_key_size(cd), 32); + EQ_(crypt_get_old_volume_key_size(cd), 32); + CRYPT_FREE(cd); + /* data shift related tests */ params2.sector_size = 512; OK_(crypt_init(&cd, DMDIR L_DEVICE_OK)); @@ -4517,6 +4546,8 @@ static void Luks2Reencryption(void) OK_(crypt_init(&cd, DMDIR L_DEVICE_OK)); OK_(crypt_load(cd, CRYPT_LUKS2, NULL)); EQ_(crypt_reencrypt_status(cd, &retparams), CRYPT_REENCRYPT_CLEAN); + /* With encryption there's no old volume key */ + EQ_(crypt_get_old_volume_key_size(cd), 0); EQ_(retparams.mode, CRYPT_REENCRYPT_ENCRYPT); OK_(strcmp(retparams.resilience, "datashift")); EQ_(retparams.data_shift, 8192); @@ -4632,6 +4663,7 @@ static void Luks2Reencryption(void) rparams.resilience = "none"; rparams.max_hotzone_size = 2048; OK_(crypt_reencrypt_init_by_passphrase(cd, NULL, PASSPHRASE, strlen(PASSPHRASE), 6, CRYPT_ANY_SLOT, NULL, NULL, &rparams)); + EQ_(crypt_get_old_volume_key_size(cd), 32); OK_(crypt_reencrypt_run(cd, NULL, NULL)); CRYPT_FREE(cd); OK_(crypt_init(&cd, DMDIR L_DEVICE_OK));