mirror of
https://github.com/ibm-s390-linux/s390-tools.git
synced 2026-08-05 02:14:52 +00:00
zkey-cryptsetup: Add new 'convert' command
The 'convert' command converts a LUKS2 volume that uses a clear volume key and the 'aes' cipher to use a secure volume key and the 'paes' cipher. Optionally, the volume can use the integrity option with LUKS2 using a clear key integrity key. Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com> Reviewed-by: Jorg Schmidbauer <jschmidb@de.ibm.com> Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
This commit is contained in:
committed by
Jan Höppner
parent
c80a0c8af0
commit
efdd34a56c
38
zkey/pkey.c
38
zkey/pkey.c
@@ -1384,19 +1384,23 @@ int validate_secure_key(int pkey_fd,
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a key verification pattern of a secure key by encrypting the all
|
||||
* Generate a key verification pattern of a secure AES key by encrypting the all
|
||||
* zero message with the secure key using the AF_ALG interface
|
||||
*
|
||||
* @param[in] key the secure key token
|
||||
* @param[in] key_size the size of the secure key
|
||||
* @param[in] vp buffer where the verification pattern is returned
|
||||
* @param[in] vp_len the size of the buffer
|
||||
* @param[in] cipher the cipher to use ('cbc([p]aes)' or 'xts([p]aes)'),
|
||||
* or null to determine it from the secure key.
|
||||
* @param[in] verbose if true, verbose messages are printed
|
||||
*
|
||||
* @returns 0 on success, a negative errno in case of an error
|
||||
*/
|
||||
int generate_key_verification_pattern(const u8 *key, size_t key_size,
|
||||
char *vp, size_t vp_len, bool verbose)
|
||||
int generate_aes_key_verification_pattern(const u8 *key, size_t key_size,
|
||||
char *vp, size_t vp_len,
|
||||
const char *cipher,
|
||||
bool verbose)
|
||||
{
|
||||
int tfmfd = -1, opfd = -1, rc = 0, retry_count = 0;
|
||||
char null_msg[ENC_ZERO_LEN];
|
||||
@@ -1429,8 +1433,13 @@ int generate_key_verification_pattern(const u8 *key, size_t key_size,
|
||||
goto out;
|
||||
}
|
||||
|
||||
snprintf((char *)sa.salg_name, sizeof(sa.salg_name), "%s(paes)",
|
||||
is_xts_key(key, key_size) ? "xts" : "cbc");
|
||||
if (cipher != NULL) {
|
||||
util_strlcpy((char *)sa.salg_name, cipher,
|
||||
sizeof(sa.salg_name));
|
||||
} else {
|
||||
snprintf((char *)sa.salg_name, sizeof(sa.salg_name), "%s(paes)",
|
||||
is_xts_key(key, key_size) ? "xts" : "cbc");
|
||||
}
|
||||
|
||||
tfmfd = socket(AF_ALG, SOCK_SEQPACKET, 0);
|
||||
if (tfmfd < 0) {
|
||||
@@ -1541,6 +1550,25 @@ out:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a key verification pattern of a secure key by encrypting the all
|
||||
* zero message with the secure key using the AF_ALG interface
|
||||
*
|
||||
* @param[in] key the secure key token
|
||||
* @param[in] key_size the size of the secure key
|
||||
* @param[in] vp buffer where the verification pattern is returned
|
||||
* @param[in] vp_len the size of the buffer
|
||||
* @param[in] verbose if true, verbose messages are printed
|
||||
*
|
||||
* @returns 0 on success, a negative errno in case of an error
|
||||
*/
|
||||
int generate_key_verification_pattern(const u8 *key, size_t key_size,
|
||||
char *vp, size_t vp_len, bool verbose)
|
||||
{
|
||||
return generate_aes_key_verification_pattern(key, key_size, vp, vp_len,
|
||||
NULL, verbose);
|
||||
}
|
||||
|
||||
int get_master_key_verification_pattern(const u8 *key, size_t key_size,
|
||||
u8 *mkvp, bool UNUSED(verbose))
|
||||
{
|
||||
|
||||
@@ -351,6 +351,11 @@ int validate_secure_key(int pkey_fd,
|
||||
int generate_key_verification_pattern(const u8 *key, size_t key_size,
|
||||
char *vp, size_t vp_len, bool verbose);
|
||||
|
||||
int generate_aes_key_verification_pattern(const u8 *key, size_t key_size,
|
||||
char *vp, size_t vp_len,
|
||||
const char *cipher,
|
||||
bool verbose);
|
||||
|
||||
int get_master_key_verification_pattern(const u8 *key, size_t key_size,
|
||||
u8 *mkvp, bool verbose);
|
||||
|
||||
|
||||
@@ -355,6 +355,73 @@ relevance.
|
||||
.
|
||||
.
|
||||
.
|
||||
.SS "Convert a clear-key LUKS2 volume to use a secure AES volume key"
|
||||
.
|
||||
.B zkey\-cryptsetup
|
||||
.BR convert | conv
|
||||
.I device
|
||||
.BR \-\-volume\-key\-file | \-m
|
||||
.IR file\-name
|
||||
.RB [ \-\-key\-file | \-d
|
||||
.IR file\-name ]
|
||||
.RB [ \-\-keyfile\-offset | \-o
|
||||
.IR bytes ]
|
||||
.RB [ \-\-keyfile\-size | \-l
|
||||
.IR bytes ]
|
||||
.RB [ \-\-tries | \-T
|
||||
.IR number ]
|
||||
.RB [ \-\-batch\-mode | \-q ]
|
||||
.RB [ \-\-verbose | \-V ]
|
||||
.RB [ \-\-debug | \-D ]
|
||||
.PP
|
||||
Use the
|
||||
.B convert
|
||||
command to convert a clear-key \fBLUKS2\fP volume to use a secure volume key
|
||||
and the \fBpaes\fP cipher. You must provide a secure volume key that uses
|
||||
the exact same effective key as the current volume key. The volume must not be
|
||||
open when a conversion is performed, otherwise it fails.
|
||||
.PP
|
||||
.B ATTENTION:
|
||||
It is strongly recommended to take a LUKS header backup using \fBcryptsetup
|
||||
luksHeaderBackup\fP before converting a volume. The volume might not be
|
||||
recoverable after a failing conversion, if you don't have a LUKS header backup.
|
||||
.PP
|
||||
Specify the secure key file with option
|
||||
.B \-\-volume\-key\-file
|
||||
to convert the volume to use this secure key as the new volume key.
|
||||
.PP
|
||||
To open a key slot contained in the LUKS2 header of the volume, a passphrase is
|
||||
required. You are prompted for the passphrase, unless option
|
||||
.B \-\-key\-file
|
||||
is specified. Option
|
||||
.B \-\-tries
|
||||
specifies how often a passphrase can be re-entered. When option
|
||||
.B \-\-key\-file
|
||||
is specified, the passphrase is read from the specified file. You can specify
|
||||
options
|
||||
.B \-\-keyfile\-offset
|
||||
and
|
||||
.B \-\-keyfile\-size
|
||||
to control which part of the key file is used as passphrase. These options
|
||||
behave in the same way the same as with \fBcryptsetup\fP.
|
||||
.PP
|
||||
The
|
||||
.B convert
|
||||
command creates a new key slot with the specified secure AES volume key.
|
||||
The new key slot uses the same password based key derivation function as
|
||||
the key slot that is used to open the volume. LUKS2 volumes typically default to
|
||||
.B Argon2i
|
||||
as password based key derivation function,
|
||||
but this might cause out-of-memory errors when multiple encrypted volumes are
|
||||
unlocked automatically at boot through /etc/crypttab. Because PAES
|
||||
uses secure AES keys as volume keys, the security of the key derivation
|
||||
function used to encrypt the volume key in the LUKS key slots is of less
|
||||
relevance. Use \fBcryptsetup luksConvertKey --pbkdf pbkdf2\fP to convert
|
||||
the key slot(s) to use \fBPBKDF2\fP as password based key derivation function
|
||||
after the conversion.
|
||||
.
|
||||
.
|
||||
.
|
||||
.
|
||||
.SH OPTIONS
|
||||
.
|
||||
@@ -415,6 +482,22 @@ Suppresses all confirmation questions. Use with care!
|
||||
.
|
||||
.
|
||||
.
|
||||
.SS "Options for the convert command"
|
||||
.TP
|
||||
.BR \-m ", " \-\-volume\-key\-file\~\fIfile\-name\fP
|
||||
Specifies the name of a file containing the secure AES key that is used as
|
||||
volume key for the converted volume.
|
||||
.TP
|
||||
.BR \-\-master\-key\-file\~\fIfile\-name\fP
|
||||
Alias for the
|
||||
.BR \-\-volume\-key\-file\~\fIfile\-name\fP
|
||||
option.
|
||||
.TP
|
||||
.BR \-q ", " \-\-batch\-mode
|
||||
Suppresses all confirmation questions. Use with care!
|
||||
.
|
||||
.
|
||||
.
|
||||
.SS "Options for supplying the passphrase"
|
||||
.TP
|
||||
.BR \-d ", " \-\-key\-file\~\fIfile\-name\fP
|
||||
|
||||
@@ -82,7 +82,7 @@ static const struct util_prg prg = {
|
||||
{
|
||||
.owner = "IBM Corp.",
|
||||
.pub_first = 2018,
|
||||
.pub_last = 2024,
|
||||
.pub_last = 2025,
|
||||
},
|
||||
UTIL_PRG_COPYRIGHT_END
|
||||
}
|
||||
@@ -125,6 +125,7 @@ static struct zkey_cryptsetup_globals {
|
||||
#define COMMAND_VALIDATE "validate"
|
||||
#define COMMAND_SETVP "setvp"
|
||||
#define COMMAND_SETKEY "setkey"
|
||||
#define COMMAND_CONVERT "convert"
|
||||
|
||||
#define ZKEY_CRYPTSETUP_COMMAND_MAX_LEN 10
|
||||
|
||||
@@ -251,6 +252,33 @@ static struct util_opt opt_vec[] = {
|
||||
.desc = "Suppresses all confirmation questions. Use with care!",
|
||||
.command = COMMAND_SETKEY,
|
||||
},
|
||||
/***********************************************************/
|
||||
{
|
||||
.flags = UTIL_OPT_FLAG_SECTION,
|
||||
.desc = "OPTIONS",
|
||||
.command = COMMAND_CONVERT,
|
||||
},
|
||||
{
|
||||
.option = {"volume-key-file", required_argument, NULL, 'm'},
|
||||
.argument = "FILE-NAME",
|
||||
.desc = "Specifies the name of a file containing the secure "
|
||||
"AES key that is set as new volume key",
|
||||
.command = COMMAND_CONVERT,
|
||||
},
|
||||
{
|
||||
.option = {"master-key-file", required_argument, NULL, 'm'},
|
||||
.argument = "FILE-NAME",
|
||||
.desc = "Alias for the '--volume-key-file'|'-m' option",
|
||||
.command = COMMAND_CONVERT,
|
||||
.flags = UTIL_OPT_FLAG_NOSHORT,
|
||||
},
|
||||
OPT_PASSPHRASE_ENTRY(COMMAND_CONVERT),
|
||||
{
|
||||
.option = {"batch-mode", 0, NULL, 'q'},
|
||||
.desc = "Suppresses all confirmation questions. Use with care!",
|
||||
.command = COMMAND_CONVERT,
|
||||
},
|
||||
|
||||
/***********************************************************/
|
||||
{
|
||||
.flags = UTIL_OPT_FLAG_SECTION,
|
||||
@@ -288,12 +316,14 @@ struct zkey_cryptsetup_command {
|
||||
int has_options;
|
||||
char *pos_arg;
|
||||
int open_device;
|
||||
const char *expected_cipher;
|
||||
};
|
||||
|
||||
static int command_reencipher(void);
|
||||
static int command_validate(void);
|
||||
static int command_setvp(void);
|
||||
static int command_setkey(void);
|
||||
static int command_convert(void);
|
||||
|
||||
static struct zkey_cryptsetup_command zkey_cryptsetup_commands[] = {
|
||||
{
|
||||
@@ -308,6 +338,7 @@ static struct zkey_cryptsetup_command zkey_cryptsetup_commands[] = {
|
||||
.has_options = 1,
|
||||
.pos_arg = "DEVICE",
|
||||
.open_device = 1,
|
||||
.expected_cipher = "paes",
|
||||
},
|
||||
{
|
||||
.command = COMMAND_VALIDATE,
|
||||
@@ -320,6 +351,7 @@ static struct zkey_cryptsetup_command zkey_cryptsetup_commands[] = {
|
||||
.has_options = 1,
|
||||
.pos_arg = "DEVICE",
|
||||
.open_device = 1,
|
||||
.expected_cipher = "paes",
|
||||
},
|
||||
{
|
||||
.command = COMMAND_SETVP,
|
||||
@@ -334,6 +366,7 @@ static struct zkey_cryptsetup_command zkey_cryptsetup_commands[] = {
|
||||
.has_options = 1,
|
||||
.pos_arg = "DEVICE",
|
||||
.open_device = 1,
|
||||
.expected_cipher = "paes",
|
||||
},
|
||||
{
|
||||
.command = COMMAND_SETKEY,
|
||||
@@ -346,6 +379,22 @@ static struct zkey_cryptsetup_command zkey_cryptsetup_commands[] = {
|
||||
.has_options = 1,
|
||||
.pos_arg = "DEVICE",
|
||||
.open_device = 1,
|
||||
.expected_cipher = "paes",
|
||||
},
|
||||
{
|
||||
.command = COMMAND_CONVERT,
|
||||
.abbrev_len = 4,
|
||||
.function = command_convert,
|
||||
.need_pkey_device = 1,
|
||||
.short_desc = "Convert a clear-key LUKS2 volume to use a "
|
||||
"secure volume key",
|
||||
.long_desc = "Convert a LUKS2 volume that uses a clear volume "
|
||||
"key and the 'aes' cipher to use a secure volume "
|
||||
"key and the 'paes' cipher",
|
||||
.has_options = 1,
|
||||
.pos_arg = "DEVICE",
|
||||
.open_device = 1,
|
||||
.expected_cipher = "aes",
|
||||
},
|
||||
{ .command = NULL }
|
||||
};
|
||||
@@ -1149,7 +1198,8 @@ static int put_vp_token(struct crypt_device *cd, int token,
|
||||
/*
|
||||
* Open the LUKS2 device
|
||||
*/
|
||||
static int open_device(const char *device, struct crypt_device **cd)
|
||||
static int open_device(const char *device, struct crypt_device **cd,
|
||||
const char *expected_cipher)
|
||||
{
|
||||
const struct crypt_pbkdf_type pbkdf2 = {
|
||||
.type = CRYPT_KDF_PBKDF2,
|
||||
@@ -1180,9 +1230,9 @@ static int open_device(const char *device, struct crypt_device **cd)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (strcmp(crypt_get_cipher(cdev), "paes") != 0) {
|
||||
warnx("Device '%s' is not encrypted using the 'paes' cipher",
|
||||
device);
|
||||
if (strcmp(crypt_get_cipher(cdev), expected_cipher) != 0) {
|
||||
warnx("Device '%s' is not encrypted using the '%s' cipher",
|
||||
device, expected_cipher);
|
||||
rc = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
@@ -1386,7 +1436,7 @@ static int check_keysize_and_cipher_mode(const u8 *key, size_t keysize)
|
||||
static int open_keyslot(int keyslot, char **key, size_t *keysize,
|
||||
size_t *integrity_keysize,
|
||||
char **password, size_t *password_len,
|
||||
const char *prompt)
|
||||
const char *prompt, bool no_keysize_check)
|
||||
{
|
||||
struct crypt_params_integrity ip = { 0 };
|
||||
#ifdef HAVE_CRYPT_KEYSLOT_GET_PBKDF
|
||||
@@ -1414,10 +1464,13 @@ static int open_keyslot(int keyslot, char **key, size_t *keysize,
|
||||
pr_verbose("Integrity key size: %u", ip.integrity_key_size);
|
||||
}
|
||||
|
||||
rc = check_keysize_and_cipher_mode(NULL,
|
||||
vkeysize - ip.integrity_key_size);
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
if (!no_keysize_check) {
|
||||
rc = check_keysize_and_cipher_mode(NULL,
|
||||
vkeysize -
|
||||
ip.integrity_key_size);
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
}
|
||||
|
||||
vkey = malloc(vkeysize);
|
||||
if (vkey == NULL) {
|
||||
@@ -1528,7 +1581,7 @@ static int validate_keyslot(int keyslot, char **key, size_t *keysize,
|
||||
int rc, is_old;
|
||||
|
||||
rc = open_keyslot(keyslot, &vkey, &vkeysize, &ikeysize,
|
||||
password, password_len, prompt);
|
||||
password, password_len, prompt, false);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
@@ -1570,6 +1623,27 @@ out:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the number of active key slots in a LUKS2 volume.
|
||||
*/
|
||||
static int count_active_keyslots(struct crypt_device *cd)
|
||||
{
|
||||
crypt_keyslot_info info;
|
||||
int i, n;
|
||||
|
||||
for (i = 0, n = 0; ; i++) {
|
||||
info = crypt_keyslot_status(cd, i);
|
||||
if (info == CRYPT_SLOT_INVALID)
|
||||
break;
|
||||
if (info < CRYPT_SLOT_ACTIVE || info > CRYPT_SLOT_ACTIVE_LAST)
|
||||
continue;
|
||||
|
||||
n++;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
/*
|
||||
* Prepares for a re-enciphering of a secure volume key. Dependent on the
|
||||
* options specified by the user and the state of the volume key, it starts
|
||||
@@ -2002,7 +2076,7 @@ static int command_validate(void)
|
||||
|
||||
util_asprintf(&prompt, "Enter passphrase for '%s': ", g.pos_arg);
|
||||
rc = open_keyslot(CRYPT_ANY_SLOT, &key, &keysize, &integrity_keysize,
|
||||
NULL, NULL, prompt);
|
||||
NULL, NULL, prompt, false);
|
||||
free(prompt);
|
||||
if (rc < 0)
|
||||
goto out;
|
||||
@@ -2228,7 +2302,7 @@ static int command_setkey(void)
|
||||
|
||||
util_asprintf(&prompt, "Enter passphrase for '%s': ", g.pos_arg);
|
||||
rc = open_keyslot(CRYPT_ANY_SLOT, &key, &keysize, &integrity_keysize,
|
||||
&password, &password_len, prompt);
|
||||
&password, &password_len, prompt, false);
|
||||
free(prompt);
|
||||
if (rc < 0)
|
||||
goto out;
|
||||
@@ -2337,6 +2411,238 @@ out:
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Command handler for 'convert'.
|
||||
*
|
||||
* Convert a LUKS2 volume that uses a clear volume key and the 'aes' cipher
|
||||
* to use a secure volume key and the 'paes' cipher.
|
||||
*/
|
||||
static int command_convert(void)
|
||||
{
|
||||
struct crypt_params_integrity ip_new = { 0 };
|
||||
struct crypt_params_integrity ip = { 0 };
|
||||
struct crypt_params_luks2 luks2 = { 0 };
|
||||
char new_vp[VERIFICATION_PATTERN_LEN];
|
||||
struct crypt_device *new_cd = NULL;
|
||||
char vp[VERIFICATION_PATTERN_LEN];
|
||||
struct vp_token vp_tok = { 0 };
|
||||
size_t integrity_keysize = 0;
|
||||
size_t password_len = 0;
|
||||
size_t newekey_size = 0;
|
||||
size_t newkey_size = 0;
|
||||
char *password = NULL;
|
||||
size_t ekeysize = 0;
|
||||
size_t keysize = 0;
|
||||
u8 *newkey = NULL;
|
||||
int num_keyslots;
|
||||
u8 *key = NULL;
|
||||
int is_old_mk;
|
||||
char *prompt;
|
||||
int is_xts;
|
||||
char *msg;
|
||||
int rc;
|
||||
|
||||
/* Check preconditions */
|
||||
if (strcmp(crypt_get_cipher_mode(g.cd), "xts-plain64") != 0 &&
|
||||
strcmp(crypt_get_cipher_mode(g.cd), "cbc-plain64") != 0) {
|
||||
warnx("The volume uses cipher mode '%s' and thus can not be "
|
||||
"converted to use the 'paes' cipher",
|
||||
crypt_get_cipher_mode(g.cd));
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
is_xts = (strncmp(crypt_get_cipher_mode(g.cd), "xts-", 4) == 0);
|
||||
|
||||
/* Read new volume key and validate it */
|
||||
if (g.volume_key_file == NULL) {
|
||||
misc_print_required_parm("--volume-key-file/-m");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
newkey = read_secure_key(g.volume_key_file, &newkey_size, g.verbose);
|
||||
if (newkey == NULL)
|
||||
return EXIT_FAILURE;
|
||||
|
||||
rc = crypt_get_integrity_info(g.cd, &ip);
|
||||
if (rc == 0)
|
||||
integrity_keysize = ip.integrity_key_size;
|
||||
|
||||
newekey_size = newkey_size - integrity_keysize;
|
||||
|
||||
rc = check_keysize_and_cipher_mode(newkey, newekey_size);
|
||||
if (rc != 0)
|
||||
goto out;
|
||||
|
||||
rc = validate_secure_key(g.pkey_fd, newkey, newekey_size, NULL,
|
||||
&is_old_mk, NULL, g.verbose);
|
||||
if (rc != 0) {
|
||||
warnx("The secure key in file '%s' is not valid",
|
||||
g.volume_key_file);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (is_secure_key(newkey, newekey_size) &&
|
||||
is_old_mk) {
|
||||
util_asprintf(&msg, "The secure key in file '%s' is "
|
||||
"enciphered with the master key in the OLD "
|
||||
"master key register. Do you want to set this "
|
||||
"key as the new volume key anyway [y/N]?",
|
||||
g.volume_key_file);
|
||||
util_print_indented(msg, 0);
|
||||
free(msg);
|
||||
|
||||
if (!_prompt_for_yes()) {
|
||||
warnx("Device '%s' is left unchanged", g.pos_arg);
|
||||
rc = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
rc = generate_key_verification_pattern(newkey, newekey_size,
|
||||
new_vp, sizeof(new_vp),
|
||||
g.verbose);
|
||||
if (rc != 0) {
|
||||
warnx("Failed to generate the verification pattern: %s",
|
||||
strerror(-rc));
|
||||
warnx("Make sure that kernel module 'paes_s390' is loaded and "
|
||||
"that the 'paes' cipher is available");
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Get current (clear) volume key from LUKS2 header */
|
||||
util_asprintf(&prompt, "Enter passphrase for '%s': ", g.pos_arg);
|
||||
rc = open_keyslot(CRYPT_ANY_SLOT, (char **)&key, &keysize, NULL,
|
||||
&password, &password_len, prompt, true);
|
||||
free(prompt);
|
||||
if (rc < 0)
|
||||
goto out;
|
||||
|
||||
ekeysize = keysize - integrity_keysize;
|
||||
|
||||
if (integrity_keysize > 0 &&
|
||||
memcmp(newkey + newekey_size, key + ekeysize,
|
||||
integrity_keysize) != 0) {
|
||||
warnx("The secure key in file '%s' contains a different "
|
||||
"integrity key (i.e. the last %lu bytes of the key) than "
|
||||
"the current volume key.", g.volume_key_file,
|
||||
integrity_keysize);
|
||||
rc = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = generate_aes_key_verification_pattern(key, ekeysize,
|
||||
vp, sizeof(vp),
|
||||
is_xts ?
|
||||
"xts(aes)" : "cbc(aes)",
|
||||
g.verbose);
|
||||
if (rc != 0) {
|
||||
warnx("Failed to generate the verification pattern: %s",
|
||||
strerror(-rc));
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (strcmp(vp, new_vp) != 0) {
|
||||
warnx("The verification patterns of the new and old "
|
||||
"volume keys do not match");
|
||||
rc = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
num_keyslots = count_active_keyslots(g.cd);
|
||||
pr_verbose("Number of keyslots before conversion: %d", num_keyslots);
|
||||
|
||||
util_print_indented("WARNING: It is strongly recommended to take a "
|
||||
"LUKS header backup using 'cryptsetup "
|
||||
"luksHeaderBackup' before continuing. The volume "
|
||||
"might not be recoverable after a failing "
|
||||
"conversion, if you don't have a LUKS header "
|
||||
"backup.", 0);
|
||||
util_asprintf(&msg, "Do you really want to convert device '%s' to "
|
||||
"use a secure volume key? [y/N]?", g.pos_arg);
|
||||
util_print_indented(msg, 0);
|
||||
free(msg);
|
||||
|
||||
if (!_prompt_for_yes()) {
|
||||
warnx("Device '%s' is left unchanged", g.pos_arg);
|
||||
rc = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Open the device freshly for crypt_format */
|
||||
rc = crypt_init(&new_cd, g.pos_arg);
|
||||
if (rc != 0) {
|
||||
warnx("Failed to open device '%s': %s", g.pos_arg,
|
||||
strerror(-rc));
|
||||
goto out;
|
||||
}
|
||||
|
||||
crypt_set_log_callback(new_cd, cryptsetup_log, NULL);
|
||||
|
||||
/* Re-format the device with the same settings, but using 'paes' */
|
||||
#ifdef CRYPT_ACTIVATE_ERROR_AS_CORRUPTION /* Indicates libcryptsetup > 2.7.5 */
|
||||
ip_new.integrity_key_size = integrity_keysize;
|
||||
#endif
|
||||
|
||||
luks2.pbkdf = crypt_get_pbkdf_type(g.cd);
|
||||
luks2.integrity = integrity_keysize > 0 ? ip.integrity : NULL;
|
||||
luks2.integrity_params = integrity_keysize > 0 ? &ip_new : NULL;
|
||||
luks2.data_alignment = 0;
|
||||
luks2.data_device = NULL;
|
||||
luks2.sector_size = crypt_get_sector_size(g.cd);
|
||||
luks2.label = crypt_get_label(g.cd);
|
||||
luks2.subsystem = crypt_get_subsystem(g.cd);
|
||||
|
||||
rc = crypt_set_data_offset(new_cd, crypt_get_data_offset(g.cd));
|
||||
if (rc != 0) {
|
||||
warnx("Failed to set data size: %s", strerror(-rc));
|
||||
goto out;
|
||||
}
|
||||
rc = crypt_format(new_cd, CRYPT_LUKS2, "paes",
|
||||
crypt_get_cipher_mode(g.cd), crypt_get_uuid(g.cd),
|
||||
(char *)newkey, newkey_size, &luks2);
|
||||
if (rc != 0) {
|
||||
warnx("Failed to reformat the LUKS header: %s",
|
||||
strerror(-rc));
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Add a key slot with the current password */
|
||||
rc = crypt_keyslot_add_by_volume_key(new_cd, CRYPT_ANY_SLOT, NULL, 0,
|
||||
password, password_len);
|
||||
if (rc != 0) {
|
||||
warnx("Failed to add a key slotr: %s", strerror(-rc));
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Add the verification pattern token */
|
||||
memcpy(vp_tok.verification_pattern, new_vp,
|
||||
sizeof(vp_tok.verification_pattern));
|
||||
|
||||
rc = put_vp_token(new_cd, -1, &vp_tok);
|
||||
if (rc < 0)
|
||||
goto out;
|
||||
|
||||
printf("The device '%s' has been successfully converted\n", g.pos_arg);
|
||||
if (num_keyslots > 1) {
|
||||
util_print_indented("\nWARNING: Before converting, the "
|
||||
"volume's LUKS header had multiple active "
|
||||
"key slots with the same key, but "
|
||||
"different passwords. Use 'cryptsetup "
|
||||
"luksAddKey' if you need more than one key "
|
||||
"slot.", 0);
|
||||
}
|
||||
|
||||
out:
|
||||
secure_free(password, password_len);
|
||||
secure_free(newkey, newkey_size);
|
||||
secure_free(key, keysize);
|
||||
|
||||
if (new_cd != NULL)
|
||||
crypt_free(new_cd);
|
||||
|
||||
return rc < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
static bool is_command(struct zkey_cryptsetup_command *command, const char *str)
|
||||
{
|
||||
char command_str[ZKEY_CRYPTSETUP_COMMAND_STR_LEN];
|
||||
@@ -2535,7 +2841,7 @@ int main(int argc, char *argv[])
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = open_device(g.pos_arg, &g.cd);
|
||||
rc = open_device(g.pos_arg, &g.cd, command->expected_cipher);
|
||||
if (rc != 0) {
|
||||
g.cd = NULL;
|
||||
rc = EXIT_FAILURE;
|
||||
|
||||
Reference in New Issue
Block a user