diff -rupN cryptsetup-2.3.3.orig/tests/api-test-2.c cryptsetup-2.3.3/tests/api-test-2.c --- cryptsetup-2.3.3.orig/tests/api-test-2.c 2021-02-17 19:48:46.483519319 +0100 +++ cryptsetup-2.3.3/tests/api-test-2.c 2021-02-17 19:49:10.527493909 +0100 @@ -2876,6 +2876,12 @@ static void Luks2KeyslotParams(void) const char *mk_hex2 = "bb21158c733229347bd4e681891e213d94c685be6a5b84818afe7a78a6de7a1e"; size_t key_size_ret, key_size = strlen(mk_hex) / 2, keyslot_key_size = 16; uint64_t r_payload_offset; + const struct crypt_pbkdf_type fast_pbkdf = { + .type = "pbkdf2", + .hash = "sha256", + .iterations = 1000, + .flags = CRYPT_PBKDF_NO_BENCHMARK + }; crypt_decode_key(key, mk_hex, key_size); crypt_decode_key(key2, mk_hex2, key_size); @@ -2889,7 +2895,7 @@ static void Luks2KeyslotParams(void) EQ_(key_size, 2 * keyslot_key_size); /* test crypt_keyslot_add_by_key */ OK_(crypt_init(&cd, DMDIR L_DEVICE_OK)); - crypt_set_iteration_time(cd, 1); + OK_(crypt_set_pbkdf_type(cd, &fast_pbkdf)); OK_(crypt_format(cd, CRYPT_LUKS2, cipher, cipher_mode, NULL, key, key_size, NULL)); NULL_(crypt_keyslot_get_encryption(cd, 0, &key_size_ret)); OK_(strcmp(crypt_keyslot_get_encryption(cd, CRYPT_ANY_SLOT, &key_size_ret), cipher_spec)); @@ -2948,7 +2954,7 @@ static void Luks2KeyslotParams(void) OK_(strcmp(crypt_keyslot_get_encryption(cd, 7, &key_size_ret), cipher_keyslot)); EQ_(key_size_ret, keyslot_key_size); - crypt_set_iteration_time(cd, 1); + OK_(crypt_set_pbkdf_type(cd, &fast_pbkdf)); EQ_(8, crypt_keyslot_change_by_passphrase(cd, 1, 8, PASSPHRASE1, strlen(PASSPHRASE1), PASSPHRASE, strlen(PASSPHRASE))); OK_(strcmp(crypt_keyslot_get_encryption(cd, 8, &key_size_ret), cipher_spec)); EQ_(key_size_ret, key_size); @@ -2977,7 +2983,7 @@ static void Luks2KeyslotParams(void) /* LUKS1 compatible calls */ OK_(crypt_init(&cd, DMDIR L_DEVICE_OK)); - crypt_set_iteration_time(cd, 1); + OK_(crypt_set_pbkdf_type(cd, &fast_pbkdf)); OK_(crypt_format(cd, CRYPT_LUKS1, cipher, cipher_mode, NULL, key, key_size, NULL)); NULL_(crypt_keyslot_get_encryption(cd, 0, &key_size_ret)); OK_(strcmp(crypt_keyslot_get_encryption(cd, CRYPT_ANY_SLOT, &key_size_ret), cipher_spec)); @@ -2987,6 +2993,18 @@ static void Luks2KeyslotParams(void) EQ_(key_size_ret, key_size); CRYPT_FREE(cd); + /* LUKS2 cipher null checks */ + OK_(crypt_init(&cd, DMDIR L_DEVICE_OK)); + OK_(crypt_set_pbkdf_type(cd, &fast_pbkdf)); + OK_(crypt_format(cd, CRYPT_LUKS2, "cipher_null", "ecb", NULL, key, key_size, NULL)); + FAIL_(crypt_keyslot_set_encryption(cd, "null", 32), "cipher null is not allowed"); + FAIL_(crypt_keyslot_set_encryption(cd, "cipher_null", 32), "cipher null is not allowed"); + FAIL_(crypt_keyslot_set_encryption(cd, "cipher_null-ecb", 32), "cipher null is not allowed"); + EQ_(0, crypt_keyslot_add_by_volume_key(cd, 0, key, key_size, PASSPHRASE, strlen(PASSPHRASE))); + NOTNULL_(crypt_keyslot_get_encryption(cd, 0, &key_size_ret)); + NULL_(strstr(crypt_keyslot_get_encryption(cd, 0, &key_size_ret), "null")); + CRYPT_FREE(cd); + _cleanup_dmdevices(); _remove_keyfiles(); } diff -rupN cryptsetup-2.3.3.orig/tests/luks2-reencryption-test cryptsetup-2.3.3/tests/luks2-reencryption-test --- cryptsetup-2.3.3.orig/tests/luks2-reencryption-test 2021-02-17 19:48:46.493519309 +0100 +++ cryptsetup-2.3.3/tests/luks2-reencryption-test 2021-02-17 19:50:13.397427467 +0100 @@ -1365,6 +1365,33 @@ echo $PWD1 | $CRYPTSETUP luksKillSlot $D echo -e "$PWD1\n$PWD1\n$PWD1\n$PWD1\n$PWD1\n$PWD1\n$PWD1\n$PWD1\n$PWD1\n$PWD1\n$PWD1\n$PWD1\n$PWD1\n$PWD2" | $CRYPTSETUP reencrypt $DEV -q 2>/dev/null && fail echo $PWD1 | $CRYPTSETUP reencrypt $DEV --resume-only -q 2>/dev/null && fail echo -e "$PWD1\n$PWD1\n$PWD1\n$PWD1\n$PWD1\n$PWD1\n$PWD1\n$PWD1\n$PWD1\n$PWD1\n$PWD1\n$PWD1\n$PWD1\n$PWD1" | $CRYPTSETUP reencrypt $DEV -q || fail + +echo "[24] Reencryption with initial cipher_null" +# aka custom encryption +prepare dev_size_mb=32 +echo $PWD1 | $CRYPTSETUP -q luksFormat --type luks2 -s 128 -c cipher_null-ecb --offset 8192 $FAST_PBKDF_ARGON $DEV || fail +wipe $PWD1 +check_hash $PWD1 $HASH1 +echo $PWD1 | $CRYPTSETUP reencrypt $DEV -c aes-xts-plain64 -q $FAST_PBKDF_ARGON || fail +check_hash $PWD1 $HASH1 + +# online +echo $PWD1 | $CRYPTSETUP -q luksFormat --type luks2 -s 128 -c cipher_null-ecb --offset 8192 $FAST_PBKDF_ARGON $DEV || fail +wipe $PWD1 +echo $PWD1 | $CRYPTSETUP open $DEV $DEV_NAME +echo $PWD1 | $CRYPTSETUP reencrypt $DEV -c aes-xts-plain64 -q $FAST_PBKDF_ARGON || fail +check_hash_dev /dev/mapper/$DEV_NAME $HASH1 +$CRYPTSETUP status $DEV_NAME | grep -q "key location: keyring" || fail +$CRYPTSETUP close $DEV_NAME + +# simulate LUKS2 device with cipher_null in both keyslot and segment (it can be created only by up conversion from LUKS1) +echo $PWD1 | $CRYPTSETUP -q luksFormat --type luks1 -s 128 -c cipher_null-ecb --offset 8192 $FAST_PBKDF2 $DEV || fail +$CRYPTSETUP convert -q --type luks2 $DEV || fail +wipe $PWD1 +echo $PWD1 | $CRYPTSETUP reencrypt $DEV -c aes-xts-plain64 -q $FAST_PBKDF_ARGON || fail +check_hash $PWD1 $HASH1 +# both keyslot and segment cipher must not be null +$CRYPTSETUP luksDump $DEV | grep -q "cipher_null" && fail remove_mapping exit 0 diff -rupN cryptsetup-2.3.3.orig/lib/utils_crypt.c cryptsetup-2.3.3/lib/utils_crypt.c --- cryptsetup-2.3.3.orig/lib/utils_crypt.c 2021-02-17 17:48:06.535007396 +0100 +++ cryptsetup-2.3.3/lib/utils_crypt.c 2021-02-17 17:49:07.552948180 +0100 @@ -174,3 +174,10 @@ ssize_t crypt_hex_to_bytes(const char *h *result = bytes; return i; } + +bool crypt_is_cipher_null(const char *cipher_spec) +{ + if (!cipher_spec) + return false; + return (strstr(cipher_spec, "cipher_null") || !strcmp(cipher_spec, "null")); +} diff -rupN cryptsetup-2.3.3.orig/lib/utils_crypt.h cryptsetup-2.3.3/lib/utils_crypt.h --- cryptsetup-2.3.3.orig/lib/utils_crypt.h 2021-02-17 17:48:06.535007396 +0100 +++ cryptsetup-2.3.3/lib/utils_crypt.h 2021-02-17 17:49:07.552948180 +0100 @@ -23,6 +23,7 @@ #ifndef _UTILS_CRYPT_H #define _UTILS_CRYPT_H +#include #include #define MAX_CIPHER_LEN 32 @@ -38,4 +39,6 @@ int crypt_parse_pbkdf(const char *s, con ssize_t crypt_hex_to_bytes(const char *hex, char **result, int safe_alloc); +bool crypt_is_cipher_null(const char *cipher_spec); + #endif /* _UTILS_CRYPT_H */ diff -rupN cryptsetup-2.3.3.orig/src/cryptsetup.c cryptsetup-2.3.3/src/cryptsetup.c --- cryptsetup-2.3.3.orig/src/cryptsetup.c 2021-02-17 17:48:06.538007393 +0100 +++ cryptsetup-2.3.3/src/cryptsetup.c 2021-02-17 17:52:54.174722763 +0100 @@ -1281,7 +1281,7 @@ static int _luksFormat(struct crypt_devi } /* Never call pwquality if using null cipher */ - if (tools_is_cipher_null(cipher)) + if (crypt_is_cipher_null(cipher)) opt_force_password = 1; if ((r = crypt_init(&cd, header_device))) { @@ -1679,7 +1679,7 @@ static int luksAddUnboundKey(void) goto out; /* Never call pwquality if using null cipher */ - if (tools_is_cipher_null(crypt_get_cipher(cd))) + if (crypt_is_cipher_null(crypt_get_cipher(cd))) opt_force_password = 1; keysize = opt_key_size / 8; @@ -1746,7 +1746,7 @@ static int action_luksAddKey(void) goto out; /* Never call pwquality if using null cipher */ - if (tools_is_cipher_null(crypt_get_cipher(cd))) + if (crypt_is_cipher_null(crypt_get_cipher(cd))) opt_force_password = 1; keysize = crypt_get_volume_key_size(cd); @@ -1849,7 +1849,7 @@ static int action_luksChangeKey(void) goto out; /* Never call pwquality if using null cipher */ - if (tools_is_cipher_null(crypt_get_cipher(cd))) + if (crypt_is_cipher_null(crypt_get_cipher(cd))) opt_force_password = 1; r = set_pbkdf_params(cd, crypt_get_type(cd)); diff -rupN cryptsetup-2.3.3.orig/src/cryptsetup.h cryptsetup-2.3.3/src/cryptsetup.h --- cryptsetup-2.3.3.orig/src/cryptsetup.h 2021-02-17 17:48:06.538007393 +0100 +++ cryptsetup-2.3.3/src/cryptsetup.h 2021-02-17 17:54:15.556641129 +0100 @@ -97,7 +97,6 @@ int tools_get_key(const char *prompt, void tools_passphrase_msg(int r); int tools_is_stdin(const char *key_file); int tools_string_to_size(struct crypt_device *cd, const char *s, uint64_t *size); -int tools_is_cipher_null(const char *cipher); void tools_clear_line(void); diff -rupN cryptsetup-2.3.3.orig/src/utils_tools.c cryptsetup-2.3.3/src/utils_tools.c --- cryptsetup-2.3.3.orig/src/utils_tools.c 2021-02-17 17:48:06.538007393 +0100 +++ cryptsetup-2.3.3/src/utils_tools.c 2021-02-17 17:49:07.572948160 +0100 @@ -596,14 +596,6 @@ out: return r; } -int tools_is_cipher_null(const char *cipher) -{ - if (!cipher) - return 0; - - return !strcmp(cipher, "cipher_null") ? 1 : 0; -} - /* * Keyfile - is standard input treated as a binary file (no EOL handling). */ From 03cc8a9ce4c1e04283eb0e0da658aa4509e74949 Mon Sep 17 00:00:00 2001 From: Ondrej Kozina Date: Wed, 10 Feb 2021 17:50:49 +0100 Subject: [PATCH 3/9] Fix broken detection of null cipher in LUKS2. This bug enabled to create LUKS2 keyslots encrypted by cipher_null when explicitely requested by user. LUKS2 was never meant to allow keyslot encryption with cipher_null. cipher_null is meant for debug purposes only as a segment cipher. --- lib/luks2/luks2_keyslot.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/luks2/luks2_keyslot.c b/lib/luks2/luks2_keyslot.c index ed51e24..414189c 100644 --- a/lib/luks2/luks2_keyslot.c +++ b/lib/luks2/luks2_keyslot.c @@ -155,7 +155,7 @@ int LUKS2_keyslot_cipher_incompatible(struct crypt_device *cd, const char *ciphe { char cipher[MAX_CIPHER_LEN], cipher_mode[MAX_CIPHER_LEN]; - if (!cipher_spec || !strcmp(cipher_spec, "null") || !strcmp(cipher_spec, "cipher_null")) + if (!cipher_spec || crypt_is_cipher_null(cipher_spec)) return 1; if (crypt_parse_name_and_mode(cipher_spec, cipher, NULL, cipher_mode) < 0) -- 1.8.3.1 diff -rupN cryptsetup-2.3.3.orig/lib/luks2/luks2_token.c cryptsetup-2.3.3/lib/luks2/luks2_token.c --- cryptsetup-2.3.3.orig/lib/luks2/luks2_token.c 2021-02-17 17:59:35.532320163 +0100 +++ cryptsetup-2.3.3/lib/luks2/luks2_token.c 2021-02-17 18:01:49.925185354 +0100 @@ -383,6 +383,7 @@ int LUKS2_token_open_and_activate(struct uint32_t flags, void *usrptr) { + bool use_keyring; int keyslot, r; char *buffer; size_t buffer_len; @@ -404,7 +405,13 @@ int LUKS2_token_open_and_activate(struct keyslot = r; - if ((name || (flags & CRYPT_ACTIVATE_KEYRING_KEY)) && crypt_use_keyring_for_vk(cd)) { + if (!crypt_use_keyring_for_vk(cd)) + use_keyring = false; + else + use_keyring = ((name && !crypt_is_cipher_null(crypt_get_cipher(cd))) || + (flags & CRYPT_ACTIVATE_KEYRING_KEY)); + + if (use_keyring) { if (!(r = LUKS2_volume_key_load_in_keyring_by_keyslot(cd, hdr, vk, keyslot))) flags |= CRYPT_ACTIVATE_KEYRING_KEY; } diff -rupN cryptsetup-2.3.3.orig/lib/setup.c cryptsetup-2.3.3/lib/setup.c --- cryptsetup-2.3.3.orig/lib/setup.c 2021-02-17 17:59:35.529320166 +0100 +++ cryptsetup-2.3.3/lib/setup.c 2021-02-17 18:00:03.676291932 +0100 @@ -3879,6 +3879,7 @@ static int _open_and_activate(struct cry size_t passphrase_size, uint32_t flags) { + bool use_keyring; int r; struct volume_key *vk = NULL; @@ -3890,8 +3891,13 @@ static int _open_and_activate(struct cry return r; keyslot = r; - if ((name || (flags & CRYPT_ACTIVATE_KEYRING_KEY)) && - crypt_use_keyring_for_vk(cd)) { + if (!crypt_use_keyring_for_vk(cd)) + use_keyring = false; + else + use_keyring = ((name && !crypt_is_cipher_null(crypt_get_cipher(cd))) || + (flags & CRYPT_ACTIVATE_KEYRING_KEY)); + + if (use_keyring) { r = LUKS2_volume_key_load_in_keyring_by_keyslot(cd, &cd->u.luks2.hdr, vk, keyslot); if (r < 0) @@ -4269,6 +4275,7 @@ int crypt_activate_by_volume_key(struct size_t volume_key_size, uint32_t flags) { + bool use_keyring; struct volume_key *vk = NULL; int r; @@ -4344,8 +4351,12 @@ int crypt_activate_by_volume_key(struct if (r > 0) r = 0; - if (!r && (name || (flags & CRYPT_ACTIVATE_KEYRING_KEY)) && - crypt_use_keyring_for_vk(cd)) { + if (!crypt_use_keyring_for_vk(cd)) + use_keyring = false; + else + use_keyring = (name && !crypt_is_cipher_null(crypt_get_cipher(cd))) || (flags & CRYPT_ACTIVATE_KEYRING_KEY); + + if (!r && use_keyring) { r = LUKS2_key_description_by_segment(cd, &cd->u.luks2.hdr, vk, CRYPT_DEFAULT_SEGMENT); if (!r) From ed2117c72417d85c7b2f20d5859ca558eaf61c62 Mon Sep 17 00:00:00 2001 From: Ondrej Kozina Date: Thu, 11 Feb 2021 11:43:10 +0100 Subject: [PATCH 5/9] Fix device comparison for dm-crypt with cipher_null. Do not compare volume keys if segment uses cipher_null. The key is ignored by lower layer (internal libdevmapper) anyway. --- lib/setup.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/lib/setup.c b/lib/setup.c index ffd9b7b..7286e10 100644 --- a/lib/setup.c +++ b/lib/setup.c @@ -2380,11 +2380,6 @@ static int _compare_crypt_devices(struct crypt_device *cd, if (!src->u.crypt.vk || !tgt->u.crypt.vk) return -EINVAL; - if (_compare_volume_keys(src->u.crypt.vk, 0, tgt->u.crypt.vk, tgt->u.crypt.vk->key_description != NULL)) { - log_dbg(cd, "Keys in context and target device do not match."); - return -EINVAL; - } - /* CIPHER checks */ if (!src->u.crypt.cipher || !tgt->u.crypt.cipher) return -EINVAL; @@ -2392,6 +2387,14 @@ static int _compare_crypt_devices(struct crypt_device *cd, log_dbg(cd, "Cipher specs do not match."); return -EINVAL; } + + if (tgt->u.crypt.vk->keylength == 0 && crypt_is_cipher_null(tgt->u.crypt.cipher)) + log_dbg(cd, "Existing device uses cipher null. Skipping key comparison."); + else if (_compare_volume_keys(src->u.crypt.vk, 0, tgt->u.crypt.vk, tgt->u.crypt.vk->key_description != NULL)) { + log_dbg(cd, "Keys in context and target device do not match."); + return -EINVAL; + } + if (crypt_strcmp(src->u.crypt.integrity, tgt->u.crypt.integrity)) { log_dbg(cd, "Integrity parameters do not match."); return -EINVAL; -- 1.8.3.1 From 01f896711ed54bff7c1ccf944d2295929af7c75c Mon Sep 17 00:00:00 2001 From: Ondrej Kozina Date: Thu, 11 Feb 2021 12:17:02 +0100 Subject: [PATCH 6/9] Replace bogus cipher_null keyslots before reencryption. By mistake LUKS2 allowed keyslots 'not-so-encrypted' by cipher_null (only explicitly requested by --cipher or --keyslot-cipher parameters). If we encounter such old key during reencryption let's replace the cipher for new keyslot with default LUKS2 keyslot cipher. --- src/cryptsetup.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/cryptsetup.c b/src/cryptsetup.c index 957c24e..5e22286 100644 --- a/src/cryptsetup.c +++ b/src/cryptsetup.c @@ -1091,6 +1091,12 @@ static int set_keyslot_params(struct crypt_device *cd, int keyslot) if (!cipher) return -EINVAL; + if (crypt_is_cipher_null(cipher)) { + log_dbg("Keyslot %d uses cipher_null. Replacing with default encryption in new keyslot.", keyslot); + cipher = DEFAULT_LUKS2_KEYSLOT_CIPHER; + key_size = DEFAULT_LUKS2_KEYSLOT_KEYBITS / 8; + } + if (crypt_keyslot_set_encryption(cd, cipher, key_size)) return -EINVAL; -- 1.8.3.1 diff -rupN cryptsetup-2.3.3.orig/lib/luks2/luks2_reencrypt.c cryptsetup-2.3.3/lib/luks2/luks2_reencrypt.c --- cryptsetup-2.3.3.orig/lib/luks2/luks2_reencrypt.c 2021-02-17 18:03:49.547065362 +0100 +++ cryptsetup-2.3.3/lib/luks2/luks2_reencrypt.c 2021-02-17 18:09:43.610710202 +0100 @@ -2238,7 +2238,7 @@ static int reencrypt_verify_and_upload_k if (LUKS2_digest_verify_by_digest(cd, hdr, digest_new, vk) != digest_new) return -EINVAL; - if (crypt_use_keyring_for_vk(cd) && + if (crypt_use_keyring_for_vk(cd) && !crypt_is_cipher_null(reencrypt_segment_cipher_new(hdr)) && (r = LUKS2_volume_key_load_in_keyring_by_digest(cd, hdr, vk, crypt_volume_key_get_id(vk)))) return r; } @@ -2254,7 +2254,7 @@ static int reencrypt_verify_and_upload_k r = -EINVAL; goto err; } - if (crypt_use_keyring_for_vk(cd) && + if (crypt_use_keyring_for_vk(cd) && !crypt_is_cipher_null(reencrypt_segment_cipher_old(hdr)) && (r = LUKS2_volume_key_load_in_keyring_by_digest(cd, hdr, vk, crypt_volume_key_get_id(vk)))) goto err; } @@ -2664,6 +2664,7 @@ static int reencrypt_load_by_passphrase( struct luks2_hdr *hdr; struct crypt_lock_handle *reencrypt_lock; struct luks2_reenc_context *rh; + const struct volume_key *vk; struct crypt_dm_active_device dmd_target, dmd_source = { .uuid = crypt_get_uuid(cd), .flags = CRYPT_ACTIVATE_SHARED /* turn off exclusive open checks */ @@ -2730,6 +2731,19 @@ static int reencrypt_load_by_passphrase( goto err; flags = dmd_target.flags; + /* + * By default reencryption code aims to retain flags from existing dm device. + * The keyring activation flag can not be inherited if original cipher is null. + * + * In this case override the flag based on decision made in reencrypt_verify_and_upload_keys + * above. The code checks if new VK is eligible for keyring. + */ + vk = crypt_volume_key_by_id(*vks, LUKS2_reencrypt_digest_new(hdr)); + if (vk && vk->key_description && crypt_is_cipher_null(reencrypt_segment_cipher_old(hdr))) { + flags |= CRYPT_ACTIVATE_KEYRING_KEY; + dmd_source.flags |= CRYPT_ACTIVATE_KEYRING_KEY; + } + r = LUKS2_assembly_multisegment_dmd(cd, hdr, *vks, LUKS2_get_segments_jobj(hdr), &dmd_source); if (!r) { r = crypt_compare_dm_devices(cd, &dmd_source, &dmd_target); diff -rupN cryptsetup-2.3.3.orig/src/cryptsetup.c cryptsetup-2.3.3/src/cryptsetup.c --- cryptsetup-2.3.3.orig/src/cryptsetup.c 2021-02-17 18:12:12.162561190 +0100 +++ cryptsetup-2.3.3/src/cryptsetup.c 2021-02-17 18:19:04.842147234 +0100 @@ -3142,6 +3142,11 @@ static int action_reencrypt_luks2(struct _set_reencryption_flags(¶ms.flags); + if (!opt_cipher && crypt_is_cipher_null(crypt_get_cipher(cd))) { + log_std(_("Switching data encryption cipher to %s.\n"), DEFAULT_CIPHER(LUKS1)); + opt_cipher = DEFAULT_CIPHER(LUKS1); + } + if (!opt_cipher) { strncpy(cipher, crypt_get_cipher(cd), MAX_CIPHER_LEN - 1); strncpy(mode, crypt_get_cipher_mode(cd), MAX_CIPHER_LEN - 1); diff -rupN cryptsetup-2.3.3.orig/tests/luks2-reencryption-test cryptsetup-2.3.3/tests/luks2-reencryption-test --- cryptsetup-2.3.3.orig/tests/luks2-reencryption-test 2021-02-17 18:25:01.393788684 +0100 +++ cryptsetup-2.3.3/tests/luks2-reencryption-test 2021-02-17 18:26:00.864726663 +0100 @@ -1388,9 +1388,9 @@ $CRYPTSETUP close $DEV_NAME echo $PWD1 | $CRYPTSETUP -q luksFormat --type luks1 -s 128 -c cipher_null-ecb --offset 8192 $FAST_PBKDF2 $DEV || fail $CRYPTSETUP convert -q --type luks2 $DEV || fail wipe $PWD1 -echo $PWD1 | $CRYPTSETUP reencrypt $DEV -c aes-xts-plain64 -q $FAST_PBKDF_ARGON || fail +echo $PWD1 | $CRYPTSETUP reencrypt $DEV -q $FAST_PBKDF_ARGON >/dev/null || fail check_hash $PWD1 $HASH1 -# both keyslot and segment cipher must not be null +# both keyslot and segment cipher must not be null after reencryption with default params $CRYPTSETUP luksDump $DEV | grep -q "cipher_null" && fail remove_mapping From 030d50f6baff62466c611c868d860c6c3a3efef9 Mon Sep 17 00:00:00 2001 From: Ondrej Kozina Date: Wed, 17 Feb 2021 15:00:19 +0100 Subject: [PATCH] Fix reencryption test on systems w/o keyring. --- tests/luks2-reencryption-test | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/tests/luks2-reencryption-test b/tests/luks2-reencryption-test index 51b5473..6e6b381 100755 --- a/tests/luks2-reencryption-test +++ b/tests/luks2-reencryption-test @@ -654,6 +654,18 @@ function reencrypt_online_fixed_size() { fi } +function setup_luks2_env() { + echo $PWD1 | $CRYPTSETUP luksFormat --type luks2 $FAST_PBKDF_ARGON $DEV || fail + echo $PWD1 | $CRYPTSETUP open $DEV $DEV_NAME || fail + HAVE_KEYRING=$($CRYPTSETUP status $DEV_NAME | grep "key location: keyring") + if [ -n "$HAVE_KEYRING" ]; then + HAVE_KEYRING=1 + else + HAVE_KEYRING=0 + fi + $CRYPTSETUP close $DEV_NAME || fail +} + function valgrind_setup() { which valgrind >/dev/null 2>&1 || fail "Cannot find valgrind." @@ -705,9 +717,11 @@ HASH7=18a393d1a505e22ccf3e29effe3005ea8627e4c36b7cca0e53f58121f49b67e1 # 60 MiBs of zeroes HASH8=cf5ac69ca412f9b3b1a8b8de27d368c5c05ed4b1b6aa40e6c38d9cbf23711342 +prepare dev_size_mb=32 +setup_luks2_env + echo "[1] Reencryption" echo -n "[512 sector]" -prepare dev_size_mb=32 echo $PWD1 | $CRYPTSETUP -q luksFormat --type luks2 -s 128 -c aes-cbc-essiv:sha256 --offset 8192 $FAST_PBKDF_ARGON $DEV || fail wipe $PWD1 check_hash $PWD1 $HASH1 @@ -1412,7 +1426,9 @@ wipe $PWD1 echo $PWD1 | $CRYPTSETUP open $DEV $DEV_NAME echo $PWD1 | $CRYPTSETUP reencrypt $DEV -c aes-xts-plain64 -q $FAST_PBKDF_ARGON || fail check_hash_dev /dev/mapper/$DEV_NAME $HASH1 -$CRYPTSETUP status $DEV_NAME | grep -q "key location: keyring" || fail +if [ $HAVE_KEYRING -gt 0 ]; then + $CRYPTSETUP status $DEV_NAME | grep -q "key location: keyring" || fail +fi $CRYPTSETUP close $DEV_NAME # simulate LUKS2 device with cipher_null in both keyslot and segment (it can be created only by up conversion from LUKS1) -- 1.8.3.1 diff -rupN cryptsetup-2.3.3.orig/src/cryptsetup.c cryptsetup-2.3.3/src/cryptsetup.c --- cryptsetup-2.3.3.orig/src/cryptsetup.c 2021-02-18 12:37:44.903909498 +0100 +++ cryptsetup-2.3.3/src/cryptsetup.c 2021-02-18 12:45:49.208492236 +0100 @@ -1196,6 +1196,21 @@ static int strcmp_or_null(const char *st return !str ? 0 : strcmp(str, expected); } +static int get_adjusted_key_size(const char *cipher_mode, uint32_t default_size_bits, int integrity_keysize) +{ + int keysize_bits = opt_key_size; + +#ifdef ENABLE_LUKS_ADJUST_XTS_KEYSIZE + if (!opt_key_size && !strncmp(cipher_mode, "xts-", 4)) { + if (default_size_bits == 128) + keysize_bits = 256; + else if (default_size_bits == 256) + keysize_bits = 512; + } +#endif + return (keysize_bits ?: default_size_bits) / 8 + integrity_keysize; +} + static int _luksFormat(struct crypt_device **r_cd, char **r_password, size_t *r_passwordLen) { int r = -EINVAL, keysize, integrity_keysize = 0, fd, created = 0; @@ -1328,15 +1343,7 @@ static int _luksFormat(struct crypt_devi goto out; } -#ifdef ENABLE_LUKS_ADJUST_XTS_KEYSIZE - if (!opt_key_size && !strncmp(cipher_mode, "xts-", 4)) { - if (DEFAULT_LUKS1_KEYBITS == 128) - opt_key_size = 256; - else if (DEFAULT_LUKS1_KEYBITS == 256) - opt_key_size = 512; - } -#endif - keysize = (opt_key_size ?: DEFAULT_LUKS1_KEYBITS) / 8 + integrity_keysize; + keysize = get_adjusted_key_size(cipher_mode, DEFAULT_LUKS1_KEYBITS, integrity_keysize); if (opt_random) crypt_set_rng_type(cd, CRYPT_RNG_RANDOM); @@ -3163,10 +3170,8 @@ static int action_reencrypt_luks2(struct if (r) return r; - if (opt_key_size) - key_size = opt_key_size / 8; - else if (opt_cipher) - key_size = DEFAULT_LUKS1_KEYBITS / 8; + if (opt_key_size || opt_cipher) + key_size = get_adjusted_key_size(mode, DEFAULT_LUKS1_KEYBITS, 0); else key_size = crypt_get_volume_key_size(cd); diff -rupN cryptsetup-2.3.3.orig/tests/luks2-reencryption-test cryptsetup-2.3.3/tests/luks2-reencryption-test --- cryptsetup-2.3.3.orig/tests/luks2-reencryption-test 2021-02-18 12:37:44.916909486 +0100 +++ cryptsetup-2.3.3/tests/luks2-reencryption-test 2021-02-18 12:39:33.589815857 +0100 @@ -648,7 +648,7 @@ function reencrypt_online_fixed_size() { } function setup_luks2_env() { - echo $PWD1 | $CRYPTSETUP luksFormat --type luks2 $FAST_PBKDF_ARGON $DEV || fail + echo $PWD1 | $CRYPTSETUP luksFormat --type luks2 -c aes-xts-plain64 $FAST_PBKDF_ARGON $DEV || fail echo $PWD1 | $CRYPTSETUP open $DEV $DEV_NAME || fail HAVE_KEYRING=$($CRYPTSETUP status $DEV_NAME | grep "key location: keyring") if [ -n "$HAVE_KEYRING" ]; then @@ -656,6 +656,8 @@ function setup_luks2_env() { else HAVE_KEYRING=0 fi + DEF_XTS_KEY=$($CRYPTSETUP status $DEV_NAME | grep "keysize:" | sed 's/\( keysize: \)\([0-9]\+\)\(.*\)/\2/') + [ -n "$DEF_XTS_KEY" ] || fail "Failed to parse xts mode key size." $CRYPTSETUP close $DEV_NAME || fail } @@ -730,6 +732,8 @@ check_hash $PWD1 $HASH1 echo $PWD1 | $CRYPTSETUP reencrypt $DEV -q -c aes-xts-plain64 --init-only $FAST_PBKDF_ARGON || fail echo $PWD1 | $CRYPTSETUP open $DEV $DEV_NAME || fail echo $PWD1 | $CRYPTSETUP reencrypt --active-name /dev/mapper/$DEV_NAME --resilience none -q || fail +XTS_KEY=$($CRYPTSETUP status $DEV_NAME | grep "keysize:" | sed 's/\( keysize: \)\([0-9]\+\)\(.*\)/\2/') +[ "$XTS_KEY" -eq "$DEF_XTS_KEY" ] || fail "xts mode has wrong key size after reencryption ($XTS_KEY != expected $DEF_XTS_KEY)" echo $PWD1 | $CRYPTSETUP close $DEV_NAME || fail echo -n "[OK][4096 sector]" prepare sector_size=4096 dev_size_mb=32 diff -rupN cryptsetup-2.3.3.orig/lib/libdevmapper.c cryptsetup-2.3.3/lib/libdevmapper.c --- cryptsetup-2.3.3.orig/lib/libdevmapper.c 2021-02-18 16:21:00.863470374 +0100 +++ cryptsetup-2.3.3/lib/libdevmapper.c 2021-02-18 16:22:36.330393562 +0100 @@ -639,11 +639,13 @@ static char *get_dm_crypt_params(const s if (!strncmp(cipher_dm, "cipher_null-", 12)) null_cipher = 1; - if (flags & CRYPT_ACTIVATE_KEYRING_KEY) { + if (null_cipher) + hexkey = crypt_safe_alloc(2); + else if (flags & CRYPT_ACTIVATE_KEYRING_KEY) { keystr_len = strlen(tgt->u.crypt.vk->key_description) + int_log10(tgt->u.crypt.vk->keylength) + 10; hexkey = crypt_safe_alloc(keystr_len); } else - hexkey = crypt_safe_alloc(null_cipher ? 2 : (tgt->u.crypt.vk->keylength * 2 + 1)); + hexkey = crypt_safe_alloc(tgt->u.crypt.vk->keylength * 2 + 1); if (!hexkey) return NULL; From 284a49443e2a833e33714f9fa0f03b8e0233d68d Mon Sep 17 00:00:00 2001 From: Ondrej Kozina Date: Thu, 18 Feb 2021 15:01:01 +0100 Subject: [PATCH 3/3] Extend LUKS2 reencryption tests w/ cipher_null. --- tests/luks2-reencryption-test | 106 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 104 insertions(+), 2 deletions(-) diff --git a/tests/luks2-reencryption-test b/tests/luks2-reencryption-test index 9bdf60a..05c2151 100755 --- a/tests/luks2-reencryption-test +++ b/tests/luks2-reencryption-test @@ -297,7 +297,7 @@ function reencrypt_recover() { # $1 sector size, $2 resilience, $3 digest, [$4 h test -z "$4" || _hdr="--header $4" error_writes $OVRDEV $OLD_DEV $ERROFFSET $ERRLENGTH - echo $PWD1 | $CRYPTSETUP reencrypt $DEV $_hdr --hotzone-size 1M --resilience $2 --sector-size $1 -q $FAST_PBKDF_ARGON 2>/dev/null && fail + echo $PWD1 | $CRYPTSETUP reencrypt $DEV $_hdr --hotzone-size 1M --resilience $2 --sector-size $1 -q $FAST_PBKDF_ARGON >/dev/null 2>&1 && fail fix_writes $OVRDEV $OLD_DEV echo $PWD1 | $CRYPTSETUP -q repair $DEV $_hdr || fail @@ -318,7 +318,7 @@ function reencrypt_recover_online() { # $1 sector size, $2 resilience, $3 digest echo $PWD1 | $CRYPTSETUP open $DEV $_hdr $DEV_NAME || fail error_writes $OVRDEV $OLD_DEV $ERROFFSET $ERRLENGTH - echo $PWD1 | $CRYPTSETUP reencrypt --active-name $DEV_NAME $_hdr --hotzone-size 1M --resilience $2 --sector-size $1 -q $FAST_PBKDF_ARGON 2>/dev/null && fail + echo $PWD1 | $CRYPTSETUP reencrypt --active-name $DEV_NAME $_hdr --hotzone-size 1M --resilience $2 --sector-size $1 -q $FAST_PBKDF_ARGON >/dev/null 2>&1 && fail $CRYPTSETUP status $DEV_NAME $_hdr | grep -q "reencryption: in-progress" || fail $CRYPTSETUP close $DEV_NAME || fail fix_writes $OVRDEV $OLD_DEV @@ -1444,5 +1444,107 @@ check_hash $PWD1 $HASH1 # both keyslot and segment cipher must not be null after reencryption with default params $CRYPTSETUP luksDump $DEV | grep -q "cipher_null" && fail +# multistep reencryption with initial cipher_null +preparebig 64 +echo $PWD1 | $CRYPTSETUP luksFormat --type luks2 $DEV -c null --offset 16384 -q $FAST_PBKDF_ARGON || fail +echo $PWD1 | $CRYPTSETUP open $DEV $DEV_NAME +wipe_dev /dev/mapper/$DEV_NAME +echo $PWD1 | $CRYPTSETUP reencrypt $DEV --hotzone-size 1M --resilience none -q $FAST_PBKDF_ARGON >/dev/null || fail +$CRYPTSETUP close $DEV_NAME +check_hash $PWD1 $HASH5 + +echo $PWD1 | $CRYPTSETUP luksFormat --type luks2 $DEV -c null --offset 16384 -q $FAST_PBKDF_ARGON || fail +wipe $PWD1 +echo $PWD1 | $CRYPTSETUP reencrypt $DEV --hotzone-size 1M --resilience none -q $FAST_PBKDF_ARGON >/dev/null || fail +check_hash $PWD1 $HASH5 + +echo "[25] Reencryption recovery with cipher_null" +# (check opt-io size optimization in reencryption code does not affect recovery) +# device with opt-io size 32k +prepare_linear_dev 32 opt_blks=64 $OPT_XFERLEN_EXP +OFFSET=8192 + +echo "sector size 512->512" + +get_error_offsets 32 $OFFSET +echo $PWD1 | $CRYPTSETUP -q luksFormat --type luks2 -c null --sector-size 512 --offset $OFFSET $FAST_PBKDF_ARGON $DEV || fail +wipe $PWD1 +check_hash $PWD1 $HASH1 + +echo "ERR writes to sectors [$ERROFFSET,$(($ERROFFSET+$ERRLENGTH-1))]" +reencrypt_recover 512 checksum $HASH1 +echo $PWD1 | $CRYPTSETUP -q luksFormat --type luks2 -c null --sector-size 512 --offset $OFFSET $FAST_PBKDF_ARGON $DEV || fail +wipe $PWD1 +reencrypt_recover 512 journal $HASH1 + +if [ -n "$DM_SECTOR_SIZE" ]; then + echo "sector size 512->4096" + + get_error_offsets 32 $OFFSET 4096 + echo $PWD1 | $CRYPTSETUP -q luksFormat --type luks2 -c null --sector-size 512 --offset $OFFSET $FAST_PBKDF_ARGON $DEV || fail + wipe $PWD1 + check_hash $PWD1 $HASH1 + + echo "ERR writes to sectors [$ERROFFSET,$(($ERROFFSET+$ERRLENGTH-1))]" + reencrypt_recover 4096 checksum $HASH1 + echo $PWD1 | $CRYPTSETUP -q luksFormat --type luks2 -c null --sector-size 512 --offset $OFFSET $FAST_PBKDF_ARGON $DEV || fail + wipe $PWD1 + check_hash $PWD1 $HASH1 + reencrypt_recover 4096 journal $HASH1 + + echo "sector size 4096->4096" + + get_error_offsets 32 $OFFSET 4096 + echo $PWD1 | $CRYPTSETUP -q luksFormat --type luks2 -c null --sector-size 4096 -c aes-cbc-essiv:sha256 --offset $OFFSET $FAST_PBKDF_ARGON $DEV || fail + wipe $PWD1 + check_hash $PWD1 $HASH1 + + echo "ERR writes to sectors [$ERROFFSET,$(($ERROFFSET+$ERRLENGTH-1))]" + reencrypt_recover 4096 checksum $HASH1 + reencrypt_recover 4096 journal $HASH1 +fi + +echo "[26] Reencryption recovery with cipher_null (online i/o error)" + +echo "sector size 512->512" + +get_error_offsets 32 $OFFSET +echo $PWD1 | $CRYPTSETUP -q luksFormat --type luks2 --sector-size 512 -c null --offset $OFFSET $FAST_PBKDF_ARGON $DEV || fail +wipe $PWD1 +check_hash $PWD1 $HASH1 + +echo "ERR writes to sectors [$ERROFFSET,$(($ERROFFSET+$ERRLENGTH-1))]" +reencrypt_recover_online 512 checksum $HASH1 +echo $PWD1 | $CRYPTSETUP -q luksFormat --type luks2 --sector-size 512 -c null --offset $OFFSET $FAST_PBKDF_ARGON $DEV || fail +wipe $PWD1 +reencrypt_recover_online 512 journal $HASH1 + +if [ -n "$DM_SECTOR_SIZE" ]; then + echo "sector size 512->4096" + + get_error_offsets 32 $OFFSET 4096 + echo $PWD1 | $CRYPTSETUP -q luksFormat --type luks2 -c null --sector-size 512 --offset $OFFSET $FAST_PBKDF_ARGON $DEV || fail + wipe $PWD1 + check_hash $PWD1 $HASH1 + + echo "ERR writes to sectors [$ERROFFSET,$(($ERROFFSET+$ERRLENGTH-1))]" + reencrypt_recover_online 4096 checksum $HASH1 + echo $PWD1 | $CRYPTSETUP -q luksFormat --type luks2 -c null --sector-size 512 --offset $OFFSET $FAST_PBKDF_ARGON $DEV || fail + wipe $PWD1 + check_hash $PWD1 $HASH1 + reencrypt_recover_online 4096 journal $HASH1 + + echo "sector size 4096->4096" + + get_error_offsets 32 $OFFSET 4096 + echo $PWD1 | $CRYPTSETUP -q luksFormat --type luks2 -c null --sector-size 4096 -c aes-cbc-essiv:sha256 --offset $OFFSET $FAST_PBKDF_ARGON $DEV || fail + wipe $PWD1 + check_hash $PWD1 $HASH1 + + echo "ERR writes to sectors [$ERROFFSET,$(($ERROFFSET+$ERRLENGTH-1))]" + reencrypt_recover_online 4096 checksum $HASH1 + reencrypt_recover_online 4096 journal $HASH1 +fi + remove_mapping exit 0 -- 1.8.3.1