mirror of
https://gitlab.com/cryptsetup/cryptsetup.git
synced 2025-12-14 12:20:00 +01:00
Add libLUKS2.
This commit is contained in:
529
src/cryptsetup.c
529
src/cryptsetup.c
@@ -22,6 +22,7 @@
|
||||
*/
|
||||
|
||||
#include "cryptsetup.h"
|
||||
#include <uuid/uuid.h>
|
||||
|
||||
static const char *opt_cipher = NULL;
|
||||
static const char *opt_hash = NULL;
|
||||
@@ -43,6 +44,8 @@ static long opt_new_keyfile_size = 0;
|
||||
static long opt_keyfile_offset = 0;
|
||||
static long opt_new_keyfile_offset = 0;
|
||||
static int opt_key_slot = CRYPT_ANY_SLOT;
|
||||
static int opt_token = CRYPT_ANY_TOKEN;
|
||||
static int opt_token_only = 0;
|
||||
static uint64_t opt_size = 0;
|
||||
static uint64_t opt_offset = 0;
|
||||
static uint64_t opt_skip = 0;
|
||||
@@ -69,10 +72,21 @@ static int opt_veracrypt_query_pim = 0;
|
||||
static int opt_deferred_remove = 0;
|
||||
//FIXME: check uint32 overflow for long type
|
||||
static const char *opt_pbkdf = NULL;
|
||||
static long opt_pbkdf_memory = 1024;
|
||||
static long opt_pbkdf_parallel = 2;
|
||||
static long opt_pbkdf_memory = DEFAULT_LUKS2_MEMORY_KB;
|
||||
static long opt_pbkdf_parallel = DEFAULT_LUKS2_PARALLEL_THREADS;
|
||||
static long opt_pbkdf_iterations = 0;
|
||||
static int opt_iteration_time = 0;
|
||||
static int opt_disable_locks = 0;
|
||||
static int opt_disable_keyring = 0;
|
||||
static const char *opt_priority = NULL; /* normal */
|
||||
static const char *opt_integrity = NULL; /* none */
|
||||
static int opt_integrity_nojournal = 0;
|
||||
static int opt_integrity_no_wipe = 0;
|
||||
static const char *opt_key_description = NULL;
|
||||
static int opt_sector_size = 512;
|
||||
static int opt_persistent = 0;
|
||||
static const char *opt_label = NULL;
|
||||
static const char *opt_subsystem = NULL;
|
||||
|
||||
static const char **action_argv;
|
||||
static int action_argc;
|
||||
@@ -86,6 +100,23 @@ static const char *uuid_or_device_header(const char **data_device)
|
||||
return uuid_or_device(opt_header_device ?: action_argv[0]);
|
||||
}
|
||||
|
||||
static const char *luksType(const char *type)
|
||||
{
|
||||
if (type && !strcmp(type, "luks2"))
|
||||
return CRYPT_LUKS2;
|
||||
|
||||
if (type && !strcmp(type, "luks1"))
|
||||
return CRYPT_LUKS1;
|
||||
|
||||
if (type && !strcmp(type, "luks"))
|
||||
return CRYPT_LUKS; /* NULL */
|
||||
|
||||
if (type && *type)
|
||||
return type;
|
||||
|
||||
return CRYPT_LUKS; /* NULL */
|
||||
}
|
||||
|
||||
static int _verify_passphrase(int def)
|
||||
{
|
||||
/* Batch mode switch off verify - if not overrided by -y */
|
||||
@@ -117,6 +148,13 @@ static void _set_activation_flags(uint32_t *flags)
|
||||
|
||||
if (opt_perf_submit_from_crypt_cpus)
|
||||
*flags |= CRYPT_ACTIVATE_SUBMIT_FROM_CRYPT_CPUS;
|
||||
|
||||
if (opt_integrity_nojournal)
|
||||
*flags |= CRYPT_ACTIVATE_NO_JOURNAL;
|
||||
|
||||
/* In persistent mode, we use what is set on command line */
|
||||
if (opt_persistent)
|
||||
*flags |= CRYPT_ACTIVATE_IGNORE_PERSISTENT;
|
||||
}
|
||||
|
||||
static int action_open_plain(void)
|
||||
@@ -449,12 +487,45 @@ static int action_close(void)
|
||||
|
||||
static int action_resize(void)
|
||||
{
|
||||
struct crypt_device *cd = NULL;
|
||||
int r;
|
||||
size_t passwordLen;
|
||||
struct crypt_active_device cad;
|
||||
char *password = NULL;
|
||||
struct crypt_device *cd = NULL;
|
||||
|
||||
r = crypt_init_by_name_and_header(&cd, action_argv[0], opt_header_device);
|
||||
if (r == 0)
|
||||
r = crypt_resize(cd, action_argv[0], opt_size);
|
||||
if (r == 0) {
|
||||
r = crypt_get_active_device(cd, action_argv[0], &cad);
|
||||
|
||||
if (!r && (cad.flags & CRYPT_ACTIVATE_KEYRING_KEY)) {
|
||||
if (opt_disable_keyring) {
|
||||
r = -EINVAL;
|
||||
log_err(_("Resize of active device requires volume key in keyring but --disable-keyring option is set.\n"));
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* try load VK in kernel keyring using token */
|
||||
r = crypt_activate_by_token(cd, NULL, opt_token, NULL, CRYPT_ACTIVATE_KEYRING_KEY);
|
||||
if (r < 0) {
|
||||
if (opt_token_only)
|
||||
goto out;
|
||||
|
||||
r = tools_get_key(NULL, &password, &passwordLen,
|
||||
opt_keyfile_offset, opt_keyfile_size, opt_key_file,
|
||||
opt_timeout, _verify_passphrase(0), 0, cd);
|
||||
if (r < 0)
|
||||
goto out;
|
||||
|
||||
r = crypt_activate_by_passphrase(cd, NULL, opt_key_slot, password, passwordLen, CRYPT_ACTIVATE_KEYRING_KEY);
|
||||
|
||||
crypt_safe_free(password);
|
||||
}
|
||||
}
|
||||
|
||||
if (r >= 0)
|
||||
r = crypt_resize(cd, action_argv[0], opt_size);
|
||||
}
|
||||
out:
|
||||
|
||||
crypt_free(cd);
|
||||
return r;
|
||||
@@ -464,6 +535,7 @@ static int action_status(void)
|
||||
{
|
||||
crypt_status_info ci;
|
||||
struct crypt_active_device cad;
|
||||
struct crypt_params_integrity ip = {};
|
||||
struct crypt_device *cd = NULL;
|
||||
char *backing_file;
|
||||
const char *device;
|
||||
@@ -504,8 +576,17 @@ static int action_status(void)
|
||||
if (r < 0)
|
||||
goto out;
|
||||
|
||||
r = crypt_get_integrity_info(cd, &ip);
|
||||
if (r < 0 && r != -ENOTSUP)
|
||||
goto out;
|
||||
|
||||
log_std(" cipher: %s-%s\n", crypt_get_cipher(cd), crypt_get_cipher_mode(cd));
|
||||
log_std(" keysize: %d bits\n", crypt_get_volume_key_size(cd) * 8);
|
||||
log_std(" key location: %s\n", (cad.flags & CRYPT_ACTIVATE_KEYRING_KEY) ? "keyring" : "dm-crypt");
|
||||
if (ip.integrity)
|
||||
log_std(" integrity: %s\n", ip.integrity);
|
||||
if (ip.integrity_key_size)
|
||||
log_std(" integrity keysize: %d bits\n", ip.integrity_key_size * 8);
|
||||
device = crypt_get_device_name(cd);
|
||||
log_std(" device: %s\n", device);
|
||||
if (crypt_loop_device(device)) {
|
||||
@@ -513,6 +594,7 @@ static int action_status(void)
|
||||
log_std(" loop: %s\n", backing_file);
|
||||
free(backing_file);
|
||||
}
|
||||
log_std(" sector size: %d\n", crypt_get_sector_size(cd));
|
||||
log_std(" offset: %" PRIu64 " sectors\n", cad.offset);
|
||||
log_std(" size: %" PRIu64 " sectors\n", cad.size);
|
||||
if (cad.iv_offset)
|
||||
@@ -569,7 +651,7 @@ static int action_benchmark_kdf(const char *kdf, const char *hash, size_t key_si
|
||||
} else {
|
||||
struct crypt_pbkdf_type pbkdf = {
|
||||
.type = kdf,
|
||||
.time_ms = opt_iteration_time ?: 800,
|
||||
.time_ms = opt_iteration_time ?: DEFAULT_LUKS2_ITER_TIME,
|
||||
.max_memory_kb = opt_pbkdf_memory,
|
||||
.parallel_threads = opt_pbkdf_parallel,
|
||||
};
|
||||
@@ -765,6 +847,14 @@ static int set_pbkdf_params(struct crypt_device *cd, const char *dev_type)
|
||||
pbkdf.type = CRYPT_KDF_PBKDF2;
|
||||
pbkdf.hash = opt_hash ?: DEFAULT_LUKS1_HASH;
|
||||
pbkdf.time_ms = opt_iteration_time ?: DEFAULT_LUKS1_ITER_TIME;
|
||||
} else if (!strcmp(dev_type, CRYPT_LUKS2)) {
|
||||
pbkdf.type = opt_pbkdf ?: DEFAULT_LUKS2_PBKDF;
|
||||
pbkdf.hash = opt_hash ?: DEFAULT_LUKS1_HASH;
|
||||
pbkdf.time_ms = opt_iteration_time ?: DEFAULT_LUKS2_ITER_TIME;
|
||||
if (strcmp(pbkdf.type, CRYPT_KDF_PBKDF2)) {
|
||||
pbkdf.max_memory_kb = opt_pbkdf_memory;
|
||||
pbkdf.parallel_threads = opt_pbkdf_parallel;
|
||||
}
|
||||
} else
|
||||
return 0;
|
||||
|
||||
@@ -784,9 +874,8 @@ static int action_luksRepair(void)
|
||||
if ((r = crypt_init(&cd, action_argv[0])))
|
||||
goto out;
|
||||
|
||||
/* Currently only LUKS1 allows repair */
|
||||
crypt_set_log_callback(cd, quiet_log, NULL);
|
||||
r = crypt_load(cd, CRYPT_LUKS1, NULL);
|
||||
r = crypt_load(cd, luksType(opt_type), NULL);
|
||||
crypt_set_log_callback(cd, tool_log, NULL);
|
||||
if (r == 0) {
|
||||
log_verbose(_("No known problems detected for LUKS header.\n"));
|
||||
@@ -796,18 +885,53 @@ static int action_luksRepair(void)
|
||||
r = yesDialog(_("Really try to repair LUKS device header?"),
|
||||
NULL) ? 0 : -EINVAL;
|
||||
if (r == 0)
|
||||
r = crypt_repair(cd, CRYPT_LUKS1, NULL);
|
||||
r = crypt_repair(cd, luksType(opt_type), NULL);
|
||||
out:
|
||||
crypt_free(cd);
|
||||
return r;
|
||||
}
|
||||
|
||||
static int _wipe_data_device(struct crypt_device *cd)
|
||||
{
|
||||
char tmp_name[64], tmp_path[128], tmp_uuid[40];
|
||||
uuid_t tmp_uuid_bin;
|
||||
int r;
|
||||
|
||||
if (!opt_batch_mode)
|
||||
log_std(_("Wiping device to initialize integrity checksum.\n"
|
||||
"You can interrupt this by pressing CTRL+c "
|
||||
"(rest of not wiped device will contain invalid checksum).\n"));
|
||||
|
||||
/* Activate the device a temporary one */
|
||||
uuid_generate(tmp_uuid_bin);
|
||||
uuid_unparse(tmp_uuid_bin, tmp_uuid);
|
||||
if (snprintf(tmp_name, sizeof(tmp_name), "temporary-cryptsetup-%s", tmp_uuid) < 0)
|
||||
return -EINVAL;
|
||||
if (snprintf(tmp_path, sizeof(tmp_path), "%s/%s", crypt_get_dir(), tmp_name) < 0)
|
||||
return -EINVAL;
|
||||
|
||||
r = crypt_activate_by_volume_key(cd, tmp_name, NULL, 0,
|
||||
CRYPT_ACTIVATE_PRIVATE | CRYPT_ACTIVATE_NO_JOURNAL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* Wipe the device */
|
||||
set_int_handler(0);
|
||||
r = crypt_wipe(cd, tmp_path, CRYPT_WIPE_ZERO, 0, 0, DEFAULT_WIPE_BLOCK,
|
||||
0, &tools_wipe_progress, NULL);
|
||||
if (crypt_deactivate(cd, tmp_name))
|
||||
log_err(_("Cannot deactivate temporary device %s.\n"), tmp_path);
|
||||
set_int_block(0);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int action_luksFormat(void)
|
||||
{
|
||||
int r = -EINVAL, keysize;
|
||||
int r = -EINVAL, keysize, integrity_keysize = 0, luks_version;
|
||||
const char *header_device;
|
||||
char *msg = NULL, *key = NULL, cipher [MAX_CIPHER_LEN], cipher_mode[MAX_CIPHER_LEN];
|
||||
char *password = NULL;
|
||||
char *msg = NULL, *key = NULL, *password = NULL;
|
||||
char cipher [MAX_CIPHER_LEN], cipher_mode[MAX_CIPHER_LEN], integrity[MAX_CIPHER_LEN];
|
||||
size_t passwordLen;
|
||||
struct crypt_device *cd = NULL;
|
||||
struct crypt_params_luks1 params = {
|
||||
@@ -815,6 +939,25 @@ static int action_luksFormat(void)
|
||||
.data_alignment = opt_align_payload,
|
||||
.data_device = opt_header_device ? action_argv[0] : NULL,
|
||||
};
|
||||
struct crypt_params_luks2 params2 = {
|
||||
.data_alignment = params.data_alignment,
|
||||
.data_device = params.data_device,
|
||||
.sector_size = opt_sector_size,
|
||||
.label = opt_label,
|
||||
.subsystem = opt_subsystem
|
||||
};
|
||||
|
||||
if (!opt_type)
|
||||
return -EINVAL;
|
||||
else if (!strcmp(opt_type, "luks2"))
|
||||
luks_version = 2;
|
||||
else
|
||||
luks_version = 1;
|
||||
|
||||
if (opt_sector_size > 512 && luks_version == 1) {
|
||||
log_err(_("Unsupported encryption sector size.\n"));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
header_device = opt_header_device ?: action_argv[0];
|
||||
|
||||
@@ -836,6 +979,16 @@ static int action_luksFormat(void)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (luks_version == 2 && opt_integrity) {
|
||||
r = crypt_parse_integrity_mode(opt_integrity, integrity, &integrity_keysize);
|
||||
if (r < 0) {
|
||||
log_err(_("No known integrity specification pattern detected.\n"));
|
||||
goto out;
|
||||
}
|
||||
params2.integrity = integrity;
|
||||
/* FIXME: we use default integrity_params (set to NULL) */
|
||||
}
|
||||
|
||||
/* Never call pwquality if using null cipher */
|
||||
if (tools_is_cipher_null(cipher))
|
||||
opt_force_password = 1;
|
||||
@@ -846,7 +999,7 @@ static int action_luksFormat(void)
|
||||
goto out;
|
||||
}
|
||||
|
||||
keysize = (opt_key_size ?: DEFAULT_LUKS1_KEYBITS) / 8;
|
||||
keysize = (opt_key_size ?: DEFAULT_LUKS1_KEYBITS) / 8 + integrity_keysize;
|
||||
|
||||
if (opt_random)
|
||||
crypt_set_rng_type(cd, CRYPT_RNG_RANDOM);
|
||||
@@ -865,14 +1018,21 @@ static int action_luksFormat(void)
|
||||
goto out;
|
||||
}
|
||||
|
||||
r = set_pbkdf_params(cd, CRYPT_LUKS1);
|
||||
if (luks_version == 1)
|
||||
r = set_pbkdf_params(cd, CRYPT_LUKS1);
|
||||
else
|
||||
r = set_pbkdf_params(cd, CRYPT_LUKS2);
|
||||
if (r) {
|
||||
log_err(_("Failed to set pbkdf parameters.\n"));
|
||||
goto out;
|
||||
}
|
||||
|
||||
r = crypt_format(cd, CRYPT_LUKS1, cipher, cipher_mode,
|
||||
opt_uuid, key, keysize, ¶ms);
|
||||
if (luks_version == 1)
|
||||
r = crypt_format(cd, CRYPT_LUKS1, cipher, cipher_mode,
|
||||
opt_uuid, key, keysize, ¶ms);
|
||||
else
|
||||
r = crypt_format(cd, CRYPT_LUKS2, cipher, cipher_mode,
|
||||
opt_uuid, key, keysize, ¶ms2);
|
||||
check_signal(&r);
|
||||
if (r < 0)
|
||||
goto out;
|
||||
@@ -880,6 +1040,11 @@ static int action_luksFormat(void)
|
||||
r = crypt_keyslot_add_by_volume_key(cd, opt_key_slot,
|
||||
key, keysize,
|
||||
password, passwordLen);
|
||||
if (r < 0)
|
||||
goto out;
|
||||
|
||||
if (opt_integrity && !opt_integrity_no_wipe)
|
||||
r = _wipe_data_device(cd);
|
||||
out:
|
||||
crypt_free(cd);
|
||||
crypt_safe_free(key);
|
||||
@@ -905,7 +1070,7 @@ static int action_open_luks(void)
|
||||
if ((r = crypt_init(&cd, header_device)))
|
||||
goto out;
|
||||
|
||||
if ((r = crypt_load(cd, CRYPT_LUKS1, NULL)))
|
||||
if ((r = crypt_load(cd, luksType(opt_type), NULL)))
|
||||
goto out;
|
||||
|
||||
if (data_device &&
|
||||
@@ -928,6 +1093,10 @@ static int action_open_luks(void)
|
||||
r = crypt_activate_by_volume_key(cd, activated_name,
|
||||
key, keysize, activate_flags);
|
||||
} else {
|
||||
r = crypt_activate_by_token(cd, activated_name, opt_token, NULL, activate_flags);
|
||||
if (r >= 0 || opt_token_only)
|
||||
goto out;
|
||||
|
||||
tries = (opt_key_file && !tools_is_stdin(opt_key_file)) ? 1 : opt_tries;
|
||||
do {
|
||||
r = tools_get_key(NULL, &password, &passwordLen,
|
||||
@@ -945,6 +1114,11 @@ static int action_open_luks(void)
|
||||
} while ((r == -EPERM || r == -ERANGE) && (--tries > 0));
|
||||
}
|
||||
out:
|
||||
if (r >= 0 && opt_persistent &&
|
||||
crypt_persistent_flags_set(cd, CRYPT_FLAGS_ACTIVATION, activate_flags))
|
||||
log_err(_("Device activated but cannot make flags persistent.\n"));
|
||||
|
||||
|
||||
crypt_safe_free(key);
|
||||
crypt_safe_free(password);
|
||||
crypt_free(cd);
|
||||
@@ -959,7 +1133,7 @@ static int verify_keyslot(struct crypt_device *cd, int key_slot,
|
||||
crypt_keyslot_info ki;
|
||||
char *password = NULL;
|
||||
size_t passwordLen;
|
||||
int i, r;
|
||||
int i, max, r;
|
||||
|
||||
ki = crypt_keyslot_status(cd, key_slot);
|
||||
if (ki == CRYPT_SLOT_ACTIVE_LAST && !opt_batch_mode && !key_file &&
|
||||
@@ -969,7 +1143,7 @@ static int verify_keyslot(struct crypt_device *cd, int key_slot,
|
||||
r = tools_get_key(msg_pass, &password, &passwordLen,
|
||||
keyfile_offset, keyfile_size, key_file, opt_timeout,
|
||||
_verify_passphrase(0), 0, cd);
|
||||
if(r < 0)
|
||||
if (r < 0)
|
||||
goto out;
|
||||
|
||||
if (ki == CRYPT_SLOT_ACTIVE_LAST) {
|
||||
@@ -978,13 +1152,18 @@ static int verify_keyslot(struct crypt_device *cd, int key_slot,
|
||||
password, passwordLen, 0);
|
||||
} else {
|
||||
/* try all other keyslots */
|
||||
for (i = 0; i < crypt_keyslot_max(CRYPT_LUKS1); i++) {
|
||||
r = crypt_keyslot_max(crypt_get_type(cd));
|
||||
if (r < 0)
|
||||
goto out;
|
||||
max = r;
|
||||
|
||||
for (i = 0; i < max ; i++) {
|
||||
if (i == key_slot)
|
||||
continue;
|
||||
ki = crypt_keyslot_status(cd, key_slot);
|
||||
if (ki == CRYPT_SLOT_ACTIVE)
|
||||
r = crypt_activate_by_passphrase(cd, NULL, i,
|
||||
password, passwordLen, 0);
|
||||
ki = crypt_keyslot_status(cd, i);
|
||||
if (ki == CRYPT_SLOT_ACTIVE || ki == CRYPT_SLOT_ACTIVE_LAST)
|
||||
r = crypt_activate_by_passphrase(cd, NULL, i,
|
||||
password, passwordLen, 0);
|
||||
if (r == i)
|
||||
break;
|
||||
}
|
||||
@@ -1011,21 +1190,9 @@ static int action_luksKillSlot(void)
|
||||
|
||||
crypt_set_confirm_callback(cd, yesDialog, NULL);
|
||||
|
||||
if ((r = crypt_load(cd, CRYPT_LUKS1, NULL)))
|
||||
if ((r = crypt_load(cd, luksType(opt_type), NULL)))
|
||||
goto out;
|
||||
|
||||
switch (crypt_keyslot_status(cd, opt_key_slot)) {
|
||||
case CRYPT_SLOT_ACTIVE_LAST:
|
||||
case CRYPT_SLOT_ACTIVE:
|
||||
log_verbose(_("Key slot %d selected for deletion.\n"), opt_key_slot);
|
||||
break;
|
||||
case CRYPT_SLOT_INACTIVE:
|
||||
log_err(_("Key %d not active. Can't wipe.\n"), opt_key_slot);
|
||||
case CRYPT_SLOT_INVALID:
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!opt_batch_mode || opt_key_file || !isatty(STDIN_FILENO)) {
|
||||
r = verify_keyslot(cd, opt_key_slot,
|
||||
_("This is the last keyslot. Device will become unusable after purging this key."),
|
||||
@@ -1059,7 +1226,7 @@ static int action_luksRemoveKey(void)
|
||||
|
||||
crypt_set_confirm_callback(cd, yesDialog, NULL);
|
||||
|
||||
if ((r = crypt_load(cd, CRYPT_LUKS1, NULL)))
|
||||
if ((r = crypt_load(cd, luksType(opt_type), NULL)))
|
||||
goto out;
|
||||
|
||||
r = tools_get_key(_("Enter passphrase to be deleted: "),
|
||||
@@ -1109,7 +1276,7 @@ static int action_luksAddKey(void)
|
||||
|
||||
crypt_set_confirm_callback(cd, yesDialog, NULL);
|
||||
|
||||
if ((r = crypt_load(cd, CRYPT_LUKS1, NULL)))
|
||||
if ((r = crypt_load(cd, luksType(opt_type), NULL)))
|
||||
goto out;
|
||||
|
||||
/* Never call pwquality if using null cipher */
|
||||
@@ -1194,7 +1361,7 @@ static int action_luksChangeKey(void)
|
||||
if ((r = crypt_init(&cd, uuid_or_device_header(NULL))))
|
||||
goto out;
|
||||
|
||||
if ((r = crypt_load(cd, CRYPT_LUKS1, NULL)))
|
||||
if ((r = crypt_load(cd, luksType(opt_type), NULL)))
|
||||
goto out;
|
||||
|
||||
/* Never call pwquality if using null cipher */
|
||||
@@ -1253,7 +1420,7 @@ static int action_isLuks(void)
|
||||
goto out;
|
||||
|
||||
crypt_set_log_callback(cd, quiet_log, NULL);
|
||||
r = crypt_load(cd, CRYPT_LUKS1, NULL);
|
||||
r = crypt_load(cd, luksType(opt_type), NULL);
|
||||
out:
|
||||
crypt_free(cd);
|
||||
return r;
|
||||
@@ -1270,7 +1437,7 @@ static int action_luksUUID(void)
|
||||
|
||||
crypt_set_confirm_callback(cd, yesDialog, NULL);
|
||||
|
||||
if ((r = crypt_load(cd, CRYPT_LUKS1, NULL)))
|
||||
if ((r = crypt_load(cd, luksType(opt_type), NULL)))
|
||||
goto out;
|
||||
|
||||
if (opt_uuid)
|
||||
@@ -1347,7 +1514,7 @@ static int action_luksDump(void)
|
||||
if ((r = crypt_init(&cd, uuid_or_device_header(NULL))))
|
||||
goto out;
|
||||
|
||||
if ((r = crypt_load(cd, CRYPT_LUKS1, NULL)))
|
||||
if ((r = crypt_load(cd, luksType(opt_type), NULL)))
|
||||
goto out;
|
||||
|
||||
if (opt_dump_master_key)
|
||||
@@ -1382,7 +1549,7 @@ static int action_luksResume(void)
|
||||
if ((r = crypt_init_by_name_and_header(&cd, action_argv[0], uuid_or_device(opt_header_device))))
|
||||
goto out;
|
||||
|
||||
if ((r = crypt_load(cd, CRYPT_LUKS1, NULL)))
|
||||
if ((r = crypt_load(cd, luksType(opt_type), NULL)))
|
||||
goto out;
|
||||
|
||||
tries = (opt_key_file && !tools_is_stdin(opt_key_file)) ? 1 : opt_tries;
|
||||
@@ -1421,7 +1588,7 @@ static int action_luksBackup(void)
|
||||
|
||||
crypt_set_confirm_callback(cd, yesDialog, NULL);
|
||||
|
||||
r = crypt_header_backup(cd, CRYPT_LUKS1, opt_header_backup_file);
|
||||
r = crypt_header_backup(cd, NULL, opt_header_backup_file);
|
||||
out:
|
||||
crypt_free(cd);
|
||||
return r;
|
||||
@@ -1441,7 +1608,7 @@ static int action_luksRestore(void)
|
||||
goto out;
|
||||
|
||||
crypt_set_confirm_callback(cd, yesDialog, NULL);
|
||||
r = crypt_header_restore(cd, CRYPT_LUKS1, opt_header_backup_file);
|
||||
r = crypt_header_restore(cd, NULL, opt_header_backup_file);
|
||||
out:
|
||||
crypt_free(cd);
|
||||
return r;
|
||||
@@ -1452,7 +1619,9 @@ static int action_open(void)
|
||||
if (!opt_type)
|
||||
return -EINVAL;
|
||||
|
||||
if (!strcmp(opt_type, "luks") || !strcmp(opt_type, "luks1")) {
|
||||
if (!strcmp(opt_type, "luks") ||
|
||||
!strcmp(opt_type, "luks1") ||
|
||||
!strcmp(opt_type, "luks2")) {
|
||||
if (action_argc < 2 && !opt_test_passphrase)
|
||||
goto args;
|
||||
return action_open_luks();
|
||||
@@ -1482,14 +1651,14 @@ static int action_luksErase(void)
|
||||
struct crypt_device *cd = NULL;
|
||||
crypt_keyslot_info ki;
|
||||
char *msg = NULL;
|
||||
int i, r;
|
||||
int i, max, r;
|
||||
|
||||
if ((r = crypt_init(&cd, uuid_or_device_header(NULL))))
|
||||
goto out;
|
||||
|
||||
crypt_set_confirm_callback(cd, yesDialog, NULL);
|
||||
|
||||
if ((r = crypt_load(cd, CRYPT_LUKS1, NULL)))
|
||||
if ((r = crypt_load(cd, luksType(opt_type), NULL)))
|
||||
goto out;
|
||||
|
||||
if(asprintf(&msg, _("This operation will erase all keyslots on device %s.\n"
|
||||
@@ -1504,7 +1673,12 @@ static int action_luksErase(void)
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (i = 0; i < crypt_keyslot_max(CRYPT_LUKS1); i++) {
|
||||
/* Safety check */
|
||||
max = crypt_keyslot_max(crypt_get_type(cd));
|
||||
if (max <= 0)
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < max; i++) {
|
||||
ki = crypt_keyslot_status(cd, i);
|
||||
if (ki == CRYPT_SLOT_ACTIVE || ki == CRYPT_SLOT_ACTIVE_LAST) {
|
||||
r = crypt_keyslot_destroy(cd, i);
|
||||
@@ -1518,6 +1692,182 @@ out:
|
||||
return r;
|
||||
}
|
||||
|
||||
static int action_luksConvert(void)
|
||||
{
|
||||
struct crypt_device *cd = NULL;
|
||||
char *msg = NULL;
|
||||
const char *to_type, *from_type;
|
||||
int r;
|
||||
|
||||
if (!strcmp(opt_type, "luks2")) {
|
||||
to_type = CRYPT_LUKS2;
|
||||
} else if (!strcmp(opt_type, "luks1")) {
|
||||
to_type = CRYPT_LUKS1;
|
||||
} else {
|
||||
log_err(_("Missing LUKS target type, option --type is required.\n"));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if ((r = crypt_init(&cd, uuid_or_device_header(NULL))))
|
||||
return r;
|
||||
|
||||
crypt_set_confirm_callback(cd, yesDialog, NULL);
|
||||
|
||||
if ((r = crypt_load(cd, CRYPT_LUKS, NULL)) ||
|
||||
!(from_type = crypt_get_type(cd))) {
|
||||
crypt_free(cd);
|
||||
return r;
|
||||
}
|
||||
|
||||
if (!strcmp(from_type, to_type)) {
|
||||
log_err(_("Device is already %s type.\n"), to_type);
|
||||
crypt_free(cd);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (asprintf(&msg, _("This operation will convert %s to %s format.\n"),
|
||||
uuid_or_device_header(NULL), to_type) == -1) {
|
||||
crypt_free(cd);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (yesDialog(msg, NULL))
|
||||
r = crypt_convert(cd, to_type, NULL);
|
||||
else
|
||||
r = -EPERM;
|
||||
|
||||
free(msg);
|
||||
crypt_free(cd);
|
||||
return r;
|
||||
}
|
||||
|
||||
static int _config_priority(struct crypt_device *cd)
|
||||
{
|
||||
crypt_keyslot_info cs;
|
||||
crypt_keyslot_priority priority = CRYPT_SLOT_PRIORITY_INVALID;
|
||||
|
||||
if (!strcmp("normal", opt_priority))
|
||||
priority = CRYPT_SLOT_PRIORITY_NORMAL;
|
||||
else if (!strcmp("prefer", opt_priority))
|
||||
priority = CRYPT_SLOT_PRIORITY_PREFER;
|
||||
else if (!strcmp("ignore", opt_priority))
|
||||
priority = CRYPT_SLOT_PRIORITY_IGNORE;
|
||||
|
||||
cs = crypt_keyslot_status(cd, opt_key_slot);
|
||||
if (cs != CRYPT_SLOT_INVALID)
|
||||
return crypt_keyslot_set_priority(cd, opt_key_slot, priority);
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int _config_labels(struct crypt_device *cd)
|
||||
{
|
||||
return crypt_set_label(cd, opt_label, opt_subsystem);
|
||||
}
|
||||
|
||||
static int action_luksConfig(void)
|
||||
{
|
||||
struct crypt_device *cd = NULL;
|
||||
int r;
|
||||
|
||||
if (!opt_priority && !opt_label && !opt_subsystem) {
|
||||
log_err(_("Option --priority, --label or --subsystem is missing.\n"));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if ((r = crypt_init(&cd, uuid_or_device_header(NULL))))
|
||||
return r;
|
||||
|
||||
if ((r = crypt_load(cd, CRYPT_LUKS2, NULL)))
|
||||
goto out;
|
||||
|
||||
if (opt_priority && (r = _config_priority(cd)))
|
||||
goto out;
|
||||
|
||||
if ((opt_label || opt_subsystem) && (r = _config_labels(cd)))
|
||||
goto out;
|
||||
out:
|
||||
crypt_free(cd);
|
||||
return r;
|
||||
}
|
||||
|
||||
static int _token_add(struct crypt_device *cd)
|
||||
{
|
||||
int r, token;
|
||||
crypt_token_info token_info;
|
||||
const struct crypt_token_params_luks2_keyring params = {
|
||||
.key_description = opt_key_description
|
||||
};
|
||||
|
||||
if (opt_token != CRYPT_ANY_TOKEN) {
|
||||
token_info = crypt_token_status(cd, opt_token, NULL);
|
||||
if (token_info < CRYPT_TOKEN_INACTIVE) {
|
||||
log_err(_("Token %d is invalid.\n"), opt_token);
|
||||
return -EINVAL;
|
||||
} else if (token_info > CRYPT_TOKEN_INACTIVE) {
|
||||
log_err(_("Token %d in use.\n"), opt_token);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
r = crypt_token_luks2_keyring_set(cd, opt_token, ¶ms);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
token = r;
|
||||
|
||||
r = crypt_token_assign_keyslot(cd, token, opt_key_slot);
|
||||
if (r < 0) {
|
||||
log_err(_("Failed to assign token %d to keyslot %d.\n"), token, opt_key_slot);
|
||||
(void) crypt_token_json_set(cd, token, NULL);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int action_token(void)
|
||||
{
|
||||
int add, r;
|
||||
struct crypt_device *cd = NULL;
|
||||
|
||||
if (!strcmp(action_argv[0], "add")) {
|
||||
if (!opt_key_description) {
|
||||
log_err(_("--key-description parameter is mandatory for token add action.\n"));
|
||||
return -EINVAL;
|
||||
}
|
||||
add = 1;
|
||||
} else if (!strcmp(action_argv[0], "remove")) {
|
||||
if (opt_token == CRYPT_ANY_TOKEN) {
|
||||
log_err(_("Missing --token option specifying token for removal.\n"));
|
||||
return -EINVAL;
|
||||
}
|
||||
add = 0;
|
||||
} else {
|
||||
log_err(_("Invalid token operation %s.\n"), action_argv[0]);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if ((r = crypt_init(&cd, uuid_or_device(opt_header_device ?: action_argv[1]))))
|
||||
return r;
|
||||
|
||||
if ((r = crypt_load(cd, CRYPT_LUKS2, NULL))) {
|
||||
crypt_free(cd);
|
||||
return r;
|
||||
}
|
||||
|
||||
r = add ? _token_add(cd) : crypt_token_json_set(cd, opt_token, NULL);
|
||||
if (r < 0) {
|
||||
if (add)
|
||||
log_err(_("Failed to add keyring token %d.\n"), opt_token);
|
||||
else
|
||||
log_err(_("Failed to remove token %d.\n"), opt_token);
|
||||
}
|
||||
|
||||
crypt_free(cd);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static struct action_type {
|
||||
const char *type;
|
||||
int (*handler)(void);
|
||||
@@ -1533,6 +1883,8 @@ static struct action_type {
|
||||
{ "benchmark", action_benchmark, 0, 0, N_("[--cipher <cipher>]"), N_("benchmark cipher") },
|
||||
{ "repair", action_luksRepair, 1, 1, N_("<device>"), N_("try to repair on-disk metadata") },
|
||||
{ "erase", action_luksErase , 1, 1, N_("<device>"), N_("erase all keyslots (remove encryption key)") },
|
||||
{ "convert", action_luksConvert, 1, 1, N_("<device>"), N_("convert LUKS from/to LUKS2 format") },
|
||||
{ "config", action_luksConfig, 1, 1, N_("<device>"), N_("set permanent configuration options for LUKS2") },
|
||||
{ "luksFormat", action_luksFormat, 1, 1, N_("<device> [<new key file>]"), N_("formats a LUKS device") },
|
||||
{ "luksAddKey", action_luksAddKey, 1, 1, N_("<device> [<new key file>]"), N_("add key to LUKS device") },
|
||||
{ "luksRemoveKey",action_luksRemoveKey,1, 1, N_("<device> [<key file>]"), N_("removes supplied key or key file from LUKS device") },
|
||||
@@ -1546,6 +1898,7 @@ static struct action_type {
|
||||
{ "luksResume", action_luksResume, 1, 1, N_("<device>"), N_("Resume suspended LUKS device.") },
|
||||
{ "luksHeaderBackup", action_luksBackup,1,1, N_("<device>"), N_("Backup LUKS device header and keyslots") },
|
||||
{ "luksHeaderRestore",action_luksRestore,1,1,N_("<device>"), N_("Restore LUKS device header and keyslots") },
|
||||
{ "token", action_token, 2, 0, N_("<add|remove> <device>"), N_("Add or remove keyring token") },
|
||||
{}
|
||||
};
|
||||
|
||||
@@ -1582,9 +1935,12 @@ static void help(poptContext popt_context,
|
||||
log_std(_("\nDefault compiled-in key and passphrase parameters:\n"
|
||||
"\tMaximum keyfile size: %dkB, "
|
||||
"Maximum interactive passphrase length %d (characters)\n"
|
||||
"Default PBKDF2 iteration time for LUKS: %d (ms)\n"),
|
||||
"Default PBKDF2 iteration time for LUKS: %d (ms)\n"
|
||||
"Default PBKDF for LUKS2: %s\n"
|
||||
"\tIteration time: %d, Memory required: %dkB, Parallel threads: %d\n"),
|
||||
DEFAULT_KEYFILE_SIZE_MAXKB, DEFAULT_PASSPHRASE_SIZE_MAX,
|
||||
DEFAULT_LUKS1_ITER_TIME);
|
||||
DEFAULT_LUKS1_ITER_TIME, DEFAULT_LUKS2_PBKDF, DEFAULT_LUKS2_ITER_TIME,
|
||||
DEFAULT_LUKS2_MEMORY_KB, DEFAULT_LUKS2_PARALLEL_THREADS);
|
||||
|
||||
log_std(_("\nDefault compiled-in device cipher parameters:\n"
|
||||
"\tloop-AES: %s, Key %d bits\n"
|
||||
@@ -1689,6 +2045,19 @@ int main(int argc, const char **argv)
|
||||
{ "pbkdf-memory", '\0', POPT_ARG_LONG, &opt_pbkdf_memory, 0, N_("PBKDF memory cost limit"), N_("kilobytes") },
|
||||
{ "pbkdf-parallel", '\0', POPT_ARG_LONG, &opt_pbkdf_parallel, 0, N_("PBKDF parallel cost "), N_("threads") },
|
||||
{ "pbkdf-force-iterations",'\0',POPT_ARG_LONG, &opt_pbkdf_iterations, 0, N_("PBKDF iterations cost (forced, disables benchmark)"), NULL },
|
||||
{ "priority", '\0', POPT_ARG_STRING, &opt_priority, 0, N_("Keyslot priority (ignore/normal/prefer)"), NULL },
|
||||
{ "disable-locks", '\0', POPT_ARG_NONE, &opt_disable_locks, 0, N_("Disable locking of on-disk metadata"), NULL },
|
||||
{ "disable-keyring", '\0', POPT_ARG_NONE, &opt_disable_keyring, 0, N_("Disable loading volume keys via kernel keyring"), NULL },
|
||||
{ "integrity", 'I', POPT_ARG_STRING, &opt_integrity, 0, N_("Data integrity algorithm (LUKS2 only)"), NULL },
|
||||
{ "integrity-no-journal",'\0',POPT_ARG_NONE, &opt_integrity_nojournal, 0, N_("Disable journal for integrity device."), NULL },
|
||||
{ "integrity-no-wipe", '\0', POPT_ARG_NONE, &opt_integrity_no_wipe, 0, N_("Do not wipe device after format"), NULL },
|
||||
{ "token-only", '\0', POPT_ARG_NONE, &opt_token_only, 0, N_("Do not ask for passphrase if activation by token fails"), NULL },
|
||||
{ "token-id", '\0', POPT_ARG_INT, &opt_token, 0, N_("Token number (default: any)"), NULL },
|
||||
{ "key-description", '\0', POPT_ARG_STRING, &opt_key_description, 0, N_("Key description"), NULL },
|
||||
{ "sector-size", '\0', POPT_ARG_INT, &opt_sector_size, 0, N_("Encryption sector size (default: 512 bytes)"), NULL },
|
||||
{ "persistent", '\0', POPT_ARG_NONE, &opt_persistent, 0, N_("Set activation flags persistent for device."), NULL },
|
||||
{ "label", '\0', POPT_ARG_STRING, &opt_label, 0, N_("Set label for the LUKS2 device."), NULL },
|
||||
{ "subsystem", '\0', POPT_ARG_STRING, &opt_subsystem, 0, N_("Set subsystem label for the LUKS2 device."), NULL },
|
||||
POPT_TABLEEND
|
||||
};
|
||||
poptContext popt_context;
|
||||
@@ -1801,6 +2170,9 @@ int main(int argc, const char **argv)
|
||||
} else if (!strcmp(aname, "luksErase")) {
|
||||
aname = "erase";
|
||||
opt_type = "luks";
|
||||
} else if (!strcmp(aname, "luksConfig")) {
|
||||
aname = "config";
|
||||
opt_type = "luks2";
|
||||
}
|
||||
|
||||
for(action = action_types; action->type; action++)
|
||||
@@ -1831,6 +2203,11 @@ int main(int argc, const char **argv)
|
||||
_("Option --allow-discards is allowed only for open operation.\n"),
|
||||
poptGetInvocationName(popt_context));
|
||||
|
||||
if (opt_persistent && strcmp(aname, "open"))
|
||||
usage(popt_context, EXIT_FAILURE,
|
||||
_("Option --persistent is allowed only for open operation.\n"),
|
||||
poptGetInvocationName(popt_context));
|
||||
|
||||
if (opt_key_size &&
|
||||
strcmp(aname, "luksFormat") &&
|
||||
strcmp(aname, "open") &&
|
||||
@@ -1840,8 +2217,24 @@ int main(int argc, const char **argv)
|
||||
"To limit read from keyfile use --keyfile-size=(bytes)."),
|
||||
poptGetInvocationName(popt_context));
|
||||
|
||||
if (opt_integrity && strcmp(aname, "luksFormat"))
|
||||
usage(popt_context, EXIT_FAILURE,
|
||||
_("Option --integrity is allowed only for luksFormat (LUKS2).\n"),
|
||||
poptGetInvocationName(popt_context));
|
||||
|
||||
if (opt_integrity_no_wipe && !opt_integrity)
|
||||
usage(popt_context, EXIT_FAILURE,
|
||||
_("Option --integrity-no-wipe"
|
||||
" can be used only for format action with integrity extension.\n"),
|
||||
poptGetInvocationName(popt_context));
|
||||
|
||||
if ((opt_label || opt_subsystem) && strcmp(aname, "luksFormat") && strcmp(aname, "config"))
|
||||
usage(popt_context, EXIT_FAILURE,
|
||||
_("Options --label and --subsystem are allowed only for luksFormat and config LUKS2 operations.\n"),
|
||||
poptGetInvocationName(popt_context));
|
||||
|
||||
if (opt_test_passphrase && (strcmp(aname, "open") ||
|
||||
(strcmp(opt_type, "luks") && strcmp(opt_type, "tcrypt"))))
|
||||
(strncmp(opt_type, "luks", 4) && strcmp(opt_type, "tcrypt"))))
|
||||
usage(popt_context, EXIT_FAILURE,
|
||||
_("Option --test-passphrase is allowed only for open of LUKS and TCRYPT devices.\n"),
|
||||
poptGetInvocationName(popt_context));
|
||||
@@ -1853,8 +2246,7 @@ int main(int argc, const char **argv)
|
||||
|
||||
if (!strcmp(aname, "luksKillSlot") && action_argc > 1)
|
||||
opt_key_slot = atoi(action_argv[1]);
|
||||
if (opt_key_slot != CRYPT_ANY_SLOT &&
|
||||
(opt_key_slot < 0 || opt_key_slot >= crypt_keyslot_max(CRYPT_LUKS1)))
|
||||
if (opt_key_slot != CRYPT_ANY_SLOT && opt_key_slot < 0)
|
||||
usage(popt_context, EXIT_FAILURE, _("Key slot is invalid."),
|
||||
poptGetInvocationName(popt_context));
|
||||
|
||||
@@ -1945,9 +2337,19 @@ int main(int argc, const char **argv)
|
||||
}
|
||||
}
|
||||
|
||||
if (opt_priority && strcmp(opt_priority, "normal") && strcmp(opt_priority, "prefer") && strcmp(opt_priority, "ignore"))
|
||||
usage(popt_context, EXIT_FAILURE,
|
||||
_("Option --priority can be only ignore/normal/prefer.\n"),
|
||||
poptGetInvocationName(popt_context));
|
||||
|
||||
if (!strcmp(aname, "config") && opt_priority && opt_key_slot == CRYPT_ANY_SLOT)
|
||||
usage(popt_context, EXIT_FAILURE,
|
||||
_("Keyslot specification is required.\n"),
|
||||
poptGetInvocationName(popt_context));
|
||||
|
||||
if (opt_pbkdf && crypt_parse_pbkdf(opt_pbkdf, &opt_pbkdf))
|
||||
usage(popt_context, EXIT_FAILURE,
|
||||
_("PBKDF can be only pbkdf2 or argon2i/argon2id.\n"),
|
||||
_("Password-based key derivation function (PBKDF) can be only pbkdf2 or argon2i/argon2id.\n"),
|
||||
poptGetInvocationName(popt_context));
|
||||
|
||||
if (opt_pbkdf_iterations && opt_iteration_time)
|
||||
@@ -1955,12 +2357,27 @@ int main(int argc, const char **argv)
|
||||
_("PBKDF forced iterations cannot be combined with iteration time option.\n"),
|
||||
poptGetInvocationName(popt_context));
|
||||
|
||||
if ((opt_sector_size != 512 && strcmp(aname, "luksFormat")) || opt_sector_size < 512
|
||||
|| opt_sector_size > 4096 || (opt_sector_size & (opt_sector_size - 1)))
|
||||
usage(popt_context, EXIT_FAILURE,
|
||||
_("Unsupported encryption sector size.\n"),
|
||||
poptGetInvocationName(popt_context));
|
||||
|
||||
if (opt_debug) {
|
||||
opt_verbose = 1;
|
||||
crypt_set_debug_level(-1);
|
||||
dbg_version_and_cmd(argc, argv);
|
||||
}
|
||||
|
||||
if (opt_disable_locks && crypt_metadata_locking(NULL, 0)) {
|
||||
log_std(_("Cannot disable metadata locking.\n"));
|
||||
poptFreeContext(popt_context);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (opt_disable_keyring)
|
||||
(void) crypt_volume_key_keyring(NULL, 0);
|
||||
|
||||
r = run_action(action);
|
||||
poptFreeContext(popt_context);
|
||||
return r;
|
||||
|
||||
Reference in New Issue
Block a user