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;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
* the master encryption key from the key slot.
|
||||
@ -944,12 +1114,8 @@ qcrypto_block_luks_create(QCryptoBlock *block,
|
||||
QCryptoBlockCreateOptionsLUKS luks_opts;
|
||||
Error *local_err = 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 i;
|
||||
g_autoptr(QCryptoCipher) cipher = NULL;
|
||||
g_autoptr(QCryptoIVGen) ivgen = NULL;
|
||||
g_autofree char *password = NULL;
|
||||
const char *cipher_alg;
|
||||
const char *cipher_mode;
|
||||
@ -1172,9 +1338,7 @@ qcrypto_block_luks_create(QCryptoBlock *block,
|
||||
* to use the first key slot */
|
||||
splitkeylen = luks->header.master_key_len * QCRYPTO_BLOCK_LUKS_STRIPES;
|
||||
for (i = 0; i < QCRYPTO_BLOCK_LUKS_NUM_KEY_SLOTS; i++) {
|
||||
luks->header.key_slots[i].active = i == 0 ?
|
||||
QCRYPTO_BLOCK_LUKS_KEY_SLOT_ENABLED :
|
||||
QCRYPTO_BLOCK_LUKS_KEY_SLOT_DISABLED;
|
||||
luks->header.key_slots[i].active = QCRYPTO_BLOCK_LUKS_KEY_SLOT_DISABLED;
|
||||
luks->header.key_slots[i].stripes = QCRYPTO_BLOCK_LUKS_STRIPES;
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
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
|
||||
* slot headers, rounded up to the nearest sector, combined with
|
||||
@ -1313,23 +1376,21 @@ qcrypto_block_luks_create(QCryptoBlock *block,
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (qcrypto_block_luks_store_header(block, writefunc, opaque, errp) < 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Write out the master key material, starting at the
|
||||
* sector immediately following the partition header. */
|
||||
if (writefunc(block,
|
||||
luks->header.key_slots[0].key_offset_sector *
|
||||
QCRYPTO_BLOCK_LUKS_SECTOR_SIZE,
|
||||
splitkey, splitkeylen,
|
||||
opaque,
|
||||
errp) != splitkeylen) {
|
||||
/* populate the slot 0 with the password encrypted master key*/
|
||||
/* This will also store the header */
|
||||
if (qcrypto_block_luks_store_key(block,
|
||||
0,
|
||||
password,
|
||||
masterkey,
|
||||
luks_opts.iter_time,
|
||||
writefunc,
|
||||
opaque,
|
||||
errp) < 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
memset(masterkey, 0, luks->header.master_key_len);
|
||||
memset(slotkey, 0, luks->header.master_key_len);
|
||||
|
||||
return 0;
|
||||
|
||||
@ -1337,9 +1398,6 @@ qcrypto_block_luks_create(QCryptoBlock *block,
|
||||
if (masterkey) {
|
||||
memset(masterkey, 0, luks->header.master_key_len);
|
||||
}
|
||||
if (slotkey) {
|
||||
memset(slotkey, 0, luks->header.master_key_len);
|
||||
}
|
||||
|
||||
qcrypto_block_free_cipher(block);
|
||||
qcrypto_ivgen_free(block->ivgen);
|
||||
|
Loading…
Reference in New Issue
Block a user