qcrypto-luks: extract store and load header

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:
Maxim Levitsky 2019-09-26 00:35:22 +03:00 committed by Daniel P. Berrangé
parent 61dd8a9a52
commit dde2c5afeb
1 changed files with 93 additions and 62 deletions

View File

@ -409,6 +409,97 @@ qcrypto_block_luks_essiv_cipher(QCryptoCipherAlgorithm cipher,
}
}
/*
* Stores the main LUKS header, taking care of endianess
*/
static int
qcrypto_block_luks_store_header(QCryptoBlock *block,
QCryptoBlockWriteFunc writefunc,
void *opaque,
Error **errp)
{
const QCryptoBlockLUKS *luks = block->opaque;
Error *local_err = NULL;
size_t i;
g_autofree QCryptoBlockLUKSHeader *hdr_copy = NULL;
/* Create a copy of the header */
hdr_copy = g_new0(QCryptoBlockLUKSHeader, 1);
memcpy(hdr_copy, &luks->header, sizeof(QCryptoBlockLUKSHeader));
/*
* Everything on disk uses Big Endian (tm), so flip header fields
* before writing them
*/
cpu_to_be16s(&hdr_copy->version);
cpu_to_be32s(&hdr_copy->payload_offset_sector);
cpu_to_be32s(&hdr_copy->master_key_len);
cpu_to_be32s(&hdr_copy->master_key_iterations);
for (i = 0; i < QCRYPTO_BLOCK_LUKS_NUM_KEY_SLOTS; i++) {
cpu_to_be32s(&hdr_copy->key_slots[i].active);
cpu_to_be32s(&hdr_copy->key_slots[i].iterations);
cpu_to_be32s(&hdr_copy->key_slots[i].key_offset_sector);
cpu_to_be32s(&hdr_copy->key_slots[i].stripes);
}
/* Write out the partition header and key slot headers */
writefunc(block, 0, (const uint8_t *)hdr_copy, sizeof(*hdr_copy),
opaque, &local_err);
if (local_err) {
error_propagate(errp, local_err);
return -1;
}
return 0;
}
/*
* Loads the main LUKS header,and byteswaps it to native endianess
* And run basic sanity checks on it
*/
static int
qcrypto_block_luks_load_header(QCryptoBlock *block,
QCryptoBlockReadFunc readfunc,
void *opaque,
Error **errp)
{
ssize_t rv;
size_t i;
QCryptoBlockLUKS *luks = block->opaque;
/*
* Read the entire LUKS header, minus the key material from
* the underlying device
*/
rv = readfunc(block, 0,
(uint8_t *)&luks->header,
sizeof(luks->header),
opaque,
errp);
if (rv < 0) {
return rv;
}
/*
* The header is always stored in big-endian format, so
* convert everything to native
*/
be16_to_cpus(&luks->header.version);
be32_to_cpus(&luks->header.payload_offset_sector);
be32_to_cpus(&luks->header.master_key_len);
be32_to_cpus(&luks->header.master_key_iterations);
for (i = 0; i < QCRYPTO_BLOCK_LUKS_NUM_KEY_SLOTS; i++) {
be32_to_cpus(&luks->header.key_slots[i].active);
be32_to_cpus(&luks->header.key_slots[i].iterations);
be32_to_cpus(&luks->header.key_slots[i].key_offset_sector);
be32_to_cpus(&luks->header.key_slots[i].stripes);
}
return 0;
}
/*
* Given a key slot, and user password, this will attempt to unlock
* the master encryption key from the key slot.
@ -622,7 +713,6 @@ qcrypto_block_luks_open(QCryptoBlock *block,
{
QCryptoBlockLUKS *luks = NULL;
Error *local_err = NULL;
size_t i;
g_autofree uint8_t *masterkey = NULL;
char *ivgen_name, *ivhash_name;
g_autofree char *password = NULL;
@ -644,30 +734,10 @@ qcrypto_block_luks_open(QCryptoBlock *block,
luks = g_new0(QCryptoBlockLUKS, 1);
block->opaque = luks;
/* Read the entire LUKS header, minus the key material from
* the underlying device */
if (readfunc(block, 0,
(uint8_t *)&luks->header,
sizeof(luks->header),
opaque,
errp) < 0) {
if (qcrypto_block_luks_load_header(block, readfunc, opaque, errp) < 0) {
goto fail;
}
/* The header is always stored in big-endian format, so
* convert everything to native */
be16_to_cpus(&luks->header.version);
be32_to_cpus(&luks->header.payload_offset_sector);
be32_to_cpus(&luks->header.master_key_len);
be32_to_cpus(&luks->header.master_key_iterations);
for (i = 0; i < QCRYPTO_BLOCK_LUKS_NUM_KEY_SLOTS; i++) {
be32_to_cpus(&luks->header.key_slots[i].active);
be32_to_cpus(&luks->header.key_slots[i].iterations);
be32_to_cpus(&luks->header.key_slots[i].key_offset_sector);
be32_to_cpus(&luks->header.key_slots[i].stripes);
}
if (memcmp(luks->header.magic, qcrypto_block_luks_magic,
QCRYPTO_BLOCK_LUKS_MAGIC_LEN) != 0) {
error_setg(errp, "Volume is not in LUKS format");
@ -1216,46 +1286,7 @@ qcrypto_block_luks_create(QCryptoBlock *block,
goto error;
}
/* Everything on disk uses Big Endian, so flip header fields
* before writing them */
cpu_to_be16s(&luks->header.version);
cpu_to_be32s(&luks->header.payload_offset_sector);
cpu_to_be32s(&luks->header.master_key_len);
cpu_to_be32s(&luks->header.master_key_iterations);
for (i = 0; i < QCRYPTO_BLOCK_LUKS_NUM_KEY_SLOTS; i++) {
cpu_to_be32s(&luks->header.key_slots[i].active);
cpu_to_be32s(&luks->header.key_slots[i].iterations);
cpu_to_be32s(&luks->header.key_slots[i].key_offset_sector);
cpu_to_be32s(&luks->header.key_slots[i].stripes);
}
/* Write out the partition header and key slot headers */
writefunc(block, 0,
(const uint8_t *)&luks->header,
sizeof(luks->header),
opaque,
&local_err);
/* Delay checking local_err until we've byte-swapped */
/* Byte swap the header back to native, in case we need
* to read it again later */
be16_to_cpus(&luks->header.version);
be32_to_cpus(&luks->header.payload_offset_sector);
be32_to_cpus(&luks->header.master_key_len);
be32_to_cpus(&luks->header.master_key_iterations);
for (i = 0; i < QCRYPTO_BLOCK_LUKS_NUM_KEY_SLOTS; i++) {
be32_to_cpus(&luks->header.key_slots[i].active);
be32_to_cpus(&luks->header.key_slots[i].iterations);
be32_to_cpus(&luks->header.key_slots[i].key_offset_sector);
be32_to_cpus(&luks->header.key_slots[i].stripes);
}
if (local_err) {
error_propagate(errp, local_err);
if (qcrypto_block_luks_store_header(block, writefunc, opaque, errp) < 0) {
goto error;
}