On 17.08.2020 13:44, Ingo Franzki wrote: > Hi, > > I just played a little bit with the LUKS2 online reencryption feature (using code from current master). > Works great (as far as I can tell) for clear key (i.e. AES cipher), but it fails for the wrapped key cipher PAES. > > It fails because it always generates a new volume key by random, regardless which cipher is used. > For the PAES cipher, a key generated by random wont work, such a key must be generated by the HSM. > > For 'cryptsetup luksFormat' we use it with a key generated outside of cryptsetup, passing the key via --master-key-file (together with --key-size). > To make 'cryptsetup reencrypt' work with PAES, we would also need to pass in the new key via --master-key-file (and --key-size). > Unfortunately, the reencrypt action does not use the master key file option. > > Function action_reencrypt() calls crypt_keyslot_add_by_key() which then calls crypt_keyslot_add_by_key() but passes NULL as volume key. > Thus a new randomly generated key is used. If the key specified with the master key file options would be passed here, it should work with the PAES cipher also. > > This would not only be beneficial for PAES, but also for clear key AES cipher, allowing to use a specified key as volume key (like with luksFormat). > > If I try to use 'cryptsetup reencrypt' with an existing LUKS2 volume encrypted with PAES it fails as follows: > > # cryptsetup reencrypt /dev/loop0 --debug > ... snip debug messages ... > Enter passphrase for key slot 0: > ... snip debug messages ... > # Checking if cipher paes-cbc-plain64 is usable. > # Userspace crypto wrapper cannot use paes-cbc-plain64 (-22). > Failed to setup dm-crypt key mapping for device /dev/loop0. > Check that kernel supports paes-cbc-plain64 cipher (check syslog for more info). > > This is because function LUKS2_check_cipher() is called which again generates a new volume key to test the cipher by random. > So the code should use 'if (!crypt_cipher_wrapped_key(....))' like it does at other places (e.g. in _crypt_format_luks2() ) to not check the cipher for wrapped key ciphers (PAES is the only such at the moment). > > So I think with a few code changes, it should be possible to make online reencryption also work with the PAES cipher, when the volume key is generated outside of cryptsetup and passed in via --master-key-file. > > What _does_ work, is to reencrypt a LUKS2 PAES volume with a clear key cipher: > > # cryptsetup reencrypt /dev/loop0 --cipher aes-cbc-plain64 > Enter passphrase for key slot 0: > Finished, time 01:22.875, 984 MiB written, speed 11.9 MiB/s > With this little patch I was able to get it to work: >From 7090e50a80d09add1418fc7debd254883561fb77 Mon Sep 17 00:00:00 2001 From: Ingo Franzki <ifranzki@xxxxxxxxxxxxx> Date: Mon, 17 Aug 2020 17:15:05 +0200 Subject: [PATCH] Support online reencryption for PAES cipher Signed-off-by: Ingo Franzki <ifranzki@xxxxxxxxxxxxx> --- lib/luks2/luks2_reencrypt.c | 2 +- man/cryptsetup.8 | 2 +- src/cryptsetup.c | 9 ++++++++- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/lib/luks2/luks2_reencrypt.c b/lib/luks2/luks2_reencrypt.c index f9815d86..4429f532 100644 --- a/lib/luks2/luks2_reencrypt.c +++ b/lib/luks2/luks2_reencrypt.c @@ -2988,7 +2988,7 @@ static int reencrypt_init_by_passphrase(struct crypt_device *cd, if (flags & CRYPT_REENCRYPT_RECOVERY) return reencrypt_recovery_by_passphrase(cd, hdr, keyslot_old, keyslot_new, passphrase, passphrase_size); - if (cipher) { + if (cipher && !crypt_cipher_wrapped_key(cipher, cipher_mode)) { r = crypt_keyslot_get_key_size(cd, keyslot_new); if (r < 0) return r; diff --git a/man/cryptsetup.8 b/man/cryptsetup.8 index bc3fff61..3154d479 100644 --- a/man/cryptsetup.8 +++ b/man/cryptsetup.8 @@ -199,7 +199,7 @@ as soon as possible and mounted (used) before full data area encryption is compl Action supports following additional \fB<options>\fR [\-\-encrypt, \-\-decrypt, \-\-device\-size, \-\-resilience, \-\-resilience-hash, \-\-hotzone-size, \-\-init\-only, \-\-resume\-only, -\-\-reduce\-device\-size]. +\-\-reduce\-device\-size, \-\-master\-key\-file, \-\-key\-size]. .SH PLAIN MODE Plain dm-crypt encrypts the device sector-by-sector with a diff --git a/src/cryptsetup.c b/src/cryptsetup.c index 4fb962c8..4e46b9e9 100644 --- a/src/cryptsetup.c +++ b/src/cryptsetup.c @@ -3089,6 +3089,7 @@ static int action_reencrypt_luks2(struct crypt_device *cd) size_t i, vk_size, kp_size; int r, keyslot_old = CRYPT_ANY_SLOT, keyslot_new = CRYPT_ANY_SLOT, key_size; char dm_name[PATH_MAX], cipher [MAX_CIPHER_LEN], mode[MAX_CIPHER_LEN], *vk; + char *key = NULL; const char *active_name = NULL; struct keyslot_passwords *kp; struct crypt_params_luks2 luks2_params = {}; @@ -3131,6 +3132,12 @@ static int action_reencrypt_luks2(struct crypt_device *cd) if (!key_size) return -EINVAL; + if (ARG_SET(OPT_MASTER_KEY_FILE_ID)) { + r = crypt_cli_read_mk(ARG_STR(OPT_MASTER_KEY_FILE_ID), &key, key_size); + if (r < 0) + return r; + } + r = crypt_keyslot_max(CRYPT_LUKS2); if (r < 0) return r; @@ -3158,7 +3165,7 @@ static int action_reencrypt_luks2(struct crypt_device *cd) r = set_keyslot_params(cd, i); if (r < 0) break; - r = crypt_keyslot_add_by_key(cd, CRYPT_ANY_SLOT, NULL, key_size, + r = crypt_keyslot_add_by_key(cd, CRYPT_ANY_SLOT, key, key_size, kp[i].password, kp[i].passwordLen, CRYPT_VOLUME_KEY_NO_SEGMENT); tools_keyslot_msg(r, CREATED); if (r < 0) -- 2.16.2.windows.1 -- Ingo Franzki eMail: ifranzki@xxxxxxxxxxxxx Tel: ++49 (0)7031-16-4648 Fax: ++49 (0)7031-16-3456 Linux on IBM Z Development, Schoenaicher Str. 220, 71032 Boeblingen, Germany IBM Deutschland Research & Development GmbH / Vorsitzender des Aufsichtsrats: Matthias Hartmann Geschäftsführung: Dirk Wittkopp Sitz der Gesellschaft: Böblingen / Registergericht: Amtsgericht Stuttgart, HRB 243294 IBM DATA Privacy Statement: https://www.ibm.com/privacy/us/en/ _______________________________________________ dm-crypt mailing list dm-crypt@xxxxxxxx https://www.saout.de/mailman/listinfo/dm-crypt