From patchwork Tue Jan 12 18:56:12 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: =?utf-8?q?Daniel_P=2E_Berrang=C3=A9?= X-Patchwork-Id: 566687 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id A36FE14032F for ; Wed, 13 Jan 2016 06:02:33 +1100 (AEDT) Received: from localhost ([::1]:33745 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1aJ4D9-00044K-1a for incoming@patchwork.ozlabs.org; Tue, 12 Jan 2016 14:02:31 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:43660) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1aJ47p-0001f1-PJ for qemu-devel@nongnu.org; Tue, 12 Jan 2016 13:57:08 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1aJ47l-0003UB-O7 for qemu-devel@nongnu.org; Tue, 12 Jan 2016 13:57:01 -0500 Received: from mx1.redhat.com ([209.132.183.28]:35419) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1aJ47P-0003Mg-4u; Tue, 12 Jan 2016 13:56:48 -0500 Received: from int-mx10.intmail.prod.int.phx2.redhat.com (int-mx10.intmail.prod.int.phx2.redhat.com [10.5.11.23]) by mx1.redhat.com (Postfix) with ESMTPS id B0B29C07584C; Tue, 12 Jan 2016 18:56:34 +0000 (UTC) Received: from t530wlan.home.berrange.com.com (vpn1-7-155.ams2.redhat.com [10.36.7.155]) by int-mx10.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id u0CIuRmj019273; Tue, 12 Jan 2016 13:56:33 -0500 From: "Daniel P. Berrange" To: qemu-devel@nongnu.org Date: Tue, 12 Jan 2016 18:56:12 +0000 Message-Id: <1452624982-19332-6-git-send-email-berrange@redhat.com> In-Reply-To: <1452624982-19332-1-git-send-email-berrange@redhat.com> References: <1452624982-19332-1-git-send-email-berrange@redhat.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.23 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x X-Received-From: 209.132.183.28 Cc: qemu-block@nongnu.org Subject: [Qemu-devel] [PATCH v1 05/15] crypto: add block encryption framework X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Add a generic framework for support different block encryption formats. Upon instantiating a QCryptoBlock object, it will read the encryption header and extract the encryption keys. It is then possible to call methods to encrypt/decrypt data buffers. There is also a mode whereby it will create/initialize a new encryption header on a previously unformatted volume. The initial framework comes with support for the legacy QCow AES based encryption. This enables code in the QCow driver to be consolidated later. Signed-off-by: Daniel P. Berrange --- crypto/Makefile.objs | 2 + crypto/block-qcowaes.c | 165 ++++++++++++++++++++++++++++++++ crypto/block-qcowaes.h | 28 ++++++ crypto/block.c | 254 +++++++++++++++++++++++++++++++++++++++++++++++++ crypto/blockpriv.h | 89 +++++++++++++++++ include/crypto/block.h | 222 ++++++++++++++++++++++++++++++++++++++++++ qapi/crypto.json | 65 +++++++++++++ 7 files changed, 825 insertions(+) create mode 100644 crypto/block-qcowaes.c create mode 100644 crypto/block-qcowaes.h create mode 100644 crypto/block.c create mode 100644 crypto/blockpriv.h create mode 100644 include/crypto/block.h diff --git a/crypto/Makefile.objs b/crypto/Makefile.objs index 1e08a3a..b5b32a6 100644 --- a/crypto/Makefile.objs +++ b/crypto/Makefile.objs @@ -15,6 +15,8 @@ crypto-obj-y += ivgen-essiv.o crypto-obj-y += ivgen-plain.o crypto-obj-y += ivgen-plain64.o crypto-obj-y += afsplit.o +crypto-obj-y += block.o +crypto-obj-y += block-qcowaes.o # Let the userspace emulators avoid linking gnutls/etc crypto-aes-obj-y = aes.o diff --git a/crypto/block-qcowaes.c b/crypto/block-qcowaes.c new file mode 100644 index 0000000..cf8ff50 --- /dev/null +++ b/crypto/block-qcowaes.c @@ -0,0 +1,165 @@ +/* + * QEMU Crypto block device encryption QCOWAES format + * + * Copyright (c) 2015 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + * + */ + +#include "config-host.h" + +#include "crypto/block-qcowaes.h" +#include "crypto/secret.h" + +static gboolean +qcrypto_block_qcowaes_has_format(const uint8_t *buf G_GNUC_UNUSED, + size_t buf_size G_GNUC_UNUSED) +{ + return false; +} + + +static int +qcrypto_block_qcowaes_init(QCryptoBlock *block, + const char *keyid, + Error **errp) +{ + char *password; + int ret; + uint8_t keybuf[16]; + int len, i; + + memset(keybuf, 0, 16); + + password = qcrypto_secret_lookup_as_utf8(keyid, errp); + if (!password) { + return -1; + } + + len = strlen(password); + if (len > 16) { + len = 16; + } + for (i = 0; i < len; i++) { + keybuf[i] = password[i]; + } + g_free(password); + + block->niv = qcrypto_cipher_get_iv_len(QCRYPTO_CIPHER_ALG_AES_128, + QCRYPTO_CIPHER_MODE_CBC); + block->ivgen = qcrypto_ivgen_new(QCRYPTO_IVGEN_ALG_PLAIN64, + 0, 0, NULL, 0, errp); + if (!block->ivgen) { + ret = -ENOTSUP; + goto fail; + } + + block->cipher = qcrypto_cipher_new(QCRYPTO_CIPHER_ALG_AES_128, + QCRYPTO_CIPHER_MODE_CBC, + keybuf, G_N_ELEMENTS(keybuf), + errp); + if (!block->cipher) { + ret = -ENOTSUP; + goto fail; + } + + block->payload_offset = 0; + + return 0; + + fail: + qcrypto_cipher_free(block->cipher); + qcrypto_ivgen_free(block->ivgen); + return ret; +} + + +static int +qcrypto_block_qcowaes_open(QCryptoBlock *block, + QCryptoBlockOpenOptions *options, + QCryptoBlockReadFunc readfunc G_GNUC_UNUSED, + void *opaque G_GNUC_UNUSED, + unsigned int flags, + Error **errp) +{ + if (flags & QCRYPTO_BLOCK_OPEN_NO_IO) { + return 0; + } else { + if (!options->u.qcowaes->key_id) { + error_setg(errp, "Parameter 'key-id' is required to initialize cipher"); + return -1; + } + return qcrypto_block_qcowaes_init(block, options->u.qcowaes->key_id, errp); + } +} + + +static int +qcrypto_block_qcowaes_create(QCryptoBlock *block, + QCryptoBlockCreateOptions *options, + QCryptoBlockInitFunc initfunc G_GNUC_UNUSED, + QCryptoBlockWriteFunc writefunc G_GNUC_UNUSED, + void *opaque G_GNUC_UNUSED, + Error **errp) +{ + if (!options->u.qcowaes->key_id) { + error_setg(errp, "Parameter 'key-id' is required to initialize cipher"); + return -1; + } + /* QCow2 has no special header, since everything is hardwired */ + return qcrypto_block_qcowaes_init(block, options->u.qcowaes->key_id, errp); +} + + +static void +qcrypto_block_qcowaes_cleanup(QCryptoBlock *block) +{ +} + + +static int +qcrypto_block_qcowaes_decrypt(QCryptoBlock *block, + uint64_t startsector, + uint8_t *buf, + size_t len, + Error **errp) +{ + return qcrypto_block_decrypt_helper(block->cipher, + block->niv, block->ivgen, + startsector, buf, len, errp); +} + + +static int +qcrypto_block_qcowaes_encrypt(QCryptoBlock *block, + uint64_t startsector, + uint8_t *buf, + size_t len, + Error **errp) +{ + return qcrypto_block_encrypt_helper(block->cipher, + block->niv, block->ivgen, + startsector, buf, len, errp); +} + + +const QCryptoBlockDriver qcrypto_block_driver_qcowaes = { + .open = qcrypto_block_qcowaes_open, + .create = qcrypto_block_qcowaes_create, + .cleanup = qcrypto_block_qcowaes_cleanup, + .decrypt = qcrypto_block_qcowaes_decrypt, + .encrypt = qcrypto_block_qcowaes_encrypt, + .has_format = qcrypto_block_qcowaes_has_format, +}; diff --git a/crypto/block-qcowaes.h b/crypto/block-qcowaes.h new file mode 100644 index 0000000..e43b7e5 --- /dev/null +++ b/crypto/block-qcowaes.h @@ -0,0 +1,28 @@ +/* + * QEMU Crypto block device encryption QCow AES format + * + * Copyright (c) 2015 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + * + */ + +#ifndef QCRYPTO_BLOCK_QCOWAES_H__ +#define QCRYPTO_BLOCK_QCOWAES_H__ + +#include "crypto/blockpriv.h" + +extern const QCryptoBlockDriver qcrypto_block_driver_qcowaes; + +#endif /* QCRYPTO_BLOCK_QCOWAES_H__ */ diff --git a/crypto/block.c b/crypto/block.c new file mode 100644 index 0000000..657f4a9 --- /dev/null +++ b/crypto/block.c @@ -0,0 +1,254 @@ +/* + * QEMU Crypto block device encryption + * + * Copyright (c) 2015 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + * + */ + +#include "crypto/blockpriv.h" +#include "crypto/block-qcowaes.h" + +static const QCryptoBlockDriver *qcrypto_block_drivers[] = { + [Q_CRYPTO_BLOCK_FORMAT_QCOWAES] = &qcrypto_block_driver_qcowaes, +}; + + +gboolean qcrypto_block_has_format(QCryptoBlockFormat format, + const uint8_t *buf, + size_t len) +{ + const QCryptoBlockDriver *driver; + + if (format >= G_N_ELEMENTS(qcrypto_block_drivers) || + !qcrypto_block_drivers[format]) { + return false; + } + + driver = qcrypto_block_drivers[format]; + + return driver->has_format(buf, len); +} + + +QCryptoBlock *qcrypto_block_open(QCryptoBlockOpenOptions *options, + QCryptoBlockReadFunc readfunc, + void *opaque, + unsigned int flags, + Error **errp) +{ + QCryptoBlock *block = g_new0(QCryptoBlock, 1); + + block->format = options->format; + + if (options->format >= G_N_ELEMENTS(qcrypto_block_drivers) || + !qcrypto_block_drivers[options->format]) { + error_setg(errp, "Unsupported block driver %d", options->format); + g_free(block); + return NULL; + } + + block->driver = qcrypto_block_drivers[options->format]; + + if (block->driver->open(block, options, readfunc, opaque, flags, errp) < 0) { + g_free(block); + return NULL; + } + + return block; +} + + +QCryptoBlock *qcrypto_block_create(QCryptoBlockCreateOptions *options, + QCryptoBlockInitFunc initfunc, + QCryptoBlockWriteFunc writefunc, + void *opaque, + Error **errp) +{ + QCryptoBlock *block = g_new0(QCryptoBlock, 1); + + block->format = options->format; + + if (options->format >= G_N_ELEMENTS(qcrypto_block_drivers) || + !qcrypto_block_drivers[options->format]) { + error_setg(errp, "Unsupported block driver %d", options->format); + g_free(block); + return NULL; + } + + block->driver = qcrypto_block_drivers[options->format]; + + if (block->driver->create(block, options, initfunc, + writefunc, opaque, errp) < 0) { + g_free(block); + return NULL; + } + + return block; +} + + +int qcrypto_block_decrypt(QCryptoBlock *block, + uint64_t startsector, + uint8_t *buf, + size_t len, + Error **errp) +{ + return block->driver->decrypt(block, startsector, buf, len, errp); +} + + +int qcrypto_block_encrypt(QCryptoBlock *block, + uint64_t startsector, + uint8_t *buf, + size_t len, + Error **errp) +{ + return block->driver->encrypt(block, startsector, buf, len, errp); +} + + +QCryptoCipher *qcrypto_block_get_cipher(QCryptoBlock *block) +{ + return block->cipher; +} + + +QCryptoIVGen *qcrypto_block_get_ivgen(QCryptoBlock *block) +{ + return block->ivgen; +} + + +uint64_t qcrypto_block_get_payload_offset(QCryptoBlock *block) +{ + return block->payload_offset; +} + + +void qcrypto_block_free(QCryptoBlock *block) +{ + if (!block) { + return; + } + + block->driver->cleanup(block); + + g_free(block); +} + + +int qcrypto_block_decrypt_helper(QCryptoCipher *cipher, + size_t niv, + QCryptoIVGen *ivgen, + uint64_t startsector, + uint8_t *buf, + size_t len, + Error **errp) +{ + size_t nsectors = len / 512; + size_t i; + uint8_t *iv; + int ret = -1; + + if (len % 512) { + error_setg(errp, "Length %zu must be a multiple of sector size", + len); + return -1; + } + + iv = niv ? g_new0(uint8_t, niv) : NULL; + + for (i = 0; i < nsectors; i++) { + if (niv) { + if (qcrypto_ivgen_calculate(ivgen, + startsector + i, + iv, niv, + errp) < 0) { + goto cleanup; + } + + if (qcrypto_cipher_setiv(cipher, + iv, niv, + errp) < 0) { + goto cleanup; + } + } + if (qcrypto_cipher_decrypt(cipher, + buf + (i * 512), + buf + (i * 512), + 512, + errp) < 0) { + goto cleanup; + } + } + + ret = 0; + cleanup: + g_free(iv); + return ret; +} + + +int qcrypto_block_encrypt_helper(QCryptoCipher *cipher, + size_t niv, + QCryptoIVGen *ivgen, + uint64_t startsector, + uint8_t *buf, + size_t len, + Error **errp) +{ + size_t nsectors = len / 512; + size_t i; + uint8_t *iv; + int ret = -1; + + if (len % 512) { + error_setg(errp, "Length %zu must be a multiple of sector size", + len); + return -1; + } + + iv = niv ? g_new0(uint8_t, niv) : NULL; + + for (i = 0; i < nsectors; i++) { + if (niv) { + if (qcrypto_ivgen_calculate(ivgen, + startsector + i, + iv, niv, + errp) < 0) { + goto cleanup; + } + + if (qcrypto_cipher_setiv(cipher, + iv, niv, + errp) < 0) { + goto cleanup; + } + } + if (qcrypto_cipher_encrypt(cipher, + buf + (i * 512), + buf + (i * 512), + 512, + errp) < 0) { + goto cleanup; + } + } + + ret = 0; + cleanup: + g_free(iv); + return ret; +} diff --git a/crypto/blockpriv.h b/crypto/blockpriv.h new file mode 100644 index 0000000..7ca42c5 --- /dev/null +++ b/crypto/blockpriv.h @@ -0,0 +1,89 @@ +/* + * QEMU Crypto block device encryption + * + * Copyright (c) 2015 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + * + */ + +#ifndef QCRYPTO_BLOCK_PRIV_H__ +#define QCRYPTO_BLOCK_PRIV_H__ + +#include "crypto/block.h" + +typedef struct QCryptoBlockDriver QCryptoBlockDriver; + +struct QCryptoBlock { + QCryptoBlockFormat format; + + const QCryptoBlockDriver *driver; + void *opaque; + + QCryptoCipher *cipher; + QCryptoIVGen *ivgen; + size_t niv; + uint64_t payload_offset; /* In 512 byte sectors */ +}; + +struct QCryptoBlockDriver { + int (*open)(QCryptoBlock *block, + QCryptoBlockOpenOptions *options, + QCryptoBlockReadFunc readfunc, + void *opaque, + unsigned int flags, + Error **errp); + + int (*create)(QCryptoBlock *block, + QCryptoBlockCreateOptions *options, + QCryptoBlockInitFunc initfunc, + QCryptoBlockWriteFunc writefunc, + void *opaque, + Error **errp); + + void (*cleanup)(QCryptoBlock *block); + + int (*encrypt)(QCryptoBlock *block, + uint64_t startsector, + uint8_t *buf, + size_t len, + Error **errp); + int (*decrypt)(QCryptoBlock *block, + uint64_t startsector, + uint8_t *buf, + size_t len, + Error **errp); + + gboolean (*has_format)(const uint8_t *buf, + size_t buflen); +}; + + +int qcrypto_block_decrypt_helper(QCryptoCipher *cipher, + size_t niv, + QCryptoIVGen *ivgen, + uint64_t startsector, + uint8_t *buf, + size_t len, + Error **errp); + +int qcrypto_block_encrypt_helper(QCryptoCipher *cipher, + size_t niv, + QCryptoIVGen *ivgen, + uint64_t startsector, + uint8_t *buf, + size_t len, + Error **errp); + +#endif /* QCRYPTO_BLOCK_PRIV_H__ */ diff --git a/include/crypto/block.h b/include/crypto/block.h new file mode 100644 index 0000000..e4834b3 --- /dev/null +++ b/include/crypto/block.h @@ -0,0 +1,222 @@ +/* + * QEMU Crypto block device encryption + * + * Copyright (c) 2015 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + * + */ + +#ifndef QCRYPTO_BLOCK_H__ +#define QCRYPTO_BLOCK_H__ + +#include "crypto/cipher.h" +#include "crypto/ivgen.h" + +typedef struct QCryptoBlock QCryptoBlock; + +/* See also QCryptoBlockFormat, QCryptoBlockCreateOptions + * and QCryptoBlockOpenOptions in qapi/crypto.json */ + +typedef ssize_t (*QCryptoBlockReadFunc)(QCryptoBlock *block, + size_t offset, + uint8_t *buf, + size_t buflen, + Error **errp, + void *opaque); + +typedef ssize_t (*QCryptoBlockInitFunc)(QCryptoBlock *block, + size_t headerlen, + Error **errp, + void *opaque); + +typedef ssize_t (*QCryptoBlockWriteFunc)(QCryptoBlock *block, + size_t offset, + const uint8_t *buf, + size_t buflen, + Error **errp, + void *opaque); + +/** + * qcrypto_block_has_format: + * @format: the encryption format + * @buf: the data from head of the volume + * @len: the length of @buf in bytes + * + * Given @len bytes of data from the head of a storage volume + * in @buf, probe to determine if the volume has the encryption + * format specified in @format. + * + * Returns: true if the data in @buf matches @format + */ +gboolean qcrypto_block_has_format(QCryptoBlockFormat format, + const uint8_t *buf, + size_t buflen); + +typedef enum { + QCRYPTO_BLOCK_OPEN_NO_IO = (1 << 0), +} QCryptoBlockOpenFlags; + +/** + * qcrypto_block_open: + * @options: the encryption options + * @readfunc: callback for reading data from the volume + * @opaque: data to pass to @readfunc + * @flags: bitmask of QCryptoBlockOpenFlags values + * @errp: pointer to an uninitialized error object + * + * Create a new block encryption object for an existing + * storage volume encrypted with format identified by + * the parameters in @options. + * + * This will use @readfunc to initialize the encryption + * context based on the volume header(s), extracting the + * master key(s) as required. + * + * If @flags contains QCRYPTO_BLOCK_OPEN_NO_IO then + * the open process will be optimized to skip any parts + * that are only required to perform I/O. In particular + * this would usually avoid the need to decrypt any + * master keys. The only thing that can be done with + * the resulting QCryptoBlock object would be to query + * metadata such as the payload offset. There will be + * no cipher or ivgen objects available. + * + * If any part of initializing the encryption context + * fails an error will be returned. This could be due + * to the volume being in the wrong format, an cipher + * or IV generator algorithm that is not supoported, + * or incorrect passphrases. + * + * Returns: a block encryption format, or NULL on error + */ +QCryptoBlock *qcrypto_block_open(QCryptoBlockOpenOptions *options, + QCryptoBlockReadFunc readfunc, + void *opaque, + unsigned int flags, + Error **errp); + +/** + * qcrypto_block_create: + * @format: the encryption format + * @keyid: ID of a QCryptoSecret with key for unlocking master key + * @initfunc: callback for initializing volume header + * @writefunc: callback for writing data to the volume header + * @opaque: data to pass to @initfunc & @writefunc + * @errp: pointer to an uninitialized error object + * + * Create a new block encryption object for initializing + * a storage volume to be encrypted with format identified + * by the parameters in @options. + * + * This method will allocate space for a new volume header + * using @initfunc and then write header data using @writefunc, + * generating new master keys, etc as required. Any existing + * data present on the volume will be irrevokably destroyed. + * + * If any part of initializing the encryption context + * fails an error will be returned. This could be due + * to the volume being in the wrong format, an cipher + * or IV generator algorithm that is not supoported, + * or incorrect passphrases. + * + * Returns: a block encryption format, or NULL on error + */ +QCryptoBlock *qcrypto_block_create(QCryptoBlockCreateOptions *options, + QCryptoBlockInitFunc initfunc, + QCryptoBlockWriteFunc writefunc, + void *opaque, + Error **errp); + +/** + * @qcrypto_block_decrypt: + * @block: the block encryption object + * @startsector: the sector from which @buf was read + * @buf: the buffer to decrypt + * @len: the length of @buf in bytes + * @errp: pointer to an uninitialized error object + * + * Decrypt @len bytes of cipher text in @buf, writing + * plain text back into @buf + * + * Returns 0 on success, -1 on failure + */ +int qcrypto_block_decrypt(QCryptoBlock *block, + uint64_t startsector, + uint8_t *buf, + size_t len, + Error **errp); + +/** + * @qcrypto_block_encrypt: + * @block: the block encryption object + * @startsector: the sector to which @buf will be written + * @buf: the buffer to decrypt + * @len: the length of @buf in bytes + * @errp: pointer to an uninitialized error object + * + * Encrypt @len bytes of plain text in @buf, writing + * cipher text back into @buf + * + * Returns 0 on success, -1 on failure + */ +int qcrypto_block_encrypt(QCryptoBlock *block, + uint64_t startsector, + uint8_t *buf, + size_t len, + Error **errp); + +/** + * qcrypto_block_get_cipher: + * @block: the block encryption object + * + * Get the cipher to use for payload encryption + * + * Returns: the cipher object + */ +QCryptoCipher *qcrypto_block_get_cipher(QCryptoBlock *block); + +/** + * qcrypto_block_get_ivgen: + * @block: the block encryption object + * + * Get the initialization vector generator to use for + * payload encryption + * + * Returns: the IV generator object + */ +QCryptoIVGen *qcrypto_block_get_ivgen(QCryptoBlock *block); + +/** + * qcrypto_block_get_payload_offset: + * @block: the block encryption object + * + * Get the offset to the payload indicated by the + * encryption header. The offset is measured in + * 512 byte sectors + * + * Returns: the payload offset in sectors. + */ +uint64_t qcrypto_block_get_payload_offset(QCryptoBlock *block); + +/** + * qcrypto_block_free: + * @block: the block encryption object + * + * Release all resources associated with the encryption + * object + */ +void qcrypto_block_free(QCryptoBlock *block); + +#endif /* QCRYPTO_BLOCK_H__ */ diff --git a/qapi/crypto.json b/qapi/crypto.json index 48946b0..07b9b46 100644 --- a/qapi/crypto.json +++ b/qapi/crypto.json @@ -94,3 +94,68 @@ { 'enum': 'QCryptoIVGenAlgorithm', 'prefix': 'QCRYPTO_IVGEN_ALG', 'data': ['plain', 'plain64', 'essiv']} + +## +# QCryptoBlockFormat: +# +# The supported full disk encryption formats +# +# @qcowaes: QCow/QCow2 built-in AES-CBC encryption. Do not use +# +# Since: 2.6 +## +{ 'enum': 'QCryptoBlockFormat', +# 'prefix': 'QCRYPTO_BLOCK_FORMAT', + 'data': ['qcowaes']} + +## +# QCryptoBlockOptionsBase: +# +# The common options that apply to all full disk +# encryption formats +# +# @format: the encryption format +# +# Since: 2.6 +## +{ 'struct': 'QCryptoBlockOptionsBase', + 'data': { 'format': 'QCryptoBlockFormat' }} + +## +# QCryptoBlockOptionsQCowAES: +# +# The options that apply to QCow AES encryption format +# +# @key-id: the ID of a QCryptoSecret object providing the decryption key +# +# Since: 2.6 +## +{ 'struct': 'QCryptoBlockOptionsQCowAES', + 'data': { '*key-id': 'str' }} + +## +# QCryptoBlockOpenOptions: +# +# The options that are available for all encryption formats +# when opening an existing volume +# +# Since: 2.6 +## +{ 'union': 'QCryptoBlockOpenOptions', + 'base': 'QCryptoBlockOptionsBase', + 'discriminator': 'format', + 'data': { 'qcowaes': 'QCryptoBlockOptionsQCowAES' } } + + +## +# QCryptoBlockCreateOptions: +# +# The options that are available for all encryption formats +# when initializing a new volume +# +# Since: 2.6 +## +{ 'union': 'QCryptoBlockCreateOptions', + 'base': 'QCryptoBlockOptionsBase', + 'discriminator': 'format', + 'data': { 'qcowaes': 'QCryptoBlockOptionsQCowAES' } }