Commit dde2c5af authored by Maxim Levitsky's avatar Maxim Levitsky Committed by Daniel P. Berrangé
Browse files

qcrypto-luks: extract store and load header

parent 61dd8a9a
Loading
Loading
Loading
Loading
+93 −62
Original line number Diff line number Diff line
@@ -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;
    }