Commit e364041b authored by Milan Broz's avatar Milan Broz

Add --keep-key to cryptsetup-reencrypt.

This allows change of LUKS header hash (and iteration count) without
the need to reencrypt the whole data area.
parent de37457a
......@@ -67,6 +67,9 @@ you can destructively shrink device with \-\-reduce-device-size option.
.TP
.B "\-\-hash, \-h \fI<hash-spec>\fR"
Specifies the hash used in the LUKS key setup scheme and volume key digest.
NOTE: if this parameter is not specified, default hash algorithm is always used
for new device header.
.TP
.B "\-\-iter-time, \-i \fI<milliseconds>\fR"
The number of milliseconds to spend with PBKDF2 passphrase processing for the
......@@ -100,6 +103,12 @@ Read a maximum of \fIvalue\fR bytes from the key file.
Default is to read the whole file up to the compiled-in
maximum.
.TP
.B "\-\-keep-key"
Do not change encryption key, just reencrypt the LUKS header and keyslots.
This option can be combined only with \fI\-\-hash\fR or \fI\-\-iter-time\fR
options.
.TP
.B "\-\-tries, \-T"
Number of retries for invalid passphrase entry.
.TP
......
......@@ -47,6 +47,7 @@ static int opt_tries = 3;
static int opt_key_slot = CRYPT_ANY_SLOT;
static int opt_key_size = 0;
static int opt_new = 0;
static int opt_keep_key = 0;
static const char *opt_reduce_size_str = NULL;
static uint64_t opt_reduce_size = 0;
......@@ -424,7 +425,8 @@ out:
static int create_new_header(struct reenc_ctx *rc, const char *cipher,
const char *cipher_mode, const char *uuid,
int key_size, struct crypt_params_luks1 *params)
const char *key, int key_size,
struct crypt_params_luks1 *params)
{
struct crypt_device *cd_new = NULL;
int i, r;
......@@ -441,7 +443,7 @@ static int create_new_header(struct reenc_ctx *rc, const char *cipher,
crypt_set_iteration_time(cd_new, opt_iteration_time);
if ((r = crypt_format(cd_new, CRYPT_LUKS1, cipher, cipher_mode,
uuid, NULL, key_size, params)))
uuid, key, key_size, params)))
goto out;
log_verbose(_("New LUKS header for device %s created.\n"), rc->device);
......@@ -464,6 +466,8 @@ static int backup_luks_headers(struct reenc_ctx *rc)
struct crypt_device *cd = NULL;
struct crypt_params_luks1 params = {0};
char cipher [MAX_CIPHER_LEN], cipher_mode[MAX_CIPHER_LEN];
char *old_key = NULL;
size_t old_key_size;
int r;
log_dbg("Creating LUKS header backup for device %s.", rc->device);
......@@ -494,14 +498,30 @@ static int backup_luks_headers(struct reenc_ctx *rc)
}
}
if (opt_keep_key) {
log_dbg("Keeping key from old header.");
old_key_size = crypt_get_volume_key_size(cd);
old_key = crypt_safe_alloc(old_key_size);
if (!old_key) {
r = -ENOMEM;
goto out;
}
r = crypt_volume_key_get(cd, CRYPT_ANY_SLOT, old_key, &old_key_size,
rc->p[rc->keyslot].password, rc->p[rc->keyslot].passwordLen);
if (r < 0)
goto out;
}
r = create_new_header(rc,
opt_cipher ? cipher : crypt_get_cipher(cd),
opt_cipher ? cipher_mode : crypt_get_cipher_mode(cd),
crypt_get_uuid(cd),
old_key,
opt_key_size ? opt_key_size / 8 : crypt_get_volume_key_size(cd),
&params);
out:
crypt_free(cd);
crypt_safe_free(old_key);
if (r)
log_err(_("Creation of LUKS backup headers failed.\n"));
return r;
......@@ -559,7 +579,7 @@ static int backup_fake_header(struct reenc_ctx *rc)
r = create_new_header(rc,
opt_cipher ? cipher : DEFAULT_LUKS1_CIPHER,
opt_cipher ? cipher_mode : DEFAULT_LUKS1_MODE,
NULL,
NULL, NULL,
(opt_key_size ? opt_key_size : DEFAULT_LUKS1_KEYBITS) / 8,
&params);
out:
......@@ -1087,11 +1107,15 @@ static int run_reencrypt(const char *device)
goto out;
}
if ((r = activate_luks_headers(&rc)))
goto out;
if (!opt_keep_key) {
log_dbg("Running data area reencryption.");
if ((r = activate_luks_headers(&rc)))
goto out;
if ((r = copy_data(&rc)))
goto out;
if ((r = copy_data(&rc)))
goto out;
} else
log_dbg("Keeping existing key, skipping data area reencryption.");
r = restore_luks_header(&rc);
out:
......@@ -1130,6 +1154,7 @@ int main(int argc, const char **argv)
{ "cipher", 'c', POPT_ARG_STRING, &opt_cipher, 0, N_("The cipher used to encrypt the disk (see /proc/crypto)"), NULL },
{ "key-size", 's', POPT_ARG_INT, &opt_key_size, 0, N_("The size of the encryption key"), N_("BITS") },
{ "hash", 'h', POPT_ARG_STRING, &opt_hash, 0, N_("The hash used to create the encryption key from the passphrase"), NULL },
{ "keep-key", '\0', POPT_ARG_NONE, &opt_keep_key, 0, N_("Do not change key, no data area reencryption."), NULL },
{ "key-file", 'd', POPT_ARG_STRING, &opt_key_file, 0, N_("Read the key from a file."), NULL },
{ "iter-time", 'i', POPT_ARG_INT, &opt_iteration_time, 0, N_("PBKDF2 iteration time for LUKS (in ms)"), N_("msecs") },
{ "batch-mode", 'q', POPT_ARG_NONE, &opt_batch_mode, 0, N_("Do not ask for confirmation"), NULL },
......@@ -1235,6 +1260,10 @@ int main(int argc, const char **argv)
usage(popt_context, EXIT_FAILURE, _("Option --new must be used together with --reduce-device-size."),
poptGetInvocationName(popt_context));
if (opt_keep_key && ((!opt_hash && !opt_iteration_time) || opt_cipher || opt_new))
usage(popt_context, EXIT_FAILURE, _("Option --keep-key can be used only with --hash or --iter-time."),
poptGetInvocationName(popt_context));
if (opt_debug) {
opt_verbose = 1;
crypt_set_debug_level(-1);
......
......@@ -255,5 +255,16 @@ add_scsi_device sector_size=512 physblk_exp=3 dev_size_mb=8
simple_scsi_reenc "[4096/512 sector]"
echo "[OK]"
echo "[8] Header only reencryption (hash and iteration time)"
echo $PWD1 | $CRYPTSETUP -q luksFormat --hash sha1 $LOOPDEV1 || fail
wipe $PWD1
check_hash $PWD1 $HASH1
echo $PWD1 | $REENC $LOOPDEV1 -q --keep-key --hash sha256 --iter-time 1
check_hash $PWD1 $HASH1
echo $PWD1 | $REENC $LOOPDEV1 -q --keep-key --hash sha512
check_hash $PWD1 $HASH1
echo $PWD1 | $REENC $LOOPDEV1 -q --keep-key --iter-time 1
check_hash $PWD1 $HASH1
remove_mapping
exit 0
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment