qcrypto_block_luks_create(QCryptoBlock *block,

                          QCryptoBlockCreateOptions *options,

                          const char *optprefix,

                          QCryptoBlockInitFunc initfunc,

                          QCryptoBlockWriteFunc writefunc,

                          void *opaque,

                          Error **errp)

{

    QCryptoBlockLUKS *luks;

    QCryptoBlockCreateOptionsLUKS luks_opts;

    Error *local_err = NULL;

    uint8_t *masterkey = NULL;

    uint8_t *slotkey = NULL;

    uint8_t *splitkey = NULL;

    size_t splitkeylen = 0;

    size_t i;

    QCryptoCipher *cipher = NULL;

    QCryptoIVGen *ivgen = NULL;

    char *password;

    const char *cipher_alg;

    const char *cipher_mode;

    const char *ivgen_alg;

    const char *ivgen_hash_alg = NULL;

    const char *hash_alg;

    char *cipher_mode_spec = NULL;

    QCryptoCipherAlgorithm ivcipheralg = 0;

    uint64_t iters;



    memcpy(&luks_opts, &options->u.luks, sizeof(luks_opts));

    if (!luks_opts.has_iter_time) {

        luks_opts.iter_time = 2000;

    }

    if (!luks_opts.has_cipher_alg) {

        luks_opts.cipher_alg = QCRYPTO_CIPHER_ALG_AES_256;

    }

    if (!luks_opts.has_cipher_mode) {

        luks_opts.cipher_mode = QCRYPTO_CIPHER_MODE_XTS;

    }

    if (!luks_opts.has_ivgen_alg) {

        luks_opts.ivgen_alg = QCRYPTO_IVGEN_ALG_PLAIN64;

    }

    if (!luks_opts.has_hash_alg) {

        luks_opts.hash_alg = QCRYPTO_HASH_ALG_SHA256;

    }

    if (luks_opts.ivgen_alg == QCRYPTO_IVGEN_ALG_ESSIV) {

        if (!luks_opts.has_ivgen_hash_alg) {

            luks_opts.ivgen_hash_alg = QCRYPTO_HASH_ALG_SHA256;

            luks_opts.has_ivgen_hash_alg = true;

        }

    }

    /* Note we're allowing ivgen_hash_alg to be set even for

     * non-essiv iv generators that don't need a hash. It will

     * be silently ignored, for compatibility with dm-crypt */



    if (!options->u.luks.key_secret) {

        error_setg(errp, "Parameter '%skey-secret' is required for cipher",

                   optprefix ? optprefix : "");

        return -1;

    }

    password = qcrypto_secret_lookup_as_utf8(luks_opts.key_secret, errp);

    if (!password) {

        return -1;

    }



    luks = g_new0(QCryptoBlockLUKS, 1);

    block->opaque = luks;



    memcpy(luks->header.magic, qcrypto_block_luks_magic,

           QCRYPTO_BLOCK_LUKS_MAGIC_LEN);



    /* We populate the header in native endianness initially and

     * then convert everything to big endian just before writing

     * it out to disk

     */

    luks->header.version = QCRYPTO_BLOCK_LUKS_VERSION;

    qcrypto_block_luks_uuid_gen(luks->header.uuid);



    cipher_alg = qcrypto_block_luks_cipher_alg_lookup(luks_opts.cipher_alg,

                                                      errp);

    if (!cipher_alg) {

        goto error;

    }



    cipher_mode = QCryptoCipherMode_str(luks_opts.cipher_mode);

    ivgen_alg = QCryptoIVGenAlgorithm_str(luks_opts.ivgen_alg);

    if (luks_opts.has_ivgen_hash_alg) {

        ivgen_hash_alg = QCryptoHashAlgorithm_str(luks_opts.ivgen_hash_alg);

        cipher_mode_spec = g_strdup_printf("%s-%s:%s", cipher_mode, ivgen_alg,

                                           ivgen_hash_alg);

    } else {

        cipher_mode_spec = g_strdup_printf("%s-%s", cipher_mode, ivgen_alg);

    }

    hash_alg = QCryptoHashAlgorithm_str(luks_opts.hash_alg);





    if (strlen(cipher_alg) >= QCRYPTO_BLOCK_LUKS_CIPHER_NAME_LEN) {

        error_setg(errp, "Cipher name '%s' is too long for LUKS header",

                   cipher_alg);

        goto error;

    }

    if (strlen(cipher_mode_spec) >= QCRYPTO_BLOCK_LUKS_CIPHER_MODE_LEN) {

        error_setg(errp, "Cipher mode '%s' is too long for LUKS header",

                   cipher_mode_spec);

        goto error;

    }

    if (strlen(hash_alg) >= QCRYPTO_BLOCK_LUKS_HASH_SPEC_LEN) {

        error_setg(errp, "Hash name '%s' is too long for LUKS header",

                   hash_alg);

        goto error;

    }



    if (luks_opts.ivgen_alg == QCRYPTO_IVGEN_ALG_ESSIV) {

        ivcipheralg = qcrypto_block_luks_essiv_cipher(luks_opts.cipher_alg,

                                                      luks_opts.ivgen_hash_alg,

                                                      &local_err);

        if (local_err) {

            error_propagate(errp, local_err);

            goto error;

        }

    } else {

        ivcipheralg = luks_opts.cipher_alg;

    }



    strcpy(luks->header.cipher_name, cipher_alg);

    strcpy(luks->header.cipher_mode, cipher_mode_spec);

    strcpy(luks->header.hash_spec, hash_alg);



    luks->header.key_bytes = qcrypto_cipher_get_key_len(luks_opts.cipher_alg);

    if (luks_opts.cipher_mode == QCRYPTO_CIPHER_MODE_XTS) {

        luks->header.key_bytes *= 2;

    }



    /* Generate the salt used for hashing the master key

     * with PBKDF later

     */

    if (qcrypto_random_bytes(luks->header.master_key_salt,

                             QCRYPTO_BLOCK_LUKS_SALT_LEN,

                             errp) < 0) {

        goto error;

    }



    /* Generate random master key */

    masterkey = g_new0(uint8_t, luks->header.key_bytes);

    if (qcrypto_random_bytes(masterkey,

                             luks->header.key_bytes, errp) < 0) {

        goto error;

    }





    /* Setup the block device payload encryption objects */

    block->cipher = qcrypto_cipher_new(luks_opts.cipher_alg,

                                       luks_opts.cipher_mode,

                                       masterkey, luks->header.key_bytes,

                                       errp);

    if (!block->cipher) {

        goto error;

    }



    block->kdfhash = luks_opts.hash_alg;

    block->niv = qcrypto_cipher_get_iv_len(luks_opts.cipher_alg,

                                           luks_opts.cipher_mode);

    block->ivgen = qcrypto_ivgen_new(luks_opts.ivgen_alg,

                                     ivcipheralg,

                                     luks_opts.ivgen_hash_alg,

                                     masterkey, luks->header.key_bytes,

                                     errp);



    if (!block->ivgen) {

        goto error;

    }





    /* Determine how many iterations we need to hash the master

     * key, in order to have 1 second of compute time used

     */

    iters = qcrypto_pbkdf2_count_iters(luks_opts.hash_alg,

                                       masterkey, luks->header.key_bytes,

                                       luks->header.master_key_salt,

                                       QCRYPTO_BLOCK_LUKS_SALT_LEN,

                                       QCRYPTO_BLOCK_LUKS_DIGEST_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;



    /* Why /= 8 ?  That matches cryptsetup, but there's no

     * explanation why they chose /= 8... Probably so that

     * if all 8 keyslots are active we only spend 1 second

     * in total time to check all keys */

    iters /= 8;

    if (iters > UINT32_MAX) {

        error_setg_errno(errp, ERANGE,

                         "PBKDF iterations %llu larger than %u",

                         (unsigned long long)iters, UINT32_MAX);

        goto error;

    }

    iters = MAX(iters, QCRYPTO_BLOCK_LUKS_MIN_MASTER_KEY_ITERS);

    luks->header.master_key_iterations = iters;



    /* Hash the master key, saving the result in the LUKS

     * header. This hash is used when opening the encrypted

     * device to verify that the user password unlocked a

     * valid master key

     */

    if (qcrypto_pbkdf2(luks_opts.hash_alg,

                       masterkey, luks->header.key_bytes,

                       luks->header.master_key_salt,

                       QCRYPTO_BLOCK_LUKS_SALT_LEN,

                       luks->header.master_key_iterations,

                       luks->header.master_key_digest,

                       QCRYPTO_BLOCK_LUKS_DIGEST_LEN,

                       errp) < 0) {

        goto error;

    }





    /* Although LUKS has multiple key slots, we're just going

     * to use the first key slot */

    splitkeylen = luks->header.key_bytes * 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].stripes = QCRYPTO_BLOCK_LUKS_STRIPES;



        /* This calculation doesn't match that shown in the spec,

         * but instead follows the cryptsetup implementation.

         */

        luks->header.key_slots[i].key_offset =

            (QCRYPTO_BLOCK_LUKS_KEY_SLOT_OFFSET /

             QCRYPTO_BLOCK_LUKS_SECTOR_SIZE) +

            (ROUND_UP(DIV_ROUND_UP(splitkeylen, QCRYPTO_BLOCK_LUKS_SECTOR_SIZE),

                      (QCRYPTO_BLOCK_LUKS_KEY_SLOT_OFFSET /

                       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.key_bytes,

                                       &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.key_bytes);

    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.key_bytes,

                       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.key_bytes,

                                errp);

    if (!cipher) {

        goto error;

    }



    ivgen = qcrypto_ivgen_new(luks_opts.ivgen_alg,

                              ivcipheralg,

                              luks_opts.ivgen_hash_alg,

                              slotkey, luks->header.key_bytes,

                              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.key_bytes,

                               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_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

     * the size of each master key material region, also rounded up

     * to the nearest sector */

    luks->header.payload_offset =

        (QCRYPTO_BLOCK_LUKS_KEY_SLOT_OFFSET /

         QCRYPTO_BLOCK_LUKS_SECTOR_SIZE) +

        (ROUND_UP(DIV_ROUND_UP(splitkeylen, QCRYPTO_BLOCK_LUKS_SECTOR_SIZE),

                  (QCRYPTO_BLOCK_LUKS_KEY_SLOT_OFFSET /

                   QCRYPTO_BLOCK_LUKS_SECTOR_SIZE)) *

         QCRYPTO_BLOCK_LUKS_NUM_KEY_SLOTS);



    block->payload_offset = luks->header.payload_offset *

        QCRYPTO_BLOCK_LUKS_SECTOR_SIZE;



    /* Reserve header space to match payload offset */

    initfunc(block, block->payload_offset, opaque, &local_err);

    if (local_err) {

        error_propagate(errp, local_err);

        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);

    cpu_to_be32s(&luks->header.key_bytes);

    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);

        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);

    be32_to_cpus(&luks->header.key_bytes);

    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);

        be32_to_cpus(&luks->header.key_slots[i].stripes);

    }



    if (local_err) {

        error_propagate(errp, local_err);

        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 *

                  QCRYPTO_BLOCK_LUKS_SECTOR_SIZE,

                  splitkey, splitkeylen,

                  opaque,

                  errp) != splitkeylen) {

        goto error;

    }



    luks->cipher_alg = luks_opts.cipher_alg;

    luks->cipher_mode = luks_opts.cipher_mode;

    luks->ivgen_alg = luks_opts.ivgen_alg;

    luks->ivgen_hash_alg = luks_opts.ivgen_hash_alg;

    luks->hash_alg = luks_opts.hash_alg;



    memset(masterkey, 0, luks->header.key_bytes);

    g_free(masterkey);

    memset(slotkey, 0, luks->header.key_bytes);

    g_free(slotkey);

    g_free(splitkey);

    g_free(password);

    g_free(cipher_mode_spec);



    qcrypto_ivgen_free(ivgen);

    qcrypto_cipher_free(cipher);



    return 0;



 error:

    if (masterkey) {

        memset(masterkey, 0, luks->header.key_bytes);

    }

    g_free(masterkey);

    if (slotkey) {

        memset(slotkey, 0, luks->header.key_bytes);

    }

    g_free(slotkey);

    g_free(splitkey);

    g_free(password);

    g_free(cipher_mode_spec);



    qcrypto_ivgen_free(ivgen);

    qcrypto_cipher_free(cipher);



    g_free(luks);

    return -1;

}

qcrypto_block_luks_create(QCryptoBlock *block,

                          QCryptoBlockCreateOptions *options,

                          const char *optprefix,

                          QCryptoBlockInitFunc initfunc,

                          QCryptoBlockWriteFunc writefunc,

                          void *opaque,

                          Error **errp)

{

    QCryptoBlockLUKS *luks;

    QCryptoBlockCreateOptionsLUKS luks_opts;

    Error *local_err = NULL;

    uint8_t *masterkey = NULL;

    uint8_t *slotkey = NULL;

    uint8_t *splitkey = NULL;

    size_t splitkeylen = 0;

    size_t i;

    QCryptoCipher *cipher = NULL;

    QCryptoIVGen *ivgen = NULL;

    char *password;

    const char *cipher_alg;

    const char *cipher_mode;

    const char *ivgen_alg;

    const char *ivgen_hash_alg = NULL;

    const char *hash_alg;

    char *cipher_mode_spec = NULL;

    QCryptoCipherAlgorithm ivcipheralg = 0;

    uint64_t iters;



    memcpy(&luks_opts, &options->u.luks, sizeof(luks_opts));

    if (!luks_opts.has_iter_time) {

        luks_opts.iter_time = 2000;

    }

    if (!luks_opts.has_cipher_alg) {

        luks_opts.cipher_alg = QCRYPTO_CIPHER_ALG_AES_256;

    }

    if (!luks_opts.has_cipher_mode) {

        luks_opts.cipher_mode = QCRYPTO_CIPHER_MODE_XTS;

    }

    if (!luks_opts.has_ivgen_alg) {

        luks_opts.ivgen_alg = QCRYPTO_IVGEN_ALG_PLAIN64;

    }

    if (!luks_opts.has_hash_alg) {

        luks_opts.hash_alg = QCRYPTO_HASH_ALG_SHA256;

    }

    if (luks_opts.ivgen_alg == QCRYPTO_IVGEN_ALG_ESSIV) {

        if (!luks_opts.has_ivgen_hash_alg) {

            luks_opts.ivgen_hash_alg = QCRYPTO_HASH_ALG_SHA256;

            luks_opts.has_ivgen_hash_alg = true;

        }

    }

    







    if (!options->u.luks.key_secret) {

        error_setg(errp, "Parameter '%skey-secret' is required for cipher",

                   optprefix ? optprefix : "");

        return -1;

    }

    password = qcrypto_secret_lookup_as_utf8(luks_opts.key_secret, errp);

    if (!password) {

        return -1;

    }



    luks = g_new0(QCryptoBlockLUKS, 1);

    block->opaque = luks;



    memcpy(luks->header.magic, qcrypto_block_luks_magic,

           QCRYPTO_BLOCK_LUKS_MAGIC_LEN);



    







    luks->header.version = QCRYPTO_BLOCK_LUKS_VERSION;

    qcrypto_block_luks_uuid_gen(luks->header.uuid);



    cipher_alg = qcrypto_block_luks_cipher_alg_lookup(luks_opts.cipher_alg,

                                                      errp);

    if (!cipher_alg) {

        goto error;

    }



    cipher_mode = QCryptoCipherMode_str(luks_opts.cipher_mode);

    ivgen_alg = QCryptoIVGenAlgorithm_str(luks_opts.ivgen_alg);

    if (luks_opts.has_ivgen_hash_alg) {

        ivgen_hash_alg = QCryptoHashAlgorithm_str(luks_opts.ivgen_hash_alg);

        cipher_mode_spec = g_strdup_printf("%s-%s:%s", cipher_mode, ivgen_alg,

                                           ivgen_hash_alg);

    } else {

        cipher_mode_spec = g_strdup_printf("%s-%s", cipher_mode, ivgen_alg);

    }

    hash_alg = QCryptoHashAlgorithm_str(luks_opts.hash_alg);





    if (strlen(cipher_alg) >= QCRYPTO_BLOCK_LUKS_CIPHER_NAME_LEN) {

        error_setg(errp, "Cipher name '%s' is too long for LUKS header",

                   cipher_alg);

        goto error;

    }

    if (strlen(cipher_mode_spec) >= QCRYPTO_BLOCK_LUKS_CIPHER_MODE_LEN) {

        error_setg(errp, "Cipher mode '%s' is too long for LUKS header",

                   cipher_mode_spec);

        goto error;

    }

    if (strlen(hash_alg) >= QCRYPTO_BLOCK_LUKS_HASH_SPEC_LEN) {

        error_setg(errp, "Hash name '%s' is too long for LUKS header",

                   hash_alg);

        goto error;

    }



    if (luks_opts.ivgen_alg == QCRYPTO_IVGEN_ALG_ESSIV) {

        ivcipheralg = qcrypto_block_luks_essiv_cipher(luks_opts.cipher_alg,

                                                      luks_opts.ivgen_hash_alg,

                                                      &local_err);

        if (local_err) {

            error_propagate(errp, local_err);

            goto error;

        }

    } else {

        ivcipheralg = luks_opts.cipher_alg;

    }



    strcpy(luks->header.cipher_name, cipher_alg);

    strcpy(luks->header.cipher_mode, cipher_mode_spec);

    strcpy(luks->header.hash_spec, hash_alg);



    luks->header.key_bytes = qcrypto_cipher_get_key_len(luks_opts.cipher_alg);

    if (luks_opts.cipher_mode == QCRYPTO_CIPHER_MODE_XTS) {

        luks->header.key_bytes *= 2;

    }



    





    if (qcrypto_random_bytes(luks->header.master_key_salt,

                             QCRYPTO_BLOCK_LUKS_SALT_LEN,

                             errp) < 0) {

        goto error;

    }



    

    masterkey = g_new0(uint8_t, luks->header.key_bytes);

    if (qcrypto_random_bytes(masterkey,

                             luks->header.key_bytes, errp) < 0) {

        goto error;

    }





    

    block->cipher = qcrypto_cipher_new(luks_opts.cipher_alg,

                                       luks_opts.cipher_mode,

                                       masterkey, luks->header.key_bytes,

                                       errp);

    if (!block->cipher) {

        goto error;

    }



    block->kdfhash = luks_opts.hash_alg;

    block->niv = qcrypto_cipher_get_iv_len(luks_opts.cipher_alg,

                                           luks_opts.cipher_mode);

    block->ivgen = qcrypto_ivgen_new(luks_opts.ivgen_alg,

                                     ivcipheralg,

                                     luks_opts.ivgen_hash_alg,

                                     masterkey, luks->header.key_bytes,

                                     errp);



    if (!block->ivgen) {

        goto error;

    }





    





    iters = qcrypto_pbkdf2_count_iters(luks_opts.hash_alg,

                                       masterkey, luks->header.key_bytes,

                                       luks->header.master_key_salt,

                                       QCRYPTO_BLOCK_LUKS_SALT_LEN,

                                       QCRYPTO_BLOCK_LUKS_DIGEST_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;

    }



    

    iters = iters * luks_opts.iter_time / 1000;



    







    iters /= 8;

    if (iters > UINT32_MAX) {

        error_setg_errno(errp, ERANGE,

                         "PBKDF iterations %llu larger than %u",

                         (unsigned long long)iters, UINT32_MAX);

        goto error;

    }

    iters = MAX(iters, QCRYPTO_BLOCK_LUKS_MIN_MASTER_KEY_ITERS);

    luks->header.master_key_iterations = iters;



    









    if (qcrypto_pbkdf2(luks_opts.hash_alg,

                       masterkey, luks->header.key_bytes,

                       luks->header.master_key_salt,

                       QCRYPTO_BLOCK_LUKS_SALT_LEN,

                       luks->header.master_key_iterations,

                       luks->header.master_key_digest,

                       QCRYPTO_BLOCK_LUKS_DIGEST_LEN,

                       errp) < 0) {

        goto error;

    }





    



    splitkeylen = luks->header.key_bytes * 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].stripes = QCRYPTO_BLOCK_LUKS_STRIPES;



        





        luks->header.key_slots[i].key_offset =

            (QCRYPTO_BLOCK_LUKS_KEY_SLOT_OFFSET /

             QCRYPTO_BLOCK_LUKS_SECTOR_SIZE) +

            (ROUND_UP(DIV_ROUND_UP(splitkeylen, QCRYPTO_BLOCK_LUKS_SECTOR_SIZE),

                      (QCRYPTO_BLOCK_LUKS_KEY_SLOT_OFFSET /

                       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;

    }



    





    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.key_bytes,

                                       &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;

    }



    

    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);





    





    slotkey = g_new0(uint8_t, luks->header.key_bytes);

    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.key_bytes,

                       errp) < 0) {

        goto error;

    }





    





    cipher = qcrypto_cipher_new(luks_opts.cipher_alg,

                                luks_opts.cipher_mode,

                                slotkey, luks->header.key_bytes,

                                errp);

    if (!cipher) {

        goto error;

    }



    ivgen = qcrypto_ivgen_new(luks_opts.ivgen_alg,

                              ivcipheralg,

                              luks_opts.ivgen_hash_alg,

                              slotkey, luks->header.key_bytes,

                              errp);

    if (!ivgen) {

        goto error;

    }



    





    splitkey = g_new0(uint8_t, splitkeylen);



    if (qcrypto_afsplit_encode(luks_opts.hash_alg,

                               luks->header.key_bytes,

                               luks->header.key_slots[0].stripes,

                               masterkey,

                               splitkey,

                               errp) < 0) {

        goto error;

    }



    



    if (qcrypto_block_encrypt_helper(cipher, block->niv, ivgen,

                                     QCRYPTO_BLOCK_LUKS_SECTOR_SIZE,

                                     0,

                                     splitkey,

                                     splitkeylen,

                                     errp) < 0) {

        goto error;

    }





    







    luks->header.payload_offset =

        (QCRYPTO_BLOCK_LUKS_KEY_SLOT_OFFSET /

         QCRYPTO_BLOCK_LUKS_SECTOR_SIZE) +

        (ROUND_UP(DIV_ROUND_UP(splitkeylen, QCRYPTO_BLOCK_LUKS_SECTOR_SIZE),

                  (QCRYPTO_BLOCK_LUKS_KEY_SLOT_OFFSET /

                   QCRYPTO_BLOCK_LUKS_SECTOR_SIZE)) *

         QCRYPTO_BLOCK_LUKS_NUM_KEY_SLOTS);



    block->payload_offset = luks->header.payload_offset *

        QCRYPTO_BLOCK_LUKS_SECTOR_SIZE;



    

    initfunc(block, block->payload_offset, opaque, &local_err);

    if (local_err) {

        error_propagate(errp, local_err);

        goto error;

    }



    



    cpu_to_be16s(&luks->header.version);

    cpu_to_be32s(&luks->header.payload_offset);

    cpu_to_be32s(&luks->header.key_bytes);

    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);

        cpu_to_be32s(&luks->header.key_slots[i].stripes);

    }





    

    writefunc(block, 0,

              (const uint8_t *)&luks->header,

              sizeof(luks->header),

              opaque,

              &local_err);



    



    



    be16_to_cpus(&luks->header.version);

    be32_to_cpus(&luks->header.payload_offset);

    be32_to_cpus(&luks->header.key_bytes);

    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);

        be32_to_cpus(&luks->header.key_slots[i].stripes);

    }



    if (local_err) {

        error_propagate(errp, local_err);

        goto error;

    }



    



    if (writefunc(block,

                  luks->header.key_slots[0].key_offset *

                  QCRYPTO_BLOCK_LUKS_SECTOR_SIZE,

                  splitkey, splitkeylen,

                  opaque,

                  errp) != splitkeylen) {

        goto error;

    }



    luks->cipher_alg = luks_opts.cipher_alg;

    luks->cipher_mode = luks_opts.cipher_mode;

    luks->ivgen_alg = luks_opts.ivgen_alg;

    luks->ivgen_hash_alg = luks_opts.ivgen_hash_alg;

    luks->hash_alg = luks_opts.hash_alg;



    memset(masterkey, 0, luks->header.key_bytes);

    g_free(masterkey);

    memset(slotkey, 0, luks->header.key_bytes);

    g_free(slotkey);

    g_free(splitkey);

    g_free(password);

    g_free(cipher_mode_spec);



    qcrypto_ivgen_free(ivgen);

    qcrypto_cipher_free(cipher);



    return 0;



 error:

    if (masterkey) {

        memset(masterkey, 0, luks->header.key_bytes);

    }

    g_free(masterkey);

    if (slotkey) {

        memset(slotkey, 0, luks->header.key_bytes);

    }

    g_free(slotkey);

    g_free(splitkey);

    g_free(password);

    g_free(cipher_mode_spec);



    qcrypto_ivgen_free(ivgen);

    qcrypto_cipher_free(cipher);



    g_free(luks);

    return -1;

}

FUNC_0(QCryptoBlock *VAR_0,

                          QCryptoBlockCreateOptions *VAR_1,

                          const char *VAR_2,

                          QCryptoBlockInitFunc VAR_3,

                          QCryptoBlockWriteFunc VAR_4,

                          void *VAR_5,

                          Error **VAR_6)

{

    QCryptoBlockLUKS *luks;

    QCryptoBlockCreateOptionsLUKS luks_opts;

    Error *local_err = NULL;

    uint8_t *masterkey = NULL;

    uint8_t *slotkey = NULL;

    uint8_t *splitkey = NULL;

    size_t splitkeylen = 0;

    size_t i;

    QCryptoCipher *cipher = NULL;

    QCryptoIVGen *ivgen = NULL;

    char *VAR_7;

    const char *VAR_8;

    const char *VAR_9;

    const char *VAR_10;

    const char *VAR_11 = NULL;

    const char *VAR_12;

    char *VAR_13 = NULL;

    QCryptoCipherAlgorithm ivcipheralg = 0;

    uint64_t iters;



    memcpy(&luks_opts, &VAR_1->u.luks, sizeof(luks_opts));

    if (!luks_opts.has_iter_time) {

        luks_opts.iter_time = 2000;

    }

    if (!luks_opts.has_cipher_alg) {

        luks_opts.VAR_8 = QCRYPTO_CIPHER_ALG_AES_256;

    }

    if (!luks_opts.has_cipher_mode) {

        luks_opts.VAR_9 = QCRYPTO_CIPHER_MODE_XTS;

    }

    if (!luks_opts.has_ivgen_alg) {

        luks_opts.VAR_10 = QCRYPTO_IVGEN_ALG_PLAIN64;

    }

    if (!luks_opts.has_hash_alg) {

        luks_opts.VAR_12 = QCRYPTO_HASH_ALG_SHA256;

    }

    if (luks_opts.VAR_10 == QCRYPTO_IVGEN_ALG_ESSIV) {

        if (!luks_opts.has_ivgen_hash_alg) {

            luks_opts.VAR_11 = QCRYPTO_HASH_ALG_SHA256;

            luks_opts.has_ivgen_hash_alg = true;

        }

    }

    







    if (!VAR_1->u.luks.key_secret) {

        error_setg(VAR_6, "Parameter '%skey-secret' is required for cipher",

                   VAR_2 ? VAR_2 : "");

        return -1;

    }

    VAR_7 = qcrypto_secret_lookup_as_utf8(luks_opts.key_secret, VAR_6);

    if (!VAR_7) {

        return -1;

    }



    luks = g_new0(QCryptoBlockLUKS, 1);

    VAR_0->VAR_5 = luks;



    memcpy(luks->header.magic, qcrypto_block_luks_magic,

           QCRYPTO_BLOCK_LUKS_MAGIC_LEN);



    







    luks->header.version = QCRYPTO_BLOCK_LUKS_VERSION;

    qcrypto_block_luks_uuid_gen(luks->header.uuid);



    VAR_8 = qcrypto_block_luks_cipher_alg_lookup(luks_opts.VAR_8,

                                                      VAR_6);

    if (!VAR_8) {

        goto error;

    }



    VAR_9 = QCryptoCipherMode_str(luks_opts.VAR_9);

    VAR_10 = QCryptoIVGenAlgorithm_str(luks_opts.VAR_10);

    if (luks_opts.has_ivgen_hash_alg) {

        VAR_11 = QCryptoHashAlgorithm_str(luks_opts.VAR_11);

        VAR_13 = g_strdup_printf("%s-%s:%s", VAR_9, VAR_10,

                                           VAR_11);

    } else {

        VAR_13 = g_strdup_printf("%s-%s", VAR_9, VAR_10);

    }

    VAR_12 = QCryptoHashAlgorithm_str(luks_opts.VAR_12);





    if (strlen(VAR_8) >= QCRYPTO_BLOCK_LUKS_CIPHER_NAME_LEN) {

        error_setg(VAR_6, "Cipher name '%s' is too long for LUKS header",

                   VAR_8);

        goto error;

    }

    if (strlen(VAR_13) >= QCRYPTO_BLOCK_LUKS_CIPHER_MODE_LEN) {

        error_setg(VAR_6, "Cipher mode '%s' is too long for LUKS header",

                   VAR_13);

        goto error;

    }

    if (strlen(VAR_12) >= QCRYPTO_BLOCK_LUKS_HASH_SPEC_LEN) {

        error_setg(VAR_6, "Hash name '%s' is too long for LUKS header",

                   VAR_12);

        goto error;

    }



    if (luks_opts.VAR_10 == QCRYPTO_IVGEN_ALG_ESSIV) {

        ivcipheralg = qcrypto_block_luks_essiv_cipher(luks_opts.VAR_8,

                                                      luks_opts.VAR_11,

                                                      &local_err);

        if (local_err) {

            error_propagate(VAR_6, local_err);

            goto error;

        }

    } else {

        ivcipheralg = luks_opts.VAR_8;

    }



    strcpy(luks->header.cipher_name, VAR_8);

    strcpy(luks->header.VAR_9, VAR_13);

    strcpy(luks->header.hash_spec, VAR_12);



    luks->header.key_bytes = qcrypto_cipher_get_key_len(luks_opts.VAR_8);

    if (luks_opts.VAR_9 == QCRYPTO_CIPHER_MODE_XTS) {

        luks->header.key_bytes *= 2;

    }



    





    if (qcrypto_random_bytes(luks->header.master_key_salt,

                             QCRYPTO_BLOCK_LUKS_SALT_LEN,

                             VAR_6) < 0) {

        goto error;

    }



    

    masterkey = g_new0(uint8_t, luks->header.key_bytes);

    if (qcrypto_random_bytes(masterkey,

                             luks->header.key_bytes, VAR_6) < 0) {

        goto error;

    }





    

    VAR_0->cipher = qcrypto_cipher_new(luks_opts.VAR_8,

                                       luks_opts.VAR_9,

                                       masterkey, luks->header.key_bytes,

                                       VAR_6);

    if (!VAR_0->cipher) {

        goto error;

    }



    VAR_0->kdfhash = luks_opts.VAR_12;

    VAR_0->niv = qcrypto_cipher_get_iv_len(luks_opts.VAR_8,

                                           luks_opts.VAR_9);

    VAR_0->ivgen = qcrypto_ivgen_new(luks_opts.VAR_10,

                                     ivcipheralg,

                                     luks_opts.VAR_11,

                                     masterkey, luks->header.key_bytes,

                                     VAR_6);



    if (!VAR_0->ivgen) {

        goto error;

    }





    





    iters = qcrypto_pbkdf2_count_iters(luks_opts.VAR_12,

                                       masterkey, luks->header.key_bytes,

                                       luks->header.master_key_salt,

                                       QCRYPTO_BLOCK_LUKS_SALT_LEN,

                                       QCRYPTO_BLOCK_LUKS_DIGEST_LEN,

                                       &local_err);

    if (local_err) {

        error_propagate(VAR_6, local_err);

        goto error;

    }



    if (iters > (ULLONG_MAX / luks_opts.iter_time)) {

        error_setg_errno(VAR_6, ERANGE,

                         "PBKDF iterations %llu too large to scale",

                         (unsigned long long)iters);

        goto error;

    }



    

    iters = iters * luks_opts.iter_time / 1000;



    







    iters /= 8;

    if (iters > UINT32_MAX) {

        error_setg_errno(VAR_6, ERANGE,

                         "PBKDF iterations %llu larger than %u",

                         (unsigned long long)iters, UINT32_MAX);

        goto error;

    }

    iters = MAX(iters, QCRYPTO_BLOCK_LUKS_MIN_MASTER_KEY_ITERS);

    luks->header.master_key_iterations = iters;



    









    if (qcrypto_pbkdf2(luks_opts.VAR_12,

                       masterkey, luks->header.key_bytes,

                       luks->header.master_key_salt,

                       QCRYPTO_BLOCK_LUKS_SALT_LEN,

                       luks->header.master_key_iterations,

                       luks->header.master_key_digest,

                       QCRYPTO_BLOCK_LUKS_DIGEST_LEN,

                       VAR_6) < 0) {

        goto error;

    }





    



    splitkeylen = luks->header.key_bytes * 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].stripes = QCRYPTO_BLOCK_LUKS_STRIPES;



        





        luks->header.key_slots[i].key_offset =

            (QCRYPTO_BLOCK_LUKS_KEY_SLOT_OFFSET /

             QCRYPTO_BLOCK_LUKS_SECTOR_SIZE) +

            (ROUND_UP(DIV_ROUND_UP(splitkeylen, QCRYPTO_BLOCK_LUKS_SECTOR_SIZE),

                      (QCRYPTO_BLOCK_LUKS_KEY_SLOT_OFFSET /

                       QCRYPTO_BLOCK_LUKS_SECTOR_SIZE)) * i);

    }



    if (qcrypto_random_bytes(luks->header.key_slots[0].salt,

                             QCRYPTO_BLOCK_LUKS_SALT_LEN,

                             VAR_6) < 0) {

        goto error;

    }



    





    iters = qcrypto_pbkdf2_count_iters(luks_opts.VAR_12,

                                       (uint8_t *)VAR_7, strlen(VAR_7),

                                       luks->header.key_slots[0].salt,

                                       QCRYPTO_BLOCK_LUKS_SALT_LEN,

                                       luks->header.key_bytes,

                                       &local_err);

    if (local_err) {

        error_propagate(VAR_6, local_err);

        goto error;

    }



    if (iters > (ULLONG_MAX / luks_opts.iter_time)) {

        error_setg_errno(VAR_6, ERANGE,

                         "PBKDF iterations %llu too large to scale",

                         (unsigned long long)iters);

        goto error;

    }



    

    iters = iters * luks_opts.iter_time / 1000;



    if (iters > UINT32_MAX) {

        error_setg_errno(VAR_6, 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);





    





    slotkey = g_new0(uint8_t, luks->header.key_bytes);

    if (qcrypto_pbkdf2(luks_opts.VAR_12,

                       (uint8_t *)VAR_7, strlen(VAR_7),

                       luks->header.key_slots[0].salt,

                       QCRYPTO_BLOCK_LUKS_SALT_LEN,

                       luks->header.key_slots[0].iterations,

                       slotkey, luks->header.key_bytes,

                       VAR_6) < 0) {

        goto error;

    }





    





    cipher = qcrypto_cipher_new(luks_opts.VAR_8,

                                luks_opts.VAR_9,

                                slotkey, luks->header.key_bytes,

                                VAR_6);

    if (!cipher) {

        goto error;

    }



    ivgen = qcrypto_ivgen_new(luks_opts.VAR_10,

                              ivcipheralg,

                              luks_opts.VAR_11,

                              slotkey, luks->header.key_bytes,

                              VAR_6);

    if (!ivgen) {

        goto error;

    }



    





    splitkey = g_new0(uint8_t, splitkeylen);



    if (qcrypto_afsplit_encode(luks_opts.VAR_12,

                               luks->header.key_bytes,

                               luks->header.key_slots[0].stripes,

                               masterkey,

                               splitkey,

                               VAR_6) < 0) {

        goto error;

    }



    



    if (qcrypto_block_encrypt_helper(cipher, VAR_0->niv, ivgen,

                                     QCRYPTO_BLOCK_LUKS_SECTOR_SIZE,

                                     0,

                                     splitkey,

                                     splitkeylen,

                                     VAR_6) < 0) {

        goto error;

    }





    







    luks->header.payload_offset =

        (QCRYPTO_BLOCK_LUKS_KEY_SLOT_OFFSET /

         QCRYPTO_BLOCK_LUKS_SECTOR_SIZE) +

        (ROUND_UP(DIV_ROUND_UP(splitkeylen, QCRYPTO_BLOCK_LUKS_SECTOR_SIZE),

                  (QCRYPTO_BLOCK_LUKS_KEY_SLOT_OFFSET /

                   QCRYPTO_BLOCK_LUKS_SECTOR_SIZE)) *

         QCRYPTO_BLOCK_LUKS_NUM_KEY_SLOTS);



    VAR_0->payload_offset = luks->header.payload_offset *

        QCRYPTO_BLOCK_LUKS_SECTOR_SIZE;



    

    VAR_3(VAR_0, VAR_0->payload_offset, VAR_5, &local_err);

    if (local_err) {

        error_propagate(VAR_6, local_err);

        goto error;

    }



    



    cpu_to_be16s(&luks->header.version);

    cpu_to_be32s(&luks->header.payload_offset);

    cpu_to_be32s(&luks->header.key_bytes);

    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);

        cpu_to_be32s(&luks->header.key_slots[i].stripes);

    }





    

    VAR_4(VAR_0, 0,

              (const uint8_t *)&luks->header,

              sizeof(luks->header),

              VAR_5,

              &local_err);



    



    



    be16_to_cpus(&luks->header.version);

    be32_to_cpus(&luks->header.payload_offset);

    be32_to_cpus(&luks->header.key_bytes);

    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);

        be32_to_cpus(&luks->header.key_slots[i].stripes);

    }



    if (local_err) {

        error_propagate(VAR_6, local_err);

        goto error;

    }



    



    if (VAR_4(VAR_0,

                  luks->header.key_slots[0].key_offset *

                  QCRYPTO_BLOCK_LUKS_SECTOR_SIZE,

                  splitkey, splitkeylen,

                  VAR_5,

                  VAR_6) != splitkeylen) {

        goto error;

    }



    luks->VAR_8 = luks_opts.VAR_8;

    luks->VAR_9 = luks_opts.VAR_9;

    luks->VAR_10 = luks_opts.VAR_10;

    luks->VAR_11 = luks_opts.VAR_11;

    luks->VAR_12 = luks_opts.VAR_12;



    memset(masterkey, 0, luks->header.key_bytes);

    g_free(masterkey);

    memset(slotkey, 0, luks->header.key_bytes);

    g_free(slotkey);

    g_free(splitkey);

    g_free(VAR_7);

    g_free(VAR_13);



    qcrypto_ivgen_free(ivgen);

    qcrypto_cipher_free(cipher);



    return 0;



 error:

    if (masterkey) {

        memset(masterkey, 0, luks->header.key_bytes);

    }

    g_free(masterkey);

    if (slotkey) {

        memset(slotkey, 0, luks->header.key_bytes);

    }

    g_free(slotkey);

    g_free(splitkey);

    g_free(VAR_7);

    g_free(VAR_13);



    qcrypto_ivgen_free(ivgen);

    qcrypto_cipher_free(cipher);



    g_free(luks);

    return -1;

}

FUNC_0(QCryptoBlock *VAR_0,
QCryptoBlockCreateOptions *VAR_1,
const char *VAR_2,
QCryptoBlockInitFunc VAR_3,
QCryptoBlockWriteFunc VAR_4,
void *VAR_5,
Error **VAR_6)
{ QCryptoBlockLUKS *luks; QCryptoBlockCreateOptionsLUKS luks_opts; Error *local_err = NULL; uint8_t *masterkey = NULL; uint8_t *slotkey = NULL; uint8_t *splitkey = NULL; size_t splitkeylen = 0; size_t i; QCryptoCipher *cipher = NULL; QCryptoIVGen *ivgen = NULL; char *VAR_7; const char *VAR_8; const char *VAR_9; const char *VAR_10; const char *VAR_11 = NULL; const char *VAR_12; char *VAR_13 = NULL; QCryptoCipherAlgorithm ivcipheralg = 0; uint64_t iters; memcpy(&luks_opts, &VAR_1->u.luks, sizeof(luks_opts)); if (!luks_opts.has_iter_time) { luks_opts.iter_time = 2000; } if (!luks_opts.has_cipher_alg) { luks_opts.VAR_8 = QCRYPTO_CIPHER_ALG_AES_256; } if (!luks_opts.has_cipher_mode) { luks_opts.VAR_9 = QCRYPTO_CIPHER_MODE_XTS; } if (!luks_opts.has_ivgen_alg) { luks_opts.VAR_10 = QCRYPTO_IVGEN_ALG_PLAIN64; } if (!luks_opts.has_hash_alg) { luks_opts.VAR_12 = QCRYPTO_HASH_ALG_SHA256; } if (luks_opts.VAR_10 == QCRYPTO_IVGEN_ALG_ESSIV) { if (!luks_opts.has_ivgen_hash_alg) { luks_opts.VAR_11 = QCRYPTO_HASH_ALG_SHA256; luks_opts.has_ivgen_hash_alg = true; } } if (!VAR_1->u.luks.key_secret) { error_setg(VAR_6, "Parameter '%skey-secret' is required for cipher",
VAR_2 ? VAR_2 : ""); return -1; } VAR_7 = qcrypto_secret_lookup_as_utf8(luks_opts.key_secret, VAR_6); if (!VAR_7) { return -1; } luks = g_new0(QCryptoBlockLUKS, 1); VAR_0->VAR_5 = luks; memcpy(luks->header.magic, qcrypto_block_luks_magic,
QCRYPTO_BLOCK_LUKS_MAGIC_LEN); luks->header.version = QCRYPTO_BLOCK_LUKS_VERSION; qcrypto_block_luks_uuid_gen(luks->header.uuid); VAR_8 = qcrypto_block_luks_cipher_alg_lookup(luks_opts.VAR_8,
VAR_6); if (!VAR_8) { goto error; } VAR_9 = QCryptoCipherMode_str(luks_opts.VAR_9); VAR_10 = QCryptoIVGenAlgorithm_str(luks_opts.VAR_10); if (luks_opts.has_ivgen_hash_alg) { VAR_11 = QCryptoHashAlgorithm_str(luks_opts.VAR_11); VAR_13 = g_strdup_printf("%s-%s:%s", VAR_9, VAR_10,
VAR_11); } else { VAR_13 = g_strdup_printf("%s-%s", VAR_9, VAR_10); } VAR_12 = QCryptoHashAlgorithm_str(luks_opts.VAR_12); if (strlen(VAR_8) >= QCRYPTO_BLOCK_LUKS_CIPHER_NAME_LEN) { error_setg(VAR_6, "Cipher name '%s' is too long for LUKS header",
VAR_8); goto error; } if (strlen(VAR_13) >= QCRYPTO_BLOCK_LUKS_CIPHER_MODE_LEN) { error_setg(VAR_6, "Cipher mode '%s' is too long for LUKS header",
VAR_13); goto error; } if (strlen(VAR_12) >= QCRYPTO_BLOCK_LUKS_HASH_SPEC_LEN) { error_setg(VAR_6, "Hash name '%s' is too long for LUKS header",
VAR_12); goto error; } if (luks_opts.VAR_10 == QCRYPTO_IVGEN_ALG_ESSIV) { ivcipheralg = qcrypto_block_luks_essiv_cipher(luks_opts.VAR_8,
luks_opts.VAR_11,
&local_err); if (local_err) { error_propagate(VAR_6, local_err); goto error; } } else { ivcipheralg = luks_opts.VAR_8; } strcpy(luks->header.cipher_name, VAR_8); strcpy(luks->header.VAR_9, VAR_13); strcpy(luks->header.hash_spec, VAR_12); luks->header.key_bytes = qcrypto_cipher_get_key_len(luks_opts.VAR_8); if (luks_opts.VAR_9 == QCRYPTO_CIPHER_MODE_XTS) { luks->header.key_bytes *= 2; } if (qcrypto_random_bytes(luks->header.master_key_salt,
QCRYPTO_BLOCK_LUKS_SALT_LEN,
VAR_6) < 0) { goto error; } masterkey = g_new0(uint8_t, luks->header.key_bytes); if (qcrypto_random_bytes(masterkey,
luks->header.key_bytes, VAR_6) < 0) { goto error; } VAR_0->cipher = qcrypto_cipher_new(luks_opts.VAR_8,
luks_opts.VAR_9,
masterkey, luks->header.key_bytes,
VAR_6); if (!VAR_0->cipher) { goto error; } VAR_0->kdfhash = luks_opts.VAR_12; VAR_0->niv = qcrypto_cipher_get_iv_len(luks_opts.VAR_8,
luks_opts.VAR_9); VAR_0->ivgen = qcrypto_ivgen_new(luks_opts.VAR_10,
ivcipheralg,
luks_opts.VAR_11,
masterkey, luks->header.key_bytes,
VAR_6); if (!VAR_0->ivgen) { goto error; } iters = qcrypto_pbkdf2_count_iters(luks_opts.VAR_12,
masterkey, luks->header.key_bytes,
luks->header.master_key_salt,
QCRYPTO_BLOCK_LUKS_SALT_LEN,
QCRYPTO_BLOCK_LUKS_DIGEST_LEN,
&local_err); if (local_err) { error_propagate(VAR_6, local_err); goto error; } if (iters > (ULLONG_MAX / luks_opts.iter_time)) { error_setg_errno(VAR_6, ERANGE,
"PBKDF iterations %llu too large to scale",
(unsigned long long)iters); goto error; } iters = iters * luks_opts.iter_time / 1000; iters /= 8; if (iters > UINT32_MAX) { error_setg_errno(VAR_6, ERANGE,
"PBKDF iterations %llu larger than %u",
(unsigned long long)iters, UINT32_MAX); goto error; } iters = MAX(iters, QCRYPTO_BLOCK_LUKS_MIN_MASTER_KEY_ITERS); luks->header.master_key_iterations = iters; if (qcrypto_pbkdf2(luks_opts.VAR_12,
masterkey, luks->header.key_bytes,
luks->header.master_key_salt,
QCRYPTO_BLOCK_LUKS_SALT_LEN,
luks->header.master_key_iterations,
luks->header.master_key_digest,
QCRYPTO_BLOCK_LUKS_DIGEST_LEN,
VAR_6) < 0) { goto error; } splitkeylen = luks->header.key_bytes * 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].stripes = QCRYPTO_BLOCK_LUKS_STRIPES; luks->header.key_slots[i].key_offset =
(QCRYPTO_BLOCK_LUKS_KEY_SLOT_OFFSET /
QCRYPTO_BLOCK_LUKS_SECTOR_SIZE) +
(ROUND_UP(DIV_ROUND_UP(splitkeylen, QCRYPTO_BLOCK_LUKS_SECTOR_SIZE),
(QCRYPTO_BLOCK_LUKS_KEY_SLOT_OFFSET /
QCRYPTO_BLOCK_LUKS_SECTOR_SIZE)) * i); } if (qcrypto_random_bytes(luks->header.key_slots[0].salt,
QCRYPTO_BLOCK_LUKS_SALT_LEN,
VAR_6) < 0) { goto error; } iters = qcrypto_pbkdf2_count_iters(luks_opts.VAR_12,
(uint8_t *)VAR_7, strlen(VAR_7),
luks->header.key_slots[0].salt,
QCRYPTO_BLOCK_LUKS_SALT_LEN,
luks->header.key_bytes,
&local_err); if (local_err) { error_propagate(VAR_6, local_err); goto error; } if (iters > (ULLONG_MAX / luks_opts.iter_time)) { error_setg_errno(VAR_6, ERANGE,
"PBKDF iterations %llu too large to scale",
(unsigned long long)iters); goto error; } iters = iters * luks_opts.iter_time / 1000; if (iters > UINT32_MAX) { error_setg_errno(VAR_6, 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); slotkey = g_new0(uint8_t, luks->header.key_bytes); if (qcrypto_pbkdf2(luks_opts.VAR_12,
(uint8_t *)VAR_7, strlen(VAR_7),
luks->header.key_slots[0].salt,
QCRYPTO_BLOCK_LUKS_SALT_LEN,
luks->header.key_slots[0].iterations,
slotkey, luks->header.key_bytes,
VAR_6) < 0) { goto error; } cipher = qcrypto_cipher_new(luks_opts.VAR_8,
luks_opts.VAR_9,
slotkey, luks->header.key_bytes,
VAR_6); if (!cipher) { goto error; } ivgen = qcrypto_ivgen_new(luks_opts.VAR_10,
ivcipheralg,
luks_opts.VAR_11,
slotkey, luks->header.key_bytes,
VAR_6); if (!ivgen) { goto error; } splitkey = g_new0(uint8_t, splitkeylen); if (qcrypto_afsplit_encode(luks_opts.VAR_12,
luks->header.key_bytes,
luks->header.key_slots[0].stripes,
masterkey,
splitkey,
VAR_6) < 0) { goto error; } if (qcrypto_block_encrypt_helper(cipher, VAR_0->niv, ivgen,
QCRYPTO_BLOCK_LUKS_SECTOR_SIZE,
0,
splitkey,
splitkeylen,
VAR_6) < 0) { goto error; } luks->header.payload_offset =
(QCRYPTO_BLOCK_LUKS_KEY_SLOT_OFFSET /
QCRYPTO_BLOCK_LUKS_SECTOR_SIZE) +
(ROUND_UP(DIV_ROUND_UP(splitkeylen, QCRYPTO_BLOCK_LUKS_SECTOR_SIZE),
(QCRYPTO_BLOCK_LUKS_KEY_SLOT_OFFSET /
QCRYPTO_BLOCK_LUKS_SECTOR_SIZE)) *
QCRYPTO_BLOCK_LUKS_NUM_KEY_SLOTS); VAR_0->payload_offset = luks->header.payload_offset *
QCRYPTO_BLOCK_LUKS_SECTOR_SIZE; VAR_3(VAR_0, VAR_0->payload_offset, VAR_5, &local_err); if (local_err) { error_propagate(VAR_6, local_err); goto error; } cpu_to_be16s(&luks->header.version); cpu_to_be32s(&luks->header.payload_offset); cpu_to_be32s(&luks->header.key_bytes); 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); cpu_to_be32s(&luks->header.key_slots[i].stripes); } VAR_4(VAR_0, 0,
(const uint8_t *)&luks->header,
sizeof(luks->header),
VAR_5,
&local_err); be16_to_cpus(&luks->header.version); be32_to_cpus(&luks->header.payload_offset); be32_to_cpus(&luks->header.key_bytes); 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); be32_to_cpus(&luks->header.key_slots[i].stripes); } if (local_err) { error_propagate(VAR_6, local_err); goto error; } if (VAR_4(VAR_0,
luks->header.key_slots[0].key_offset *
QCRYPTO_BLOCK_LUKS_SECTOR_SIZE,
splitkey, splitkeylen,
VAR_5,
VAR_6) != splitkeylen) { goto error; } luks->VAR_8 = luks_opts.VAR_8; luks->VAR_9 = luks_opts.VAR_9; luks->VAR_10 = luks_opts.VAR_10; luks->VAR_11 = luks_opts.VAR_11; luks->VAR_12 = luks_opts.VAR_12; memset(masterkey, 0, luks->header.key_bytes); g_free(masterkey); memset(slotkey, 0, luks->header.key_bytes); g_free(slotkey); g_free(splitkey); g_free(VAR_7); g_free(VAR_13); qcrypto_ivgen_free(ivgen); qcrypto_cipher_free(cipher); return 0; error:
if (masterkey) { memset(masterkey, 0, luks->header.key_bytes); } g_free(masterkey); if (slotkey) { memset(slotkey, 0, luks->header.key_bytes); } g_free(slotkey); g_free(splitkey); g_free(VAR_7); g_free(VAR_13); qcrypto_ivgen_free(ivgen); qcrypto_cipher_free(cipher); g_free(luks); return -1; }