Example #1
0
static inline void bitmap_dir_entry_to_be(Qcow2BitmapDirEntry *entry)
{
    cpu_to_be64s(&entry->bitmap_table_offset);
    cpu_to_be32s(&entry->bitmap_table_size);
    cpu_to_be32s(&entry->flags);
    cpu_to_be16s(&entry->name_size);
    cpu_to_be32s(&entry->extra_data_size);
}
Example #2
0
/**
 * ib_ud_header_init - Initialize UD header structure
 * @payload_bytes:Length of packet payload
 * @grh_present:GRH flag (if non-zero, GRH will be included)
 * @header:Structure to initialize
 *
 * ib_ud_header_init() initializes the lrh.link_version, lrh.link_next_header,
 * lrh.packet_length, grh.ip_version, grh.payload_length,
 * grh.next_header, bth.opcode, bth.pad_count and
 * bth.transport_header_version fields of a &struct ib_ud_header given
 * the payload length and whether a GRH will be included.
 */
void ib_ud_header_init(int     		    payload_bytes,
		       int    		    grh_present,
		       struct ib_ud_header *header)
{
	int header_len;

	memset(header, 0, sizeof *header);

	header_len =
		IB_LRH_BYTES  +
		IB_BTH_BYTES  +
		IB_DETH_BYTES;
	if (grh_present) {
		header_len += IB_GRH_BYTES;
	}

	header->lrh.link_version     = 0;
	header->lrh.link_next_header =
		grh_present ? IB_LNH_IBA_GLOBAL : IB_LNH_IBA_LOCAL;
	header->lrh.packet_length    = (IB_LRH_BYTES     +
					IB_BTH_BYTES     +
					IB_DETH_BYTES    +
					payload_bytes    +
					4                + /* ICRC     */
					3) / 4;            /* round up */

	header->grh_present          = grh_present;
	if (grh_present) {
		header->lrh.packet_length  += IB_GRH_BYTES / 4;

		header->grh.ip_version      = 6;
		header->grh.payload_length  =
			cpu_to_be16((IB_BTH_BYTES     +
				     IB_DETH_BYTES    +
				     payload_bytes    +
				     4                + /* ICRC     */
				     3) & ~3);          /* round up */
		header->grh.next_header     = 0x1b;
	}

	cpu_to_be16s(&header->lrh.packet_length);

	if (header->immediate_present)
		header->bth.opcode           = IB_OPCODE_UD_SEND_ONLY_WITH_IMMEDIATE;
	else
		header->bth.opcode           = IB_OPCODE_UD_SEND_ONLY;
	header->bth.pad_count                = (4 - payload_bytes) & 3;
	header->bth.transport_header_version = 0;
}
Example #3
0
/* Create UD header for an MLX send and build a data segment for it */
static int build_mlx_header(struct mthca_dev *dev, struct mthca_sqp *sqp,
			    int ind, struct ib_send_wr *wr,
			    struct mthca_mlx_seg *mlx,
			    struct mthca_data_seg *data)
{
	int header_size;
	int err;

	ib_ud_header_init(256, /* assume a MAD */
			  sqp->ud_header.grh_present,
			  &sqp->ud_header);

	err = mthca_read_ah(dev, to_mah(wr->wr.ud.ah), &sqp->ud_header);
	if (err)
		return err;
	mlx->flags &= ~cpu_to_be32(MTHCA_NEXT_SOLICIT | 1);
	mlx->flags |= cpu_to_be32((!sqp->qp.ibqp.qp_num ? MTHCA_MLX_VL15 : 0) |
				  (sqp->ud_header.lrh.destination_lid == 0xffff ?
				   MTHCA_MLX_SLR : 0) |
				  (sqp->ud_header.lrh.service_level << 8));
	mlx->rlid = sqp->ud_header.lrh.destination_lid;
	mlx->vcrc = 0;

	switch (wr->opcode) {
	case IB_WR_SEND:
		sqp->ud_header.bth.opcode = IB_OPCODE_UD_SEND_ONLY;
		sqp->ud_header.immediate_present = 0;
		break;
	case IB_WR_SEND_WITH_IMM:
		sqp->ud_header.bth.opcode = IB_OPCODE_UD_SEND_ONLY_WITH_IMMEDIATE;
		sqp->ud_header.immediate_present = 1;
		sqp->ud_header.immediate_data = wr->imm_data;
		break;
	default:
		return -EINVAL;
	}

	sqp->ud_header.lrh.virtual_lane    = !sqp->qp.ibqp.qp_num ? 15 : 0;
	if (sqp->ud_header.lrh.destination_lid == 0xffff)
		sqp->ud_header.lrh.source_lid = 0xffff;
	sqp->ud_header.bth.solicited_event = !!(wr->send_flags & IB_SEND_SOLICITED);
	if (!sqp->qp.ibqp.qp_num)
		ib_get_cached_pkey(&dev->ib_dev, sqp->port,
				   sqp->pkey_index,
				   &sqp->ud_header.bth.pkey);
	else
		ib_get_cached_pkey(&dev->ib_dev, sqp->port,
				   wr->wr.ud.pkey_index,
				   &sqp->ud_header.bth.pkey);
	cpu_to_be16s(&sqp->ud_header.bth.pkey);
	sqp->ud_header.bth.destination_qpn = cpu_to_be32(wr->wr.ud.remote_qpn);
	sqp->ud_header.bth.psn = cpu_to_be32((sqp->send_psn++) & ((1 << 24) - 1));
	sqp->ud_header.deth.qkey = cpu_to_be32(wr->wr.ud.remote_qkey & 0x80000000 ?
					       sqp->qkey : wr->wr.ud.remote_qkey);
	sqp->ud_header.deth.source_qpn = cpu_to_be32(sqp->qp.ibqp.qp_num);

	header_size = ib_ud_header_pack(&sqp->ud_header,
					sqp->header_buf +
					ind * MTHCA_UD_HEADER_SIZE);

	data->byte_count = cpu_to_be32(header_size);
	data->lkey       = cpu_to_be32(to_mpd(sqp->qp.ibqp.pd)->ntmr.ibmr.lkey);
	data->addr       = cpu_to_be64(sqp->header_dma +
				       ind * MTHCA_UD_HEADER_SIZE);

	return 0;
}
Example #4
0
static void mxu1_set_termios(struct tty_struct *tty,
			     struct usb_serial_port *port,
			     struct ktermios *old_termios)
{
	struct mxu1_port *mxport = usb_get_serial_port_data(port);
	struct mxu1_uart_config *config;
	tcflag_t cflag, iflag;
	speed_t baud;
	int status;
	unsigned int mcr;

	dev_dbg(&port->dev, "%s\n", __func__);

	cflag = tty->termios.c_cflag;
	iflag = tty->termios.c_iflag;

	if (old_termios &&
	    !tty_termios_hw_change(&tty->termios, old_termios) &&
	    tty->termios.c_iflag == old_termios->c_iflag) {
		dev_dbg(&port->dev, "%s - nothing to change\n", __func__);
		return;
	}

	dev_dbg(&port->dev,
		"%s - clfag %08x, iflag %08x\n", __func__, cflag, iflag);

	if (old_termios) {
		dev_dbg(&port->dev, "%s - old clfag %08x, old iflag %08x\n",
			__func__,
			old_termios->c_cflag,
			old_termios->c_iflag);
	}

	config = kzalloc(sizeof(*config), GFP_KERNEL);
	if (!config)
		return;

	config->wFlags = 0;

	/* these flags must be set */
	config->wFlags |= MXU1_UART_ENABLE_MS_INTS;
	config->wFlags |= MXU1_UART_ENABLE_AUTO_START_DMA;
	if (mxport->mxp_send_break == MXU1_LCR_BREAK)
		config->wFlags |= MXU1_UART_SEND_BREAK_SIGNAL;
	config->bUartMode = (u8)(mxport->mxp_uart_mode);

	switch (C_CSIZE(tty)) {
	case CS5:
		config->bDataBits = MXU1_UART_5_DATA_BITS;
		break;
	case CS6:
		config->bDataBits = MXU1_UART_6_DATA_BITS;
		break;
	case CS7:
		config->bDataBits = MXU1_UART_7_DATA_BITS;
		break;
	default:
	case CS8:
		config->bDataBits = MXU1_UART_8_DATA_BITS;
		break;
	}

	if (C_PARENB(tty)) {
		config->wFlags |= MXU1_UART_ENABLE_PARITY_CHECKING;
		if (C_CMSPAR(tty)) {
			if (C_PARODD(tty))
				config->bParity = MXU1_UART_MARK_PARITY;
			else
				config->bParity = MXU1_UART_SPACE_PARITY;
		} else {
			if (C_PARODD(tty))
				config->bParity = MXU1_UART_ODD_PARITY;
			else
				config->bParity = MXU1_UART_EVEN_PARITY;
		}
	} else {
		config->bParity = MXU1_UART_NO_PARITY;
	}

	if (C_CSTOPB(tty))
		config->bStopBits = MXU1_UART_2_STOP_BITS;
	else
		config->bStopBits = MXU1_UART_1_STOP_BITS;

	if (C_CRTSCTS(tty)) {
		/* RTS flow control must be off to drop RTS for baud rate B0 */
		if (C_BAUD(tty) != B0)
			config->wFlags |= MXU1_UART_ENABLE_RTS_IN;
		config->wFlags |= MXU1_UART_ENABLE_CTS_OUT;
	}

	if (I_IXOFF(tty) || I_IXON(tty)) {
		config->cXon  = START_CHAR(tty);
		config->cXoff = STOP_CHAR(tty);

		if (I_IXOFF(tty))
			config->wFlags |= MXU1_UART_ENABLE_X_IN;

		if (I_IXON(tty))
			config->wFlags |= MXU1_UART_ENABLE_X_OUT;
	}

	baud = tty_get_baud_rate(tty);
	if (!baud)
		baud = 9600;
	config->wBaudRate = MXU1_BAUD_BASE / baud;

	dev_dbg(&port->dev, "%s - BaudRate=%d, wBaudRate=%d, wFlags=0x%04X, bDataBits=%d, bParity=%d, bStopBits=%d, cXon=%d, cXoff=%d, bUartMode=%d\n",
		__func__, baud, config->wBaudRate, config->wFlags,
		config->bDataBits, config->bParity, config->bStopBits,
		config->cXon, config->cXoff, config->bUartMode);

	cpu_to_be16s(&config->wBaudRate);
	cpu_to_be16s(&config->wFlags);

	status = mxu1_send_ctrl_data_urb(port->serial, MXU1_SET_CONFIG, 0,
					 MXU1_UART1_PORT, (u8 *)config,
					 sizeof(*config));
	if (status)
		dev_err(&port->dev, "cannot set config: %d\n", status);

	mutex_lock(&mxport->mxp_mutex);
	mcr = mxport->mxp_mcr;

	if (C_BAUD(tty) == B0)
		mcr &= ~(MXU1_MCR_DTR | MXU1_MCR_RTS);
	else if (old_termios && (old_termios->c_cflag & CBAUD) == B0)
		mcr |= ~(MXU1_MCR_DTR | MXU1_MCR_RTS);

	status = mxu1_set_mcr(port, mcr);
	if (status)
		dev_err(&port->dev, "cannot set modem control: %d\n", status);
	else
		mxport->mxp_mcr = mcr;

	mutex_unlock(&mxport->mxp_mutex);

	kfree(config);
}
Example #5
0
static int
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, 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;
}