Skip to content

Commit

Permalink
crypto: add support for querying parameters for block encryption
Browse files Browse the repository at this point in the history
When creating new block encryption volumes, we accept a list of
parameters to control the formatting process. It is useful to
be able to query what those parameters were for existing block
devices. Add a qcrypto_block_get_info() method which returns a
QCryptoBlockInfo instance to report this data.

Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
Message-id: 1469192015-16487-2-git-send-email-berrange@redhat.com
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Max Reitz <mreitz@redhat.com>
  • Loading branch information
berrange authored and XanClic committed Jul 26, 2016
1 parent 54a16a6 commit 40c8502
Show file tree
Hide file tree
Showing 5 changed files with 191 additions and 0 deletions.
67 changes: 67 additions & 0 deletions crypto/block-luks.c
Expand Up @@ -201,6 +201,15 @@ QEMU_BUILD_BUG_ON(sizeof(struct QCryptoBlockLUKSHeader) != 592);

struct QCryptoBlockLUKS {
QCryptoBlockLUKSHeader header;

/* Cache parsed versions of what's in header fields,
* as we can't rely on QCryptoBlock.cipher being
* non-NULL */
QCryptoCipherAlgorithm cipher_alg;
QCryptoCipherMode cipher_mode;
QCryptoIVGenAlgorithm ivgen_alg;
QCryptoHashAlgorithm ivgen_hash_alg;
QCryptoHashAlgorithm hash_alg;
};


Expand Down Expand Up @@ -847,6 +856,12 @@ qcrypto_block_luks_open(QCryptoBlock *block,
block->payload_offset = luks->header.payload_offset *
QCRYPTO_BLOCK_LUKS_SECTOR_SIZE;

luks->cipher_alg = cipheralg;
luks->cipher_mode = ciphermode;
luks->ivgen_alg = ivalg;
luks->ivgen_hash_alg = ivhash;
luks->hash_alg = hash;

g_free(masterkey);
g_free(password);

Expand Down Expand Up @@ -1271,6 +1286,12 @@ qcrypto_block_luks_create(QCryptoBlock *block,
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);
Expand Down Expand Up @@ -1305,6 +1326,51 @@ qcrypto_block_luks_create(QCryptoBlock *block,
}


static int qcrypto_block_luks_get_info(QCryptoBlock *block,
QCryptoBlockInfo *info,
Error **errp)
{
QCryptoBlockLUKS *luks = block->opaque;
QCryptoBlockInfoLUKSSlot *slot;
QCryptoBlockInfoLUKSSlotList *slots = NULL, **prev = &info->u.luks.slots;
size_t i;

info->u.luks.cipher_alg = luks->cipher_alg;
info->u.luks.cipher_mode = luks->cipher_mode;
info->u.luks.ivgen_alg = luks->ivgen_alg;
if (info->u.luks.ivgen_alg == QCRYPTO_IVGEN_ALG_ESSIV) {
info->u.luks.has_ivgen_hash_alg = true;
info->u.luks.ivgen_hash_alg = luks->ivgen_hash_alg;
}
info->u.luks.hash_alg = luks->hash_alg;
info->u.luks.payload_offset = block->payload_offset;
info->u.luks.master_key_iters = luks->header.master_key_iterations;
info->u.luks.uuid = g_strndup((const char *)luks->header.uuid,
sizeof(luks->header.uuid));

for (i = 0; i < QCRYPTO_BLOCK_LUKS_NUM_KEY_SLOTS; i++) {
slots = g_new0(QCryptoBlockInfoLUKSSlotList, 1);
*prev = slots;

slots->value = slot = g_new0(QCryptoBlockInfoLUKSSlot, 1);
slot->active = luks->header.key_slots[i].active ==
QCRYPTO_BLOCK_LUKS_KEY_SLOT_ENABLED;
slot->key_offset = luks->header.key_slots[i].key_offset
* QCRYPTO_BLOCK_LUKS_SECTOR_SIZE;
if (slot->active) {
slot->has_iters = true;
slot->iters = luks->header.key_slots[i].iterations;
slot->has_stripes = true;
slot->stripes = luks->header.key_slots[i].stripes;
}

prev = &slots->next;
}

return 0;
}


static void qcrypto_block_luks_cleanup(QCryptoBlock *block)
{
g_free(block->opaque);
Expand Down Expand Up @@ -1342,6 +1408,7 @@ qcrypto_block_luks_encrypt(QCryptoBlock *block,
const QCryptoBlockDriver qcrypto_block_driver_luks = {
.open = qcrypto_block_luks_open,
.create = qcrypto_block_luks_create,
.get_info = qcrypto_block_luks_get_info,
.cleanup = qcrypto_block_luks_cleanup,
.decrypt = qcrypto_block_luks_decrypt,
.encrypt = qcrypto_block_luks_encrypt,
Expand Down
17 changes: 17 additions & 0 deletions crypto/block.c
Expand Up @@ -105,6 +105,23 @@ QCryptoBlock *qcrypto_block_create(QCryptoBlockCreateOptions *options,
}


QCryptoBlockInfo *qcrypto_block_get_info(QCryptoBlock *block,
Error **errp)
{
QCryptoBlockInfo *info = g_new0(QCryptoBlockInfo, 1);

info->format = block->format;

if (block->driver->get_info &&
block->driver->get_info(block, info, errp) < 0) {
g_free(info);
return NULL;
}

return info;
}


int qcrypto_block_decrypt(QCryptoBlock *block,
uint64_t startsector,
uint8_t *buf,
Expand Down
4 changes: 4 additions & 0 deletions crypto/blockpriv.h
Expand Up @@ -53,6 +53,10 @@ struct QCryptoBlockDriver {
void *opaque,
Error **errp);

int (*get_info)(QCryptoBlock *block,
QCryptoBlockInfo *info,
Error **errp);

void (*cleanup)(QCryptoBlock *block);

int (*encrypt)(QCryptoBlock *block,
Expand Down
16 changes: 16 additions & 0 deletions include/crypto/block.h
Expand Up @@ -138,6 +138,22 @@ QCryptoBlock *qcrypto_block_create(QCryptoBlockCreateOptions *options,
void *opaque,
Error **errp);


/**
* qcrypto_block_get_info:
* @block: the block encryption object
* @errp: pointer to a NULL-initialized error object
*
* Get information about the configuration options for the
* block encryption object. This includes details such as
* the cipher algorithms, modes, and initialization vector
* generators.
*
* Returns: a block encryption info object, or NULL on error
*/
QCryptoBlockInfo *qcrypto_block_get_info(QCryptoBlock *block,
Error **errp);

/**
* @qcrypto_block_decrypt:
* @block: the block encryption object
Expand Down
87 changes: 87 additions & 0 deletions qapi/crypto.json
Expand Up @@ -224,3 +224,90 @@
'discriminator': 'format',
'data': { 'qcow': 'QCryptoBlockOptionsQCow',
'luks': 'QCryptoBlockCreateOptionsLUKS' } }


##
# QCryptoBlockInfoBase:
#
# The common information that applies to all full disk
# encryption formats
#
# @format: the encryption format
#
# Since: 2.7
##
{ 'struct': 'QCryptoBlockInfoBase',
'data': { 'format': 'QCryptoBlockFormat' }}


##
# QCryptoBlockInfoLUKSSlot:
#
# Information about the LUKS block encryption key
# slot options
#
# @active: whether the key slot is currently in use
# @key-offset: offset to the key material in bytes
# @iters: #optional number of PBKDF2 iterations for key material
# @stripes: #optional number of stripes for splitting key material
#
# Since: 2.7
##
{ 'struct': 'QCryptoBlockInfoLUKSSlot',
'data': {'active': 'bool',
'*iters': 'int',
'*stripes': 'int',
'key-offset': 'int' } }


##
# QCryptoBlockInfoLUKS:
#
# Information about the LUKS block encryption options
#
# @cipher-alg: the cipher algorithm for data encryption
# @cipher-mode: the cipher mode for data encryption
# @ivgen-alg: the initialization vector generator
# @ivgen-hash-alg: #optional the initialization vector generator hash
# @hash-alg: the master key hash algorithm
# @payload-offset: offset to the payload data in bytes
# @master-key-iters: number of PBKDF2 iterations for key material
# @uuid: unique identifier for the volume
# @slots: information about each key slot
#
# Since: 2.7
##
{ 'struct': 'QCryptoBlockInfoLUKS',
'data': {'cipher-alg': 'QCryptoCipherAlgorithm',
'cipher-mode': 'QCryptoCipherMode',
'ivgen-alg': 'QCryptoIVGenAlgorithm',
'*ivgen-hash-alg': 'QCryptoHashAlgorithm',
'hash-alg': 'QCryptoHashAlgorithm',
'payload-offset': 'int',
'master-key-iters': 'int',
'uuid': 'str',
'slots': [ 'QCryptoBlockInfoLUKSSlot' ] }}

##
# QCryptoBlockInfoQCow:
#
# Information about the QCow block encryption options
#
# Since: 2.7
##
{ 'struct': 'QCryptoBlockInfoQCow',
'data': { }}


##
# QCryptoBlockInfo:
#
# Information about the block encryption options
#
# Since: 2.7
##
{ 'union': 'QCryptoBlockInfo',
'base': 'QCryptoBlockInfoBase',
'discriminator': 'format',
'data': { 'qcow': 'QCryptoBlockInfoQCow',
'luks': 'QCryptoBlockInfoLUKS' } }

0 comments on commit 40c8502

Please sign in to comment.