diff --git a/SOURCES/cryptsetup-2.3.4-fix-crypto-backend-to-properly-handle-ECB-mode.patch b/SOURCES/cryptsetup-2.3.4-fix-crypto-backend-to-properly-handle-ECB-mode.patch new file mode 100644 index 0000000..8fdfda0 --- /dev/null +++ b/SOURCES/cryptsetup-2.3.4-fix-crypto-backend-to-properly-handle-ECB-mode.patch @@ -0,0 +1,48 @@ +From f3906957675e466bbe7fa97a725f56c7c494d4a5 Mon Sep 17 00:00:00 2001 +From: Milan Broz +Date: Tue, 21 Jul 2020 14:14:54 +0200 +Subject: [PATCH] Fix crypto backend to properly handle ECB mode. + +Despite it should be never used, it should still work :) + +Bug introduced in version 2.3.2. +--- + lib/crypto_backend/crypto_storage.c | 2 +- + tests/compat-test2 | 9 +++++++++ + 2 files changed, 10 insertions(+), 1 deletion(-) + +diff --git a/lib/crypto_backend/crypto_storage.c b/lib/crypto_backend/crypto_storage.c +index 8b6c19c..92dbae7 100644 +--- a/lib/crypto_backend/crypto_storage.c ++++ b/lib/crypto_backend/crypto_storage.c +@@ -64,7 +64,7 @@ static int crypt_sector_iv_init(struct crypt_sector_iv *ctx, + memset(ctx, 0, sizeof(*ctx)); + + ctx->iv_size = crypt_cipher_ivsize(cipher_name, mode_name); +- if (ctx->iv_size < 8) ++ if (ctx->iv_size < 0 || (strcmp(mode_name, "ecb") && ctx->iv_size < 8)) + return -ENOENT; + + if (!strcmp(cipher_name, "cipher_null") || +diff --git a/tests/compat-test2 b/tests/compat-test2 +index 0fad999..c3852cd 100755 +--- a/tests/compat-test2 ++++ b/tests/compat-test2 +@@ -1023,5 +1023,14 @@ echo $PWD3 | $CRYPTSETUP luksConvertKey --key-slot 22 $LOOPDEV --keyslot-cipher + [ "$($CRYPTSETUP luksDump $IMG | grep -A8 -m1 "22: luks2" | grep "Cipher:" | sed -e 's/[[:space:]]\+Cipher:\ \+//g')" = $KEYSLOT_CIPHER ] || fail + [ "$($CRYPTSETUP luksDump $IMG | grep -A8 -m1 "22: luks2" | grep "Cipher key:"| sed -e 's/[[:space:]]\+Cipher\ key:\ \+//g')" = "128 bits" ] || fail + ++prepare "[42] Some encryption compatibility mode tests" wipe ++CIPHERS="aes-ecb aes-cbc-null aes-cbc-plain64 aes-cbc-essiv:sha256 aes-xts-plain64" ++key_size=256 ++for cipher in $CIPHERS ; do ++ echo -n "[$cipher/$key_size]" ++ $CRYPTSETUP -q luksFormat --type luks2 $LOOPDEV $KEY1 $FAST_PBKDF_OPT --cipher $cipher --key-size $key_size || fail ++done ++echo ++ + remove_mapping + exit 0 +-- +1.8.3.1 + diff --git a/SOURCES/cryptsetup-2.3.4-luks2-validation-32bit-fix.patch b/SOURCES/cryptsetup-2.3.4-luks2-validation-32bit-fix.patch new file mode 100644 index 0000000..f708ba9 --- /dev/null +++ b/SOURCES/cryptsetup-2.3.4-luks2-validation-32bit-fix.patch @@ -0,0 +1,341 @@ +From 52f5cb8cedf22fb3e14c744814ec8af7614146c7 Mon Sep 17 00:00:00 2001 +From: Tobias Stoeckmann +Date: Mon, 24 Aug 2020 19:21:43 +0200 +Subject: [PATCH 01/11] Check segment gaps regardless of heap space. + +Segments are validated in hdr_validate_segments. Gaps in segment keys +are detected when collecting offsets. But if an invalid segment is very +large, larger than count, it could happen that cryptsetup is unable to +allocate enough memory, not giving a clue about what actually is the +problem. + +Therefore check for gaps even if not enough memory is available. This +gives much more information with debug output enabled. + +Obviously cryptsetup still fails if segments are perfectly fine but not +enough RAM available. But at that stage, the user knows that it's the +fault of the system, not of an invalid segment. +--- + lib/luks2/luks2_json_metadata.c | 19 ++++++++++++------- + 1 file changed, 12 insertions(+), 7 deletions(-) + +diff --git a/lib/luks2/luks2_json_metadata.c b/lib/luks2/luks2_json_metadata.c +index 23556f2..ea5c7f7 100644 +--- a/lib/luks2/luks2_json_metadata.c ++++ b/lib/luks2/luks2_json_metadata.c +@@ -679,11 +679,10 @@ static int hdr_validate_segments(struct crypt_device *cd, json_object *hdr_jobj) + if (first_backup < 0) + first_backup = count; + +- intervals = malloc(first_backup * sizeof(*intervals)); +- if (!intervals) { +- log_dbg(cd, "Not enough memory."); +- return 1; +- } ++ if (first_backup <= count && (size_t)first_backup < SIZE_MAX / sizeof(*intervals)) ++ intervals = malloc(first_backup * sizeof(*intervals)); ++ else ++ intervals = NULL; + + for (i = 0; i < first_backup; i++) { + jobj = json_segments_get_segment(jobj_segments, i); +@@ -692,8 +691,14 @@ static int hdr_validate_segments(struct crypt_device *cd, json_object *hdr_jobj) + free(intervals); + return 1; + } +- intervals[i].offset = json_segment_get_offset(jobj, 0); +- intervals[i].length = json_segment_get_size(jobj, 0) ?: UINT64_MAX; ++ if (intervals != NULL) { ++ intervals[i].offset = json_segment_get_offset(jobj, 0); ++ intervals[i].length = json_segment_get_size(jobj, 0) ?: UINT64_MAX; ++ } ++ } ++ if (intervals == NULL) { ++ log_dbg(cd, "Not enough memory."); ++ return 1; + } + + r = !validate_segment_intervals(cd, first_backup, intervals); +-- +1.8.3.1 + +From 46ee71edcd13e1dad50815ad65c28779aa6f7503 Mon Sep 17 00:00:00 2001 +From: Ondrej Kozina +Date: Tue, 25 Aug 2020 19:32:48 +0200 +Subject: [PATCH 07/11] Avoid needlessly large allocations in LUKS2 validation + code. + +In case LUKS2 backup segment creates gap in between last regular +segment and backup segment report invalid metadata imediately. We stop +on first error so there's no need to allocate large memory on heap +(we may ran with mlock(MCL_FUTURE) set). + +Example: +- total segments count is 3 +- regular segments have keys "0" and "1" +- first backup segment has key "42" +--- + lib/luks2/luks2_json_metadata.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/lib/luks2/luks2_json_metadata.c b/lib/luks2/luks2_json_metadata.c +index ea5c7f7..5b73b34 100644 +--- a/lib/luks2/luks2_json_metadata.c ++++ b/lib/luks2/luks2_json_metadata.c +@@ -676,10 +676,16 @@ static int hdr_validate_segments(struct crypt_device *cd, json_object *hdr_jobj) + return 1; + } + ++ /* avoid needlessly large allocation when first backup segment is invalid */ ++ if (first_backup >= count) { ++ log_dbg(cd, "Gap between last regular segment and backup segment at key %d.", first_backup); ++ return 1; ++ } ++ + if (first_backup < 0) + first_backup = count; + +- if (first_backup <= count && (size_t)first_backup < SIZE_MAX / sizeof(*intervals)) ++ if ((size_t)first_backup < SIZE_MAX / sizeof(*intervals)) + intervals = malloc(first_backup * sizeof(*intervals)); + else + intervals = NULL; +-- +1.8.3.1 + +From 752c9a52798f11d3b765b673ebaa3058eb25316e Mon Sep 17 00:00:00 2001 +From: Ondrej Kozina +Date: Tue, 25 Aug 2020 19:23:21 +0200 +Subject: [PATCH 08/11] Simplify validation code a bit. + +Keep it simple. If there's not enough memory we can't validate +segments. The LUKS2 specification does not recommend to continue +processing LUKS2 metadata if it can not be properly validated. +--- + lib/luks2/luks2_json_metadata.c | 19 ++++++++----------- + 1 file changed, 8 insertions(+), 11 deletions(-) + +diff --git a/lib/luks2/luks2_json_metadata.c b/lib/luks2/luks2_json_metadata.c +index 5b73b34..df89401 100644 +--- a/lib/luks2/luks2_json_metadata.c ++++ b/lib/luks2/luks2_json_metadata.c +@@ -594,9 +594,9 @@ static bool validate_segment_intervals(struct crypt_device *cd, + static int hdr_validate_segments(struct crypt_device *cd, json_object *hdr_jobj) + { + json_object *jobj_segments, *jobj_digests, *jobj_offset, *jobj_size, *jobj_type, *jobj_flags, *jobj; +- struct interval *intervals; + uint64_t offset, size; + int i, r, count, first_backup = -1; ++ struct interval *intervals = NULL; + + if (!json_object_object_get_ex(hdr_jobj, "segments", &jobj_segments)) { + log_dbg(cd, "Missing segments section."); +@@ -687,8 +687,11 @@ static int hdr_validate_segments(struct crypt_device *cd, json_object *hdr_jobj) + + if ((size_t)first_backup < SIZE_MAX / sizeof(*intervals)) + intervals = malloc(first_backup * sizeof(*intervals)); +- else +- intervals = NULL; ++ ++ if (!intervals) { ++ log_dbg(cd, "Not enough memory."); ++ return 1; ++ } + + for (i = 0; i < first_backup; i++) { + jobj = json_segments_get_segment(jobj_segments, i); +@@ -697,14 +700,8 @@ static int hdr_validate_segments(struct crypt_device *cd, json_object *hdr_jobj) + free(intervals); + return 1; + } +- if (intervals != NULL) { +- intervals[i].offset = json_segment_get_offset(jobj, 0); +- intervals[i].length = json_segment_get_size(jobj, 0) ?: UINT64_MAX; +- } +- } +- if (intervals == NULL) { +- log_dbg(cd, "Not enough memory."); +- return 1; ++ intervals[i].offset = json_segment_get_offset(jobj, 0); ++ intervals[i].length = json_segment_get_size(jobj, 0) ?: UINT64_MAX; + } + + r = !validate_segment_intervals(cd, first_backup, intervals); +-- +1.8.3.1 + +From 96da06430b6f5c2588c619082f2c5880df9cc776 Mon Sep 17 00:00:00 2001 +From: Ondrej Kozina +Date: Wed, 26 Aug 2020 17:24:05 +0200 +Subject: [PATCH 09/11] Add test for LUKS2 segments validation code fix. + +--- + ...enerate-luks2-segment-wrong-backup-key-0.img.sh | 67 ++++++++++++++++++++++ + ...enerate-luks2-segment-wrong-backup-key-1.img.sh | 67 ++++++++++++++++++++++ + tests/luks2-validation-test | 2 + + 3 files changed, 136 insertions(+) + create mode 100755 tests/generators/generate-luks2-segment-wrong-backup-key-0.img.sh + create mode 100755 tests/generators/generate-luks2-segment-wrong-backup-key-1.img.sh + +diff --git a/tests/generators/generate-luks2-segment-wrong-backup-key-0.img.sh b/tests/generators/generate-luks2-segment-wrong-backup-key-0.img.sh +new file mode 100755 +index 0000000..2499a5e +--- /dev/null ++++ b/tests/generators/generate-luks2-segment-wrong-backup-key-0.img.sh +@@ -0,0 +1,67 @@ ++#!/bin/bash ++ ++. lib.sh ++ ++# ++# *** Description *** ++# ++# generate primary header with wrong backup segment id ++# ++# secondary header is corrupted on purpose as well ++# ++ ++# $1 full target dir ++# $2 full source luks2 image ++ ++function prepare() ++{ ++ cp $SRC_IMG $TGT_IMG ++ test -d $TMPDIR || mkdir $TMPDIR ++ read_luks2_json0 $TGT_IMG $TMPDIR/json0 ++ read_luks2_bin_hdr0 $TGT_IMG $TMPDIR/hdr0 ++ read_luks2_bin_hdr1 $TGT_IMG $TMPDIR/hdr1 ++} ++ ++function generate() ++{ ++ # create illegal backup segment key (used to be bug in 32bit implementations) ++ json_str=$(jq -c '.segments[(.segments | length + 1 | tostring)] = { "type" : "linear", "offset" : "512", "size" : "512", "flags":["backup-x"]}' $TMPDIR/json0) ++ test ${#json_str} -lt $((LUKS2_JSON_SIZE*512)) || exit 2 ++ ++ write_luks2_json "$json_str" $TMPDIR/json0 ++ ++ merge_bin_hdr_with_json $TMPDIR/hdr0 $TMPDIR/json0 $TMPDIR/area0 ++ erase_checksum $TMPDIR/area0 ++ chks0=$(calc_sha256_checksum_file $TMPDIR/area0) ++ write_checksum $chks0 $TMPDIR/area0 ++ write_luks2_hdr0 $TMPDIR/area0 $TGT_IMG ++ kill_bin_hdr $TMPDIR/hdr1 ++ write_luks2_hdr1 $TMPDIR/hdr1 $TGT_IMG ++} ++ ++function check() ++{ ++ read_luks2_bin_hdr1 $TGT_IMG $TMPDIR/hdr_res1 ++ local str_res1=$(head -c 6 $TMPDIR/hdr_res1) ++ test "$str_res1" = "VACUUM" || exit 2 ++ ++ read_luks2_json0 $TGT_IMG $TMPDIR/json_res0 ++ jq -c 'if .segments | length < 2 ++ then error("Unexpected segments count") else empty end' $TMPDIR/json_res0 || exit 5 ++} ++ ++function cleanup() ++{ ++ rm -f $TMPDIR/* ++ rm -fd $TMPDIR ++} ++ ++test $# -eq 2 || exit 1 ++ ++TGT_IMG=$1/$(test_img_name $0) ++SRC_IMG=$2 ++ ++prepare ++generate ++check ++cleanup +diff --git a/tests/generators/generate-luks2-segment-wrong-backup-key-1.img.sh b/tests/generators/generate-luks2-segment-wrong-backup-key-1.img.sh +new file mode 100755 +index 0000000..702fe71 +--- /dev/null ++++ b/tests/generators/generate-luks2-segment-wrong-backup-key-1.img.sh +@@ -0,0 +1,67 @@ ++#!/bin/bash ++ ++. lib.sh ++ ++# ++# *** Description *** ++# ++# generate primary header with wrong backup segment id ++# ++# secondary header is corrupted on purpose as well ++# ++ ++# $1 full target dir ++# $2 full source luks2 image ++ ++function prepare() ++{ ++ cp $SRC_IMG $TGT_IMG ++ test -d $TMPDIR || mkdir $TMPDIR ++ read_luks2_json0 $TGT_IMG $TMPDIR/json0 ++ read_luks2_bin_hdr0 $TGT_IMG $TMPDIR/hdr0 ++ read_luks2_bin_hdr1 $TGT_IMG $TMPDIR/hdr1 ++} ++ ++function generate() ++{ ++ # create illegal backup segment key (used to be bug in 32bit implementations) ++ json_str=$(jq -c '(.segments."0".offset | tonumber) as $i | .segments[range(1;65) | tostring] = { "type" : "linear", "offset" : ($i + 512 | tostring), "size" : "512" } | .segments."268435472" = { "type":"linear","offset":"512","size":"512","flags":["backup-x"]}' $TMPDIR/json0) ++ test ${#json_str} -lt $((LUKS2_JSON_SIZE*512)) || exit 2 ++ ++ write_luks2_json "$json_str" $TMPDIR/json0 ++ ++ merge_bin_hdr_with_json $TMPDIR/hdr0 $TMPDIR/json0 $TMPDIR/area0 ++ erase_checksum $TMPDIR/area0 ++ chks0=$(calc_sha256_checksum_file $TMPDIR/area0) ++ write_checksum $chks0 $TMPDIR/area0 ++ write_luks2_hdr0 $TMPDIR/area0 $TGT_IMG ++ kill_bin_hdr $TMPDIR/hdr1 ++ write_luks2_hdr1 $TMPDIR/hdr1 $TGT_IMG ++} ++ ++function check() ++{ ++ read_luks2_bin_hdr1 $TGT_IMG $TMPDIR/hdr_res1 ++ local str_res1=$(head -c 6 $TMPDIR/hdr_res1) ++ test "$str_res1" = "VACUUM" || exit 2 ++ ++ read_luks2_json0 $TGT_IMG $TMPDIR/json_res0 ++ jq -c 'if .segments | length < 64 ++ then error("Unexpected segments count") else empty end' $TMPDIR/json_res0 || exit 5 ++} ++ ++function cleanup() ++{ ++ rm -f $TMPDIR/* ++ rm -fd $TMPDIR ++} ++ ++test $# -eq 2 || exit 1 ++ ++TGT_IMG=$1/$(test_img_name $0) ++SRC_IMG=$2 ++ ++prepare ++generate ++check ++cleanup +diff --git a/tests/luks2-validation-test b/tests/luks2-validation-test +index 52945ba..04183fb 100755 +--- a/tests/luks2-validation-test ++++ b/tests/luks2-validation-test +@@ -199,6 +199,8 @@ RUN luks2-segment-unknown-type.img "R" "Validation rejected segment with all m + RUN luks2-segment-two.img "R" "Validation rejected two valid segments" + RUN luks2-segment-wrong-flags.img "F" "Failed to detect invalid flags field" + RUN luks2-segment-wrong-flags-element.img "F" "Failed to detect invalid flags content" ++RUN luks2-segment-wrong-backup-key-0.img "F" "Failed to detect gap in backup segments" ++RUN luks2-segment-wrong-backup-key-1.img "F" "Failed to detect gap in backup segments" + + echo "[6] Test metadata size and keyslots size (config section)" + RUN luks2-invalid-keyslots-size-c0.img "F" "Failed to detect too large keyslots_size in config section" +-- +1.8.3.1 + diff --git a/SOURCES/cryptsetup-2.3.5-fix-reencryption-cipher_null.patch b/SOURCES/cryptsetup-2.3.5-fix-reencryption-cipher_null.patch new file mode 100644 index 0000000..3db63c1 --- /dev/null +++ b/SOURCES/cryptsetup-2.3.5-fix-reencryption-cipher_null.patch @@ -0,0 +1,769 @@ +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 + diff --git a/SPECS/cryptsetup.spec b/SPECS/cryptsetup.spec index 1f84918..aedeee3 100644 --- a/SPECS/cryptsetup.spec +++ b/SPECS/cryptsetup.spec @@ -5,7 +5,7 @@ Obsoletes: cryptsetup-python3 Summary: A utility for setting up encrypted disks Name: cryptsetup Version: 2.3.3 -Release: 1%{?dist} +Release: 4%{?dist} License: GPLv2+ and LGPLv2+ Group: Applications/System URL: https://gitlab.com/cryptsetup/cryptsetup @@ -23,6 +23,9 @@ Source0: https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/cryptsetup-%{ups Patch0: %{name}-add-system-library-paths.patch # Remove the patch when (if ever) osci infrastructure gets stable enough Patch1: %{name}-disable-verity-compat-test.patch +Patch2: %{name}-2.3.4-luks2-validation-32bit-fix.patch +Patch3: %{name}-2.3.4-fix-crypto-backend-to-properly-handle-ECB-mode.patch +Patch4: %{name}-2.3.5-fix-reencryption-cipher_null.patch %description The cryptsetup package contains a utility for setting up @@ -79,6 +82,9 @@ can be used for offline reencryption of disk in situ. %prep %setup -q -n cryptsetup-%{upstream_version} %patch1 -p1 +%patch2 -p1 +%patch3 -p1 +%patch4 -p1 %patch0 -p1 chmod -x misc/dracut_90reencrypt/* @@ -138,6 +144,20 @@ rm -rf %{buildroot}/%{_libdir}/*.la %clean %changelog +* Wed Feb 17 2021 Ondrej Kozina - 2.3.3-4 +- patch: Fix reencryption for custom devices with data segments + set to use cipher_null. +- Resolves: #1927409 + +* Wed Feb 03 2021 Ondrej Kozina - 2.3.3-3 +- patch: Fix crypto backend to properly handle ECB mode. +- Resolves: #1859091 + +* Thu Aug 27 2020 Ondrej Kozina - 2.3.3-2 +- patch: Fix possible memory corruption in LUKS2 validation + code in 32bit library. +- Resolves: #1872294 + * Thu May 28 2020 Ondrej Kozina - 2.3.3-1 - Update to cryptsetup 2.3.3 - Resolves: #1796826 #1743891 #1785748