func: qcrypto_block_luks_create(QCryptoBlock *block,
  
                            QCryptoBlockCreateOptions *options,
  
                            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 'key-secret' is required for cipher");
  
          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_lookup[luks_opts.cipher_mode];
  
      ivgen_alg = QCryptoIVGenAlgorithm_lookup[luks_opts.ivgen_alg];
  
      if (luks_opts.has_ivgen_hash_alg) {
  
          ivgen_hash_alg = QCryptoHashAlgorithm_lookup[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_lookup[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, &local_err, opaque);
  
      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),
  
                &local_err,
  
                opaque);
  
  
  
      /* 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,
  
                    errp,
  
                    opaque) != 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;
  
  }
  