diff options
Diffstat (limited to 'crypto')
-rw-r--r-- | crypto/block-luks.c | 155 |
1 files changed, 93 insertions, 62 deletions
diff --git a/crypto/block-luks.c b/crypto/block-luks.c index b8f9b9c20a..47371edf13 100644 --- a/crypto/block-luks.c +++ b/crypto/block-luks.c @@ -410,6 +410,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; } |