On Thu, Feb 04, 2016 at 05:23:32PM -0700, Eric Blake wrote: > On 01/20/2016 10:38 AM, Daniel P. Berrange wrote: > > 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 <berra...@redhat.com> > > --- > > crypto/Makefile.objs | 2 + > > crypto/block-qcow.c | 167 +++++++++++++++++++++++++++++ > > crypto/block-qcow.h | 28 +++++ > > crypto/block.c | 263 > > ++++++++++++++++++++++++++++++++++++++++++++++ > > crypto/blockpriv.h | 90 ++++++++++++++++ > > include/crypto/block.h | 233 ++++++++++++++++++++++++++++++++++++++++ > > qapi/crypto.json | 67 ++++++++++++ > > tests/.gitignore | 1 + > > tests/Makefile | 2 + > > tests/test-crypto-block.c | 239 +++++++++++++++++++++++++++++++++++++++++ > > 10 files changed, 1092 insertions(+) > > create mode 100644 crypto/block-qcow.c > > create mode 100644 crypto/block-qcow.h > > create mode 100644 crypto/block.c > > create mode 100644 crypto/blockpriv.h > > create mode 100644 include/crypto/block.h > > create mode 100644 tests/test-crypto-block.c > > > > > +++ b/crypto/block-qcow.c > > @@ -0,0 +1,167 @@ > > +/* > > + * QEMU Crypto block device encryption QCow/QCow2 AES-CBC format > > + * > > + * Copyright (c) 2015-2016 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 > > <http://www.gnu.org/licenses/>. > > + * > > + */ > > Maybe worth a big comment stating that this file exists for backwards > compatibility, and no one in their right mind should copy the code > and/or encrypt new files with it.
Heh, yeah. > > +static gboolean > > +qcrypto_block_qcow_has_format(const uint8_t *buf G_GNUC_UNUSED, > > + size_t buf_size G_GNUC_UNUSED) > > +{ > > + return false; > > +} > > When I see gboolean, I think TRUE/FALSE. Yes, C99 'false' happens to > promote to the correct value for whatever integer type gboolean is, but > this would read nicer if it returned 'bool'. Yeah, dunno what I was thinking really. I use gboolean in a few places due to the gmainloop callback API contract, but this should not have needed it. > > +static int > > +qcrypto_block_qcow_init(QCryptoBlock *block, > > + const char *keysecret, > > + Error **errp) > > +{ > > + char *password; > > + int ret; > > + uint8_t keybuf[16]; > > + int len, i; > > + > > + memset(keybuf, 0, 16); > > + > > + password = qcrypto_secret_lookup_as_utf8(keysecret, errp); > > + if (!password) { > > + return -1; > > + } > > + > > + len = strlen(password); > > + if (len > 16) { > > + len = 16; > > + } > > + for (i = 0; i < len; i++) { > > + keybuf[i] = password[i]; > > + } > > What - we really throw away anything longer than 16 bytes? Yes, that's how awesome legacy qcow2 encryption is :-) > Would a memcpy() be any nicer than an open-coded loop? Sure. > > +++ b/crypto/blockpriv.h > > > + > > +typedef struct QCryptoBlockDriver QCryptoBlockDriver; > > + > > +struct QCryptoBlock { > > + QCryptoBlockFormat format; > > + > > + const QCryptoBlockDriver *driver; > > + void *opaque; > > + > > + QCryptoCipher *cipher; > > + QCryptoIVGen *ivgen; > > + QCryptoHashAlgorithm kdfhash; > > + size_t niv; > > + uint64_t payload_offset; /* In 512 byte sectors */ > > Someday, we may want to support 4k sectors natively. I don't envy the > person making the conversion, but we could at least make their life > easier by representing this in bytes instead of units of 512-byte sectors. Ok will do. > > +}; > > + > > +struct QCryptoBlockDriver { > > + int (*open)(QCryptoBlock *block, > > + QCryptoBlockOpenOptions *options, > > + QCryptoBlockReadFunc readfunc, > > + void *opaque, > > + unsigned int flags, > > + Error **errp); > > No documentation on any of these contracts? They're essentially identical to the public API contracts, so I figured it was redundant to duplicate those docs. > > +/** > > + * 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, > > Again, this should probably be 'bool', not gboolean. Yep > > +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 > > From the guest's point of view, right? Yes & no, it is the sector of whatever underlying storage holds the image. If there are other formats beneath the crypto format it might not correspond to the guest OS seen sector. > > +/** > > + * 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); > > Please, let's use bytes here, not sectors. Ok Regards, Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|