Commit 307a7ad0 authored by Milan Broz's avatar Milan Broz Committed by Ondrej Kozina

Add keyslot encryption params.

This patch makes available LUKS2 per-keyslot encryption settings to user.

In LUKS2, keyslot can use different encryption that data.

We can use new crypt_keyslot_get_encryption and crypt_keyslot_set_encryption
API calls to set/get this encryption.

For cryptsetup new --keyslot-cipher and --keyslot-key-size options are added.

The default keyslot encryption algorithm (if cannot be derived from data encryption)
is now available as configure options (default is aes-xts-plain64 with 512-bits key).
NOTE: default was increased from 256-bits.
parent 0039834b
......@@ -564,6 +564,9 @@ CS_NUM_WITH([luks2-iter-time], [Argon2 PBKDF iteration time for LUKS2 (in
CS_NUM_WITH([luks2-memory-kb], [Argon2 PBKDF memory cost for LUKS2 (in kB)], [1048576])
CS_NUM_WITH([luks2-parallel-threads],[Argon2 PBKDF max parallel cost for LUKS2 (if CPUs available)], [4])
CS_STR_WITH([luks2-keyslot-cipher], [fallback cipher for LUKS2 keyslot (if data encryption is incompatible)], [aes-xts-plain64])
CS_NUM_WITH([luks2-keyslot-keybits],[fallback key size for LUKS2 keyslot (if data encryption is incompatible)], [512])
CS_STR_WITH([loopaes-cipher], [cipher for loop-AES mode], [aes])
CS_NUM_WITH([loopaes-keybits],[key length in bits for loop-AES mode], [256])
......
......@@ -1634,6 +1634,39 @@ int crypt_keyslot_area(struct crypt_device *cd,
*/
int crypt_keyslot_get_key_size(struct crypt_device *cd, int keyslot);
/**
* Get cipher and key size for keyslot encryption.
* Use for LUKS2 keyslot to set different encryption type than for data encryption.
* Parameters will be used for next keyslot operations.
*
* @param cd crypt device handle
* @param keyslot keyslot number of CRYPT_ANY_SLOT for default
* @param key_size encryption key size (in bytes)
*
* @return cipher specification on success or @e NULL.
*
* @note This is the encryption of keyslot itself, not the data encryption algorithm!
*/
const char *crypt_keyslot_get_encryption(struct crypt_device *cd, int keyslot, size_t *key_size);
/**
* Set encryption for keyslot.
* Use for LUKS2 keyslot to set different encryption type than for data encryption.
* Parameters will be used for next keyslot operations that create or change a keyslot.
*
* @param cd crypt device handle
* @param cipher (e.g. "aes-xts-plain64")
* @param key_size encryption key size (in bytes)
*
* @return @e 0 on success or negative errno value otherwise.
*
* @note To reset to default keyslot encryption (the same as for data)
* set cipher to NULL and key size to 0.
*/
int crypt_keyslot_set_encryption(struct crypt_device *cd,
const char *cipher,
size_t key_size);
/**
* Get directory where mapped crypt devices are created
*
......
......@@ -97,6 +97,8 @@ CRYPTSETUP_2.0 {
crypt_keyslot_area;
crypt_keyslot_status;
crypt_keyslot_get_key_size;
crypt_keyslot_set_encryption;
crypt_keyslot_get_encryption;
crypt_get_dir;
crypt_set_debug_level;
crypt_log;
......
......@@ -163,7 +163,7 @@ uint64_t LUKS2_hdr_and_areas_size(json_object *jobj);
uint64_t LUKS2_keyslots_size(json_object *jobj);
uint64_t LUKS2_metadata_size(json_object *jobj);
int LUKS2_keyslot_cipher_incompatible(struct crypt_device *cd);
int LUKS2_keyslot_cipher_incompatible(struct crypt_device *cd, const char *cipher_spec);
/*
* Generic LUKS2 keyslot
......@@ -341,11 +341,10 @@ int LUKS2_get_sector_size(struct luks2_hdr *hdr);
const char *LUKS2_get_cipher(struct luks2_hdr *hdr, int segment);
const char *LUKS2_get_integrity(struct luks2_hdr *hdr, int segment);
int LUKS2_keyslot_params_default(struct crypt_device *cd, struct luks2_hdr *hdr,
size_t key_size, struct luks2_keyslot_params *params);
int LUKS2_get_keyslot_params(struct luks2_hdr *hdr, int keyslot,
struct luks2_keyslot_params *params);
struct luks2_keyslot_params *params);
int LUKS2_get_volume_key_size(struct luks2_hdr *hdr, int segment);
int LUKS2_get_keyslot_stored_key_size(struct luks2_hdr *hdr, int keyslot);
const char *LUKS2_get_keyslot_cipher(struct luks2_hdr *hdr, int keyslot, size_t *key_size);
int LUKS2_keyslot_find_empty(struct luks2_hdr *hdr, const char *type);
int LUKS2_keyslot_active_count(struct luks2_hdr *hdr, int segment);
int LUKS2_keyslot_for_segment(struct luks2_hdr *hdr, int keyslot, int segment);
......
......@@ -1662,76 +1662,30 @@ const char *LUKS2_get_cipher(struct luks2_hdr *hdr, int segment)
}
static int luks2_keyslot_af_params(json_object *jobj_af, struct luks2_keyslot_params *params)
const char *LUKS2_get_keyslot_cipher(struct luks2_hdr *hdr, int keyslot, size_t *key_size)
{
int r;
json_object *jobj_type, *jobj1;
/* currently we only support luks1 AF */
json_object_object_get_ex(jobj_af, "type", &jobj_type);
if (strcmp(json_object_get_string(jobj_type), "luks1"))
return 1;
/* process luks1 af params */
json_object_object_get_ex(jobj_af, "stripes", &jobj1);
params->af.luks1.stripes = json_object_get_int(jobj1);
if (params->af.luks1.stripes != LUKS_STRIPES)
return 1;
json_object *jobj_keyslot, *jobj_area, *jobj1;
json_object_object_get_ex(jobj_af, "hash", &jobj1);
r = snprintf(params->af.luks1.hash, sizeof(params->af.luks1.hash), "%s",
json_object_get_string(jobj1));
if (r < 0 || (size_t)r >= sizeof(params->af.luks1.hash))
return 1;
params->af_type = LUKS2_KEYSLOT_AF_LUKS1;
return 0;
}
jobj_keyslot = LUKS2_get_keyslot_jobj(hdr, keyslot);
if (!jobj_keyslot)
return NULL;
static int luks2_keyslot_area_params(json_object *jobj_area, struct luks2_keyslot_params *params)
{
int r;
json_object *jobj_type, *jobj1;
if (!json_object_object_get_ex(jobj_keyslot, "area", &jobj_area))
return NULL;
/* currently we only support raw length preserving area encryption */
json_object_object_get_ex(jobj_area, "type", &jobj_type);
if (strcmp(json_object_get_string(jobj_type), "raw"))
return 1;
/* process raw area encryption params */
json_object_object_get_ex(jobj_area, "encryption", &jobj1);
r = snprintf(params->area.raw.encryption, sizeof(params->area.raw.encryption), "%s",
json_object_get_string(jobj1));
if (r < 0 || (size_t)r >= sizeof(params->area.raw.encryption))
return 1;
json_object_object_get_ex(jobj_area, "key_size", &jobj1);
params->area.raw.key_size = json_object_get_int(jobj1);
params->area_type = LUKS2_KEYSLOT_AREA_RAW;
return 0;
}
/* keyslot must be validated */
int LUKS2_get_keyslot_params(struct luks2_hdr *hdr, int keyslot, struct luks2_keyslot_params *params)
{
json_object *jobj_keyslot, *jobj_af, *jobj_area;
jobj_keyslot = LUKS2_get_keyslot_jobj(hdr, keyslot);
if (!jobj_keyslot)
return -ENOENT;
json_object_object_get_ex(jobj_area, "type", &jobj1);
if (strcmp(json_object_get_string(jobj1), "raw"))
return NULL;
if (!json_object_object_get_ex(jobj_keyslot, "area", &jobj_area) ||
!json_object_object_get_ex(jobj_keyslot, "af", &jobj_af))
return -EINVAL;
if (!json_object_object_get_ex(jobj_area, "key_size", &jobj1))
return NULL;
*key_size = json_object_get_int(jobj1);
if (luks2_keyslot_af_params(jobj_af, params))
return -EINVAL;
if (luks2_keyslot_area_params(jobj_area, params))
return -EINVAL;
if (!json_object_object_get_ex(jobj_area, "encryption", &jobj1))
return NULL;
return 0;
return json_object_get_string(jobj1);
}
const char *LUKS2_get_integrity(struct luks2_hdr *hdr, int segment)
......
......@@ -111,13 +111,18 @@ int LUKS2_keyslot_active_count(struct luks2_hdr *hdr, int segment)
return num;
}
int LUKS2_keyslot_cipher_incompatible(struct crypt_device *cd)
int LUKS2_keyslot_cipher_incompatible(struct crypt_device *cd, const char *cipher_spec)
{
const char *cipher = crypt_get_cipher(cd);
const char *cipher_mode = crypt_get_cipher_mode(cd);
char cipher[MAX_CIPHER_LEN], cipher_mode[MAX_CIPHER_LEN];
if (!cipher_spec || !strcmp(cipher_spec, "null") || !strcmp(cipher_spec, "cipher_null"))
return 1;
if (crypt_parse_name_and_mode(cipher_spec, cipher, NULL, cipher_mode) < 0)
return 1;
/* Keyslot is already authenticated; we cannot use integrity tags here */
if (crypt_get_integrity_tag_size(cd) || !cipher)
if (crypt_get_integrity_tag_size(cd))
return 1;
/* Wrapped key schemes cannot be used for keyslot encryption */
......@@ -132,45 +137,38 @@ int LUKS2_keyslot_cipher_incompatible(struct crypt_device *cd)
}
int LUKS2_keyslot_params_default(struct crypt_device *cd, struct luks2_hdr *hdr,
size_t key_size, struct luks2_keyslot_params *params)
struct luks2_keyslot_params *params)
{
int r, integrity_key_size = crypt_get_integrity_key_size(cd);
const struct crypt_pbkdf_type *pbkdf = crypt_get_pbkdf_type(cd);
const char *cipher_spec;
size_t key_size;
int r;
if (!hdr || !pbkdf || !params)
return -EINVAL;
params->af_type = LUKS2_KEYSLOT_AF_LUKS1;
/*
* set keyslot area encryption parameters
*/
params->area_type = LUKS2_KEYSLOT_AREA_RAW;
/* set keyslot AF parameters */
/* currently we use hash for AF from pbkdf settings */
r = snprintf(params->af.luks1.hash, sizeof(params->af.luks1.hash),
"%s", pbkdf->hash);
if (r < 0 || (size_t)r >= sizeof(params->af.luks1.hash))
cipher_spec = crypt_keyslot_get_encryption(cd, CRYPT_ANY_SLOT, &key_size);
if (!cipher_spec || !key_size)
return -EINVAL;
params->af.luks1.stripes = 4000;
/* set keyslot area encryption parameters */
/* short circuit authenticated encryption hardcoded defaults */
if (LUKS2_keyslot_cipher_incompatible(cd) || key_size == 0) {
// FIXME: fixed cipher and key size can be wrong
snprintf(params->area.raw.encryption, sizeof(params->area.raw.encryption),
"aes-xts-plain64");
params->area.raw.key_size = 32;
return 0;
}
r = snprintf(params->area.raw.encryption, sizeof(params->area.raw.encryption),
"%s", LUKS2_get_cipher(hdr, CRYPT_DEFAULT_SEGMENT));
params->area.raw.key_size = key_size;
r = snprintf(params->area.raw.encryption, sizeof(params->area.raw.encryption), "%s", cipher_spec);
if (r < 0 || (size_t)r >= sizeof(params->area.raw.encryption))
return -EINVAL;
/* Slot encryption tries to use the same key size as for the main algorithm */
if ((size_t)integrity_key_size > key_size)
/*
* set keyslot AF parameters
*/
params->af_type = LUKS2_KEYSLOT_AF_LUKS1;
/* currently we use hash for AF from pbkdf settings */
r = snprintf(params->af.luks1.hash, sizeof(params->af.luks1.hash), "%s", pbkdf->hash);
if (r < 0 || (size_t)r >= sizeof(params->af.luks1.hash))
return -EINVAL;
params->area.raw.key_size = key_size - integrity_key_size;
params->af.luks1.stripes = 4000;
return 0;
}
......
......@@ -388,27 +388,25 @@ static int luks2_keyslot_update_json(struct crypt_device *cd,
const struct luks2_keyslot_params *params)
{
const struct crypt_pbkdf_type *pbkdf;
json_object *jobj_af, *jobj_area, *jobj_kdf, *jobj1;
json_object *jobj_af, *jobj_area, *jobj_kdf;
char salt[LUKS_SALTSIZE], *salt_base64 = NULL;
int r, keyslot_key_len;
int r;
/* jobj_keyslot is not yet validated */
if (!json_object_object_get_ex(jobj_keyslot, "af", &jobj_af) ||
!json_object_object_get_ex(jobj_keyslot, "area", &jobj_area) ||
!json_object_object_get_ex(jobj_area, "key_size", &jobj1))
!json_object_object_get_ex(jobj_keyslot, "area", &jobj_area))
return -EINVAL;
/* we do not allow any 'area' object modifications yet */
keyslot_key_len = json_object_get_int(jobj1);
if (keyslot_key_len < 0)
return -EINVAL;
/* update area encryption parameters */
json_object_object_add(jobj_area, "encryption", json_object_new_string(params->area.raw.encryption));
json_object_object_add(jobj_area, "key_size", json_object_new_int(params->area.raw.key_size));
pbkdf = crypt_get_pbkdf_type(cd);
if (!pbkdf)
return -EINVAL;
r = crypt_benchmark_pbkdf_internal(cd, CONST_CAST(struct crypt_pbkdf_type *)pbkdf, keyslot_key_len);
r = crypt_benchmark_pbkdf_internal(cd, CONST_CAST(struct crypt_pbkdf_type *)pbkdf, params->area.raw.key_size);
if (r < 0)
return r;
......@@ -498,8 +496,6 @@ static int luks2_keyslot_alloc(struct crypt_device *cd,
/* Area object */
jobj_area = json_object_new_object();
json_object_object_add(jobj_area, "type", json_object_new_string("raw"));
json_object_object_add(jobj_area, "encryption", json_object_new_string(params->area.raw.encryption));
json_object_object_add(jobj_area, "key_size", json_object_new_int(params->area.raw.key_size));
json_object_object_add(jobj_area, "offset", json_object_new_uint64(area_offset));
json_object_object_add(jobj_area, "size", json_object_new_uint64(area_length));
json_object_object_add(jobj_keyslot, "area", jobj_area);
......@@ -610,6 +606,9 @@ static int luks2_keyslot_dump(struct crypt_device *cd, int keyslot)
json_object_object_get_ex(jobj_area, "encryption", &jobj1);
log_std(cd, "\tCipher: %s\n", json_object_get_string(jobj1));
json_object_object_get_ex(jobj_area, "key_size", &jobj1);
log_std(cd, "\tCipher key: %u bits\n", json_object_get_uint32(jobj1) * 8);
json_object_object_get_ex(jobj_kdf, "type", &jobj1);
log_std(cd, "\tPBKDF: %s\n", json_object_get_string(jobj1));
......
......@@ -591,7 +591,8 @@ static int keyslot_LUKS1_compatible(struct crypt_device *cd,
{
json_object *jobj_keyslot, *jobj, *jobj_kdf, *jobj_af;
uint64_t l2_offset, l2_length;
int ks_key_size;
size_t ks_key_size;
const char *ks_cipher, *data_cipher;
jobj_keyslot = LUKS2_get_keyslot_jobj(hdr, keyslot);
if (!jobj_keyslot)
......@@ -621,9 +622,10 @@ static int keyslot_LUKS1_compatible(struct crypt_device *cd,
/* FIXME: should this go to validation code instead (aka invalid luks2 header if assigned to segment 0)? */
/* FIXME: check all keyslots are assigned to segment id 0, and segments count == 1 */
ks_key_size = LUKS2_get_keyslot_stored_key_size(hdr, keyslot);
if (ks_key_size < 0 || (int)key_size != LUKS2_get_keyslot_stored_key_size(hdr, keyslot)) {
log_dbg(cd, "Key length in keyslot %d is different from volume key length", keyslot);
ks_cipher = LUKS2_get_keyslot_cipher(hdr, keyslot, &ks_key_size);
data_cipher = LUKS2_get_cipher(hdr, CRYPT_DEFAULT_SEGMENT);
if (!ks_cipher || !data_cipher || key_size != ks_key_size || strcmp(ks_cipher, data_cipher)) {
log_dbg(cd, "Cipher in keyslot %d is different from volume key encryption.", keyslot);
return 0;
}
......
......@@ -70,6 +70,8 @@ struct crypt_device {
struct luks2_hdr hdr;
char cipher[MAX_CIPHER_LEN]; /* only for compatibility */
char cipher_mode[MAX_CIPHER_LEN]; /* only for compatibility */
char *keyslot_cipher;
unsigned int keyslot_key_size;
} luks2;
struct { /* used in CRYPT_PLAIN */
struct crypt_params_plain hdr;
......@@ -687,6 +689,7 @@ static int _crypt_load_luks2(struct crypt_device *cd, int reload, int repair)
r = 0;
memcpy(&cd->u.luks2.hdr, &hdr2, sizeof(hdr2));
cd->u.luks2.keyslot_cipher = NULL;
out:
if (r) {
......@@ -1033,6 +1036,7 @@ static void crypt_free_type(struct crypt_device *cd)
free(cd->u.plain.cipher_spec);
} else if (isLUKS2(cd->type)) {
LUKS2_hdr_free(cd, &cd->u.luks2.hdr);
free(cd->u.luks2.keyslot_cipher);
} else if (isLUKS1(cd->type)) {
free(cd->u.luks1.cipher_spec);
} else if (isLOOPAES(cd->type)) {
......@@ -1570,6 +1574,7 @@ static int _crypt_format_luks2(struct crypt_device *cd,
uint64_t dev_size;
cd->u.luks2.hdr.jobj = NULL;
cd->u.luks2.keyslot_cipher = NULL;
if (!cipher || !cipher_mode)
return -EINVAL;
......@@ -3130,7 +3135,7 @@ int crypt_keyslot_add_by_passphrase(struct crypt_device *cd,
digest = r;
if (r >= 0)
r = LUKS2_keyslot_params_default(cd, &cd->u.luks2.hdr, vk->keylength, &params);
r = LUKS2_keyslot_params_default(cd, &cd->u.luks2.hdr, &params);
if (r >= 0)
r = LUKS2_digest_assign(cd, &cd->u.luks2.hdr, keyslot, digest, 1, 0);
......@@ -3215,9 +3220,10 @@ int crypt_keyslot_change_by_passphrase(struct crypt_device *cd,
r = LUKS_set_key(keyslot_new, new_passphrase, new_passphrase_size,
&cd->u.luks1.hdr, vk, cd);
} else if (isLUKS2(cd->type)) {
r = LUKS2_get_keyslot_params(&cd->u.luks2.hdr, keyslot_old, &params);
r = LUKS2_keyslot_params_default(cd, &cd->u.luks2.hdr, &params);
if (r)
goto out;
if (keyslot_old != keyslot_new) {
r = LUKS2_digest_assign(cd, &cd->u.luks2.hdr, keyslot_new, digest, 1, 0);
if (r < 0)
......@@ -3325,7 +3331,7 @@ int crypt_keyslot_add_by_keyfile_device_offset(struct crypt_device *cd,
digest = r;
if (r >= 0)
r = LUKS2_keyslot_params_default(cd, &cd->u.luks2.hdr, vk->keylength, &params);
r = LUKS2_keyslot_params_default(cd, &cd->u.luks2.hdr, &params);
if (r >= 0)
r = LUKS2_digest_assign(cd, &cd->u.luks2.hdr, keyslot, digest, 1, 0);
......@@ -4564,6 +4570,61 @@ int crypt_keyslot_get_key_size(struct crypt_device *cd, int keyslot)
return -EINVAL;
}
int crypt_keyslot_set_encryption(struct crypt_device *cd,
const char *cipher,
size_t key_size)
{
if (!cd || !cipher || ! key_size || !isLUKS2(cd->type))
return -EINVAL;
if (LUKS2_keyslot_cipher_incompatible(cd, cipher))
return -EINVAL;
free(cd->u.luks2.keyslot_cipher);
cd->u.luks2.keyslot_cipher = strdup(cipher);
if (!cd->u.luks2.keyslot_cipher)
return -ENOMEM;
cd->u.luks2.keyslot_key_size = key_size;
return 0;
}
const char *crypt_keyslot_get_encryption(struct crypt_device *cd, int keyslot, size_t *key_size)
{
const char *cipher;
if (!cd || !isLUKS(cd->type) || !key_size)
return NULL;
if (isLUKS1(cd->type)) {
if (keyslot != CRYPT_ANY_SLOT &&
LUKS_keyslot_info(&cd->u.luks1.hdr, keyslot) < CRYPT_SLOT_ACTIVE)
return NULL;
*key_size = crypt_get_volume_key_size(cd);
return cd->u.luks1.cipher_spec;
}
if (keyslot != CRYPT_ANY_SLOT)
return LUKS2_get_keyslot_cipher(&cd->u.luks2.hdr, keyslot, key_size);
/* Keyslot encryption was set through crypt_keyslot_set_encryption() */
if (cd->u.luks2.keyslot_cipher) {
*key_size = cd->u.luks2.keyslot_key_size;
return cd->u.luks2.keyslot_cipher;
}
/* Try to reuse volume encryption parameters */
cipher = LUKS2_get_cipher(&cd->u.luks2.hdr, CRYPT_DEFAULT_SEGMENT);
if (!LUKS2_keyslot_cipher_incompatible(cd, cipher)) {
*key_size = crypt_get_volume_key_size(cd);
return cipher;
}
/* Fallback to default LUKS2 keyslot encryption */
*key_size = DEFAULT_LUKS2_KEYSLOT_KEYBITS / 8;
return DEFAULT_LUKS2_KEYSLOT_CIPHER;
}
int crypt_set_data_offset(struct crypt_device *cd, uint64_t data_offset)
{
if (!cd)
......@@ -5185,20 +5246,18 @@ int crypt_keyslot_add_by_key(struct crypt_device *cd,
flags &= ~CRYPT_VOLUME_KEY_SET;
/* no segment flag or new vk flag requires new key digest */
if (flags & (CRYPT_VOLUME_KEY_NO_SEGMENT | CRYPT_VOLUME_KEY_SET)) {
if (flags & (CRYPT_VOLUME_KEY_NO_SEGMENT | CRYPT_VOLUME_KEY_SET))
digest = LUKS2_digest_create(cd, "pbkdf2", &cd->u.luks2.hdr, vk);
r = LUKS2_keyslot_params_default(cd, &cd->u.luks2.hdr, 0, &params);
} else
r = LUKS2_keyslot_params_default(cd, &cd->u.luks2.hdr, vk->keylength, &params);
r = digest;
if (r < 0) {
log_err(cd, _("Failed to initialise default LUKS2 keyslot parameters."));
log_err(cd, _("Volume key does not match the volume."));
goto out;
}
r = digest;
r = LUKS2_keyslot_params_default(cd, &cd->u.luks2.hdr, &params);
if (r < 0) {
log_err(cd, _("Volume key does not match the volume."));
log_err(cd, _("Failed to initialise default LUKS2 keyslot parameters."));
goto out;
}
......
......@@ -254,8 +254,9 @@ For LUKS2, additional \fB<options>\fR can be
[\-\-integrity, \-\-integrity\-no\-wipe, \-\-sector\-size,
\-\-label, \-\-subsystem,
\-\-pbkdf, \-\-pbkdf\-memory, \-\-pbkdf\-parallel,
\-\-disable\-locks, \-\-disable\-keyring.
\-\-luks2\-metadata\-size, \-\-luks2\-keyslots\-size].
\-\-disable\-locks, \-\-disable\-keyring,
\-\-luks2\-metadata\-size, \-\-luks2\-keyslots\-size,
\-\-keyslot\-cipher, \-\-keyslot\-key\-size].
\fBWARNING:\fR Doing a luksFormat on an existing LUKS container will
make all data the old container permanently irretrievable unless
......@@ -317,7 +318,7 @@ is not required.
\-\-keyfile\-size, \-\-new\-keyfile\-offset,
\-\-new\-keyfile\-size, \-\-key\-slot, \-\-master\-key\-file,
\-\-iter\-time, \-\-force\-password, \-\-header, \-\-disable\-locks,
\-\-unbound, \-\-type].
\-\-unbound, \-\-type, \-\-keyslot\-cipher, \-\-keyslot\-key\-size].
.PP
\fIluksRemoveKey\fR <device> [<key file with passphrase to be removed>]
.IP
......@@ -360,7 +361,7 @@ inaccessible.
\fB<options>\fR can be [\-\-key\-file, \-\-keyfile\-offset,
\-\-keyfile\-size, \-\-new\-keyfile\-offset,
\-\-new\-keyfile\-size, \-\-key\-slot, \-\-force\-password, \-\-header,
\-\-disable\-locks, \-\-type].
\-\-disable\-locks, \-\-type, \-\-keyslot\-cipher, \-\-keyslot\-key\-size].
.PP
.PP
\fIluksConvertKey\fR <device>
......@@ -384,7 +385,8 @@ parameters have been wiped and make the LUKS container inaccessible.
\fB<options>\fR can be [\-\-key\-file, \-\-keyfile\-offset,
\-\-keyfile\-size, \-\-key\-slot, \-\-header, \-\-disable\-locks,
\-\-iter-time, \-\-pbkdf, \-\-pbkdf\-force\-iterations,
\-\-pbkdf\-memory, \-\-pbkdf\-parallel].
\-\-pbkdf\-memory, \-\-pbkdf\-parallel,
\-\-keyslot\-cipher, \-\-keyslot\-key\-size].
.PP
\fIluksKillSlot\fR <device> <key slot number>
.IP
......@@ -1235,6 +1237,12 @@ This option can be used to set specific size of the LUKS2 binary keyslot area
of 4096 bytes with maximum size 128MB.
The <size> can be specified with unit suffix (for example 128k).
.TP
.B "\-\-keyslot\-cipher <cipher\-spec>"
This option can be used to set specific cipher encryption for the LUKS2 keyslot area.
.TP
.B "\-\-keyslot\-key\-size <bits>"
This option can be used to set specific key size for the LUKS2 keyslot area.
.TP
.B "\-\-integrity\-no\-journal"
Activate device with integrity protection without using data journal (direct
write of data and integrity tags).
......
......@@ -25,6 +25,7 @@
#include <uuid/uuid.h>
static const char *opt_cipher = NULL;
static const char *opt_keyslot_cipher = NULL;
static const char *opt_hash = NULL;
static int opt_verify_passphrase = 0;
......@@ -40,6 +41,7 @@ static const char *opt_uuid = NULL;
static const char *opt_header_device = NULL;
static const char *opt_type = "luks";
static int opt_key_size = 0;
static int opt_keyslot_key_size = 0;
static long opt_keyfile_size = 0;
static long opt_new_keyfile_size = 0;
static uint64_t opt_keyfile_offset = 0;
......@@ -169,6 +171,21 @@ static void _set_activation_flags(uint32_t *flags)
*flags |= CRYPT_ACTIVATE_ALLOW_UNBOUND_KEY;
}
static int _set_keyslot_encryption_params(struct crypt_device *cd)
{
const char *type = crypt_get_type(cd);
if (!opt_keyslot_key_size && !opt_keyslot_cipher)
return 0;
if (!type || strcmp(type, CRYPT_LUKS2)) {
log_err(_("Keyslot encryption parameters can be set only for LUKS2 device."));
return -EINVAL;
}
return crypt_keyslot_set_encryption(cd, opt_keyslot_cipher, opt_keyslot_key_size / 8);
}
static int action_open_plain(void)
{
struct crypt_device *cd = NULL, *cd1 = NULL;
......@@ -1163,6 +1180,10 @@ static int action_luksFormat(void)
if (r < 0)
goto out;
r = _set_keyslot_encryption_params(cd);
if (r < 0)
goto out;
r = crypt_keyslot_add_by_volume_key(cd, opt_key_slot,
key, keysize,
password, passwordLen);
......@@ -1445,6 +1466,10 @@ static int luksAddUnboundKey(void)
goto out;
}
r = _set_keyslot_encryption_params(cd);
if (r < 0)
goto out;
/* Never call pwquality if using null cipher */
if (tools_is_cipher_null(crypt_get_cipher(cd)))
opt_force_password = 1;
......@@ -1508,6 +1533,10 @@ static int action_luksAddKey(void)
goto out;
}
r = _set_keyslot_encryption_params(cd);
if (r < 0)
goto out;
/* Never call pwquality if using null cipher */
if (tools_is_cipher_null(crypt_get_cipher(cd)))
opt_force_password = 1;
......@@ -1600,6 +1629,10 @@ static int action_luksChangeKey(void)
goto out;
}
r = _set_keyslot_encryption_params(cd);
if (r < 0)
goto out;
/* Never call pwquality if using null cipher */
if (tools_is_cipher_null(crypt_get_cipher(cd)))
opt_force_password = 1;
......@@ -1660,6 +1693,10 @@ static int action_luksConvertKey(void)
goto out;
}
r = _set_keyslot_encryption_params(cd);
if (r < 0)
goto out;
if (crypt_keyslot_status(cd, opt_key_slot) == CRYPT_SLOT_INACTIVE) {
r = -EINVAL;
log_err(_("Keyslot %d is not active."), opt_key_slot);
......@@ -2523,6 +2560,8 @@ int main(int argc, const char **argv)
{ "luks2-metadata-size",'\0',POPT_ARG_STRING,&opt_luks2_metadata_size_str,0,N_("LUKS2 header metadata area size"), N_("bytes") },
{ "luks2-keyslots-size",'\0',POPT_ARG_STRING,&opt_luks2_keyslots_size_str,0,N_("LUKS2 header keyslots area size"), N_("bytes") },
{ "refresh", '\0', POPT_ARG_NONE, &opt_refresh, 0, N_("Refresh (reactivate) device with new parameters"), NULL },
{ "keyslot-key-size", '\0', POPT_ARG_INT, &opt_keyslot_key_size, 0, N_("LUKS2 keyslot: The size of the encryption key"), N_("BITS") },
{ "keyslot-cipher", '\0', POPT_ARG_STRING, &opt_keyslot_cipher, 0, N_("LUKS2 keyslot: The cipher used for keyslot encryption"), NULL },
POPT_TABLEEND
};
poptContext popt_context;
......@@ -2733,7 +2772,7 @@ int main(int argc, const char **argv)
_("Option --test-passphrase is allowed only for open of LUKS and TCRYPT devices.\n"),
poptGetInvocationName(popt_context));
if (opt_key_size % 8)
if (opt_key_size % 8 || opt_keyslot_key_size % 8)
usage(popt_context, EXIT_FAILURE,
_("Key size must be a multiple of 8 bits"),
poptGetInvocationName(popt_context));
......
......@@ -2550,6 +2550,126 @@ static void Luks2KeyslotAdd(void)
crypt_free(cd);
}
static void Luks2KeyslotParams(void)
{
char key[128], key2[128];
struct crypt_device *cd;
const char *cipher = "aes", *cipher_mode="xts-plain64";
const char *cipher_spec = "aes-xts-plain64", *cipher_keyslot = "aes-cbc-essiv:sha256";
const char *mk_hex = "bb21158c733229347bd4e681891e213d94c685be6a5b84818afe7a78a6de7a1a";
const char *mk_hex2 = "bb21158c733229347bd4e681891e213d94c685be6a5b84818afe7a78a6de7a1e";
size_t key_size_ret, key_size = strlen(mk_hex) / 2, keyslot_key_size = 16;
crypt_decode_key(key, mk_hex, key_size);
crypt_decode_key(key2, mk_hex2, key_size);
OK_(prepare_keyfile(KEYFILE1, PASSPHRASE, strlen(PASSPHRASE)));
OK_(prepare_keyfile(KEYFILE2, PASSPHRASE1, strlen(PASSPHRASE1)));
EQ_(key_size, 2 * keyslot_key_size);
/* test crypt_keyslot_add_by_key */
OK_(crypt_init(&cd, DEVICE_1));
crypt_set_iteration_time(cd, 1);
OK_(crypt_format(cd, CRYPT_LUKS2, cipher, cipher_mode, NULL, key, key_size, NULL));
NULL_(crypt_keyslot_get_encryption(cd, 0, &key_size_ret));
OK_(strcmp(crypt_keyslot_get_encryption(cd, CRYPT_ANY_SLOT, &key_size_ret), cipher_spec));
EQ_(key_size_ret, key_size);
// Normal slots
EQ_(0, crypt_keyslot_add_by_volume_key(cd, 0, key, key_size, PASSPHRASE, strlen(PASSPHRASE)));
EQ_(1, crypt_keyslot_add_by_passphrase(cd, 1, PASSPHRASE, strlen(PASSPHRASE), PASSPHRASE1,strlen(PASSPHRASE1)));
EQ_(2, crypt_keyslot_add_by_key(cd, 2, key2, key_size, PASSPHRASE1, strlen(PASSPHRASE1), CRYPT_VOLUME_KEY_NO_SEGMENT));
EQ_(6, crypt_keyslot_add_by_keyfile(cd, 6, KEYFILE1, 0, KEYFILE2, 0));
// Slots with different encryption type
OK_(crypt_keyslot_set_encryption(cd, cipher_keyslot, keyslot_key_size));
OK_(strcmp(crypt_keyslot_get_encryption(cd, CRYPT_ANY_SLOT, &key_size_ret), cipher_keyslot));
EQ_(key_size_ret, keyslot_key_size);
EQ_(3, crypt_keyslot_add_by_volume_key(cd, 3, key, key_size, PASSPHRASE, strlen(PASSPHRASE)));
EQ_(4, crypt_keyslot_add_by_passphrase(cd, 4, PASSPHRASE, strlen(PASSPHRASE), PASSPHRASE1,strlen(PASSPHRASE1)));
EQ_(5, crypt_keyslot_add_by_key(cd, 5, key2, key_size, PASSPHRASE1, strlen(PASSPHRASE1), CRYPT_VOLUME_KEY_NO_SEGMENT));
EQ_(7, crypt_keyslot_add_by_keyfile(cd, 7, KEYFILE1, 0, KEYFILE2, 0));
crypt_free(cd);
OK_(crypt_init(&cd, DEVICE_1));
OK_(crypt_load(cd, CRYPT_LUKS2, NULL));
EQ_(crypt_keyslot_status(cd, 0), CRYPT_SLOT_ACTIVE);
OK_(strcmp(crypt_keyslot_get_encryption(cd, 0, &key_size_ret), cipher_spec));
EQ_(key_size_ret, key_size);
EQ_(crypt_keyslot_status(cd, 1), CRYPT_SLOT_ACTIVE);
OK_(strcmp(crypt_keyslot_get_encryption(cd, 1, &key_size_ret), cipher_spec));
EQ_(key_size_ret, key_size);
EQ_(crypt_keyslot_status(cd, 2), CRYPT_SLOT_UNBOUND);
OK_(strcmp(crypt_keyslot_get_encryption(cd, 2, &key_size_ret), cipher_spec));
EQ_(key_size_ret, key_size);
EQ_(crypt_keyslot_status(cd, 6), CRYPT_SLOT_ACTIVE);