mirror of
https://gitlab.com/cryptsetup/cryptsetup.git
synced 2025-12-13 03:40:05 +01:00
Check cipher before writing metadata (LUKS2).
Some ciphers and key sizes created on-disk metadata that cannot be used. Use the same test for length-preserving cipher as LUKS1. Also check if key for integrity algorithm is not too small. Fixes #373.
This commit is contained in:
@@ -106,10 +106,8 @@ int INTEGRITY_data_sectors(struct crypt_device *cd,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int INTEGRITY_key_size(struct crypt_device *cd)
|
int INTEGRITY_key_size(struct crypt_device *cd, const char *integrity)
|
||||||
{
|
{
|
||||||
const char *integrity = crypt_get_integrity(cd);
|
|
||||||
|
|
||||||
if (!integrity)
|
if (!integrity)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
|||||||
@@ -50,7 +50,8 @@ int INTEGRITY_dump(struct crypt_device *cd, struct device *device, uint64_t offs
|
|||||||
int INTEGRITY_data_sectors(struct crypt_device *cd,
|
int INTEGRITY_data_sectors(struct crypt_device *cd,
|
||||||
struct device *device, uint64_t offset,
|
struct device *device, uint64_t offset,
|
||||||
uint64_t *data_sectors);
|
uint64_t *data_sectors);
|
||||||
int INTEGRITY_key_size(struct crypt_device *cd);
|
int INTEGRITY_key_size(struct crypt_device *cd,
|
||||||
|
const char *integrity);
|
||||||
int INTEGRITY_tag_size(struct crypt_device *cd,
|
int INTEGRITY_tag_size(struct crypt_device *cd,
|
||||||
const char *integrity,
|
const char *integrity,
|
||||||
const char *cipher,
|
const char *cipher,
|
||||||
|
|||||||
@@ -402,6 +402,10 @@ static int _keyslot_repair(struct luks_phdr *phdr, struct crypt_device *ctx)
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
r = LUKS_check_cipher(ctx, phdr->keyBytes, phdr->cipherName, phdr->cipherMode);
|
||||||
|
if (r < 0)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
vk = crypt_alloc_volume_key(phdr->keyBytes, NULL);
|
vk = crypt_alloc_volume_key(phdr->keyBytes, NULL);
|
||||||
|
|
||||||
log_verbose(ctx, _("Repairing keyslots.\n"));
|
log_verbose(ctx, _("Repairing keyslots.\n"));
|
||||||
@@ -691,23 +695,22 @@ int LUKS_write_phdr(struct luks_phdr *hdr,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Check that kernel supports requested cipher by decryption of one sector */
|
/* Check that kernel supports requested cipher by decryption of one sector */
|
||||||
static int LUKS_check_cipher(struct luks_phdr *hdr, struct crypt_device *ctx)
|
int LUKS_check_cipher(struct crypt_device *ctx, size_t keylength, const char *cipher, const char *cipher_mode)
|
||||||
{
|
{
|
||||||
int r;
|
int r;
|
||||||
struct volume_key *empty_key;
|
struct volume_key *empty_key;
|
||||||
char buf[SECTOR_SIZE];
|
char buf[SECTOR_SIZE];
|
||||||
|
|
||||||
log_dbg("Checking if cipher %s-%s is usable.", hdr->cipherName, hdr->cipherMode);
|
log_dbg("Checking if cipher %s-%s is usable.", cipher, cipher_mode);
|
||||||
|
|
||||||
empty_key = crypt_alloc_volume_key(hdr->keyBytes, NULL);
|
empty_key = crypt_alloc_volume_key(keylength, NULL);
|
||||||
if (!empty_key)
|
if (!empty_key)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
/* No need to get KEY quality random but it must avoid known weak keys. */
|
/* No need to get KEY quality random but it must avoid known weak keys. */
|
||||||
r = crypt_random_get(ctx, empty_key->key, empty_key->keylength, CRYPT_RND_NORMAL);
|
r = crypt_random_get(ctx, empty_key->key, empty_key->keylength, CRYPT_RND_NORMAL);
|
||||||
if (!r)
|
if (!r)
|
||||||
r = LUKS_decrypt_from_storage(buf, sizeof(buf), hdr->cipherName,
|
r = LUKS_decrypt_from_storage(buf, sizeof(buf), cipher, cipher_mode, empty_key, 0, ctx);
|
||||||
hdr->cipherMode, empty_key, 0, ctx);
|
|
||||||
|
|
||||||
crypt_free_volume_key(empty_key);
|
crypt_free_volume_key(empty_key);
|
||||||
crypt_memzero(buf, sizeof(buf));
|
crypt_memzero(buf, sizeof(buf));
|
||||||
@@ -767,10 +770,6 @@ int LUKS_generate_phdr(struct luks_phdr *header,
|
|||||||
|
|
||||||
LUKS_fix_header_compatible(header);
|
LUKS_fix_header_compatible(header);
|
||||||
|
|
||||||
r = LUKS_check_cipher(header, ctx);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
log_dbg("Generating LUKS header version %d using hash %s, %s, %s, MK %d bytes",
|
log_dbg("Generating LUKS header version %d using hash %s, %s, %s, MK %d bytes",
|
||||||
header->version, header->hashSpec ,header->cipherName, header->cipherMode,
|
header->version, header->hashSpec ,header->cipherName, header->cipherMode,
|
||||||
header->keyBytes);
|
header->keyBytes);
|
||||||
|
|||||||
@@ -99,6 +99,11 @@ struct luks_phdr {
|
|||||||
int LUKS_verify_volume_key(const struct luks_phdr *hdr,
|
int LUKS_verify_volume_key(const struct luks_phdr *hdr,
|
||||||
const struct volume_key *vk);
|
const struct volume_key *vk);
|
||||||
|
|
||||||
|
int LUKS_check_cipher(struct crypt_device *ctx,
|
||||||
|
size_t keylength,
|
||||||
|
const char *cipher,
|
||||||
|
const char *cipher_mode);
|
||||||
|
|
||||||
int LUKS_generate_phdr(
|
int LUKS_generate_phdr(
|
||||||
struct luks_phdr *header,
|
struct luks_phdr *header,
|
||||||
const struct volume_key *vk,
|
const struct volume_key *vk,
|
||||||
|
|||||||
@@ -155,6 +155,8 @@ int LUKS2_hdr_restore(struct crypt_device *cd,
|
|||||||
uint64_t LUKS2_hdr_and_areas_size(json_object *jobj);
|
uint64_t LUKS2_hdr_and_areas_size(json_object *jobj);
|
||||||
uint64_t LUKS2_keyslots_size(json_object *jobj);
|
uint64_t LUKS2_keyslots_size(json_object *jobj);
|
||||||
|
|
||||||
|
int LUKS2_keyslot_cipher_incompatible(struct crypt_device *cd);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Generic LUKS2 keyslot
|
* Generic LUKS2 keyslot
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -117,7 +117,7 @@ int LUKS2_keyslot_active_count(struct luks2_hdr *hdr, int segment)
|
|||||||
return num;
|
return num;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int LUKS2_keyslot_cipher_incompatible(struct crypt_device *cd)
|
int LUKS2_keyslot_cipher_incompatible(struct crypt_device *cd)
|
||||||
{
|
{
|
||||||
const char *cipher = crypt_get_cipher(cd);
|
const char *cipher = crypt_get_cipher(cd);
|
||||||
|
|
||||||
|
|||||||
21
lib/setup.c
21
lib/setup.c
@@ -1438,6 +1438,10 @@ static int _crypt_format_luks1(struct crypt_device *cd,
|
|||||||
&required_alignment,
|
&required_alignment,
|
||||||
&alignment_offset, DEFAULT_DISK_ALIGNMENT);
|
&alignment_offset, DEFAULT_DISK_ALIGNMENT);
|
||||||
|
|
||||||
|
r = LUKS_check_cipher(cd, volume_key_size, cipher, cipher_mode);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
r = LUKS_generate_phdr(&cd->u.luks1.hdr, cd->volume_key, cipher, cipher_mode,
|
r = LUKS_generate_phdr(&cd->u.luks1.hdr, cd->volume_key, cipher, cipher_mode,
|
||||||
cd->pbkdf.hash, uuid, LUKS_STRIPES,
|
cd->pbkdf.hash, uuid, LUKS_STRIPES,
|
||||||
required_alignment / SECTOR_SIZE,
|
required_alignment / SECTOR_SIZE,
|
||||||
@@ -1511,7 +1515,10 @@ static int _crypt_format_luks2(struct crypt_device *cd,
|
|||||||
else
|
else
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
if (INTEGRITY_key_size(cd, integrity) >= volume_key_size) {
|
||||||
|
log_err(cd, _("Volume key is too small for encryption with integrity extensions.\n"));
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
r = device_check_access(cd, crypt_metadata_device(cd), DEV_EXCL);
|
r = device_check_access(cd, crypt_metadata_device(cd), DEV_EXCL);
|
||||||
@@ -1563,6 +1570,14 @@ static int _crypt_format_luks2(struct crypt_device *cd,
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* FIXME: we have no way how to check AEAD ciphers,
|
||||||
|
* only length preserving mode or authenc() composed modes */
|
||||||
|
if (!LUKS2_keyslot_cipher_incompatible(cd)) {
|
||||||
|
r = LUKS_check_cipher(cd, volume_key_size, cipher, cipher_mode);
|
||||||
|
if (r < 0)
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
r = LUKS2_generate_hdr(cd, &cd->u.luks2.hdr, cd->volume_key,
|
r = LUKS2_generate_hdr(cd, &cd->u.luks2.hdr, cd->volume_key,
|
||||||
cipher, cipher_mode,
|
cipher, cipher_mode,
|
||||||
integrity, uuid,
|
integrity, uuid,
|
||||||
@@ -3618,10 +3633,10 @@ const char *crypt_get_integrity(struct crypt_device *cd)
|
|||||||
int crypt_get_integrity_key_size(struct crypt_device *cd)
|
int crypt_get_integrity_key_size(struct crypt_device *cd)
|
||||||
{
|
{
|
||||||
if (isINTEGRITY(cd->type))
|
if (isINTEGRITY(cd->type))
|
||||||
return INTEGRITY_key_size(cd);
|
return INTEGRITY_key_size(cd, crypt_get_integrity(cd));
|
||||||
|
|
||||||
if (isLUKS2(cd->type))
|
if (isLUKS2(cd->type))
|
||||||
return INTEGRITY_key_size(cd);
|
return INTEGRITY_key_size(cd, crypt_get_integrity(cd));
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1008,7 +1008,9 @@ static int action_luksFormat(void)
|
|||||||
if (luks_version != 2 && opt_integrity) {
|
if (luks_version != 2 && opt_integrity) {
|
||||||
log_err(_("Integrity option can be used only for LUKS2 format.\n"));
|
log_err(_("Integrity option can be used only for LUKS2 format.\n"));
|
||||||
goto out;
|
goto out;
|
||||||
} if (opt_integrity) {
|
}
|
||||||
|
|
||||||
|
if (opt_integrity) {
|
||||||
r = crypt_parse_integrity_mode(opt_integrity, integrity, &integrity_keysize);
|
r = crypt_parse_integrity_mode(opt_integrity, integrity, &integrity_keysize);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
log_err(_("No known integrity specification pattern detected.\n"));
|
log_err(_("No known integrity specification pattern detected.\n"));
|
||||||
|
|||||||
@@ -2748,6 +2748,11 @@ static void Luks2Integrity(void)
|
|||||||
EQ_(32+16, ip.tag_size);
|
EQ_(32+16, ip.tag_size);
|
||||||
OK_(crypt_deactivate(cd, CDEVICE_2));
|
OK_(crypt_deactivate(cd, CDEVICE_2));
|
||||||
crypt_free(cd);
|
crypt_free(cd);
|
||||||
|
|
||||||
|
OK_(crypt_init(&cd, DEVICE_2));
|
||||||
|
FAIL_(crypt_format(cd, CRYPT_LUKS2, cipher, cipher_mode, NULL, NULL, key_size - 32, ¶ms), "Wrong key size.");
|
||||||
|
FAIL_(crypt_format(cd, CRYPT_LUKS2, cipher, "xts-plainx", NULL, NULL, key_size, ¶ms), "Wrong cipher.");
|
||||||
|
crypt_free(cd);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void Luks2Flags(void)
|
static void Luks2Flags(void)
|
||||||
|
|||||||
Reference in New Issue
Block a user