qcrypto-luks: extract store key function
This function will be used later to store new keys to the luks metadata Signed-off-by: Maxim Levitsky <mlevitsk@redhat.com> Reviewed-by: Daniel P. Berrangé <berrange@redhat.com> Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
This commit is contained in:
parent
9fa9c1c28f
commit
3994a7c909
@ -623,6 +623,176 @@ qcrypto_block_luks_parse_header(QCryptoBlockLUKS *luks, Error **errp)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Given a key slot, user password, and the master key,
|
||||||
|
* will store the encrypted master key there, and update the
|
||||||
|
* in-memory header. User must then write the in-memory header
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* 0 if the keyslot was written successfully
|
||||||
|
* with the provided password
|
||||||
|
* -1 if a fatal error occurred while storing the key
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
qcrypto_block_luks_store_key(QCryptoBlock *block,
|
||||||
|
unsigned int slot_idx,
|
||||||
|
const char *password,
|
||||||
|
uint8_t *masterkey,
|
||||||
|
uint64_t iter_time,
|
||||||
|
QCryptoBlockWriteFunc writefunc,
|
||||||
|
void *opaque,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
QCryptoBlockLUKS *luks = block->opaque;
|
||||||
|
QCryptoBlockLUKSKeySlot *slot = &luks->header.key_slots[slot_idx];
|
||||||
|
g_autofree uint8_t *splitkey = NULL;
|
||||||
|
size_t splitkeylen;
|
||||||
|
g_autofree uint8_t *slotkey = NULL;
|
||||||
|
g_autoptr(QCryptoCipher) cipher = NULL;
|
||||||
|
g_autoptr(QCryptoIVGen) ivgen = NULL;
|
||||||
|
Error *local_err = NULL;
|
||||||
|
uint64_t iters;
|
||||||
|
int ret = -1;
|
||||||
|
|
||||||
|
if (qcrypto_random_bytes(slot->salt,
|
||||||
|
QCRYPTO_BLOCK_LUKS_SALT_LEN,
|
||||||
|
errp) < 0) {
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
splitkeylen = luks->header.master_key_len * slot->stripes;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Determine how many iterations are required to
|
||||||
|
* hash the user password while consuming 1 second of compute
|
||||||
|
* time
|
||||||
|
*/
|
||||||
|
iters = qcrypto_pbkdf2_count_iters(luks->hash_alg,
|
||||||
|
(uint8_t *)password, strlen(password),
|
||||||
|
slot->salt,
|
||||||
|
QCRYPTO_BLOCK_LUKS_SALT_LEN,
|
||||||
|
luks->header.master_key_len,
|
||||||
|
&local_err);
|
||||||
|
if (local_err) {
|
||||||
|
error_propagate(errp, local_err);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (iters > (ULLONG_MAX / iter_time)) {
|
||||||
|
error_setg_errno(errp, ERANGE,
|
||||||
|
"PBKDF iterations %llu too large to scale",
|
||||||
|
(unsigned long long)iters);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* iter_time was in millis, but count_iters reported for secs */
|
||||||
|
iters = iters * iter_time / 1000;
|
||||||
|
|
||||||
|
if (iters > UINT32_MAX) {
|
||||||
|
error_setg_errno(errp, ERANGE,
|
||||||
|
"PBKDF iterations %llu larger than %u",
|
||||||
|
(unsigned long long)iters, UINT32_MAX);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
slot->iterations =
|
||||||
|
MAX(iters, QCRYPTO_BLOCK_LUKS_MIN_SLOT_KEY_ITERS);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Generate a key that we'll use to encrypt the master
|
||||||
|
* key, from the user's password
|
||||||
|
*/
|
||||||
|
slotkey = g_new0(uint8_t, luks->header.master_key_len);
|
||||||
|
if (qcrypto_pbkdf2(luks->hash_alg,
|
||||||
|
(uint8_t *)password, strlen(password),
|
||||||
|
slot->salt,
|
||||||
|
QCRYPTO_BLOCK_LUKS_SALT_LEN,
|
||||||
|
slot->iterations,
|
||||||
|
slotkey, luks->header.master_key_len,
|
||||||
|
errp) < 0) {
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Setup the encryption objects needed to encrypt the
|
||||||
|
* master key material
|
||||||
|
*/
|
||||||
|
cipher = qcrypto_cipher_new(luks->cipher_alg,
|
||||||
|
luks->cipher_mode,
|
||||||
|
slotkey, luks->header.master_key_len,
|
||||||
|
errp);
|
||||||
|
if (!cipher) {
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
ivgen = qcrypto_ivgen_new(luks->ivgen_alg,
|
||||||
|
luks->ivgen_cipher_alg,
|
||||||
|
luks->ivgen_hash_alg,
|
||||||
|
slotkey, luks->header.master_key_len,
|
||||||
|
errp);
|
||||||
|
if (!ivgen) {
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Before storing the master key, we need to vastly
|
||||||
|
* increase its size, as protection against forensic
|
||||||
|
* disk data recovery
|
||||||
|
*/
|
||||||
|
splitkey = g_new0(uint8_t, splitkeylen);
|
||||||
|
|
||||||
|
if (qcrypto_afsplit_encode(luks->hash_alg,
|
||||||
|
luks->header.master_key_len,
|
||||||
|
slot->stripes,
|
||||||
|
masterkey,
|
||||||
|
splitkey,
|
||||||
|
errp) < 0) {
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Now we encrypt the split master key with the key generated
|
||||||
|
* from the user's password, before storing it
|
||||||
|
*/
|
||||||
|
if (qcrypto_block_cipher_encrypt_helper(cipher, block->niv, ivgen,
|
||||||
|
QCRYPTO_BLOCK_LUKS_SECTOR_SIZE,
|
||||||
|
0,
|
||||||
|
splitkey,
|
||||||
|
splitkeylen,
|
||||||
|
errp) < 0) {
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Write out the slot's master key material. */
|
||||||
|
if (writefunc(block,
|
||||||
|
slot->key_offset_sector *
|
||||||
|
QCRYPTO_BLOCK_LUKS_SECTOR_SIZE,
|
||||||
|
splitkey, splitkeylen,
|
||||||
|
opaque,
|
||||||
|
errp) != splitkeylen) {
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
slot->active = QCRYPTO_BLOCK_LUKS_KEY_SLOT_ENABLED;
|
||||||
|
|
||||||
|
if (qcrypto_block_luks_store_header(block, writefunc, opaque, errp) < 0) {
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
if (slotkey) {
|
||||||
|
memset(slotkey, 0, luks->header.master_key_len);
|
||||||
|
}
|
||||||
|
if (splitkey) {
|
||||||
|
memset(splitkey, 0, splitkeylen);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Given a key slot, and user password, this will attempt to unlock
|
* Given a key slot, and user password, this will attempt to unlock
|
||||||
* the master encryption key from the key slot.
|
* the master encryption key from the key slot.
|
||||||
@ -944,12 +1114,8 @@ qcrypto_block_luks_create(QCryptoBlock *block,
|
|||||||
QCryptoBlockCreateOptionsLUKS luks_opts;
|
QCryptoBlockCreateOptionsLUKS luks_opts;
|
||||||
Error *local_err = NULL;
|
Error *local_err = NULL;
|
||||||
g_autofree uint8_t *masterkey = NULL;
|
g_autofree uint8_t *masterkey = NULL;
|
||||||
g_autofree uint8_t *slotkey = NULL;
|
|
||||||
g_autofree uint8_t *splitkey = NULL;
|
|
||||||
size_t splitkeylen = 0;
|
size_t splitkeylen = 0;
|
||||||
size_t i;
|
size_t i;
|
||||||
g_autoptr(QCryptoCipher) cipher = NULL;
|
|
||||||
g_autoptr(QCryptoIVGen) ivgen = NULL;
|
|
||||||
g_autofree char *password = NULL;
|
g_autofree char *password = NULL;
|
||||||
const char *cipher_alg;
|
const char *cipher_alg;
|
||||||
const char *cipher_mode;
|
const char *cipher_mode;
|
||||||
@ -1172,9 +1338,7 @@ qcrypto_block_luks_create(QCryptoBlock *block,
|
|||||||
* to use the first key slot */
|
* to use the first key slot */
|
||||||
splitkeylen = luks->header.master_key_len * QCRYPTO_BLOCK_LUKS_STRIPES;
|
splitkeylen = luks->header.master_key_len * QCRYPTO_BLOCK_LUKS_STRIPES;
|
||||||
for (i = 0; i < QCRYPTO_BLOCK_LUKS_NUM_KEY_SLOTS; i++) {
|
for (i = 0; i < QCRYPTO_BLOCK_LUKS_NUM_KEY_SLOTS; i++) {
|
||||||
luks->header.key_slots[i].active = i == 0 ?
|
luks->header.key_slots[i].active = QCRYPTO_BLOCK_LUKS_KEY_SLOT_DISABLED;
|
||||||
QCRYPTO_BLOCK_LUKS_KEY_SLOT_ENABLED :
|
|
||||||
QCRYPTO_BLOCK_LUKS_KEY_SLOT_DISABLED;
|
|
||||||
luks->header.key_slots[i].stripes = QCRYPTO_BLOCK_LUKS_STRIPES;
|
luks->header.key_slots[i].stripes = QCRYPTO_BLOCK_LUKS_STRIPES;
|
||||||
|
|
||||||
/* This calculation doesn't match that shown in the spec,
|
/* This calculation doesn't match that shown in the spec,
|
||||||
@ -1188,107 +1352,6 @@ qcrypto_block_luks_create(QCryptoBlock *block,
|
|||||||
QCRYPTO_BLOCK_LUKS_SECTOR_SIZE)) * i);
|
QCRYPTO_BLOCK_LUKS_SECTOR_SIZE)) * i);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (qcrypto_random_bytes(luks->header.key_slots[0].salt,
|
|
||||||
QCRYPTO_BLOCK_LUKS_SALT_LEN,
|
|
||||||
errp) < 0) {
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Again we determine how many iterations are required to
|
|
||||||
* hash the user password while consuming 1 second of compute
|
|
||||||
* time */
|
|
||||||
iters = qcrypto_pbkdf2_count_iters(luks_opts.hash_alg,
|
|
||||||
(uint8_t *)password, strlen(password),
|
|
||||||
luks->header.key_slots[0].salt,
|
|
||||||
QCRYPTO_BLOCK_LUKS_SALT_LEN,
|
|
||||||
luks->header.master_key_len,
|
|
||||||
&local_err);
|
|
||||||
if (local_err) {
|
|
||||||
error_propagate(errp, local_err);
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (iters > (ULLONG_MAX / luks_opts.iter_time)) {
|
|
||||||
error_setg_errno(errp, ERANGE,
|
|
||||||
"PBKDF iterations %llu too large to scale",
|
|
||||||
(unsigned long long)iters);
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* iter_time was in millis, but count_iters reported for secs */
|
|
||||||
iters = iters * luks_opts.iter_time / 1000;
|
|
||||||
|
|
||||||
if (iters > UINT32_MAX) {
|
|
||||||
error_setg_errno(errp, ERANGE,
|
|
||||||
"PBKDF iterations %llu larger than %u",
|
|
||||||
(unsigned long long)iters, UINT32_MAX);
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
luks->header.key_slots[0].iterations =
|
|
||||||
MAX(iters, QCRYPTO_BLOCK_LUKS_MIN_SLOT_KEY_ITERS);
|
|
||||||
|
|
||||||
|
|
||||||
/* Generate a key that we'll use to encrypt the master
|
|
||||||
* key, from the user's password
|
|
||||||
*/
|
|
||||||
slotkey = g_new0(uint8_t, luks->header.master_key_len);
|
|
||||||
if (qcrypto_pbkdf2(luks_opts.hash_alg,
|
|
||||||
(uint8_t *)password, strlen(password),
|
|
||||||
luks->header.key_slots[0].salt,
|
|
||||||
QCRYPTO_BLOCK_LUKS_SALT_LEN,
|
|
||||||
luks->header.key_slots[0].iterations,
|
|
||||||
slotkey, luks->header.master_key_len,
|
|
||||||
errp) < 0) {
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Setup the encryption objects needed to encrypt the
|
|
||||||
* master key material
|
|
||||||
*/
|
|
||||||
cipher = qcrypto_cipher_new(luks_opts.cipher_alg,
|
|
||||||
luks_opts.cipher_mode,
|
|
||||||
slotkey, luks->header.master_key_len,
|
|
||||||
errp);
|
|
||||||
if (!cipher) {
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
ivgen = qcrypto_ivgen_new(luks_opts.ivgen_alg,
|
|
||||||
luks->ivgen_cipher_alg,
|
|
||||||
luks_opts.ivgen_hash_alg,
|
|
||||||
slotkey, luks->header.master_key_len,
|
|
||||||
errp);
|
|
||||||
if (!ivgen) {
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Before storing the master key, we need to vastly
|
|
||||||
* increase its size, as protection against forensic
|
|
||||||
* disk data recovery */
|
|
||||||
splitkey = g_new0(uint8_t, splitkeylen);
|
|
||||||
|
|
||||||
if (qcrypto_afsplit_encode(luks_opts.hash_alg,
|
|
||||||
luks->header.master_key_len,
|
|
||||||
luks->header.key_slots[0].stripes,
|
|
||||||
masterkey,
|
|
||||||
splitkey,
|
|
||||||
errp) < 0) {
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Now we encrypt the split master key with the key generated
|
|
||||||
* from the user's password, before storing it */
|
|
||||||
if (qcrypto_block_cipher_encrypt_helper(cipher, block->niv, ivgen,
|
|
||||||
QCRYPTO_BLOCK_LUKS_SECTOR_SIZE,
|
|
||||||
0,
|
|
||||||
splitkey,
|
|
||||||
splitkeylen,
|
|
||||||
errp) < 0) {
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* The total size of the LUKS headers is the partition header + key
|
/* The total size of the LUKS headers is the partition header + key
|
||||||
* slot headers, rounded up to the nearest sector, combined with
|
* slot headers, rounded up to the nearest sector, combined with
|
||||||
@ -1313,23 +1376,21 @@ qcrypto_block_luks_create(QCryptoBlock *block,
|
|||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (qcrypto_block_luks_store_header(block, writefunc, opaque, errp) < 0) {
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Write out the master key material, starting at the
|
/* populate the slot 0 with the password encrypted master key*/
|
||||||
* sector immediately following the partition header. */
|
/* This will also store the header */
|
||||||
if (writefunc(block,
|
if (qcrypto_block_luks_store_key(block,
|
||||||
luks->header.key_slots[0].key_offset_sector *
|
0,
|
||||||
QCRYPTO_BLOCK_LUKS_SECTOR_SIZE,
|
password,
|
||||||
splitkey, splitkeylen,
|
masterkey,
|
||||||
opaque,
|
luks_opts.iter_time,
|
||||||
errp) != splitkeylen) {
|
writefunc,
|
||||||
|
opaque,
|
||||||
|
errp) < 0) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(masterkey, 0, luks->header.master_key_len);
|
memset(masterkey, 0, luks->header.master_key_len);
|
||||||
memset(slotkey, 0, luks->header.master_key_len);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
@ -1337,9 +1398,6 @@ qcrypto_block_luks_create(QCryptoBlock *block,
|
|||||||
if (masterkey) {
|
if (masterkey) {
|
||||||
memset(masterkey, 0, luks->header.master_key_len);
|
memset(masterkey, 0, luks->header.master_key_len);
|
||||||
}
|
}
|
||||||
if (slotkey) {
|
|
||||||
memset(slotkey, 0, luks->header.master_key_len);
|
|
||||||
}
|
|
||||||
|
|
||||||
qcrypto_block_free_cipher(block);
|
qcrypto_block_free_cipher(block);
|
||||||
qcrypto_ivgen_free(block->ivgen);
|
qcrypto_ivgen_free(block->ivgen);
|
||||||
|
Loading…
Reference in New Issue
Block a user