Re: [dm-crypt] LUKS2 online reencryption with PAES cipher ?

Ingo Franzki <[email protected]>
Newsgroups de.saout.dm-crypt
Message-ID <[email protected]>
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 <[email protected]>
Date: Mon, 17 Aug 2020 17:15:05 +0200
Subject: [PATCH] Support online reencryption for PAES cipher

Signed-off-by: Ingo Franzki <[email protected]>
---
 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: [email protected]  
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/
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.