Support LUKS encryption in block devices
Subsystems (3)
v4 cover Support LUKS encryption in block devices
This series was previously submitted here:
v1: https://lists.gnu.org/archive/html/qemu-devel/2015-11/msg04748.html
v2: https://lists.gnu.org/archive/html/qemu-block/2016-01/msg00534.html
v3: https://lists.gnu.org/archive/html/qemu-devel/2016-02/msg03176.html
This patch series applies as is to master, since all the dependent block tools code is now merged.
I'd like to try to get the crypto patches + the generic luks block driver for QEMU 2.6, but leave the qcow2 enhancements for 2.7
As can be guessed from the subject, the primary goal of this patch series is to support LUKS encryption in the QEMU block layer. QEMU has increasingly been adding native clients for network block protocols (RBD, gluster, NFS, iSCSI, etc) and apps like OpenStack are embracing them as it is much easier to deal with this from a management POV than to deal with the kernel block layer & userspace tools. Unfortunately when using QEMU native clients, apps are locked out of using dm-crypt and LUKS which is undesirable.
This series introduces two new features to the block layer. First there is a general purpose 'luks' format driver which can be layered over any other existing block driver. eg it can be layed above RBD, iSCSI, etc. Second the qcow2 file format is extended so that its embedded encryption can be replaced with the LUKS data format. While you could just layer the general purpose luks driver over qcow2, this is slightly less desirable, as it removes the ability to reliably auto-detect that LUKS is used by QEMU, as opposed to used by the guest OS. Having use of LUKS encoded in the qcow2 header addresses this.
The code is designed such that there is a strict separation between the full disk encryption format and the block I/O layer. Thus there is an generic API for dealing with full disk encryption added to the crypto/ subsystem. The block layer merely calls this FDE API when required, which serves to minimize the code present in the already complex block layer.
The big change in this posting is the addition of an integration test in tests/qemu-iotests/145. This uses 'sudo cryptsetup' to create LUKS volumes on the host kernel and perform I/O to/from them. This is validated against QEMU's implementation using qemu-io. Conversely we also create LUKS volumes wth qemu-img and then validate that the kernel can use them. This proves good interoperability between the two implementations across a wide range of crypto algorithms.
The big thing that I have *not* addressed is Fam's idea about modifying the generic block layer so that it can automatically instantitate a LUKS block driver above the qcow2 driver, if qcow2 indicates that it needs encryption support. I'm still not 100% sure this is the right way to go, but I've not had time to investigate, since the focus since last posting has been on dm-crypt interoperability for the generic 'luks' block driver.
The first 11 patches add some supporting APIs and algorithms to the crypto subsystem.
The 12-13 patches introduce the general full disk encryption API to the crypto subsystem and LUKS implementation
Patches 14-18 do a little preparation to the block code for future patches.
Patch 19 addes the new 'luks' block driver format along with a test for interoperability with dm-crypt/cryptsetup
Patches 20-23 convert qcow & qcow2 to the new FDE APIs, enabling LUKS in qcow2 (but not qcow) at the same time.
Patches 24-25 clean up the horrible password handling cruft in the block layer and monitor.
Patch 26 blocks use of the legacy qcow[2] encryption from the system emulators.
Chagnes since v3:
- Rebased to resolve conflicts with recently merged code
- Add qemu/osdep.h include to all new files
- Fix unit test for new XTS default mode
Changes since v2:
- Added support for XTS cipher usage mode
- Added support for serpent, twofish & cast5 ciphers
- Use qemu/osdep.h where applicable (Eric)
- Use MAX macro where applicable (Eric)
- Use bool instead of gboolean (Eric)
- Use bytes instead of sectors in API to future proof for 4k sector sizes (Eric)
- Add asserts for LUKS structs matching spec size (Eric)
- Switch to XTS+plain64 instead of CBC+essiv for new LUKS volumes
- Add qemu I/O test 145 for dm-crypt interoperability
- Rearrange vol creation so that we treat size as the logical guest volume size, instead of physical container size (Fam).
- Push malloc of bounce buffer out of loop in LUKS block driver (Eric)
- Many misc typos/docs fixes (Fam, Eric)
Changes since v1:
- Unit testing coverage of the full disk encryption APIs
- Functional testing of LUKS driver via the qemu-iotests for the block layer
- Use GNUTLS random API for the random byte source
- Use Makefile.objs for conditional compilation of pbkdf files (Fam)
- Use 'key-secret' instead of 'key-id' as property for decryption key (Paolo)
- Rename 'fde' to 'crypto' in block code (Kevin)
- Fix accounting of encryption header clusters when checking refcounts (Kevin)
- Rename format 'qcowaes' to 'qcow' (Eric)
- Fix qapi syntax for marking optional parameters (Eric)
- Add assertions in I/O path for BDRV_O_NO_IO flag
- Cleanup return codes / error reporting (Kevin)
- Other misc fixes identified in testing
Changes since WIP:
- QAPI parameters defined for the encryption key ID
- The qcow2 integration of LUKS is working, using extra allocated clusters to store LUKS header instead of trying to expand the main qcow2 header region to > 1 cluster
- qemu-img info now works without prompting for decryption password
- Unit testing of pbkdf2, afsplit and ivgen APis.
Daniel P. Berrange (26):
crypto: add cryptographic random byte source
crypto: add support for PBKDF2 algorithm
crypto: add support for generating initialization vectors
crypto: add support for anti-forensic split algorithm
crypto: skip testing of unsupported cipher algorithms
crypto: add support for the cast5-128 cipher algorithm
crypto: add support for the serpent cipher algorithm
crypto: add support for the twofish cipher algorithm
crypto: import an implementation of the XTS cipher mode
crypto: refactor code for dealing with AES cipher
crypto: wire up XTS mode for cipher APIs
crypto: add block encryption framework
crypto: implement the LUKS block encryption format
block: add flag to indicate that no I/O will be performed qemu-img/qemu-io: don't prompt for passwords if not required
tests: redirect stderr to stdout for iotests
tests: refactor python I/O tests helper main method
tests: add output filter to python I/O tests helper
block: add generic full disk encryption driver
qcow2: make qcow2_encrypt_sectors encrypt in place
qcow2: convert QCow2 to use QCryptoBlock for encryption
qcow: make encrypt_sectors encrypt in place
qcow: convert QCow to use QCryptoBlock for encryption
block: rip out all traces of password prompting
block: remove all encryption handling APIs
block: remove support for legecy AES qcow/qcow2 encryption
Makefile.objs | 2 +- block.c | 99 +- block/Makefile.objs | 2 + block/crypto.c | 578 +++++++++++ block/io.c | 2 + block/qapi.c | 2 +- block/qcow.c | 204 ++-- block/qcow2-cluster.c | 53 +- block/qcow2-refcount.c | 10 + block/qcow2.c | 519 ++++++++-- block/qcow2.h | 24 +- blockdev.c | 41 +- crypto/Makefile.objs | 17 + crypto/afsplit.c | 158 +++ crypto/block-luks.c | 1313 ++++++++++++++++++++++++ crypto/block-luks.h | 28 + crypto/block-qcow.c | 173 ++++ crypto/block-qcow.h | 28 + crypto/block.c | 260 +++++ crypto/blockpriv.h | 92 ++ crypto/cipher-builtin.c | 207 +++- crypto/cipher-gcrypt.c | 171 +++- crypto/cipher-nettle.c | 197 +++- crypto/cipher.c | 41 +- crypto/ivgen-essiv.c | 118 +++ crypto/ivgen-essiv.h | 28 + crypto/ivgen-plain.c | 59 ++ crypto/ivgen-plain.h | 28 + crypto/ivgen-plain64.c | 59 ++ crypto/ivgen-plain64.h | 28 + crypto/ivgen.c | 99 ++ crypto/ivgenpriv.h | 49 + crypto/pbkdf-gcrypt.c | 68 ++ crypto/pbkdf-nettle.c | 65 ++ crypto/pbkdf-stub.c | 42 + crypto/pbkdf.c | 77 ++ crypto/random-gcrypt.c | 33 + crypto/random-gnutls.c | 43 + crypto/random-stub.c | 31 + crypto/xts.c | 256 +++++ docs/specs/qcow2.txt | 76 ++ hmp.c | 31 - hw/usb/dev-storage.c | 34 - include/block/block.h | 6 +- include/block/block_int.h | 1 - include/crypto/afsplit.h | 135 +++ include/crypto/block.h | 232 +++++ include/crypto/ivgen.h | 206 ++++ include/crypto/pbkdf.h | 152 +++ include/crypto/random.h | 44 + include/crypto/xts.h | 86 ++ include/monitor/monitor.h | 7 - include/qemu/osdep.h | 2 - monitor.c | 68 -- qapi/block-core.json | 46 +- qapi/crypto.json | 145 ++- qemu-img.c | 66 +- qemu-io.c | 21 - qmp.c | 10 +- tests/.gitignore | 5 + tests/Makefile | 10 + tests/qemu-iotests/049 | 2 +- tests/qemu-iotests/049.out | 10 +- tests/qemu-iotests/082.out | 189 ++++ tests/qemu-iotests/087 | 30 +- tests/qemu-iotests/087.out | 28 +- tests/qemu-iotests/134 | 18 +- tests/qemu-iotests/134.out | 33 +- tests/qemu-iotests/146 | 521 ++++++++++ tests/qemu-iotests/146.out | 2252 +++++++++++++++++++++++++++++++++++++++++ tests/qemu-iotests/common | 8 + tests/qemu-iotests/group | 1 + tests/qemu-iotests/iotests.py | 48 +- tests/test-crypto-afsplit.c | 190 ++++ tests/test-crypto-block.c | 334 ++++++ tests/test-crypto-cipher.c | 215 +++- tests/test-crypto-ivgen.c | 169 ++++ tests/test-crypto-pbkdf.c | 377 +++++++ tests/test-crypto-xts.c | 423 ++++++++ util/oslib-posix.c | 66 -- util/oslib-win32.c | 24 - 81 files changed, 10745 insertions(+), 880 deletions(-) create mode 100644 block/crypto.c create mode 100644 crypto/afsplit.c create mode 100644 crypto/block-luks.c create mode 100644 crypto/block-luks.h 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 crypto/ivgen-essiv.c create mode 100644 crypto/ivgen-essiv.h create mode 100644 crypto/ivgen-plain.c create mode 100644 crypto/ivgen-plain.h create mode 100644 crypto/ivgen-plain64.c create mode 100644 crypto/ivgen-plain64.h create mode 100644 crypto/ivgen.c create mode 100644 crypto/ivgenpriv.h create mode 100644 crypto/pbkdf-gcrypt.c create mode 100644 crypto/pbkdf-nettle.c create mode 100644 crypto/pbkdf-stub.c create mode 100644 crypto/pbkdf.c create mode 100644 crypto/random-gcrypt.c create mode 100644 crypto/random-gnutls.c create mode 100644 crypto/random-stub.c create mode 100644 crypto/xts.c create mode 100644 include/crypto/afsplit.h create mode 100644 include/crypto/block.h create mode 100644 include/crypto/ivgen.h create mode 100644 include/crypto/pbkdf.h create mode 100644 include/crypto/random.h create mode 100644 include/crypto/xts.h create mode 100755 tests/qemu-iotests/146 create mode 100644 tests/qemu-iotests/146.out create mode 100644 tests/test-crypto-afsplit.c create mode 100644 tests/test-crypto-block.c create mode 100644 tests/test-crypto-ivgen.c create mode 100644 tests/test-crypto-pbkdf.c create mode 100644 tests/test-crypto-xts.c
Signature · 1 line
2.5.0
PATCH v4 1/26 crypto: add cryptographic random byte source
There are three backend impls provided. The preferred is gnutls, which is backed by nettle in modern distros. The gcrypt impl is provided for cases where QEMU build against gnutls is disabled, but crypto is still desired. No nettle impl is provided, since it is non-trivial to use the nettle APIs for random numbers. Users of nettle should ensure gnutls is enabled for QEMU.
--- Makefile.objs | 2 +- crypto/Makefile.objs | 4 ++++ crypto/random-gcrypt.c | 33 +++++++++++++++++++++++++++++++++ crypto/random-gnutls.c | 43 +++++++++++++++++++++++++++++++++++++++++++ crypto/random-stub.c | 31 +++++++++++++++++++++++++++++++ include/crypto/random.h | 44 ++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 156 insertions(+), 1 deletion(-) create mode 100644 crypto/random-gcrypt.c create mode 100644 crypto/random-gnutls.c create mode 100644 crypto/random-stub.c create mode 100644 include/crypto/random.h
Makefile.objs +1 -1
@@ -1,6 +1,6 @@ ####################################################################### # Common libraries for tools and emulators -stub-obj-y = stubs/ +stub-obj-y = stubs/ crypto/ util-obj-y = util/ qobject/ qapi/ util-obj-y += qmp-introspect.o qapi-types.o qapi-visit.o qapi-event.o
crypto/Makefile.objs +4 -0
@@ -8,6 +8,10 @@ crypto-obj-y += tlscredsanon.o crypto-obj-y += tlscredsx509.o crypto-obj-y += tlssession.o crypto-obj-y += secret.o +crypto-obj-$(if $(CONFIG_GNUTLS),n,$(CONFIG_GCRYPT)) += random-gcrypt.o +crypto-obj-$(CONFIG_GNUTLS) += random-gnutls.o # Let the userspace emulators avoid linking gnutls/etc crypto-aes-obj-y = aes.o + +stub-obj-y += random-stub.o
crypto/random-gcrypt.c new file +33 -0
@@ -0,0 +1,33 @@ +/* +* QEMU Crypto random number provider +* +* 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/>. +* +*/ + +#include "qemu/osdep.h" + +#include "crypto/random.h" + +#include <gcrypt.h> + +int qcrypto_random_bytes (uint8_t *buf, +size_t buflen, + Error **errp G_GNUC_UNUSED) +{ +gcry_randomize (buf, buflen,GCRY_STRONG_RANDOM ); +return 0 ; +}
crypto/random-gnutls.c new file +43 -0
43 lines not on this page · raw message
crypto/random-stub.c new file +31 -0
@@ -0,0 +1,31 @@ +/* +* QEMU Crypto random number provider +* +* 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/>. +* +*/ + +#include "qemu/osdep.h" + +#include "crypto/random.h" + +int qcrypto_random_bytes(uint8_t *buf G_GNUC_UNUSED, + size_t buflen G_GNUC_UNUSED, +Error **errp) +{ +error_setg (errp,"No random byte source provided in this build" ); +return -1 ; +}
include/crypto/random.h new file +44 -0
44 lines not on this page · raw message
Signature · 1 line
2.5.0
PATCH v4 2/26 crypto: add support for PBKDF2 algorithm
In reply to Daniel P. BerrangeThe LUKS data format includes use of PBKDF2 (Password-Based Key Derivation Function). The Nettle library can provide an implementation of this, but we don't want code directly depending on a specific crypto library backend. Introduce a new include/crypto/pbkdf.h header which defines a QEMU API for invoking PBKDK2. The initial implementations are backed by nettle & gcrypt, which are commonly available with distros shipping GNUTLS.
The test suite data is taken from the cryptsetup codebase under the LGPLv2.1+ license. This merely aims to verify that whatever backend we provide for this function in QEMU will comply with the spec.
--- crypto/Makefile.objs | 4 + crypto/pbkdf-gcrypt.c | 68 +++++++++ crypto/pbkdf-nettle.c | 65 ++++++++ crypto/pbkdf-stub.c | 42 ++++++ crypto/pbkdf.c | 77 ++++++++++ include/crypto/pbkdf.h | 152 +++++++++++++++++++ tests/.gitignore | 1 + tests/Makefile | 2 + tests/test-crypto-pbkdf.c | 377 ++++++++++++++++++++++++++++++++++++++++++++++ 9 files changed, 788 insertions(+) create mode 100644 crypto/pbkdf-gcrypt.c create mode 100644 crypto/pbkdf-nettle.c create mode 100644 crypto/pbkdf-stub.c create mode 100644 crypto/pbkdf.c create mode 100644 include/crypto/pbkdf.h create mode 100644 tests/test-crypto-pbkdf.c
crypto/Makefile.objs +4 -0
@@ -10,8 +10,12 @@ crypto-obj-y += tlssession.o crypto-obj-y += secret.o crypto-obj-$(if $(CONFIG_GNUTLS),n,$(CONFIG_GCRYPT)) += random-gcrypt.o crypto-obj-$(CONFIG_GNUTLS) += random-gnutls.o +crypto-obj-y += pbkdf.o +crypto-obj-$(CONFIG_NETTLE) += pbkdf-nettle.o +crypto-obj-$(if $(CONFIG_NETTLE),n,$(CONFIG_GCRYPT)) += pbkdf-gcrypt.o # Let the userspace emulators avoid linking gnutls/etc crypto-aes-obj-y = aes.o stub-obj-y += random-stub.o +stub-obj-y += pbkdf-stub.o
crypto/pbkdf-gcrypt.c new file +68 -0
68 lines not on this page · raw message
crypto/pbkdf-nettle.c new file +65 -0
65 lines not on this page · raw message
crypto/pbkdf-stub.c new file +42 -0
42 lines not on this page · raw message
crypto/pbkdf.c new file +77 -0
77 lines not on this page · raw message
include/crypto/pbkdf.h new file +152 -0
152 lines not on this page · raw message
tests/.gitignore +1 -0
@@ -14,6 +14,7 @@ test-blockjob-txn test-coroutine test-crypto-cipher test-crypto-hash +test-crypto-pbkdf test-crypto-secret test-crypto-tlscredsx509 test-crypto-tlscredsx509-work/
tests/Makefile +2 -0
@@ -92,6 +92,7 @@ check-unit-$(CONFIG_GNUTLS) += tests/test-io-channel-tls$(EXESUF) check-unit-y += tests/test-io-channel-command$(EXESUF) check-unit-y += tests/test-io-channel-buffer$(EXESUF) check-unit-y += tests/test-base64$(EXESUF) +check-unit-y += tests/test-crypto-pbkdf$(EXESUF) check-block-$(CONFIG_POSIX) += tests/qemu-iotests-quick.sh
@@ -497,6 +498,7 @@ tests/test-io-channel-command$(EXESUF): tests/test-io-channel-command.o \ tests/io-channel-helpers.o $(test-io-obj-y) tests/test-io-channel-buffer$(EXESUF): tests/test-io-channel-buffer.o \ tests/io-channel-helpers.o $(test-io-obj-y) +tests/test-crypto-pbkdf$(EXESUF): tests/test-crypto-pbkdf.o $(test-crypto-obj-y) libqos-obj-y = tests/libqos/pci.o tests/libqos/fw_cfg.o tests/libqos/malloc.o libqos-obj-y += tests/libqos/i2c.o tests/libqos/libqos.o
tests/test-crypto-pbkdf.c new file +377 -0
377 lines not on this page · raw message
Signature · 1 line
2.5.0
Re: [Qemu-devel] [PATCH v4 02/26] crypto: add support for PBKDF2 algorithm
Quoted 9 lines · Daniel P. Berrange
The LUKS data format includes use of PBKDF2 (Password-Based Key Derivation Function). The Nettle library can provide an implementation of this, but we don't want code directly depending on a specific crypto library backend. Introduce a new
include/crypto/pbkdf.hheader which defines a QEMU API for invoking PBKDK2. The initial implementations are backed by nettle & gcrypt, which are commonly available with distros shipping GNUTLS.
Quoted 7 lines
The test suite data is taken from the cryptsetup codebase under the LGPLv2.1+ license. This merely aims to verify that whatever backend we provide for this function in QEMU will comply with the spec.
Signed-off-by Daniel P. Berrange <[email protected]>---
Signature · 2 lines
Eric Blake eblake redhat com +1-919-301-3266 Libvirt virtualization library http://libvirt.org
Re: [Qemu-devel] [PATCH v4 02/26] crypto: add support for PBKDF2 algorithm
In reply to Daniel P. BerrangeQuoted 9 lines · Daniel P. Berrange
The LUKS data format includes use of PBKDF2 (Password-Based Key Derivation Function). The Nettle library can provide an implementation of this, but we don't want code directly depending on a specific crypto library backend. Introduce a new
include/crypto/pbkdf.hheader which defines a QEMU API for invoking PBKDK2. The initial implementations are backed by nettle & gcrypt, which are commonly available with distros shipping GNUTLS.
Quoted 6 lines
The test suite data is taken from the cryptsetup codebase under the LGPLv2.1+ license. This merely aims to verify that whatever backend we provide for this function in QEMU will comply with the spec.
Signed-off-by Daniel P. Berrange <[email protected]>
PATCH v4 3/26 crypto: add support for generating initialization vectors
In reply to Daniel P. BerrangeThere are a number of different algorithms that can be used to generate initialization vectors for disk encryption. This introduces a simple internal QCryptoBlockIV object to provide a consistent internal API to the different algorithms. The initially implemented algorithms are 'plain', 'plain64' and 'essiv', each matching the same named algorithm provided by the Linux kernel dm-crypt driver.
--- crypto/Makefile.objs | 4 + crypto/ivgen-essiv.c | 118 ++++++++++++++++++++++++++ crypto/ivgen-essiv.h | 28 +++++++ crypto/ivgen-plain.c | 59 +++++++++++++ crypto/ivgen-plain.h | 28 +++++++ crypto/ivgen-plain64.c | 59 +++++++++++++ crypto/ivgen-plain64.h | 28 +++++++ crypto/ivgen.c | 99 ++++++++++++++++++++++ crypto/ivgenpriv.h | 49 +++++++++++ include/crypto/ivgen.h | 206 ++++++++++++++++++++++++++++++++++++++++++++++ qapi/crypto.json | 19 +++++ tests/.gitignore | 1 + tests/Makefile | 2 + tests/test-crypto-ivgen.c | 169 +++++++++++++++++++++++++++++++++++++ 14 files changed, 869 insertions(+) create mode 100644 crypto/ivgen-essiv.c create mode 100644 crypto/ivgen-essiv.h create mode 100644 crypto/ivgen-plain.c create mode 100644 crypto/ivgen-plain.h create mode 100644 crypto/ivgen-plain64.c create mode 100644 crypto/ivgen-plain64.h create mode 100644 crypto/ivgen.c create mode 100644 crypto/ivgenpriv.h create mode 100644 include/crypto/ivgen.h create mode 100644 tests/test-crypto-ivgen.c
crypto/Makefile.objs +4 -0
@@ -13,6 +13,10 @@ crypto-obj-$(CONFIG_GNUTLS) += random-gnutls.o crypto-obj-y += pbkdf.o crypto-obj-$(CONFIG_NETTLE) += pbkdf-nettle.o crypto-obj-$(if $(CONFIG_NETTLE),n,$(CONFIG_GCRYPT)) += pbkdf-gcrypt.o +crypto-obj-y += ivgen.o +crypto-obj-y += ivgen-essiv.o +crypto-obj-y += ivgen-plain.o +crypto-obj-y += ivgen-plain64.o # Let the userspace emulators avoid linking gnutls/etc crypto-aes-obj-y = aes.o
crypto/ivgen-essiv.c new file +118 -0
118 lines not on this page · raw message
crypto/ivgen-essiv.h new file +28 -0
@@ -0,0 +1,28 @@ +/* +* QEMU Crypto block IV generator - essiv +* +* 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/>. +* +*/ + +#include "crypto/ivgenpriv.h" + +#ifndef QCRYPTO_IVGEN_ESSIV_H__ +#define QCRYPTO_IVGEN_ESSIV_H__ + +extern struct QCryptoIVGenDriver qcrypto_ivgen_essiv; + +#endif /* QCRYPTO_IVGEN_ESSIV_H__ */
crypto/ivgen-plain.c new file +59 -0
59 lines not on this page · raw message
crypto/ivgen-plain.h new file +28 -0
@@ -0,0 +1,28 @@ +/* +* QEMU Crypto block IV generator - plain +* +* 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/>. +* +*/ + +#include "crypto/ivgenpriv.h" + +#ifndef QCRYPTO_IVGEN_PLAIN_H__ +#define QCRYPTO_IVGEN_PLAIN_H__ + +extern struct QCryptoIVGenDriver qcrypto_ivgen_plain; + +#endif /* QCRYPTO_IVGEN_PLAIN_H__ */
crypto/ivgen-plain64.c new file +59 -0
59 lines not on this page · raw message
crypto/ivgen-plain64.h new file +28 -0
@@ -0,0 +1,28 @@ +/* +* QEMU Crypto block IV generator - plain64 +* +* 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/>. +* +*/ + +#include "crypto/ivgenpriv.h" + +#ifndef QCRYPTO_IVGEN_PLAIN64_H__ +#define QCRYPTO_IVGEN_PLAIN64_H__ + +extern struct QCryptoIVGenDriver qcrypto_ivgen_plain64; + +#endif /* QCRYPTO_IVGEN_PLAIN64_H__ */
crypto/ivgen.c new file +99 -0
99 lines not on this page · raw message
crypto/ivgenpriv.h new file +49 -0
49 lines not on this page · raw message
include/crypto/ivgen.h new file +206 -0
206 lines not on this page · raw message
qapi/crypto.json +19 -0
@@ -78,3 +78,22 @@ { 'enum': 'QCryptoCipherMode', 'prefix': 'QCRYPTO_CIPHER_MODE', 'data': ['ecb', 'cbc']} + + +## +# QCryptoIVGenAlgorithm: +# +# The supported algorithms for generating initialization +# vectors for full disk encryption. The 'plain' generator +# should not be used for disks with sector numbers larger +# than 2^32, except where compatibility with pre-existing +# Linux dm-crypt volumes is required. +# +# @plain: 64-bit sector number truncated to 32-bits +# @plain64: 64-bit sector number +# @essiv: 64-bit sector number encrypted with a hash of the encryption key +# Since: 2.6 +## +{ 'enum': 'QCryptoIVGenAlgorithm', + 'prefix': 'QCRYPTO_IVGEN_ALG', + 'data': ['plain', 'plain64', 'essiv']}
tests/.gitignore +1 -0
@@ -14,6 +14,7 @@ test-blockjob-txn test-coroutine test-crypto-cipher test-crypto-hash +test-crypto-ivgen test-crypto-pbkdf test-crypto-secret test-crypto-tlscredsx509
tests/Makefile +2 -0
@@ -93,6 +93,7 @@ check-unit-y += tests/test-io-channel-command$(EXESUF) check-unit-y += tests/test-io-channel-buffer$(EXESUF) check-unit-y += tests/test-base64$(EXESUF) check-unit-y += tests/test-crypto-pbkdf$(EXESUF) +check-unit-y += tests/test-crypto-ivgen$(EXESUF) check-block-$(CONFIG_POSIX) += tests/qemu-iotests-quick.sh
@@ -499,6 +500,7 @@ tests/test-io-channel-command$(EXESUF): tests/test-io-channel-command.o \ tests/test-io-channel-buffer$(EXESUF): tests/test-io-channel-buffer.o \ tests/io-channel-helpers.o $(test-io-obj-y) tests/test-crypto-pbkdf$(EXESUF): tests/test-crypto-pbkdf.o $(test-crypto-obj-y) +tests/test-crypto-ivgen$(EXESUF): tests/test-crypto-ivgen.o $(test-crypto-obj-y) libqos-obj-y = tests/libqos/pci.o tests/libqos/fw_cfg.o tests/libqos/malloc.o libqos-obj-y += tests/libqos/i2c.o tests/libqos/libqos.o
tests/test-crypto-ivgen.c new file +169 -0
169 lines not on this page · raw message
Signature · 1 line
2.5.0
Re: [Qemu-devel] [PATCH v4 03/26] crypto: add support for generating initialization vectors
Quoted 13 lines · Daniel P. Berrange
There are a number of different algorithms that can be used to generate initialization vectors for disk encryption. This introduces a simple internal QCryptoBlockIV object to provide a consistent internal API to the different algorithms. The initially implemented algorithms are 'plain', 'plain64' and 'essiv', each matching the same named algorithm provided by the Linux kernel dm-crypt driver.
Signed-off-by Daniel P. Berrange <[email protected]>---
+++
b/crypto/ivgen-essiv.c
crypto/ivgen-essiv.c line 38
Quoted 10 lines
crypto/ivgen-essiv.c new file +10
-0+static int qcrypto_ivgen_essiv_init (QCryptoIVGen *ivgen, +const uint8_t *key,size_t nkey, +Error **errp) +{ +uint8_t *salt; +size_t nhash; +size_t nsalt; +QCryptoIVGenESSIV *essiv =g_new0 (QCryptoIVGenESSIV,1 ); + +/* Not neccessarily the same as nkey */
s/neccessarily/necessarily/
Quoted 11 lines
+++
b/include/crypto/ivgen.h+ *
+ * while (ndata) {
+ * if (qcrypto_ivgen_calculate(ivgen, sector, iv, niv, errp)< 0) {
+ * goto error;
+ * }
+ * if (qcrypto_cipher_setiv(cipher, iv, niv, errp)< 0) {
+ * goto error;
+ * }
+ * if (qcrypto_cipher_encrypt(cipher,
Quoted 3 lines
+ * data + (sector * 512),
+ * data + (sector * 512),
+ * 512, errp) < 0) {Don't you reuse a single in/out buffer later in the series? If so, don't forget to update the comment at that time (the compiler will only catch code changes).
Quoted 6 lines
+ *
+ * -QCRYPTO_IVGEN_ALG_PLAIN
+ *
+ * The IVs are generated by the 32-bit truncated sector
+ * number. This should never be used for block devices
+ * that are larger than 2^32 sectors in size
s/$/./
Quoted 13 lines
+ * All the other parameters are unused.
+ *+++
b/qapi/crypto.jsonqapi/crypto.json +5
-0@@ -78,3 +78,22 @@ { 'enum': 'QCryptoCipherMode', 'prefix': 'QCRYPTO_CIPHER_MODE', 'data': ['ecb', 'cbc']} + + +## +# QCryptoIVGenAlgorithm: +#
qapi/crypto.json line 95
Quoted 10 lines
qapi/crypto.json +10
-0+# The supported algorithms for generating initialization +# vectors for full disk encryption. The 'plain' generator +# should not be used for disks with sector numbers larger +# than 2^32, except where compatibility with pre-existing +# Linux dm-crypt volumes is required. +# +# @plain: 64-bit sector number truncated to 32-bits +# @plain64: 64-bit sector number +# @essiv: 64-bit sector number encrypted with a hash of the encryption key +# Since: 2.6
Worth warning that 'plain' and 'plain64' expose the encrypted disk to some weaknesses when compared to 'essiv'?
Fixes are minor, so I'm okay if you add:
Signature · 2 lines
Eric Blake eblake redhat com +1-919-301-3266 Libvirt virtualization library http://libvirt.org
Re: [Qemu-devel] [PATCH v4 03/26] crypto: add support for generating initialization vectors
Quoted 42 lines · Eric Blake
Quoted 13 lines · Daniel P. Berrange
There are a number of different algorithms that can be used to generate initialization vectors for disk encryption. This introduces a simple internal QCryptoBlockIV object to provide a consistent internal API to the different algorithms. The initially implemented algorithms are 'plain', 'plain64' and 'essiv', each matching the same named algorithm provided by the Linux kernel dm-crypt driver.
Signed-off-by Daniel P. Berrange <[email protected]>---
+++
b/crypto/ivgen-essiv.ccrypto/ivgen-essiv.c line 38
Quoted 10 lines
crypto/ivgen-essiv.c new file +10
-0+static int qcrypto_ivgen_essiv_init (QCryptoIVGen *ivgen, +const uint8_t *key,size_t nkey, +Error **errp) +{ +uint8_t *salt; +size_t nhash; +size_t nsalt; +QCryptoIVGenESSIV *essiv =g_new0 (QCryptoIVGenESSIV,1 ); + +/* Not neccessarily the same as nkey */ s/neccessarily/necessarily/
Quoted 11 lines
+++
b/include/crypto/ivgen.h+ *
+ * while (ndata) {
+ * if (qcrypto_ivgen_calculate(ivgen, sector, iv, niv, errp)< 0) {
+ * goto error;
+ * }
+ * if (qcrypto_cipher_setiv(cipher, iv, niv, errp)< 0) {
+ * goto error;
+ * }
+ * if (qcrypto_cipher_encrypt(cipher,Quoted 3 lines
+ * data + (sector * 512), + * data + (sector * 512), + * 512, errp) < 0) {
Quoted 3 lines
Don't you reuse a single in/out buffer later in the series? If so, don't forget to update the comment at that time (the compiler will only catch code changes).
In the higher level QCryptoBlock API we encrypt in-place, but this code example is illustrating the lower layer QCryptoCipher API usage.
Quoted 8 lines
Quoted 8 lines
qapi/crypto.json +8
-0+## +# QCryptoIVGenAlgorithm: +# +# The supported algorithms for generating initialization +# vectors for full disk encryption. The 'plain' generator +# should not be used for disks with sector numbers larger +# than 2^32, except where compatibility with pre-existing +# Linux dm-crypt volumes is required.
Quoted 8 lines
qapi/crypto.json line 95
Quoted 5 lines
qapi/crypto.json +5
-0+# +# @plain: 64-bit sector number truncated to 32-bits +# @plain64: 64-bit sector number +# @essiv: 64-bit sector number encrypted with a hash of the encryption key +# Since: 2.6Worth warning that 'plain' and 'plain64' expose the encrypted disk to some weaknesses when compared to 'essiv'?
It is a bit more complicated than that. You have to consider the combination of ivgen + encryption mode to determine if it is secure or not. eg plain64 + xts is secure but plain64 + cbc is not secure. I think explaining the security of the various combinations is too much detail for the QAPI spec here.
Quoted 2 lines
Fixes are minor, so I'm okay if you add:
Reviewed-by Eric Blake <[email protected]>
Regards,
Daniel
Signature · 4 lines
|: 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 :|
Re: [Qemu-devel] [PATCH v4 03/26] crypto: add support for generating initialization vectors
In reply to Daniel P. BerrangeQuoted 9 lines · Daniel P. Berrange
There are a number of different algorithms that can be used to generate initialization vectors for disk encryption. This introduces a simple internal QCryptoBlockIV object to provide a consistent internal API to the different algorithms. The initially implemented algorithms are 'plain', 'plain64' and 'essiv', each matching the same named algorithm provided by the Linux kernel dm-crypt driver.
Signed-off-by Daniel P. Berrange <[email protected]>
PATCH v4 4/26 crypto: add support for anti-forensic split algorithm
In reply to Daniel P. BerrangeThe LUKS format specifies an anti-forensic split algorithm which is used to artificially expand the size of the key material on disk. This is an implementation of that algorithm.
--- crypto/Makefile.objs | 1 + crypto/afsplit.c | 158 ++++++++++++++++++++++++++++++++++++ include/crypto/afsplit.h | 135 +++++++++++++++++++++++++++++++ tests/.gitignore | 1 + tests/Makefile | 2 + tests/test-crypto-afsplit.c | 190 ++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 487 insertions(+) create mode 100644 crypto/afsplit.c create mode 100644 include/crypto/afsplit.h create mode 100644 tests/test-crypto-afsplit.c
crypto/Makefile.objs +1 -0
@@ -17,6 +17,7 @@ crypto-obj-y += ivgen.o crypto-obj-y += ivgen-essiv.o crypto-obj-y += ivgen-plain.o crypto-obj-y += ivgen-plain64.o +crypto-obj-y += afsplit.o # Let the userspace emulators avoid linking gnutls/etc crypto-aes-obj-y = aes.o
crypto/afsplit.c new file +158 -0
158 lines not on this page · raw message
include/crypto/afsplit.h new file +135 -0
135 lines not on this page · raw message
tests/.gitignore +1 -0
@@ -12,6 +12,7 @@ test-base64 test-bitops test-blockjob-txn test-coroutine +test-crypto-afsplit test-crypto-cipher test-crypto-hash test-crypto-ivgen
tests/Makefile +2 -0
@@ -94,6 +94,7 @@ check-unit-y += tests/test-io-channel-buffer$(EXESUF) check-unit-y += tests/test-base64$(EXESUF) check-unit-y += tests/test-crypto-pbkdf$(EXESUF) check-unit-y += tests/test-crypto-ivgen$(EXESUF) +check-unit-y += tests/test-crypto-afsplit$(EXESUF) check-block-$(CONFIG_POSIX) += tests/qemu-iotests-quick.sh
@@ -501,6 +502,7 @@ tests/test-io-channel-buffer$(EXESUF): tests/test-io-channel-buffer.o \ tests/io-channel-helpers.o $(test-io-obj-y) tests/test-crypto-pbkdf$(EXESUF): tests/test-crypto-pbkdf.o $(test-crypto-obj-y) tests/test-crypto-ivgen$(EXESUF): tests/test-crypto-ivgen.o $(test-crypto-obj-y) +tests/test-crypto-afsplit$(EXESUF): tests/test-crypto-afsplit.o $(test-crypto-obj-y) libqos-obj-y = tests/libqos/pci.o tests/libqos/fw_cfg.o tests/libqos/malloc.o libqos-obj-y += tests/libqos/i2c.o tests/libqos/libqos.o
tests/test-crypto-afsplit.c new file +190 -0
190 lines not on this page · raw message
Signature · 1 line
2.5.0
Re: [Qemu-devel] [PATCH v4 04/26] crypto: add support for anti-forensic split algorithm
Quoted 6 lines · Daniel P. Berrange
The LUKS format specifies an anti-forensic split algorithm which is used to artificially expand the size of the key material on disk. This is an implementation of that algorithm.
Signed-off-by Daniel P. Berrange <[email protected]>---
crypto/afsplit.c line 40
Quoted 10 lines
crypto/afsplit.c new file +10
-0+static void qcrypto_afsplit_xor (size_t blocklen, +const uint8_t *in1, +const uint8_t *in2, +uint8_t *out) +{ +size_t i; +for (i =0 ; i < blocklen; i++) { + out[i] = in1[i] ^ in2[i]; + } +}
I hope the compiler can optimize this into vectored operation. But no need to change your code.
Signature · 2 lines
Eric Blake eblake redhat com +1-919-301-3266 Libvirt virtualization library http://libvirt.org
Re: [Qemu-devel] [PATCH v4 04/26] crypto: add support for anti-forensic split algorithm
In reply to Daniel P. BerrangeQuoted 75 lines · Daniel P. Berrange
The LUKS format specifies an anti-forensic split algorithm which is used to artificially expand the size of the key material on disk. This is an implementation of that algorithm.
Signed-off-by Daniel P. Berrange <[email protected]>--- crypto/Makefile.objs | 1 + crypto/afsplit.c | 158 ++++++++++++++++++++++++++++++++++++ include/crypto/afsplit.h | 135 +++++++++++++++++++++++++++++++ tests/.gitignore | 1 + tests/Makefile | 2 + tests/test-crypto-afsplit.c | 190 ++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 487 insertions(+) create mode 100644 crypto/afsplit.c create mode 100644 include/crypto/afsplit.h create mode 100644 tests/test-crypto-afsplit.ccrypto/Makefile.objs +1
-0@@ -17,6 +17,7 @@ crypto-obj-y += ivgen.o crypto-obj-y += ivgen-essiv.o crypto-obj-y += ivgen-plain.o crypto-obj-y += ivgen-plain64.o +crypto-obj-y += afsplit.o # Let the userspace emulators avoid linking gnutls/etc crypto-aes-obj-y = aes.ocrypto/afsplit.c new file +40
-0@@ -0,0 +1,158 @@ +/* +* QEMU Crypto anti forensic information splitter +* +* Copyright (c) 2015-2016 Red Hat, Inc. +* +* Derived from cryptsetup package lib/luks1/af.c +* +* Copyright (C) 2004, Clemens Fruhwirth <[email protected]> +* Copyright (C) 2009-2012, Red Hat, Inc. All rights reserved. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU 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/>. +* +*/ + +#include "qemu/osdep.h" +#include "crypto/afsplit.h" +#include "crypto/random.h" + + +static void qcrypto_afsplit_xor (size_t blocklen, +const uint8_t *in1, +const uint8_t *in2, +uint8_t *out) +{ +size_t i; +for (i =0 ; i < blocklen; i++) { + out[i] = in1[i] ^ in2[i]; + } +}
crypto/afsplit.c line 50
Quoted 10 lines
crypto/afsplit.c new file +10
-0+ + +static int qcrypto_afsplit_hash (QCryptoHashAlgorithm hash, +size_t blocklen, +uint8_t *block, +Error **errp) +{ +size_t digestlen =qcrypto_hash_digest_len (hash); + +size_t hashcount = blocklen / digestlen;
Do you want to use DIV_ROUND_UP? Because if blocklen < digestlen, hashcount is 0, and your for loop below will be skipped.
Fam
Quoted 480 lines
crypto/afsplit.c new file +108
-0+size_t finallen = blocklen % digestlen; +uint32_t i; + +if (finallen) { + hashcount++; + }else { + finallen = digestlen; + } + +for (i =0 ; i < hashcount; i++) { +uint8_t *out =NULL ; +size_t outlen =0 ; +uint32_t iv =cpu_to_be32 (i); +struct iovec in[] = { + { .iov_base = &iv, + .iov_len =sizeof (iv) }, + { .iov_base = block + (i * digestlen), + .iov_len = (i == (hashcount -1 )) ? finallen : digestlen }, + }; + +if (qcrypto_hash_bytesv (hash, + in, +G_N_ELEMENTS (in), + &out, &outlen, + errp) <0 ) { +return -1 ; + } + +assert (outlen == digestlen); +memcpy (block + (i * digestlen), out, + (i == (hashcount -1 )) ? finallen : digestlen); +g_free (out); + } + +return 0 ; +} + + +int qcrypto_afsplit_encode (QCryptoHashAlgorithm hash, +size_t blocklen, +uint32_t stripes, +const uint8_t *in, +uint8_t *out, +Error **errp) +{ +uint8_t *block =g_new0 (uint8_t, blocklen); +size_t i; +int ret =-1 ; + +for (i =0 ; i < (stripes -1 ); i++) { +if (qcrypto_random_bytes (out + (i * blocklen), blocklen, errp) <0 ) { + goto cleanup; + } + +qcrypto_afsplit_xor (blocklen, + out + (i * blocklen), + block, + block); +if (qcrypto_afsplit_hash (hash, blocklen, block, + errp) <0 ) { + goto cleanup; + } + } +qcrypto_afsplit_xor (blocklen, + in, + block, + out + (i * blocklen)); + ret =0 ; + + cleanup: +g_free (block); +return ret; +} + + +int qcrypto_afsplit_decode (QCryptoHashAlgorithm hash, +size_t blocklen, +uint32_t stripes, +const uint8_t *in, +uint8_t *out, +Error **errp) +{ +uint8_t *block =g_new0 (uint8_t, blocklen); +size_t i; +int ret =-1 ; + +for (i =0 ; i < (stripes -1 ); i++) { +qcrypto_afsplit_xor (blocklen, + in + (i * blocklen), + block, + block); +if (qcrypto_afsplit_hash (hash, blocklen, block, + errp) <0 ) { + goto cleanup; + } + } + +qcrypto_afsplit_xor (blocklen, + in + (i * blocklen), + block, + out); + + ret =0 ; + + cleanup: +g_free (block); +return ret; +}include/crypto/afsplit.h new file +135
-0@@ -0,0 +1,135 @@ +/* +* QEMU Crypto anti forensic information splitter +* +* 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 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/>. +* +*/ + +#ifndef QCRYPTO_AFSPLIT_H__ +#define QCRYPTO_AFSPLIT_H__ + +#include "crypto/hash.h" + +/** +* This module implements the anti-forensic splitter that is specified +* as part of the LUKS format: +* +* http://clemens.endorphin.org/cryptography +* http://clemens.endorphin.org/TKS1-draft.pdf +* +* The core idea is to take a short piece of data (key material) +* and process it to expand it to a much larger piece of data. +* The expansion process is reversible, to obtain the original +* short data. The key property of the expansion is that if any +* byte in the larger data set is changed / missing, it should be +* impossible to recreate the original short data. +* +* <example> +* <title>Creating a large split key for storage</title> +* <programlisting> +* size_t nkey = 32; +* uint32_t stripes = 32768; // To produce a 1 MB split key +* uint8_t *masterkey = ....a 32-byte AES key... +* uint8_t *splitkey; +* +* splitkey = g_new0(uint8_t, nkey * stripes); +* +* if (qcrypto_afsplit_encode(QCRYPTO_HASH_ALG_SHA256, +* nkey, stripes, +* masterkey, splitkey, errp) < 0) { +* g_free(splitkey); +* g_free(masterkey); +* return -1; +* } +* +* ...store splitkey somewhere... +* +* g_free(splitkey); +* g_free(masterkey); +* </programlisting> +* </example> +* +* <example> +* <title>Retrieving a master key from storage</title> +* <programlisting> +* size_t nkey = 32; +* uint32_t stripes = 32768; // To produce a 1 MB split key +* uint8_t *masterkey; +* uint8_t *splitkey = .... read in 1 MB of data... +* +* masterkey = g_new0(uint8_t, nkey); +* +* if (qcrypto_afsplit_decode(QCRYPTO_HASH_ALG_SHA256, +* nkey, stripes, +* splitkey, masterkey, errp) < 0) { +* g_free(splitkey); +* g_free(masterkey); +* return -1; +* } +* +* ..decrypt data with masterkey... +* +* g_free(splitkey); +* g_free(masterkey); +* </programlisting> +* </example> +*/ + +/** +* qcrypto_afsplit_encode: +* @hash: the hash algorithm to use for data expansion +* @blocklen: the size of @in in bytes +* @stripes: the number of times to expand @in in size +* @in: the master key to be expanded in size +* @out: preallocated buffer to hold the split key +* @errp: pointer to a NULL-initialized error object +* +* Split the data in @in, which is @blocklen bytes in +* size, to form a larger piece of data @out, which is +* @blocklen * @stripes bytes in size. +* +* Returns: 0 on success, -1 on error; +*/ +int qcrypto_afsplit_encode (QCryptoHashAlgorithm hash, +size_t blocklen, +uint32_t stripes, +const uint8_t *in, +uint8_t *out, +Error **errp); + +/** +* qcrypto_afsplit_decode: +* @hash: the hash algorithm to use for data compression +* @blocklen: the size of @out in bytes +* @stripes: the number of times to decrease @in in size +* @in: the split key to be recombined +* @out: preallocated buffer to hold the master key +* @errp: pointer to a NULL-initialized error object +* +* Join the data in @in, which is @blocklen * @stripes +* bytes in size, to form the original small piece of +* data @out, which is @blocklen bytes in size. +* +* Returns: 0 on success, -1 on error; +*/ +int qcrypto_afsplit_decode (QCryptoHashAlgorithm hash, +size_t blocklen, +uint32_t stripes, +const uint8_t *in, +uint8_t *out, +Error **errp); + +#endif /* QCRYPTO_AFSPLIT_H__ */ tests/.gitignore +1
-0@@ -12,6 +12,7 @@ test-base64 test-bitops test-blockjob-txn test-coroutine +test-crypto-afsplit test-crypto-cipher test-crypto-hash test-crypto-ivgentests/Makefile +2
-0@@ -94,6 +94,7 @@ check-unit-y += tests/test-io-channel-buffer$(EXESUF) check-unit-y += tests/test-base64$(EXESUF) check-unit-y += tests/test-crypto-pbkdf$(EXESUF) check-unit-y += tests/test-crypto-ivgen$(EXESUF) +check-unit-y += tests/test-crypto-afsplit$(EXESUF) check-block-$(CONFIG_POSIX) += tests/qemu-iotests-quick.sh@@ -501,6 +502,7 @@ tests/test-io-channel-buffer$(EXESUF): tests/test-io-channel-buffer.o \ tests/io-channel-helpers.o $(test-io-obj-y) tests/test-crypto-pbkdf$(EXESUF): tests/test-crypto-pbkdf.o $(test-crypto-obj-y) tests/test-crypto-ivgen$(EXESUF): tests/test-crypto-ivgen.o $(test-crypto-obj-y) +tests/test-crypto-afsplit$(EXESUF): tests/test-crypto-afsplit.o $(test-crypto-obj-y) libqos-obj-y = tests/libqos/pci.o tests/libqos/fw_cfg.o tests/libqos/malloc.o libqos-obj-y += tests/libqos/i2c.o tests/libqos/libqos.otests/test-crypto-afsplit.c new file +190
-0@@ -0,0 +1,190 @@ +/* +* QEMU Crypto anti-forensic splitter +* +* 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/>. +* +*/ + +#include "qemu/osdep.h" +#include "crypto/init.h" +#include "crypto/afsplit.h" + +typedef struct QCryptoAFSplitTestData QCryptoAFSplitTestData ; +struct QCryptoAFSplitTestData { +const char *path; +QCryptoHashAlgorithm hash; +uint32_t stripes; +size_t blocklen; +const uint8_t *key; +const uint8_t *splitkey; +}; + +static QCryptoAFSplitTestData test_data[] = { + { + .path ="/crypto/afsplit/sha256/5" , + .hash =QCRYPTO_HASH_ALG_SHA256 , + .stripes =5 , + .blocklen =32 , + .key = (const uint8_t *) +"\x00\x01\x02\x03\x04\x05\x06\x07" +"\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" +"\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7" +"\xa8\xa9\xaa\xab\xac\xad\xae\xaf" , + .splitkey = (const uint8_t *) +"\xfd\xd2\x73\xb1\x7d\x99\x93\x34" +"\x70\xde\xfa\x07\xc5\xac\x58\xd2" +"\x30\x67\x2f\x1a\x35\x43\x60\x7d" +"\x77\x02\xdb\x62\x3c\xcb\x2c\x33" +"\x48\x08\xb6\xf1\x7c\xa3\x20\xa0" +"\xad\x2d\x4c\xf3\xcd\x18\x6f\x53" +"\xf9\xe8\xe7\x59\x27\x3c\xa9\x54" +"\x61\x87\xb3\xaf\xf6\xf7\x7e\x64" +"\x86\xaa\x89\x7f\x1f\x9f\xdb\x86" +"\xf4\xa2\x16\xff\xa3\x4f\x8c\xa1" +"\x59\xc4\x23\x34\x28\xc4\x77\x71" +"\x83\xd4\xcd\x8e\x89\x1b\xc7\xc5" +"\xae\x4d\xa9\xcd\xc9\x72\x85\x70" +"\x13\x68\x52\x83\xfc\xb8\x11\x72" +"\xba\x3d\xc6\x4a\x28\xfa\xe2\x86" +"\x7b\x27\xab\x58\xe1\xa4\xca\xf6" +"\x9e\xbc\xfe\x0c\x92\x79\xb3\xec" +"\x1c\x5f\x79\x3b\x0d\x1e\xaa\x1a" +"\x77\x0f\x70\x19\x4b\xc8\x80\xee" +"\x27\x7c\x6e\x4a\x91\x96\x5c\xf4" + }, + { + .path ="/crypto/afsplit/sha256/5000" , + .hash =QCRYPTO_HASH_ALG_SHA256 , + .stripes =5000 , + .blocklen =16 , + .key = (const uint8_t *) +"\x00\x01\x02\x03\x04\x05\x06\x07" +"\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" , + }, + { + .path ="/crypto/afsplit/sha1/1000" , + .hash =QCRYPTO_HASH_ALG_SHA1 , + .stripes =1000 , + .blocklen =32 , + .key = (const uint8_t *) +"\x00\x01\x02\x03\x04\x05\x06\x07" +"\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" +"\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7" +"\xa8\xa9\xaa\xab\xac\xad\xae\xaf" , + }, + { + .path ="/crypto/afsplit/sha256/big" , + .hash =QCRYPTO_HASH_ALG_SHA256 , + .stripes =1000 , + .blocklen =64 , + .key = (const uint8_t *) +"\x00\x01\x02\x03\x04\x05\x06\x07" +"\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" +"\x00\x01\x02\x03\x04\x05\x06\x07" +"\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" +"\x00\x01\x02\x03\x04\x05\x06\x07" +"\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" +"\x00\x01\x02\x03\x04\x05\x06\x07" +"\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" , + }, +}; + + +static inline char hex (int i) +{ +if (i <10 ) { +return '0' + i; + } +return 'a' + (i -10 ); +} + +static char *hex_string (const uint8_t *bytes, +size_t len) +{ +char *hexstr =g_new0 (char, len *2 +1 ); +size_t i; + +for (i =0 ; i < len; i++) { + hexstr[i *2 ] =hex ((bytes[i] >>4 ) &0xf ); + hexstr[i *2 +1 ] =hex (bytes[i] &0xf ); + } + hexstr[len *2 ] ='\0' ; + +return hexstr; +} + +static void test_afsplit (const void *opaque) +{ +const QCryptoAFSplitTestData *data = opaque; +size_t splitlen = data->blocklen * data->stripes; +uint8_t *splitkey =g_new0 (uint8_t, splitlen); +uint8_t *key =g_new0 (uint8_t, data->blocklen); +gchar *expect, *actual; + +/* First time we round-trip the key */ +qcrypto_afsplit_encode (data->hash, + data->blocklen, data->stripes, + data->key, splitkey, + &error_abort); + +qcrypto_afsplit_decode (data->hash, + data->blocklen, data->stripes, + splitkey, key, + &error_abort); + + expect =hex_string (data->key, data->blocklen); + actual =hex_string (key, data->blocklen); + + g_assert_cmpstr(actual, ==, expect); + +g_free (actual); +g_free (expect); + +/* Second time we merely try decoding a previous split */ +if (data->splitkey) { +memset (key,0 , data->blocklen); + +qcrypto_afsplit_decode (data->hash, + data->blocklen, data->stripes, + data->splitkey, key, + &error_abort); + + expect =hex_string (data->key, data->blocklen); + actual =hex_string (key, data->blocklen); + + g_assert_cmpstr(actual, ==, expect); + +g_free (actual); +g_free (expect); + } + +g_free (key); +g_free (splitkey); +} + +int main (int argc,char **argv) +{ +size_t i; + +g_test_init (&argc, &argv,NULL ); + +g_assert (qcrypto_init (NULL ) ==0 ); + +for (i =0 ; i <G_N_ELEMENTS (test_data); i++) { +g_test_add_data_func (test_data[i].path, &test_data[i], test_afsplit); + } +return g_test_run (); +}Signature · 1 line
2.5.0
Re: [Qemu-devel] [PATCH v4 04/26] crypto: add support for anti-forensic split algorithm
Quoted 19 lines · Fam Zheng
Quoted 17 lines · Daniel P. Berrange
The LUKS format specifies an anti-forensic split algorithm which is used to artificially expand the size of the key material on disk. This is an implementation of that algorithm.
Signed-off-by Daniel P. Berrange <[email protected]>--- crypto/Makefile.objs | 1 + crypto/afsplit.c | 158 ++++++++++++++++++++++++++++++++++++ include/crypto/afsplit.h | 135 +++++++++++++++++++++++++++++++ tests/.gitignore | 1 + tests/Makefile | 2 + tests/test-crypto-afsplit.c | 190 ++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 487 insertions(+) create mode 100644 crypto/afsplit.c create mode 100644 include/crypto/afsplit.h create mode 100644 tests/test-crypto-afsplit.c
Quoted 11 lines
crypto/afsplit.c line 50
Quoted 8 lines
crypto/afsplit.c new file +8
-0+static int qcrypto_afsplit_hash (QCryptoHashAlgorithm hash, +size_t blocklen, +uint8_t *block, +Error **errp) +{ +size_t digestlen =qcrypto_hash_digest_len (hash); + +size_t hashcount = blocklen / digestlen;Do you want to use
DIV_ROUND_UP? Because if blocklen < digestlen, hashcount is 0, and your for loop below will be skipped.
It is not needed actually - look a couple of lines further where we do 'if (finallen) { hashcount ++ }'. This achieves the same end result.
Quoted 31 lines
Fam
Quoted 28 lines
crypto/afsplit.c new file +28
-0+size_t finallen = blocklen % digestlen; +uint32_t i; + +if (finallen) { + hashcount++; + }else { + finallen = digestlen; + } + +for (i =0 ; i < hashcount; i++) { +uint8_t *out =NULL ; +size_t outlen =0 ; +uint32_t iv =cpu_to_be32 (i); +struct iovec in[] = { + { .iov_base = &iv, + .iov_len =sizeof (iv) }, + { .iov_base = block + (i * digestlen), + .iov_len = (i == (hashcount -1 )) ? finallen : digestlen }, + }; + +if (qcrypto_hash_bytesv (hash, + in, +G_N_ELEMENTS (in), + &out, &outlen, + errp) <0 ) { +return -1 ; + } +
Quoted 8 lines
crypto/afsplit.c line 86
Quoted 8 lines
crypto/afsplit.c new file +8
-0+assert (outlen == digestlen); +memcpy (block + (i * digestlen), out, + (i == (hashcount -1 )) ? finallen : digestlen); +g_free (out); + } + +return 0 ; +}
Regards,
Daniel
Signature · 4 lines
|: 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 :|
Fam Zheng
Reviewed-byRe: [Qemu-devel] [PATCH v4 04/26] crypto: add support for anti-forensic split algorithm
Quoted 32 lines · Daniel P. Berrange
Quoted 19 lines · Fam Zheng
Quoted 17 lines · Daniel P. Berrange
The LUKS format specifies an anti-forensic split algorithm which is used to artificially expand the size of the key material on disk. This is an implementation of that algorithm.
Signed-off-by Daniel P. Berrange <[email protected]>--- crypto/Makefile.objs | 1 + crypto/afsplit.c | 158 ++++++++++++++++++++++++++++++++++++ include/crypto/afsplit.h | 135 +++++++++++++++++++++++++++++++ tests/.gitignore | 1 + tests/Makefile | 2 + tests/test-crypto-afsplit.c | 190 ++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 487 insertions(+) create mode 100644 crypto/afsplit.c create mode 100644 include/crypto/afsplit.h create mode 100644 tests/test-crypto-afsplit.cQuoted 11 lines
crypto/afsplit.c line 50
Quoted 8 lines
crypto/afsplit.c new file +8
-0+static int qcrypto_afsplit_hash (QCryptoHashAlgorithm hash, +size_t blocklen, +uint8_t *block, +Error **errp) +{ +size_t digestlen =qcrypto_hash_digest_len (hash); + +size_t hashcount = blocklen / digestlen;Do you want to use
DIV_ROUND_UP? Because if blocklen < digestlen, hashcount is 0, and your for loop below will be skipped.
Quoted 3 lines
It is not needed actually - look a couple of lines further where we do 'if (finallen) { hashcount ++ }'. This achieves the same end result.
Yes you're right.
PATCH v4 5/26 crypto: skip testing of unsupported cipher algorithms
In reply to Daniel P. BerrangeWe don't guarantee that all crypto backends will support all cipher algorithms, so we should skip tests unless the crypto backend indicates support.
--- tests/test-crypto-cipher.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
tests/test-crypto-cipher.c +3 -1
@@ -380,7 +380,9 @@ int main(int argc, char **argv)g_assert (qcrypto_init (NULL ) ==0 );for (i =0 ; i <G_N_ELEMENTS (test_data); i++) { -g_test_add_data_func (test_data[i].path, &test_data[i], test_cipher); +if (qcrypto_cipher_supports (test_data[i].alg)) { +g_test_add_data_func (test_data[i].path, &test_data[i], test_cipher); + } } g_test_add_func("/crypto/cipher/null-iv",
Signature · 1 line
2.5.0
Re: [Qemu-devel] [PATCH v4 05/26] crypto: skip testing of unsupported cipher algorithms
Quoted 27 lines · Daniel P. Berrange
We don't guarantee that all crypto backends will support all cipher algorithms, so we should skip tests unless the crypto backend indicates support.
Signed-off-by Daniel P. Berrange <[email protected]>--- tests/test-crypto-cipher.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)tests/test-crypto-cipher.c +3
-1@@ -380,7 +380,9 @@ int main(int argc, char **argv)g_assert (qcrypto_init (NULL ) ==0 );for (i =0 ; i <G_N_ELEMENTS (test_data); i++) { -g_test_add_data_func (test_data[i].path, &test_data[i], test_cipher); +if (qcrypto_cipher_supports (test_data[i].alg)) { +g_test_add_data_func (test_data[i].path, &test_data[i], test_cipher); + } } g_test_add_func("/crypto/cipher/null-iv",Signature · 1 line
2.5.0
Re: [Qemu-devel] [PATCH v4 05/26] crypto: skip testing of unsupported cipher algorithms
In reply to Daniel P. BerrangeQuoted 8 lines · Daniel P. Berrange
We don't guarantee that all crypto backends will support all cipher algorithms, so we should skip tests unless the crypto backend indicates support.
Signed-off-by Daniel P. Berrange <[email protected]>--- tests/test-crypto-cipher.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
Quoted 17 lines
tests/test-crypto-cipher.c +3
-1@@ -380,7 +380,9 @@ int main(int argc, char **argv)g_assert (qcrypto_init (NULL ) ==0 );for (i =0 ; i <G_N_ELEMENTS (test_data); i++) { -g_test_add_data_func (test_data[i].path, &test_data[i], test_cipher); +if (qcrypto_cipher_supports (test_data[i].alg)) { +g_test_add_data_func (test_data[i].path, &test_data[i], test_cipher); + } } g_test_add_func("/crypto/cipher/null-iv",
Signature · 2 lines
Eric Blake eblake redhat com +1-919-301-3266 Libvirt virtualization library http://libvirt.org
PATCH v4 6/26 crypto: add support for the cast5-128 cipher algorithm
In reply to Daniel P. BerrangeA new cipher algorithm 'cast-5-128' is defined for the Cast-5 algorithm with 128 bit key size. Smaller key sizes are supported by Cast-5, but nothing in QEMU should use them, so only 128 bit keys are permitted.
The nettle and gcrypt cipher backends are updated to support the new cipher and a test vector added to the cipher test suite. The new algorithm is enabled in the LUKS block encryption driver.
--- crypto/cipher-gcrypt.c | 18 +++++++++++++++++- crypto/cipher-nettle.c | 26 ++++++++++++++++++++++++++ crypto/cipher.c | 2 ++ qapi/crypto.json | 5 ++++- tests/test-crypto-cipher.c | 9 +++++++++ 5 files changed, 58 insertions(+), 2 deletions(-)
crypto/cipher-gcrypt.c +17 -1
@@ -29,6 +29,7 @@ bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg)case QCRYPTO_CIPHER_ALG_AES_128 :case QCRYPTO_CIPHER_ALG_AES_192 :case QCRYPTO_CIPHER_ALG_AES_256 : +case QCRYPTO_CIPHER_ALG_CAST5_128 :return true;default :return false;
@@ -84,6 +85,10 @@ QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg, gcryalg =GCRY_CIPHER_AES256 ;break ; +case QCRYPTO_CIPHER_ALG_CAST5_128 : + gcryalg =GCRY_CIPHER_CAST5 ; +break ; +default :error_setg (errp,"Unsupported cipher algorithm %d" , alg);return NULL ;
@@ -113,7 +118,18 @@ QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg, ctx->blocksize =8 ; }else { err =gcry_cipher_setkey (ctx->handle, key, nkey); - ctx->blocksize =16 ; +switch (cipher->alg) { +case QCRYPTO_CIPHER_ALG_AES_128 : +case QCRYPTO_CIPHER_ALG_AES_192 : +case QCRYPTO_CIPHER_ALG_AES_256 : + ctx->blocksize =16 ; +break ; +case QCRYPTO_CIPHER_ALG_CAST5_128 : + ctx->blocksize =8 ; +break ; +default : +g_assert_not_reached (); + } }if (err !=0 ) { error_setg(errp, "Cannot set key: %s",
crypto/cipher-nettle.c +26 -0
@@ -23,6 +23,7 @@#include <nettle/aes.h> #include <nettle/des.h> #include <nettle/cbc.h> +#include <nettle/cast128.h> #if CONFIG_NETTLE_VERSION_MAJOR <3 typedef nettle_crypt_func nettle_cipher_func ;
@@ -63,6 +64,18 @@ static void des_decrypt_wrapper(cipher_ctx_t ctx, cipher_length_t length,des_decrypt (ctx, length, dst, src); } +static void cast128_encrypt_wrapper (cipher_ctx_t ctx,cipher_length_t length, +uint8_t *dst,const uint8_t *src) +{ +cast128_encrypt (ctx, length, dst, src); +} + +static void cast128_decrypt_wrapper (cipher_ctx_t ctx,cipher_length_t length, +uint8_t *dst,const uint8_t *src) +{ +cast128_decrypt (ctx, length, dst, src); +} +typedef struct QCryptoCipherNettle QCryptoCipherNettle ;struct QCryptoCipherNettle {void *ctx_encrypt;
@@ -80,6 +93,7 @@ bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg)case QCRYPTO_CIPHER_ALG_AES_128 :case QCRYPTO_CIPHER_ALG_AES_192 :case QCRYPTO_CIPHER_ALG_AES_256 : +case QCRYPTO_CIPHER_ALG_CAST5_128 :return true;default :return false;
@@ -143,6 +157,18 @@ QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg, ctx->blocksize =AES_BLOCK_SIZE ;break ; + +case QCRYPTO_CIPHER_ALG_CAST5_128 : + ctx->ctx_encrypt = g_new0(struct cast128_ctx, 1); + ctx->ctx_decrypt =NULL ;/* 1 ctx can do both */ + +cast5_set_key (ctx->ctx_encrypt, nkey, key); + + ctx->alg_encrypt = cast128_encrypt_wrapper; + ctx->alg_decrypt = cast128_decrypt_wrapper; + + ctx->blocksize =CAST128_BLOCK_SIZE ; +break ;default :error_setg (errp,"Unsupported cipher algorithm %d" , alg); goto error;
crypto/cipher.c +2 -0
@@ -27,6 +27,7 @@ static size_t alg_key_len[QCRYPTO_CIPHER_ALG__MAX] = { [QCRYPTO_CIPHER_ALG_AES_192] = 24, [QCRYPTO_CIPHER_ALG_AES_256] = 32, [QCRYPTO_CIPHER_ALG_DES_RFB] = 8, + [QCRYPTO_CIPHER_ALG_CAST5_128] = 16, };static size_t alg_block_len[QCRYPTO_CIPHER_ALG__MAX ] = {
@@ -34,6 +35,7 @@ static size_t alg_block_len[QCRYPTO_CIPHER_ALG__MAX] = { [QCRYPTO_CIPHER_ALG_AES_192] = 16, [QCRYPTO_CIPHER_ALG_AES_256] = 16, [QCRYPTO_CIPHER_ALG_DES_RFB] = 8, + [QCRYPTO_CIPHER_ALG_CAST5_128] = 8, };static bool mode_need_iv[QCRYPTO_CIPHER_MODE__MAX ] = {
qapi/crypto.json +4 -1
@@ -59,11 +59,14 @@ # @aes-192: AES with 192 bit / 24 byte keys # @aes-256: AES with 256 bit / 32 byte keys # @des-rfb: RFB specific variant of single DES. Do not use except in VNC. +# @cast5-128: Cast5 with 128 bit / 16 byte keys # Since: 2.6 ## { 'enum': 'QCryptoCipherAlgorithm', 'prefix': 'QCRYPTO_CIPHER_ALG', - 'data': ['aes-128', 'aes-192', 'aes-256', 'des-rfb']} + 'data': ['aes-128', 'aes-192', 'aes-256', + 'des-rfb', + 'cast5-128']} ##
tests/test-crypto-cipher.c +9 -0
@@ -165,6 +165,15 @@ static QCryptoCipherTestData test_data[] = {"ffd29f1bb5596ad94ea2d8e6196b7f09" "30d8ed0bf2773af36dd82a6280c20926", }, + { +/* RFC 2144, Appendix B.1 */ + .path = "/crypto/cipher/cast5-128", + .alg = QCRYPTO_CIPHER_ALG_CAST5_128, + .mode = QCRYPTO_CIPHER_MODE_ECB, + .key = "0123456712345678234567893456789A", + .plaintext = "0123456789abcdef", + .ciphertext = "238b4fe5847e44b2", + }, };
Signature · 1 line
2.5.0
Re: [Qemu-devel] [PATCH v4 06/26] crypto: add support for the cast5-128 cipher algorithm
Quoted 11 lines · Daniel P. Berrange
A new cipher algorithm 'cast-5-128' is defined for the Cast-5 algorithm with 128 bit key size. Smaller key sizes are supported by Cast-5, but nothing in QEMU should use them, so only 128 bit keys are permitted.
The nettle and gcrypt cipher backends are updated to support the new cipher and a test vector added to the cipher test suite. The new algorithm is enabled in the LUKS block encryption driver.
Signed-off-by Daniel P. Berrange <[email protected]>
Re: [Qemu-devel] [PATCH v4 06/26] crypto: add support for the cast5-128 cipher algorithm
In reply to Daniel P. BerrangeQuoted 5 lines · Daniel P. Berrange
A new cipher algorithm 'cast-5-128' is defined for the Cast-5 algorithm with 128 bit key size. Smaller key sizes are supported by Cast-5, but nothing in QEMU should use them, so only 128 bit keys are permitted.
Quoted 7 lines
The nettle and gcrypt cipher backends are updated to support the new cipher and a test vector added to the cipher test suite. The new algorithm is enabled in the LUKS block encryption driver.
Signed-off-by Daniel P. Berrange <[email protected]>---
Signature · 2 lines
Eric Blake eblake redhat com +1-919-301-3266 Libvirt virtualization library http://libvirt.org
PATCH v4 7/26 crypto: add support for the serpent cipher algorithm
In reply to Daniel P. BerrangeNew cipher algorithms 'serpent-128', 'serpent-192' and 'serpent-256' are defined for the Serpent algorithm.
The nettle and gcrypt cipher backends are updated to support the new cipher and a test vector added to the cipher test suite. The new algorithm is enabled in the LUKS block encryption driver.
--- crypto/cipher-gcrypt.c | 18 ++++++++++++++++++ crypto/cipher-nettle.c | 31 +++++++++++++++++++++++++++++++ crypto/cipher.c | 6 ++++++ qapi/crypto.json | 6 +++++- tests/test-crypto-cipher.c | 39 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 99 insertions(+), 1 deletion(-)
crypto/cipher-gcrypt.c +18 -0
@@ -30,6 +30,9 @@ bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg)case QCRYPTO_CIPHER_ALG_AES_192 :case QCRYPTO_CIPHER_ALG_AES_256 :case QCRYPTO_CIPHER_ALG_CAST5_128 : +case QCRYPTO_CIPHER_ALG_SERPENT_128 : +case QCRYPTO_CIPHER_ALG_SERPENT_192 : +case QCRYPTO_CIPHER_ALG_SERPENT_256 :return true;default :return false;
@@ -89,6 +92,18 @@ QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg, gcryalg =GCRY_CIPHER_CAST5 ;break ; +case QCRYPTO_CIPHER_ALG_SERPENT_128 : + gcryalg =GCRY_CIPHER_SERPENT128 ; +break ; + +case QCRYPTO_CIPHER_ALG_SERPENT_192 : + gcryalg =GCRY_CIPHER_SERPENT192 ; +break ; + +case QCRYPTO_CIPHER_ALG_SERPENT_256 : + gcryalg =GCRY_CIPHER_SERPENT256 ; +break ; +default :error_setg (errp,"Unsupported cipher algorithm %d" , alg);return NULL ;
@@ -122,6 +137,9 @@ QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,case QCRYPTO_CIPHER_ALG_AES_128 :case QCRYPTO_CIPHER_ALG_AES_192 :case QCRYPTO_CIPHER_ALG_AES_256 : +case QCRYPTO_CIPHER_ALG_SERPENT_128 : +case QCRYPTO_CIPHER_ALG_SERPENT_192 : +case QCRYPTO_CIPHER_ALG_SERPENT_256 : ctx->blocksize =16 ;break ;case QCRYPTO_CIPHER_ALG_CAST5_128 :
crypto/cipher-nettle.c +31 -0
@@ -24,6 +24,7 @@#include <nettle/des.h> #include <nettle/cbc.h> #include <nettle/cast128.h> +#include <nettle/serpent.h> #if CONFIG_NETTLE_VERSION_MAJOR <3 typedef nettle_crypt_func nettle_cipher_func ;
@@ -76,6 +77,18 @@ static void cast128_decrypt_wrapper(cipher_ctx_t ctx, cipher_length_t length,cast128_decrypt (ctx, length, dst, src); } +static void serpent_encrypt_wrapper (cipher_ctx_t ctx,cipher_length_t length, +uint8_t *dst,const uint8_t *src) +{ +serpent_encrypt (ctx, length, dst, src); +} + +static void serpent_decrypt_wrapper (cipher_ctx_t ctx,cipher_length_t length, +uint8_t *dst,const uint8_t *src) +{ +serpent_decrypt (ctx, length, dst, src); +} +typedef struct QCryptoCipherNettle QCryptoCipherNettle ;struct QCryptoCipherNettle {void *ctx_encrypt;
@@ -94,6 +107,9 @@ bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg)case QCRYPTO_CIPHER_ALG_AES_192 :case QCRYPTO_CIPHER_ALG_AES_256 :case QCRYPTO_CIPHER_ALG_CAST5_128 : +case QCRYPTO_CIPHER_ALG_SERPENT_128 : +case QCRYPTO_CIPHER_ALG_SERPENT_192 : +case QCRYPTO_CIPHER_ALG_SERPENT_256 :return true;default :return false;
@@ -169,6 +185,21 @@ QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg, ctx->blocksize =CAST128_BLOCK_SIZE ;break ; + +case QCRYPTO_CIPHER_ALG_SERPENT_128 : +case QCRYPTO_CIPHER_ALG_SERPENT_192 : +case QCRYPTO_CIPHER_ALG_SERPENT_256 : + ctx->ctx_encrypt = g_new0(struct serpent_ctx, 1); + ctx->ctx_decrypt =NULL ;/* 1 ctx can do both */ + +serpent_set_key (ctx->ctx_encrypt, nkey, key); + + ctx->alg_encrypt = serpent_encrypt_wrapper; + ctx->alg_decrypt = serpent_decrypt_wrapper; + + ctx->blocksize =SERPENT_BLOCK_SIZE ; +break ; +default :error_setg (errp,"Unsupported cipher algorithm %d" , alg); goto error;
crypto/cipher.c +6 -0
@@ -28,6 +28,9 @@ static size_t alg_key_len[QCRYPTO_CIPHER_ALG__MAX] = { [QCRYPTO_CIPHER_ALG_AES_256] = 32, [QCRYPTO_CIPHER_ALG_DES_RFB] = 8, [QCRYPTO_CIPHER_ALG_CAST5_128] = 16, + [QCRYPTO_CIPHER_ALG_SERPENT_128] = 16, + [QCRYPTO_CIPHER_ALG_SERPENT_192] = 24, + [QCRYPTO_CIPHER_ALG_SERPENT_256] = 32, };static size_t alg_block_len[QCRYPTO_CIPHER_ALG__MAX ] = {
@@ -36,6 +39,9 @@ static size_t alg_block_len[QCRYPTO_CIPHER_ALG__MAX] = { [QCRYPTO_CIPHER_ALG_AES_256] = 16, [QCRYPTO_CIPHER_ALG_DES_RFB] = 8, [QCRYPTO_CIPHER_ALG_CAST5_128] = 8, + [QCRYPTO_CIPHER_ALG_SERPENT_128] = 16, + [QCRYPTO_CIPHER_ALG_SERPENT_192] = 16, + [QCRYPTO_CIPHER_ALG_SERPENT_256] = 16, };static bool mode_need_iv[QCRYPTO_CIPHER_MODE__MAX ] = {
qapi/crypto.json +5 -1
@@ -60,13 +60,17 @@ # @aes-256: AES with 256 bit / 32 byte keys # @des-rfb: RFB specific variant of single DES. Do not use except in VNC. # @cast5-128: Cast5 with 128 bit / 16 byte keys +# @serpent-128: Serpent with 128 bit / 16 byte keys +# @serpent-192: Serpent with 192 bit / 24 byte keys +# @serpent-256: Serpent with 256 bit / 32 byte keys # Since: 2.6 ## { 'enum': 'QCryptoCipherAlgorithm', 'prefix': 'QCRYPTO_CIPHER_ALG', 'data': ['aes-128', 'aes-192', 'aes-256', 'des-rfb', - 'cast5-128']} + 'cast5-128', + 'serpent-128', 'serpent-192', 'serpent-256']} ##
tests/test-crypto-cipher.c +39 -0
@@ -174,6 +174,45 @@ static QCryptoCipherTestData test_data[] = { .plaintext = "0123456789abcdef", .ciphertext = "238b4fe5847e44b2", }, + { +/* libgcrypt serpent.c */ + .path = "/crypto/cipher/serpent-128", + .alg = QCRYPTO_CIPHER_ALG_SERPENT_128, + .mode = QCRYPTO_CIPHER_MODE_ECB, + .key = "00000000000000000000000000000000", + .plaintext = "d29d576fcea3a3a7ed9099f29273d78e", + .ciphertext = "b2288b968ae8b08648d1ce9606fd992d", + }, + { +/* libgcrypt serpent.c */ + .path = "/crypto/cipher/serpent-192", + .alg = QCRYPTO_CIPHER_ALG_SERPENT_192, + .mode = QCRYPTO_CIPHER_MODE_ECB, + .key ="00000000000000000000000000000000" + "0000000000000000", + .plaintext = "d29d576fceaba3a7ed9899f2927bd78e", + .ciphertext = "130e353e1037c22405e8faefb2c3c3e9", + }, + { +/* libgcrypt serpent.c */ + .path = "/crypto/cipher/serpent-256a", + .alg = QCRYPTO_CIPHER_ALG_SERPENT_256, + .mode = QCRYPTO_CIPHER_MODE_ECB, + .key ="00000000000000000000000000000000" + "00000000000000000000000000000000", + .plaintext = "d095576fcea3e3a7ed98d9f29073d78e", + .ciphertext = "b90ee5862de69168f2bdd5125b45472b", + }, + { +/* libgcrypt serpent.c */ + .path = "/crypto/cipher/serpent-256b", + .alg = QCRYPTO_CIPHER_ALG_SERPENT_256, + .mode = QCRYPTO_CIPHER_MODE_ECB, + .key ="00000000000000000000000000000000" + "00000000000000000000000000000000", + .plaintext = "00000000010000000200000003000000", + .ciphertext = "2061a42782bd52ec691ec383b03ba77c", + }, };
Signature · 1 line
2.5.0
Re: [Qemu-devel] [PATCH v4 07/26] crypto: add support for the serpent cipher algorithm
Quoted 9 lines · Daniel P. Berrange
New cipher algorithms 'serpent-128', 'serpent-192' and 'serpent-256' are defined for the Serpent algorithm.
The nettle and gcrypt cipher backends are updated to support the new cipher and a test vector added to the cipher test suite. The new algorithm is enabled in the LUKS block encryption driver.
Signed-off-by Daniel P. Berrange <[email protected]>
Re: [Qemu-devel] [PATCH v4 07/26] crypto: add support for the serpent cipher algorithm
In reply to Daniel P. BerrangeQuoted 10 lines · Daniel P. Berrange
New cipher algorithms 'serpent-128', 'serpent-192' and 'serpent-256' are defined for the Serpent algorithm.
The nettle and gcrypt cipher backends are updated to support the new cipher and a test vector added to the cipher test suite. The new algorithm is enabled in the LUKS block encryption driver.
Signed-off-by Daniel P. Berrange <[email protected]>---
Signature · 2 lines
Eric Blake eblake redhat com +1-919-301-3266 Libvirt virtualization library http://libvirt.org
PATCH v4 8/26 crypto: add support for the twofish cipher algorithm
In reply to Daniel P. BerrangeNew cipher algorithms 'twofish-128', 'twofish-192' and 'twofish-256' are defined for the Twofish algorithm. The gcrypt backend does not support 'twofish-192'.
The nettle and gcrypt cipher backends are updated to support the new cipher and a test vector added to the cipher test suite. The new algorithm is enabled in the LUKS block encryption driver.
--- crypto/cipher-gcrypt.c | 12 ++++++++++++ crypto/cipher-nettle.c | 30 ++++++++++++++++++++++++++++++ crypto/cipher.c | 6 ++++++ qapi/crypto.json | 6 +++++- tests/test-crypto-cipher.c | 29 +++++++++++++++++++++++++++++ 5 files changed, 82 insertions(+), 1 deletion(-)
crypto/cipher-gcrypt.c +12 -0
@@ -33,6 +33,8 @@ bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg)case QCRYPTO_CIPHER_ALG_SERPENT_128 :case QCRYPTO_CIPHER_ALG_SERPENT_192 :case QCRYPTO_CIPHER_ALG_SERPENT_256 : +case QCRYPTO_CIPHER_ALG_TWOFISH_128 : +case QCRYPTO_CIPHER_ALG_TWOFISH_256 :return true;default :return false;
@@ -104,6 +106,14 @@ QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg, gcryalg =GCRY_CIPHER_SERPENT256 ;break ; +case QCRYPTO_CIPHER_ALG_TWOFISH_128 : + gcryalg =GCRY_CIPHER_TWOFISH128 ; +break ; + +case QCRYPTO_CIPHER_ALG_TWOFISH_256 : + gcryalg =GCRY_CIPHER_TWOFISH ; +break ; +default :error_setg (errp,"Unsupported cipher algorithm %d" , alg);return NULL ;
@@ -140,6 +150,8 @@ QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,case QCRYPTO_CIPHER_ALG_SERPENT_128 :case QCRYPTO_CIPHER_ALG_SERPENT_192 :case QCRYPTO_CIPHER_ALG_SERPENT_256 : +case QCRYPTO_CIPHER_ALG_TWOFISH_128 : +case QCRYPTO_CIPHER_ALG_TWOFISH_256 : ctx->blocksize =16 ;break ;case QCRYPTO_CIPHER_ALG_CAST5_128 :
crypto/cipher-nettle.c +30 -0
@@ -25,6 +25,7 @@#include <nettle/cbc.h> #include <nettle/cast128.h> #include <nettle/serpent.h> +#include <nettle/twofish.h> #if CONFIG_NETTLE_VERSION_MAJOR <3 typedef nettle_crypt_func nettle_cipher_func ;
@@ -89,6 +90,18 @@ static void serpent_decrypt_wrapper(cipher_ctx_t ctx, cipher_length_t length,serpent_decrypt (ctx, length, dst, src); } +static void twofish_encrypt_wrapper (cipher_ctx_t ctx,cipher_length_t length, +uint8_t *dst,const uint8_t *src) +{ +twofish_encrypt (ctx, length, dst, src); +} + +static void twofish_decrypt_wrapper (cipher_ctx_t ctx,cipher_length_t length, +uint8_t *dst,const uint8_t *src) +{ +twofish_decrypt (ctx, length, dst, src); +} +typedef struct QCryptoCipherNettle QCryptoCipherNettle ;struct QCryptoCipherNettle {void *ctx_encrypt;
@@ -110,6 +123,9 @@ bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg)case QCRYPTO_CIPHER_ALG_SERPENT_128 :case QCRYPTO_CIPHER_ALG_SERPENT_192 :case QCRYPTO_CIPHER_ALG_SERPENT_256 : +case QCRYPTO_CIPHER_ALG_TWOFISH_128 : +case QCRYPTO_CIPHER_ALG_TWOFISH_192 : +case QCRYPTO_CIPHER_ALG_TWOFISH_256 :return true;default :return false;
@@ -200,6 +216,20 @@ QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg, ctx->blocksize =SERPENT_BLOCK_SIZE ;break ; +case QCRYPTO_CIPHER_ALG_TWOFISH_128 : +case QCRYPTO_CIPHER_ALG_TWOFISH_192 : +case QCRYPTO_CIPHER_ALG_TWOFISH_256 : + ctx->ctx_encrypt = g_new0(struct twofish_ctx, 1); + ctx->ctx_decrypt =NULL ;/* 1 ctx can do both */ + +twofish_set_key (ctx->ctx_encrypt, nkey, key); + + ctx->alg_encrypt = twofish_encrypt_wrapper; + ctx->alg_decrypt = twofish_decrypt_wrapper; + + ctx->blocksize =TWOFISH_BLOCK_SIZE ; +break ; +default :error_setg (errp,"Unsupported cipher algorithm %d" , alg); goto error;
crypto/cipher.c +6 -0
@@ -31,6 +31,9 @@ static size_t alg_key_len[QCRYPTO_CIPHER_ALG__MAX] = { [QCRYPTO_CIPHER_ALG_SERPENT_128] = 16, [QCRYPTO_CIPHER_ALG_SERPENT_192] = 24, [QCRYPTO_CIPHER_ALG_SERPENT_256] = 32, + [QCRYPTO_CIPHER_ALG_TWOFISH_128] = 16, + [QCRYPTO_CIPHER_ALG_TWOFISH_192] = 24, + [QCRYPTO_CIPHER_ALG_TWOFISH_256] = 32, };static size_t alg_block_len[QCRYPTO_CIPHER_ALG__MAX ] = {
@@ -42,6 +45,9 @@ static size_t alg_block_len[QCRYPTO_CIPHER_ALG__MAX] = { [QCRYPTO_CIPHER_ALG_SERPENT_128] = 16, [QCRYPTO_CIPHER_ALG_SERPENT_192] = 16, [QCRYPTO_CIPHER_ALG_SERPENT_256] = 16, + [QCRYPTO_CIPHER_ALG_TWOFISH_128] = 16, + [QCRYPTO_CIPHER_ALG_TWOFISH_192] = 16, + [QCRYPTO_CIPHER_ALG_TWOFISH_256] = 16, };static bool mode_need_iv[QCRYPTO_CIPHER_MODE__MAX ] = {
qapi/crypto.json +5 -1
@@ -63,6 +63,9 @@ # @serpent-128: Serpent with 128 bit / 16 byte keys # @serpent-192: Serpent with 192 bit / 24 byte keys # @serpent-256: Serpent with 256 bit / 32 byte keys +# @twofish-128: Twofish with 128 bit / 16 byte keys +# @twofish-192: Twofish with 192 bit / 24 byte keys +# @twofish-256: Twofish with 256 bit / 32 byte keys # Since: 2.6 ## { 'enum': 'QCryptoCipherAlgorithm',
@@ -70,7 +73,8 @@ 'data': ['aes-128', 'aes-192', 'aes-256', 'des-rfb', 'cast5-128', - 'serpent-128', 'serpent-192', 'serpent-256']} + 'serpent-128', 'serpent-192', 'serpent-256', + 'twofish-128', 'twofish-192', 'twofish-256']} ##
tests/test-crypto-cipher.c +29 -0
@@ -213,6 +213,35 @@ static QCryptoCipherTestData test_data[] = { .plaintext = "00000000010000000200000003000000", .ciphertext = "2061a42782bd52ec691ec383b03ba77c", }, + { +/* Twofish paper "Known Answer Test" */ + .path = "/crypto/cipher/twofish-128", + .alg = QCRYPTO_CIPHER_ALG_TWOFISH_128, + .mode = QCRYPTO_CIPHER_MODE_ECB, + .key = "d491db16e7b1c39e86cb086b789f5419", + .plaintext = "019f9809de1711858faac3a3ba20fbc3", + .ciphertext = "6363977de839486297e661c6c9d668eb", + }, + { +/* Twofish paper "Known Answer Test", I=3 */ + .path = "/crypto/cipher/twofish-192", + .alg = QCRYPTO_CIPHER_ALG_TWOFISH_192, + .mode = QCRYPTO_CIPHER_MODE_ECB, + .key ="88b2b2706b105e36b446bb6d731a1e88" + "efa71f788965bd44", + .plaintext = "39da69d6ba4997d585b6dc073ca341b2", + .ciphertext = "182b02d81497ea45f9daacdc29193a65", + }, + { +/* Twofish paper "Known Answer Test", I=4 */ + .path = "/crypto/cipher/twofish-256", + .alg = QCRYPTO_CIPHER_ALG_TWOFISH_256, + .mode = QCRYPTO_CIPHER_MODE_ECB, + .key ="d43bb7556ea32e46f2a282b7d45b4e0d" + "57ff739d4dc92c1bd7fc01700cc8216f", + .plaintext = "90afe91bb288544f2c32dc239b2635e6", + .ciphertext = "6cb4561c40bf0a9705931cb6d408e7fa", + }, };
Signature · 1 line
2.5.0
Re: [Qemu-devel] [PATCH v4 08/26] crypto: add support for the twofish cipher algorithm
Quoted 208 lines · Daniel P. Berrange
New cipher algorithms 'twofish-128', 'twofish-192' and 'twofish-256' are defined for the Twofish algorithm. The gcrypt backend does not support 'twofish-192'.
The nettle and gcrypt cipher backends are updated to support the new cipher and a test vector added to the cipher test suite. The new algorithm is enabled in the LUKS block encryption driver.
Signed-off-by Daniel P. Berrange <[email protected]>--- crypto/cipher-gcrypt.c | 12 ++++++++++++ crypto/cipher-nettle.c | 30 ++++++++++++++++++++++++++++++ crypto/cipher.c | 6 ++++++ qapi/crypto.json | 6 +++++- tests/test-crypto-cipher.c | 29 +++++++++++++++++++++++++++++ 5 files changed, 82 insertions(+), 1 deletion(-)crypto/cipher-gcrypt.c +12
-0@@ -33,6 +33,8 @@ bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg)case QCRYPTO_CIPHER_ALG_SERPENT_128 :case QCRYPTO_CIPHER_ALG_SERPENT_192 :case QCRYPTO_CIPHER_ALG_SERPENT_256 : +case QCRYPTO_CIPHER_ALG_TWOFISH_128 : +case QCRYPTO_CIPHER_ALG_TWOFISH_256 :return true;default :return false;@@ -104,6 +106,14 @@ QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg, gcryalg =GCRY_CIPHER_SERPENT256 ;break ; +case QCRYPTO_CIPHER_ALG_TWOFISH_128 : + gcryalg =GCRY_CIPHER_TWOFISH128 ; +break ; + +case QCRYPTO_CIPHER_ALG_TWOFISH_256 : + gcryalg =GCRY_CIPHER_TWOFISH ; +break ; +default :error_setg (errp,"Unsupported cipher algorithm %d" , alg);return NULL ;@@ -140,6 +150,8 @@ QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,case QCRYPTO_CIPHER_ALG_SERPENT_128 :case QCRYPTO_CIPHER_ALG_SERPENT_192 :case QCRYPTO_CIPHER_ALG_SERPENT_256 : +case QCRYPTO_CIPHER_ALG_TWOFISH_128 : +case QCRYPTO_CIPHER_ALG_TWOFISH_256 : ctx->blocksize =16 ;break ;case QCRYPTO_CIPHER_ALG_CAST5_128 :crypto/cipher-nettle.c +30
-0@@ -25,6 +25,7 @@#include <nettle/cbc.h> #include <nettle/cast128.h> #include <nettle/serpent.h> +#include <nettle/twofish.h> #if CONFIG_NETTLE_VERSION_MAJOR <3 typedef nettle_crypt_func nettle_cipher_func ;@@ -89,6 +90,18 @@ static void serpent_decrypt_wrapper(cipher_ctx_t ctx, cipher_length_t length,serpent_decrypt (ctx, length, dst, src); } +static void twofish_encrypt_wrapper (cipher_ctx_t ctx,cipher_length_t length, +uint8_t *dst,const uint8_t *src) +{ +twofish_encrypt (ctx, length, dst, src); +} + +static void twofish_decrypt_wrapper (cipher_ctx_t ctx,cipher_length_t length, +uint8_t *dst,const uint8_t *src) +{ +twofish_decrypt (ctx, length, dst, src); +} +typedef struct QCryptoCipherNettle QCryptoCipherNettle ;struct QCryptoCipherNettle {void *ctx_encrypt;@@ -110,6 +123,9 @@ bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg)case QCRYPTO_CIPHER_ALG_SERPENT_128 :case QCRYPTO_CIPHER_ALG_SERPENT_192 :case QCRYPTO_CIPHER_ALG_SERPENT_256 : +case QCRYPTO_CIPHER_ALG_TWOFISH_128 : +case QCRYPTO_CIPHER_ALG_TWOFISH_192 : +case QCRYPTO_CIPHER_ALG_TWOFISH_256 :return true;default :return false;@@ -200,6 +216,20 @@ QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg, ctx->blocksize =SERPENT_BLOCK_SIZE ;break ; +case QCRYPTO_CIPHER_ALG_TWOFISH_128 : +case QCRYPTO_CIPHER_ALG_TWOFISH_192 : +case QCRYPTO_CIPHER_ALG_TWOFISH_256 : + ctx->ctx_encrypt = g_new0(struct twofish_ctx, 1); + ctx->ctx_decrypt =NULL ;/* 1 ctx can do both */ + +twofish_set_key (ctx->ctx_encrypt, nkey, key); + + ctx->alg_encrypt = twofish_encrypt_wrapper; + ctx->alg_decrypt = twofish_decrypt_wrapper; + + ctx->blocksize =TWOFISH_BLOCK_SIZE ; +break ; +default :error_setg (errp,"Unsupported cipher algorithm %d" , alg); goto error;crypto/cipher.c +6
-0@@ -31,6 +31,9 @@ static size_t alg_key_len[QCRYPTO_CIPHER_ALG__MAX] = { [QCRYPTO_CIPHER_ALG_SERPENT_128] = 16, [QCRYPTO_CIPHER_ALG_SERPENT_192] = 24, [QCRYPTO_CIPHER_ALG_SERPENT_256] = 32, + [QCRYPTO_CIPHER_ALG_TWOFISH_128] = 16, + [QCRYPTO_CIPHER_ALG_TWOFISH_192] = 24, + [QCRYPTO_CIPHER_ALG_TWOFISH_256] = 32, };static size_t alg_block_len[QCRYPTO_CIPHER_ALG__MAX ] = {@@ -42,6 +45,9 @@ static size_t alg_block_len[QCRYPTO_CIPHER_ALG__MAX] = { [QCRYPTO_CIPHER_ALG_SERPENT_128] = 16, [QCRYPTO_CIPHER_ALG_SERPENT_192] = 16, [QCRYPTO_CIPHER_ALG_SERPENT_256] = 16, + [QCRYPTO_CIPHER_ALG_TWOFISH_128] = 16, + [QCRYPTO_CIPHER_ALG_TWOFISH_192] = 16, + [QCRYPTO_CIPHER_ALG_TWOFISH_256] = 16, };static bool mode_need_iv[QCRYPTO_CIPHER_MODE__MAX ] = {qapi/crypto.json +5
-1@@ -63,6 +63,9 @@ # @serpent-128: Serpent with 128 bit / 16 byte keys # @serpent-192: Serpent with 192 bit / 24 byte keys # @serpent-256: Serpent with 256 bit / 32 byte keys +# @twofish-128: Twofish with 128 bit / 16 byte keys +# @twofish-192: Twofish with 192 bit / 24 byte keys +# @twofish-256: Twofish with 256 bit / 32 byte keys # Since: 2.6 ## { 'enum': 'QCryptoCipherAlgorithm',@@ -70,7 +73,8 @@ 'data': ['aes-128', 'aes-192', 'aes-256', 'des-rfb', 'cast5-128', - 'serpent-128', 'serpent-192', 'serpent-256']} + 'serpent-128', 'serpent-192', 'serpent-256', + 'twofish-128', 'twofish-192', 'twofish-256']} ##tests/test-crypto-cipher.c +29
-0@@ -213,6 +213,35 @@ static QCryptoCipherTestData test_data[] = { .plaintext = "00000000010000000200000003000000", .ciphertext = "2061a42782bd52ec691ec383b03ba77c", }, + { +/* Twofish paper "Known Answer Test" */ + .path = "/crypto/cipher/twofish-128", + .alg = QCRYPTO_CIPHER_ALG_TWOFISH_128, + .mode = QCRYPTO_CIPHER_MODE_ECB, + .key = "d491db16e7b1c39e86cb086b789f5419", + .plaintext = "019f9809de1711858faac3a3ba20fbc3", + .ciphertext = "6363977de839486297e661c6c9d668eb", + }, + { +/* Twofish paper "Known Answer Test", I=3 */ + .path = "/crypto/cipher/twofish-192", + .alg = QCRYPTO_CIPHER_ALG_TWOFISH_192, + .mode = QCRYPTO_CIPHER_MODE_ECB, + .key ="88b2b2706b105e36b446bb6d731a1e88" + "efa71f788965bd44", + .plaintext = "39da69d6ba4997d585b6dc073ca341b2", + .ciphertext = "182b02d81497ea45f9daacdc29193a65", + }, + { +/* Twofish paper "Known Answer Test", I=4 */ + .path = "/crypto/cipher/twofish-256", + .alg = QCRYPTO_CIPHER_ALG_TWOFISH_256, + .mode = QCRYPTO_CIPHER_MODE_ECB, + .key ="d43bb7556ea32e46f2a282b7d45b4e0d" + "57ff739d4dc92c1bd7fc01700cc8216f", + .plaintext = "90afe91bb288544f2c32dc239b2635e6", + .ciphertext = "6cb4561c40bf0a9705931cb6d408e7fa", + }, };Signature · 1 line
2.5.0
Re: [Qemu-devel] [PATCH v4 08/26] crypto: add support for the twofish cipher algorithm
In reply to Daniel P. BerrangeQuoted 11 lines · Daniel P. Berrange
New cipher algorithms 'twofish-128', 'twofish-192' and 'twofish-256' are defined for the Twofish algorithm. The gcrypt backend does not support 'twofish-192'.
The nettle and gcrypt cipher backends are updated to support the new cipher and a test vector added to the cipher test suite. The new algorithm is enabled in the LUKS block encryption driver.
Signed-off-by Daniel P. Berrange <[email protected]>---
Signature · 2 lines
Eric Blake eblake redhat com +1-919-301-3266 Libvirt virtualization library http://libvirt.org
PATCH v4 9/26 crypto: import an implementation of the XTS cipher mode
In reply to Daniel P. BerrangeThe XTS (XEX with tweaked-codebook and ciphertext stealing) cipher mode is commonly used in full disk encryption. There is unfortunately no implementation of it in either libgcrypt or nettle, so we need to provide our own.
The libtomcrypt project provides a repository of crypto algorithms under a choice of either "public domain" or the "what the fuck public license".
So this impl is taken from the libtomcrypt GIT repo and adapted to be compatible with the way we need to call ciphers provided by nettle/gcrypt.
--- crypto/Makefile.objs | 1 + crypto/xts.c | 256 +++++++++++++++++++++++++++++ include/crypto/xts.h | 86 ++++++++++ tests/.gitignore | 1 + tests/Makefile | 2 + tests/test-crypto-xts.c | 423 ++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 769 insertions(+) create mode 100644 crypto/xts.c create mode 100644 include/crypto/xts.h create mode 100644 tests/test-crypto-xts.c
crypto/Makefile.objs +1 -0
@@ -18,6 +18,7 @@ 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 += xts.o # Let the userspace emulators avoid linking gnutls/etc crypto-aes-obj-y = aes.o
crypto/xts.c new file +256 -0
256 lines not on this page · raw message
include/crypto/xts.h new file +86 -0
86 lines not on this page · raw message
tests/.gitignore +1 -0
@@ -25,6 +25,7 @@ test-crypto-tlssession test-crypto-tlssession-work/ test-crypto-tlssession-client/ test-crypto-tlssession-server/ +test-crypto-xts test-cutils test-hbitmap test-int128
tests/Makefile +2 -0
@@ -95,6 +95,7 @@ check-unit-y += tests/test-base64$(EXESUF) check-unit-y += tests/test-crypto-pbkdf$(EXESUF) check-unit-y += tests/test-crypto-ivgen$(EXESUF) check-unit-y += tests/test-crypto-afsplit$(EXESUF) +check-unit-y += tests/test-crypto-xts$(EXESUF) check-block-$(CONFIG_POSIX) += tests/qemu-iotests-quick.sh
@@ -476,6 +477,7 @@ tests/test-bitops$(EXESUF): tests/test-bitops.o $(test-util-obj-y) tests/test-crypto-hash$(EXESUF): tests/test-crypto-hash.o $(test-crypto-obj-y) tests/test-crypto-cipher$(EXESUF): tests/test-crypto-cipher.o $(test-crypto-obj-y) tests/test-crypto-secret$(EXESUF): tests/test-crypto-secret.o $(test-crypto-obj-y) +tests/test-crypto-xts$(EXESUF): tests/test-crypto-xts.o $(test-crypto-obj-y) tests/crypto-tls-x509-helpers.o-cflags := $(TASN1_CFLAGS) tests/crypto-tls-x509-helpers.o-libs := $(TASN1_LIBS)
tests/test-crypto-xts.c new file +423 -0
423 lines not on this page · raw message
Signature · 1 line
2.5.0
Re: [Qemu-devel] [PATCH v4 09/26] crypto: import an implementation of the XTS cipher mode
Quoted 18 lines · Daniel P. Berrange
The XTS (XEX with tweaked-codebook and ciphertext stealing) cipher mode is commonly used in full disk encryption. There is unfortunately no implementation of it in either libgcrypt or nettle, so we need to provide our own.
The libtomcrypt project provides a repository of crypto algorithms under a choice of either "public domain" or the "what the fuck public license".
So this impl is taken from the libtomcrypt GIT repo and adapted to be compatible with the way we need to call ciphers provided by nettle/gcrypt.
Signed-off-by Daniel P. Berrange <[email protected]>---
+++
b/crypto/xts.c
crypto/xts.c line 4
Quoted 4 lines
crypto/xts.c new file +4
-0@@ -0,0 +1,256 @@ +/* +* QEMU Crypto XTS cipher mode +* +* Copyright (c) 2015 Red Hat, Inc.
Want to add 2016?
crypto/xts.c line 36
Quoted 12 lines
crypto/xts.c new file +12
-0+ +#include "qemu/osdep.h" +#include "crypto/xts.h" + +static void xts_mult_x (uint8_t *I ) +{ +int x; +uint8_t t, tt; + +for (x = t =0 ; x <16 ; x++) { + tt =I [x] >>7 ; +I [x] = ((I [x] <<1 ) | t) &0xFF ;
Why '& 0xf'f? I[x] is already an 8-bit field. But since it is a direct copy from
https://github.com/libtom/libtomcrypt/blob/develop/src/modes/xts/xts_mult_x.c,
I won't reject it. (I could understand the mask if the original code were using uint_fast8_t for speed at the expense of worrying about potential padding bits, but no one does that in crypto...)
Quoted 14 lines
crypto/xts.c new file +14
-0+/** +* xts_tweak_uncrypt: +* @param ctxt: the cipher context +* @param func: the cipher function +* @src: buffer providing the cipher text of XTS_BLOCK_SIZE bytes +* @dst: buffer to output the plain text of XTS_BLOCK_SIZE bytes +* @iv: the initialization vector tweak of XTS_BLOCK_SIZE bytes +* +* Decrypt data with a tweak +*/ +static void xts_tweak_decrypt(const void *ctx, + xts_cipher_func *func, + const uint8_t *src, + uint8_t *dst,
crypto/xts.c line 68
Quoted 10 lines
crypto/xts.c new file +10
-0+ uint8_t *iv) +{ +unsigned long x; + +/* tweak encrypt block i */ +#ifdef LTC_FAST +for (x =0 ; x <XTS_BLOCK_SIZE ; x +=sizeof (LTC_FAST_TYPE )) { + *((LTC_FAST_TYPE *)&dst[x]) = + *((LTC_FAST_TYPE *)&src[x]) ^ *((LTC_FAST_TYPE *)&iv[x]); + }
Nothing in our configure sets LTC_FAST and friends; should we just nuke these expressions as dead code? I see the point of what it is trying to
do: if the data is aligned (or if the processor doesn't care about alignment), then vectorize it...
crypto/xts.c line 72
Quoted 4 lines
crypto/xts.c new file +4
-0+#else +for (x =0 ; x <XTS_BLOCK_SIZE ; x++) { + dst[x] = src[x] ^ iv[x]; + }
...but we've already argued that the compiler should be able to auto-vectorize, or at least that hot-path tweaking can be done later.
crypto/xts.c line 128
Quoted 6 lines
crypto/xts.c new file +5
-0+void xts_decrypt (const void *datactx, +const void *tweakctx, + +/* if length not divide XTS_BLOCK_SIZE then */ + if (mo > 0) {
If length is not a multiple of XTS_BLOCK_SIZE, then
crypto/xts.c line 235
Quoted 5 lines
crypto/xts.c new file +4
-0+void xts_encrypt(const void *datactx, + const void *tweakctx, + +/* if length not divide XTS_BLOCK_SIZE then */
and again
crypto/xts.c line 4
Quoted 6 lines
+++
b/include/crypto/xts.hcrypto/xts.c new file +4
-0@@ -0,0 +1,86 @@ +/* +* QEMU Crypto XTS cipher mode +* +* Copyright (c) 2015 Red Hat, Inc.
2016
crypto/xts.c line 4
Quoted 6 lines
crypto/xts.c new file +5
-0+++ b/tests/test-crypto-xts.c@@ -0,0 +1,423 @@ +/* +* QEMU Crypto XTS cipher mode +* +* Copyright (c) 2015 Red Hat, Inc.
and again
Modulo comment tweaks and a decision about whether to nuke LTC_FAST,
Signature · 2 lines
Eric Blake eblake redhat com +1-919-301-3266 Libvirt virtualization library http://libvirt.org
Re: [Qemu-devel] [PATCH v4 09/26] crypto: import an implementation of the XTS cipher mode
Quoted 37 lines · Eric Blake
Quoted 18 lines · Daniel P. Berrange
The XTS (XEX with tweaked-codebook and ciphertext stealing) cipher mode is commonly used in full disk encryption. There is unfortunately no implementation of it in either libgcrypt or nettle, so we need to provide our own.
The libtomcrypt project provides a repository of crypto algorithms under a choice of either "public domain" or the "what the fuck public license".
So this impl is taken from the libtomcrypt GIT repo and adapted to be compatible with the way we need to call ciphers provided by nettle/gcrypt.
Signed-off-by Daniel P. Berrange <[email protected]>---
+++
b/crypto/xts.ccrypto/xts.c line 4
Quoted 4 lines
crypto/xts.c new file +4
-0@@ -0,0 +1,256 @@ +/* +* QEMU Crypto XTS cipher mode +* +* Copyright (c) 2015 Red Hat, Inc. Want to add 2016?
Quoted 11 lines
crypto/xts.c new file +11
-0+ +#include "qemu/osdep.h" +#include "crypto/xts.h" + +static void xts_mult_x (uint8_t *I ) +{ +int x; +uint8_t t, tt; + +for (x = t =0 ; x <16 ; x++) { + tt =I [x] >>7 ;
Quoted 8 lines
crypto/xts.c line 36
Quoted 1 line
crypto/xts.c new file +1
-0+I [x] = ((I [x] <<1 ) | t) &0xFF ;Why '& 0xf'f? I[x] is already an 8-bit field. But since it is a direct copy from
https://github.com/libtom/libtomcrypt/blob/develop/src/modes/xts/xts_mult_x.c,
I won't reject it. (I could understand the mask if the original code were usinguint_fast8_tfor speed at the expense of worrying about potential padding bits, but no one does that in crypto...)
Yeah as you saw, this is just copied as-is from tomcrypt
Quoted 11 lines
Quoted 11 lines
crypto/xts.c new file +11
-0+static void xts_tweak_decrypt (const void *ctx, +xts_cipher_func *func, +const uint8_t *src, +uint8_t *dst, +uint8_t *iv) +{ +unsigned long x; + +/* tweak encrypt block i */ +#ifdef LTC_FAST +for (x =0 ; x <XTS_BLOCK_SIZE ; x +=sizeof (LTC_FAST_TYPE )) {
Quoted 8 lines
crypto/xts.c line 68
Quoted 3 lines
crypto/xts.c new file +3
-0+ *((LTC_FAST_TYPE *)&dst[x]) = + *((LTC_FAST_TYPE *)&src[x]) ^ *((LTC_FAST_TYPE *)&iv[x]); + }Nothing in our configure sets
LTC_FASTand friends; should we just nuke these expressions as dead code? I see the point of what it is trying to
do: if the data is aligned (or if the processor doesn't care about alignment), then vectorize it...
I'll just nuke th blocks inside LTC_FAST - I in fact meant todo that already before sending. Once all the LUKS stuff is merged we'll look at getting some complete stack performance tests done and look at where we want to optimize based on real data.
Regards,
Daniel
Signature · 4 lines
|: 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 :|
PATCH v4 10/26 crypto: refactor code for dealing with AES cipher
In reply to Daniel P. BerrangeThe built-in and nettle cipher backends for AES maintain two separate AES contexts, one for encryption and one for decryption. This is going to be inconvenient for the future code dealing with XTS, so wrap them up in a single struct so there is just one pointer to pass around for both encryptin and decryption.
--- crypto/cipher-builtin.c | 126 ++++++++++++++++++++++++++++++------------------ crypto/cipher-nettle.c | 57 +++++++++++----------- 2 files changed, 109 insertions(+), 74 deletions(-)
crypto/cipher-builtin.c +80 -46
@@ -22,10 +22,14 @@#include "crypto/aes.h" #include "crypto/desrfb.h" +typedef struct QCryptoCipherBuiltinAESContext QCryptoCipherBuiltinAESContext ; +struct QCryptoCipherBuiltinAESContext { +AES_KEY enc; +AES_KEY dec; +};typedef struct QCryptoCipherBuiltinAES QCryptoCipherBuiltinAES ;struct QCryptoCipherBuiltinAES { -AES_KEY encrypt_key; -AES_KEY decrypt_key; +QCryptoCipherBuiltinAESContext key;uint8_t iv[AES_BLOCK_SIZE ]; };typedef struct QCryptoCipherBuiltinDESRFB QCryptoCipherBuiltinDESRFB ;
@@ -67,6 +71,58 @@ static void qcrypto_cipher_free_aes(QCryptoCipher *cipher) } +static void qcrypto_cipher_aes_ecb_encrypt (AES_KEY *key, +const void *in, +void *out, +size_t len) +{ +const uint8_t *inptr = in; +uint8_t *outptr = out; +while (len) { +if (len >AES_BLOCK_SIZE ) { +AES_encrypt (inptr, outptr, key); + inptr +=AES_BLOCK_SIZE ; + outptr +=AES_BLOCK_SIZE ; + len -=AES_BLOCK_SIZE ; + }else { +uint8_t tmp1[AES_BLOCK_SIZE ], tmp2[AES_BLOCK_SIZE ]; +memcpy (tmp1, inptr, len); +/* Fill with 0 to avoid valgrind uninitialized reads */ +memset (tmp1 + len,0 ,sizeof (tmp1) - len); +AES_encrypt (tmp1, tmp2, key); +memcpy (outptr, tmp2, len); + len =0 ; + } + } +} + + +static void qcrypto_cipher_aes_ecb_decrypt (AES_KEY *key, +const void *in, +void *out, +size_t len) +{ +const uint8_t *inptr = in; +uint8_t *outptr = out; +while (len) { +if (len >AES_BLOCK_SIZE ) { +AES_decrypt (inptr, outptr, key); + inptr +=AES_BLOCK_SIZE ; + outptr +=AES_BLOCK_SIZE ; + len -=AES_BLOCK_SIZE ; + }else { +uint8_t tmp1[AES_BLOCK_SIZE ], tmp2[AES_BLOCK_SIZE ]; +memcpy (tmp1, inptr, len); +/* Fill with 0 to avoid valgrind uninitialized reads */ +memset (tmp1 + len,0 ,sizeof (tmp1) - len); +AES_decrypt (tmp1, tmp2, key); +memcpy (outptr, tmp2, len); + len =0 ; + } + } +} + + static int qcrypto_cipher_encrypt_aes(QCryptoCipher *cipher, const void *in, void *out,
@@ -75,29 +131,18 @@ static int qcrypto_cipher_encrypt_aes(QCryptoCipher *cipher, {QCryptoCipherBuiltin *ctxt = cipher->opaque; -if (cipher->mode ==QCRYPTO_CIPHER_MODE_ECB ) { -const uint8_t *inptr = in; -uint8_t *outptr = out; -while (len) { -if (len >AES_BLOCK_SIZE ) { -AES_encrypt (inptr, outptr, &ctxt->state.aes.encrypt_key); - inptr +=AES_BLOCK_SIZE ; - outptr +=AES_BLOCK_SIZE ; - len -=AES_BLOCK_SIZE ; - }else { -uint8_t tmp1[AES_BLOCK_SIZE ], tmp2[AES_BLOCK_SIZE ]; -memcpy (tmp1, inptr, len); -/* Fill with 0 to avoid valgrind uninitialized reads */ -memset (tmp1 + len,0 ,sizeof (tmp1) - len); -AES_encrypt (tmp1, tmp2, &ctxt->state.aes.encrypt_key); -memcpy (outptr, tmp2, len); - len =0 ; - } - } - }else { +switch (cipher->mode) { +case QCRYPTO_CIPHER_MODE_ECB : +qcrypto_cipher_aes_ecb_encrypt (&ctxt->state.aes.key.enc, + in, out, len); +break ; +case QCRYPTO_CIPHER_MODE_CBC :AES_cbc_encrypt (in, out, len, - &ctxt->state.aes.encrypt_key, + &ctxt->state.aes.key.enc, ctxt->state.aes.iv,1 ); +break ; +default : +g_assert_not_reached (); }return 0 ;
@@ -112,29 +157,18 @@ static int qcrypto_cipher_decrypt_aes(QCryptoCipher *cipher, {QCryptoCipherBuiltin *ctxt = cipher->opaque; -if (cipher->mode ==QCRYPTO_CIPHER_MODE_ECB ) { -const uint8_t *inptr = in; -uint8_t *outptr = out; -while (len) { -if (len >AES_BLOCK_SIZE ) { -AES_decrypt (inptr, outptr, &ctxt->state.aes.decrypt_key); - inptr +=AES_BLOCK_SIZE ; - outptr +=AES_BLOCK_SIZE ; - len -=AES_BLOCK_SIZE ; - }else { -uint8_t tmp1[AES_BLOCK_SIZE ], tmp2[AES_BLOCK_SIZE ]; -memcpy (tmp1, inptr, len); -/* Fill with 0 to avoid valgrind uninitialized reads */ -memset (tmp1 + len,0 ,sizeof (tmp1) - len); -AES_decrypt (tmp1, tmp2, &ctxt->state.aes.decrypt_key); -memcpy (outptr, tmp2, len); - len =0 ; - } - } - }else { +switch (cipher->mode) { +case QCRYPTO_CIPHER_MODE_ECB : +qcrypto_cipher_aes_ecb_decrypt (&ctxt->state.aes.key.dec, + in, out, len); +break ; +case QCRYPTO_CIPHER_MODE_CBC :AES_cbc_encrypt (in, out, len, - &ctxt->state.aes.decrypt_key, + &ctxt->state.aes.key.dec, ctxt->state.aes.iv,0 ); +break ; +default : +g_assert_not_reached (); }return 0 ;
@@ -173,12 +207,12 @@ static int qcrypto_cipher_init_aes(QCryptoCipher *cipher, ctxt =g_new0 (QCryptoCipherBuiltin,1 ); -if (AES_set_encrypt_key (key, nkey *8 , &ctxt->state.aes.encrypt_key) !=0 ) { +if (AES_set_encrypt_key (key, nkey *8 , &ctxt->state.aes.key.enc) !=0 ) {error_setg (errp,"Failed to set encryption key" ); goto error; } -if (AES_set_decrypt_key (key, nkey *8 , &ctxt->state.aes.decrypt_key) !=0 ) { +if (AES_set_decrypt_key (key, nkey *8 , &ctxt->state.aes.key.dec) !=0 ) {error_setg (errp,"Failed to set decryption key" ); goto error; }
crypto/cipher-nettle.c +29 -28
141 lines not on this page · raw message
Signature · 1 line
2.5.0
Re: [Qemu-devel] [PATCH v4 10/26] crypto: refactor code for dealing with AES cipher
Quoted 6 lines · Daniel P. Berrange
The built-in and nettle cipher backends for AES maintain two separate AES contexts, one for encryption and one for decryption. This is going to be inconvenient for the future code dealing with XTS, so wrap them up in a single struct so there is just one pointer to pass around for both encryptin and decryption.
s/encryptin/encryption/
Quoted 6 lines
Signed-off-by Daniel P. Berrange <[email protected]>--- crypto/cipher-builtin.c | 126 ++++++++++++++++++++++++++++++------------------ crypto/cipher-nettle.c | 57 +++++++++++----------- 2 files changed, 109 insertions(+), 74 deletions(-)
Signature · 2 lines
Eric Blake eblake redhat com +1-919-301-3266 Libvirt virtualization library http://libvirt.org
PATCH v4 11/26 crypto: wire up XTS mode for cipher APIs
In reply to Daniel P. BerrangeIntroduce 'XTS' as a permitted mode for the cipher APIs. With XTS the key provided must be twice the size of the key normally required for any given algorithm. This is because the key will be split into two pieces for use in XTS mode.
--- crypto/cipher-builtin.c | 85 +++++++++++++++++++++++++--- crypto/cipher-gcrypt.c | 123 ++++++++++++++++++++++++++++++++--------- crypto/cipher-nettle.c | 79 ++++++++++++++++++++++++-- crypto/cipher.c | 27 +++++++-- qapi/crypto.json | 3 +- tests/test-crypto-cipher.c | 134 ++++++++++++++++++++++++++++++++++++++++++++- 6 files changed, 405 insertions(+), 46 deletions(-)
crypto/cipher-builtin.c +76 -9
@@ -21,6 +21,7 @@#include "qemu/osdep.h" #include "crypto/aes.h" #include "crypto/desrfb.h" +#include "crypto/xts.h" typedef struct QCryptoCipherBuiltinAESContext QCryptoCipherBuiltinAESContext ;struct QCryptoCipherBuiltinAESContext {
@@ -30,6 +31,7 @@ struct QCryptoCipherBuiltinAESContext {typedef struct QCryptoCipherBuiltinAES QCryptoCipherBuiltinAES ;struct QCryptoCipherBuiltinAES {QCryptoCipherBuiltinAESContext key; +QCryptoCipherBuiltinAESContext key_tweak;uint8_t iv[AES_BLOCK_SIZE ]; };typedef struct QCryptoCipherBuiltinDESRFB QCryptoCipherBuiltinDESRFB ;
@@ -123,6 +125,30 @@ static void qcrypto_cipher_aes_ecb_decrypt(AES_KEY *key, } +static void qcrypto_cipher_aes_xts_encrypt (const void *ctx, +size_t length, +uint8_t *dst, +const uint8_t *src) +{ +const QCryptoCipherBuiltinAESContext *aesctx = ctx; + +qcrypto_cipher_aes_ecb_encrypt ((AES_KEY *)&aesctx->enc, + src, dst, length); +} + + +static void qcrypto_cipher_aes_xts_decrypt (const void *ctx, +size_t length, +uint8_t *dst, +const uint8_t *src) +{ +const QCryptoCipherBuiltinAESContext *aesctx = ctx; + +qcrypto_cipher_aes_ecb_decrypt ((AES_KEY *)&aesctx->dec, + src, dst, length); +} + + static int qcrypto_cipher_encrypt_aes(QCryptoCipher *cipher, const void *in, void *out,
@@ -141,6 +167,14 @@ static int qcrypto_cipher_encrypt_aes(QCryptoCipher *cipher, &ctxt->state.aes.key.enc, ctxt->state.aes.iv, 1);break ; +case QCRYPTO_CIPHER_MODE_XTS : +xts_encrypt (&ctxt->state.aes.key, + &ctxt->state.aes.key_tweak, + qcrypto_cipher_aes_xts_encrypt, + qcrypto_cipher_aes_xts_decrypt, + ctxt->state.aes.iv, + len, out, in); +break ;default :g_assert_not_reached (); }
@@ -167,6 +201,14 @@ static int qcrypto_cipher_decrypt_aes(QCryptoCipher *cipher, &ctxt->state.aes.key.dec, ctxt->state.aes.iv, 0);break ; +case QCRYPTO_CIPHER_MODE_XTS : +xts_decrypt (&ctxt->state.aes.key, + &ctxt->state.aes.key_tweak, + qcrypto_cipher_aes_xts_encrypt, + qcrypto_cipher_aes_xts_decrypt, + ctxt->state.aes.iv, + len, out, in); +break ;default :g_assert_not_reached (); }
@@ -200,21 +242,46 @@ static int qcrypto_cipher_init_aes(QCryptoCipher *cipher,QCryptoCipherBuiltin *ctxt;if (cipher->mode !=QCRYPTO_CIPHER_MODE_CBC && - cipher->mode !=QCRYPTO_CIPHER_MODE_ECB ) { + cipher->mode !=QCRYPTO_CIPHER_MODE_ECB && + cipher->mode !=QCRYPTO_CIPHER_MODE_XTS ) {error_setg (errp,"Unsupported cipher mode %d" , cipher->mode);return -1 ; } ctxt =g_new0 (QCryptoCipherBuiltin,1 ); -if (AES_set_encrypt_key (key, nkey *8 , &ctxt->state.aes.key.enc) !=0 ) { -error_setg (errp,"Failed to set encryption key" ); - goto error; - } +if (cipher->mode ==QCRYPTO_CIPHER_MODE_XTS ) { +if (AES_set_encrypt_key (key, nkey *4 , &ctxt->state.aes.key.enc) !=0 ) { +error_setg (errp,"Failed to set encryption key" ); + goto error; + } -if (AES_set_decrypt_key (key, nkey *8 , &ctxt->state.aes.key.dec) !=0 ) { -error_setg (errp,"Failed to set decryption key" ); - goto error; +if (AES_set_decrypt_key (key, nkey *4 , &ctxt->state.aes.key.dec) !=0 ) { +error_setg (errp,"Failed to set decryption key" ); + goto error; + } + +if (AES_set_encrypt_key (key + (nkey /2 ), nkey *4 , + &ctxt->state.aes.key_tweak.enc) !=0 ) { +error_setg (errp,"Failed to set encryption key" ); + goto error; + } + +if (AES_set_decrypt_key (key + (nkey /2 ), nkey *4 , + &ctxt->state.aes.key_tweak.dec) !=0 ) { +error_setg (errp,"Failed to set decryption key" ); + goto error; + } + }else { +if (AES_set_encrypt_key (key, nkey *8 , &ctxt->state.aes.key.enc) !=0 ) { +error_setg (errp,"Failed to set encryption key" ); + goto error; + } + +if (AES_set_decrypt_key (key, nkey *8 , &ctxt->state.aes.key.dec) !=0 ) { +error_setg (errp,"Failed to set decryption key" ); + goto error; + } } ctxt->blocksize =AES_BLOCK_SIZE ;
@@ -356,7 +423,7 @@ QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg, cipher->alg = alg; cipher->mode = mode; -if (!qcrypto_cipher_validate_key_length (alg, nkey, errp)) { +if (!qcrypto_cipher_validate_key_length (alg, mode, nkey, errp)) { goto error; }
crypto/cipher-gcrypt.c +98 -25
202 lines not on this page · raw message
crypto/cipher-nettle.c +73 -6
148 lines not on this page · raw message
crypto/cipher.c +23 -4
@@ -53,6 +53,7 @@ static size_t alg_block_len[QCRYPTO_CIPHER_ALG__MAX] = {static bool mode_need_iv[QCRYPTO_CIPHER_MODE__MAX ] = { [QCRYPTO_CIPHER_MODE_ECB ] = false, [QCRYPTO_CIPHER_MODE_CBC ] = true, + [QCRYPTO_CIPHER_MODE_XTS ] = true, };
@@ -93,6 +94,7 @@ size_t qcrypto_cipher_get_iv_len(QCryptoCipherAlgorithm alg,static bool qcrypto_cipher_validate_key_length (QCryptoCipherAlgorithm alg, +QCryptoCipherMode mode,size_t nkey,Error **errp) {
@@ -102,10 +104,27 @@ qcrypto_cipher_validate_key_length(QCryptoCipherAlgorithm alg,return false; } -if (alg_key_len[alg] != nkey) { -error_setg (errp,"Cipher key length %zu should be %zu" , - nkey, alg_key_len[alg]); -return false; +if (mode ==QCRYPTO_CIPHER_MODE_XTS ) { +if (alg ==QCRYPTO_CIPHER_ALG_DES_RFB ) { +error_setg (errp,"XTS mode not compatible with DES-RFB" ); +return false; + } +if (nkey %2 ) { +error_setg (errp,"XTS cipher key length should be a multiple of 2" ); +return false; + } + +if (alg_key_len[alg] != (nkey /2 )) { +error_setg (errp,"Cipher key length %zu should be %zu" , + nkey, alg_key_len[alg] *2 ); +return false; + } + }else { +if (alg_key_len[alg] != nkey) { +error_setg (errp,"Cipher key length %zu should be %zu" , + nkey, alg_key_len[alg]); +return false; + } }return true; }
qapi/crypto.json +2 -1
@@ -84,11 +84,12 @@ # # @ecb: Electronic Code Book # @cbc: Cipher Block Chaining +# @xts: XEX with tweaked code book and ciphertext stealing # Since: 2.6 ## { 'enum': 'QCryptoCipherMode', 'prefix': 'QCRYPTO_CIPHER_MODE', - 'data': ['ecb', 'cbc']} + 'data': ['ecb', 'cbc', 'xts']} ##
tests/test-crypto-cipher.c +133 -1
146 lines not on this page · raw message
Signature · 1 line
2.5.0
Re: [Qemu-devel] [PATCH v4 11/26] crypto: wire up XTS mode for cipher APIs
Quoted 8 lines · Daniel P. Berrange
Introduce 'XTS' as a permitted mode for the cipher APIs. With XTS the key provided must be twice the size of the key normally required for any given algorithm. This is because the key will be split into two pieces for use in XTS mode.
Signed-off-by Daniel P. Berrange <[email protected]>---
Signature · 2 lines
Eric Blake eblake redhat com +1-919-301-3266 Libvirt virtualization library http://libvirt.org
PATCH v4 12/26 crypto: add block encryption framework
In reply to Daniel P. BerrangeAdd 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.
--- crypto/Makefile.objs | 2 + crypto/block-qcow.c | 173 +++++++++++++++++++++++++++++++ crypto/block-qcow.h | 28 +++++ crypto/block.c | 258 ++++++++++++++++++++++++++++++++++++++++++++++ crypto/blockpriv.h | 92 +++++++++++++++++ include/crypto/block.h | 232 +++++++++++++++++++++++++++++++++++++++++ qapi/crypto.json | 67 ++++++++++++ tests/.gitignore | 1 + tests/Makefile | 2 + tests/test-crypto-block.c | 239 ++++++++++++++++++++++++++++++++++++++++++ 10 files changed, 1094 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
crypto/Makefile.objs +2 -0
@@ -19,6 +19,8 @@ crypto-obj-y += ivgen-plain.o crypto-obj-y += ivgen-plain64.o crypto-obj-y += afsplit.o crypto-obj-y += xts.o +crypto-obj-y += block.o +crypto-obj-y += block-qcow.o # Let the userspace emulators avoid linking gnutls/etc crypto-aes-obj-y = aes.o
crypto/block-qcow.c new file +173 -0
173 lines not on this page · raw message
crypto/block-qcow.h new file +28 -0
@@ -0,0 +1,28 @@ +/* +* 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/>. +* +*/ + +#ifndef QCRYPTO_BLOCK_QCOW_H__ +#define QCRYPTO_BLOCK_QCOW_H__ + +#include "crypto/blockpriv.h" + +extern const QCryptoBlockDriver qcrypto_block_driver_qcow; + +#endif /* QCRYPTO_BLOCK_QCOW_H__ */
crypto/block.c new file +258 -0
258 lines not on this page · raw message
crypto/blockpriv.h new file +92 -0
92 lines not on this page · raw message
include/crypto/block.h new file +232 -0
232 lines not on this page · raw message
qapi/crypto.json +67 -0
70 lines not on this page · raw message
tests/.gitignore +1 -0
@@ -13,6 +13,7 @@ test-bitops test-blockjob-txn test-coroutine test-crypto-afsplit +test-crypto-block test-crypto-cipher test-crypto-hash test-crypto-ivgen
tests/Makefile +2 -0
@@ -96,6 +96,7 @@ check-unit-y += tests/test-crypto-pbkdf$(EXESUF) check-unit-y += tests/test-crypto-ivgen$(EXESUF) check-unit-y += tests/test-crypto-afsplit$(EXESUF) check-unit-y += tests/test-crypto-xts$(EXESUF) +check-unit-y += tests/test-crypto-block$(EXESUF) check-block-$(CONFIG_POSIX) += tests/qemu-iotests-quick.sh
@@ -505,6 +506,7 @@ tests/test-io-channel-buffer$(EXESUF): tests/test-io-channel-buffer.o \ tests/test-crypto-pbkdf$(EXESUF): tests/test-crypto-pbkdf.o $(test-crypto-obj-y) tests/test-crypto-ivgen$(EXESUF): tests/test-crypto-ivgen.o $(test-crypto-obj-y) tests/test-crypto-afsplit$(EXESUF): tests/test-crypto-afsplit.o $(test-crypto-obj-y) +tests/test-crypto-block$(EXESUF): tests/test-crypto-block.o $(test-crypto-obj-y) libqos-obj-y = tests/libqos/pci.o tests/libqos/fw_cfg.o tests/libqos/malloc.o libqos-obj-y += tests/libqos/i2c.o tests/libqos/libqos.o
tests/test-crypto-block.c new file +239 -0
239 lines not on this page · raw message
Signature · 1 line
2.5.0
Re: [Qemu-devel] [PATCH v4 12/26] crypto: add block encryption framework
Quoted 1 line · Daniel P. Berrange
Add a generic framework for support different block encryption
s/support/supporting/
Quoted 22 lines
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 <[email protected]>---
+/**
+ *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 a NULL-initialized error object
Quoted 4 lines
+ *
+ * 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
s/an/a/
Quoted 7 lines
+ * or IV generator algorithm that is not supported,
+ * or incorrect passphrases.
+ *
+ * Returns: a block encryption format, or NULL on error
+ */include/crypto/block.h new file +2
-0+QCryptoBlock *qcrypto_block_open(QCryptoBlockOpenOptions *options, + QCryptoBlockReadFunc readfunc,
include/crypto/block.h line 129
Quoted 10 lines
include/crypto/block.h new file +9
-0+void *opaque, + unsigned int flags, + Error **errp); + +/** +* qcrypto_block_create: +* 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
and again
Quoted 7 lines
+++
b/qapi/crypto.jsonqapi/crypto.json +3
-0@@ -109,3 +109,70 @@ { 'enum': 'QCryptoIVGenAlgorithm', + +## +# QCryptoBlockOptionsBase:
qapi/crypto.json line 123
Quoted 10 lines
qapi/crypto.json +10
-0+# +# The common options that apply to all full disk +# encryption formats +# +# @format: the encryption format +# +# Since: 2.6 +## +{ 'struct': 'QCryptoBlockOptionsBase', + 'data': { 'format': 'QCryptoBlockFormat' }}
We are so close to having my patches in for anonymous base; depending on whose lands first, we can clean this up to get rid of the one-shot base (followup is fine).
https://lists.gnu.org/archive/html/qemu-devel/2016-03/msg02296.html
qapi/crypto.json line 146
Quoted 8 lines
qapi/crypto.json +8
-0+ +## +# QCryptoBlockOptionsQCow: +# +# The options that apply to QCow/QCow2 AES-CBC encryption format +# +# @key-secret: #optional the ID of a QCryptoSecret object providing the +# decryption key
I mentioned in a previous round that you may want to mention that it is optional only when probing the image metadata, and mandatory for reading/writing guest-visible data. Don't know if that is worth adding words here.
With the typo fixes,
Signature · 2 lines
Eric Blake eblake redhat com +1-919-301-3266 Libvirt virtualization library http://libvirt.org
PATCH v4 13/26 crypto: implement the LUKS block encryption format
In reply to Daniel P. BerrangeProvide a block encryption implementation that follows the LUKS/dm-crypt specification.
This supports all combinations of hash, cipher algorithm, cipher mode and iv generator that are implemented by the current crypto layer.
The notable missing feature is support for the 'xts' cipher mode, which is commonly used for disk encryption instead of 'cbc'. This is because it is not provided by either nettle or libgcrypt. A suitable implementation will be identified & integrated later.
There is support for opening existing volumes formatted by dm-crypt, and for formatting new volumes. In the latter case it will only use key slot 0.
--- crypto/Makefile.objs | 1 + crypto/block-luks.c | 1313 +++++++++++++++++++++++++++++++++++++++++++++ crypto/block-luks.h | 28 + crypto/block.c | 2 + qapi/crypto.json | 51 +- tests/test-crypto-block.c | 95 ++++ 6 files changed, 1486 insertions(+), 4 deletions(-) create mode 100644 crypto/block-luks.c create mode 100644 crypto/block-luks.h
crypto/Makefile.objs +1 -0
@@ -21,6 +21,7 @@ crypto-obj-y += afsplit.o crypto-obj-y += xts.o crypto-obj-y += block.o crypto-obj-y += block-qcow.o +crypto-obj-y += block-luks.o # Let the userspace emulators avoid linking gnutls/etc crypto-aes-obj-y = aes.o
crypto/block-luks.c new file +1313 -0
1,313 lines not on this page · raw message
crypto/block-luks.h new file +28 -0
@@ -0,0 +1,28 @@ +/* +* QEMU Crypto block device encryption LUKS 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/>. +* +*/ + +#ifndef QCRYPTO_BLOCK_LUKS_H__ +#define QCRYPTO_BLOCK_LUKS_H__ + +#include "crypto/blockpriv.h" + +extern const QCryptoBlockDriver qcrypto_block_driver_luks; + +#endif /* QCRYPTO_BLOCK_LUKS_H__ */
crypto/block.c +2 -0
@@ -21,9 +21,11 @@#include "qemu/osdep.h" #include "crypto/blockpriv.h" #include "crypto/block-qcow.h" +#include "crypto/block-luks.h" static const QCryptoBlockDriver *qcrypto_block_drivers[] = { [Q_CRYPTO_BLOCK_FORMAT_QCOW ] = &qcrypto_block_driver_qcow, + [Q_CRYPTO_BLOCK_FORMAT_LUKS ] = &qcrypto_block_driver_luks, };
qapi/crypto.json +47 -4
83 lines not on this page · raw message
tests/test-crypto-block.c +95 -0
107 lines not on this page · raw message
Signature · 1 line
2.5.0
Re: [Qemu-devel] [PATCH v4 13/26] crypto: implement the LUKS block encryption format
Quoted 7 lines · Daniel P. Berrange
Provide a block encryption implementation that follows the LUKS/dm-crypt specification.
This supports all combinations of hash, cipher algorithm, cipher mode and iv generator that are implemented by the current crypto layer.
Quoted 5 lines
The notable missing feature is support for the 'xts' cipher mode, which is commonly used for disk encryption instead of 'cbc'. This is because it is not provided by either nettle or libgcrypt. A suitable implementation will be identified & integrated later.
Stale paragraph, you implemented it earlier in the series.
Quoted 10 lines
There is support for opening existing volumes formatted by dm-crypt, and for formatting new volumes. In the latter case it will only use key slot 0.
Signed-off-by Daniel P. Berrange <[email protected]>---
crypto/block-luks.c new file +1
-0+static int
crypto/block-luks.c line 670
Quoted 10 lines
crypto/block-luks.c new file +9
-0+qcrypto_block_luks_open (QCryptoBlock *block, + QCryptoBlockOpenOptions *options, + QCryptoBlockReadFunc readfunc, + void *opaque, + unsigned int flags, + Error **errp) +{ +/* Read the entire LUKS header, minus the key material from +* the underling device */
s/underling/underlying/ (although the typo does read rather humorously - I now have a mental image of a LUKS overlord :)
qapi/crypto.json line 148
Quoted 12 lines
+++
b/qapi/crypto.jsonqapi/crypto.json +2
-1@@ -117,12 +117,13 @@ ## # QCryptoBlockOptionsBase:@@ -143,7 +144,8 @@ # The options that apply to QCow/QCow2 AES-CBC encryption format # # @key-secret: #optional the ID of a QCryptoSecret object providing the -# decryption key +# decryption key. Mandatory except when probing image for +# metadata only.
Aha - I think this hunk may belong earlier in the series...
qapi/crypto.json line 161
Quoted 13 lines
qapi/crypto.json +6
-0# # Since: 2.6 ##@@ -151,6 +153,45 @@ 'data': { '*key-secret': 'str' }} ## +# QCryptoBlockOptionsLUKS: +# +# The options that apply to LUKS encryption format +# +# @key-secret: #optional the ID of a QCryptoSecret object providing the +# decryption key
...Although you may want to duplicate it here.
Looks like my review on the earlier version helped, and you addressed most of my comments. What I pointed out above is minor enough that I'm okay if you fix it on the pull request without needing another round of review, so:
Signature · 2 lines
Eric Blake eblake redhat com +1-919-301-3266 Libvirt virtualization library http://libvirt.org
Re: [Qemu-devel] [PATCH v4 13/26] crypto: implement the LUKS block encryption format
Quoted 44 lines · Eric Blake
Quoted 7 lines · Daniel P. Berrange
Provide a block encryption implementation that follows the LUKS/dm-crypt specification.
This supports all combinations of hash, cipher algorithm, cipher mode and iv generator that are implemented by the current crypto layer.
Quoted 5 lines
The notable missing feature is support for the 'xts' cipher mode, which is commonly used for disk encryption instead of 'cbc'. This is because it is not provided by either nettle or libgcrypt. A suitable implementation will be identified & integrated later.
Stale paragraph, you implemented it earlier in the series.
Quoted 10 lines
There is support for opening existing volumes formatted by dm-crypt, and for formatting new volumes. In the latter case it will only use key slot 0.
Signed-off-by Daniel P. Berrange <[email protected]>---
crypto/block-luks.c new file +1
-0+static intcrypto/block-luks.c line 670
Quoted 10 lines
crypto/block-luks.c new file +9
-0+qcrypto_block_luks_open (QCryptoBlock *block, + QCryptoBlockOpenOptions *options, + QCryptoBlockReadFunc readfunc, + void *opaque, + unsigned int flags, + Error **errp) +{ +/* Read the entire LUKS header, minus the key material from +* the underling device */ s/underling/underlying/ (although the typo does read rather humorously - I now have a mental image of a LUKS overlord :)
Quoted 2 lines
+++
b/qapi/crypto.json(quoted diff) +0
-0@@ -117,12 +117,13 @@
Quoted 11 lines
qapi/crypto.json line 148
Quoted 9 lines
qapi/crypto.json +2
-1## # QCryptoBlockOptionsBase:@@ -143,7 +144,8 @@ # The options that apply to QCow/QCow2 AES-CBC encryption format # # @key-secret: #optional the ID of a QCryptoSecret object providing the -# decryption key +# decryption key. Mandatory except when probing image for +# metadata only.Aha - I think this hunk may belong earlier in the series...
Yes, it does belong in the previous patch.
Quoted 7 lines
Quoted 7 lines
qapi/crypto.json +0
-0# # Since: 2.6 ##@@ -151,6 +153,45 @@ 'data': { '*key-secret': 'str' }}
Quoted 9 lines
qapi/crypto.json line 161
Quoted 7 lines
qapi/crypto.json +6
-0## +# QCryptoBlockOptionsLUKS: +# +# The options that apply to LUKS encryption format +# +# @key-secret: #optional the ID of a QCryptoSecret object providing the +# decryption key...Although you may want to duplicate it here.
Yep, will do.
Regards,
Daniel
Signature · 4 lines
|: 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 :|
PATCH v4 14/26 block: add flag to indicate that no I/O will be performed
In reply to Daniel P. BerrangeWhen opening an image it is useful to know whether the caller intends to perform I/O on the image or not. In the case of encrypted images this will allow the block driver to avoid having to prompt for decryption keys when we merely want to query header metadata about the image. eg qemu-img info
This flag is enforced at the top level only, since even if we don't want todo I/O on the 'qcow2' file payload, the underlying 'file' driver will still need todo I/O to read the qcow2 header, for example.
--- block.c | 5 +++-- block/io.c | 2 ++ include/block/block.h | 1 + qemu-img.c | 44 ++++++++++++++++++++++---------------------- 4 files changed, 28 insertions(+), 24 deletions(-)
block.c +3 -2
@@ -720,7 +720,8 @@ static void bdrv_inherited_options(int *child_flags, QDict *child_options, flags |=BDRV_O_UNMAP ;/* Clear flags that only apply to the top layer */ - flags &= ~(BDRV_O_SNAPSHOT |BDRV_O_NO_BACKING |BDRV_O_COPY_ON_READ ); + flags &= ~(BDRV_O_SNAPSHOT |BDRV_O_NO_BACKING |BDRV_O_COPY_ON_READ | +BDRV_O_NO_IO ); *child_flags = flags; }
@@ -740,7 +741,7 @@ static void bdrv_inherited_fmt_options(int *child_flags, QDict *child_options, child_file.inherit_options (child_flags, child_options, parent_flags, parent_options); - *child_flags &= ~BDRV_O_PROTOCOL ; + *child_flags &= ~(BDRV_O_PROTOCOL |BDRV_O_NO_IO ); }const BdrvChildRole child_format = {
block/io.c +2 -0
@@ -862,6 +862,7 @@ static int coroutine_fn bdrv_aligned_preadv(BlockDriverState *bs,assert ((offset & (BDRV_SECTOR_SIZE -1 )) ==0 );assert ((bytes & (BDRV_SECTOR_SIZE -1 )) ==0 );assert (!qiov || bytes == qiov->size); +assert ((bs->open_flags &BDRV_O_NO_IO ) ==0 );/* Handle Copy on Read and associated serialisation */ if (flags &BDRV_REQ_COPY_ON_READ ) {
@@ -1148,6 +1149,7 @@ static int coroutine_fn bdrv_aligned_pwritev(BlockDriverState *bs,assert ((offset & (BDRV_SECTOR_SIZE -1 )) ==0 );assert ((bytes & (BDRV_SECTOR_SIZE -1 )) ==0 );assert (!qiov || bytes == qiov->size); +assert ((bs->open_flags &BDRV_O_NO_IO ) ==0 ); waited =wait_serialising_requests (req);assert (!waited || !req->serialising);
include/block/block.h +1 -0
@@ -91,6 +91,7 @@ typedef struct HDGeometry {#define BDRV_O_PROTOCOL 0x8000/* if no block driver is explicitly given: select an appropriate protocol driver, ignoring the format layer */ +#define BDRV_O_NO_IO 0x10000/* don't initialize for I/O */ #define BDRV_O_CACHE_MASK (BDRV_O_NOCACHE | BDRV_O_CACHE_WB | BDRV_O_NO_FLUSH)
qemu-img.c +22 -22
163 lines not on this page · raw message
Signature · 1 line
2.5.0
PATCH v4 15/26 qemu-img/qemu-io: don't prompt for passwords if not required
In reply to Daniel P. BerrangeThe qemu-img/qemu-io tools prompt for disk encryption passwords regardless of whether any are actually required. Adding a check on bdrv_key_required() avoids this prompt for disk formats which have been converted to the QCryptoSecret APIs.
This is just a temporary hack to ensure the block I/O tests continue to work after each patch, since the last patch will completely delete all the password prompting code.
--- qemu-img.c | 3 ++- qemu-io.c | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-)
qemu-img.c +2 -1
@@ -230,7 +230,8 @@ static int img_open_password(BlockBackend *blk, const char *filename,char password[256 ]; bs =blk_bs (blk); -if (bdrv_is_encrypted (bs) && !(flags &BDRV_O_NO_IO )) { +if (bdrv_is_encrypted (bs) &&bdrv_key_required (bs) && + !(flags &BDRV_O_NO_IO )) {qprintf (quiet,"Disk image '%s' is encrypted.\n" , filename);if (qemu_read_password (password,sizeof (password)) <0 ) {error_report ("No password given" );
qemu-io.c +1 -1
@@ -69,7 +69,7 @@ static int openfile(char *name, int flags, QDict *opts) } bs =blk_bs (qemuio_blk); -if (bdrv_is_encrypted (bs)) { +if (bdrv_is_encrypted (bs) &&bdrv_key_required (bs)) {char password[256 ];printf ("Disk image '%s' is encrypted.\n" , name);if (qemu_read_password (password,sizeof (password)) <0 ) {
Signature · 1 line
2.5.0
PATCH v4 16/26 tests: redirect stderr to stdout for iotests
In reply to Daniel P. BerrangeThe python I/O tests helper for running qemu-img/qemu-io setup stdout to be captured to a pipe, but left stderr untouched. As a result, if something failed in qemu-img/ qemu-io, data written to stderr would get output directly and not line up with data on the test stdout due to buffering. If we explicitly redirect stderr to the same pipe as stdout, things are much clearer when they go wrong.
--- tests/qemu-iotests/iotests.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-)
tests/qemu-iotests/iotests.py +5 -2
@@ -71,7 +71,9 @@ def qemu_img_verbose(*args): def qemu_img_pipe(*args): '''Run qemu-img and return its output''' - subp = subprocess.Popen(qemu_img_args + list(args), stdout=subprocess.PIPE) + subp = subprocess.Popen(qemu_img_args + list(args), + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT) exitcode = subp.wait() if exitcode < 0: sys.stderr.write('qemu-img received signal %i: %s\n' % (-exitcode, ' '.join(qemu_img_args + list(args))))
@@ -80,7 +82,8 @@ def qemu_img_pipe(*args): def qemu_io(*args): '''Run qemu-io and return the stdout data''' args = qemu_io_args + list(args) - subp = subprocess.Popen(args, stdout=subprocess.PIPE) + subp = subprocess.Popen(args, stdout=subprocess.PIPE, + stderr=subprocess.STDOUT) exitcode = subp.wait() if exitcode < 0: sys.stderr.write('qemu-io received signal %i: %s\n' % (-exitcode, ' '.join(args)))
Signature · 1 line
2.5.0
Re: [Qemu-devel] [PATCH v4 16/26] tests: redirect stderr to stdout for iotests
Quoted 9 lines · Daniel P. Berrange
The python I/O tests helper for running qemu-img/qemu-io setup stdout to be captured to a pipe, but left stderr untouched. As a result, if something failed in qemu-img/ qemu-io, data written to stderr would get output directly and not line up with data on the test stdout due to buffering. If we explicitly redirect stderr to the same pipe as stdout, things are much clearer when they go wrong.
Quoted 5 lines
Signed-off-by Daniel P. Berrange <[email protected]>--- tests/qemu-iotests/iotests.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-)
Signature · 2 lines
Eric Blake eblake redhat com +1-919-301-3266 Libvirt virtualization library http://libvirt.org
PATCH v4 17/26 tests: refactor python I/O tests helper main method
In reply to Daniel P. BerrangeThe iotests.py helper provides a main() method for running tests via the python unit test framework. Not all tests will want to use this, so refactor it to split the testing of compatible formats and platforms into separate helper methods
--- tests/qemu-iotests/iotests.py | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-)
tests/qemu-iotests/iotests.py +12 -6
@@ -29,7 +29,8 @@ import qtest import struct __all__ = ['imgfmt', 'imgproto', 'test_dir' 'qemu_img', 'qemu_io', - 'VM', 'QMPTestCase', 'notrun', 'main'] + 'VM', 'QMPTestCase', 'notrun', 'main', 'verify_image_format', + 'verify_platform'] # This will not work if arguments contain spaces but is necessary if we # want to support the override options that ./check supports.
@@ -394,17 +395,22 @@ def notrun(reason): print '%s not run: %s' % (seq, reason) sys.exit(0) -def main(supported_fmts=[], supported_oses=['linux']): - '''Run tests''' - - debug = '-d' in sys.argv - verbosity = 1 +def verify_image_format(supported_fmts=[]): if supported_fmts and (imgfmt not in supported_fmts): notrun('not suitable for this image format: %s' % imgfmt) +def verify_platform(supported_oses=['linux']): if True not in [sys.platform.startswith(x) for x in supported_oses]: notrun('not suitable for this OS: %s' % sys.platform) +def main(supported_fmts=[], supported_oses=['linux']): + '''Run tests''' + + debug = '-d' in sys.argv + verbosity = 1 + verify_image_format(supported_fmts) + verify_platform(supported_oses) + # We need to filter out the time taken from the output so that qemu-iotest # can reliably diff the results against master output. import StringIO
Signature · 1 line
2.5.0
Re: [Qemu-devel] [PATCH v4 17/26] tests: refactor python I/O tests helper main method
Quoted 11 lines · Daniel P. Berrange
The
iotests.pyhelper provides amain()method for running tests via the python unit test framework. Not all tests will want to use this, so refactor it to split the testing of compatible formats and platforms into separate helper methodsSigned-off-by Daniel P. Berrange <[email protected]>--- tests/qemu-iotests/iotests.py | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-)
Signature · 2 lines
Eric Blake eblake redhat com +1-919-301-3266 Libvirt virtualization library http://libvirt.org
PATCH v4 18/26 tests: add output filter to python I/O tests helper
In reply to Daniel P. BerrangeAdd a 'log' method to iotests.py which prints messages to stdout, with optional filtering of data. Port over some standard filters for present in the shell common.filter code.
--- tests/qemu-iotests/iotests.py | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-)
tests/qemu-iotests/iotests.py +24 -1
@@ -30,7 +30,8 @@ import struct __all__ = ['imgfmt', 'imgproto', 'test_dir' 'qemu_img', 'qemu_io', 'VM', 'QMPTestCase', 'notrun', 'main', 'verify_image_format', - 'verify_platform'] + 'verify_platform', 'filter_test_dir', 'filter_win32', + 'filter_qemu_io', 'filter_chown', 'log'] # This will not work if arguments contain spaces but is necessary if we # want to support the override options that ./check supports.
@@ -105,6 +106,28 @@ def create_image(name, size): i = i + 512 file.close() +test_dir_re = re.compile(r"%s" % test_dir) +def filter_test_dir(msg): + return test_dir_re.sub("TEST_DIR", msg) + +win32_re = re.compile(r"\r") +def filter_win32(msg): + return win32_re.sub("", msg) + +qemu_io_re = re.compile(r"[0-9]* ops; [0-9\/:. sec]* \([0-9\/.inf]* [EPTGMKiBbytes]*\/sec and [0-9\/.inf]* ops\/sec\)") +def filter_qemu_io(msg): + msg = filter_win32(msg) + return qemu_io_re.sub("X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)", msg) + +chown_re = re.compile(r"chown [0-9]+:[0-9]+") +def filter_chown(msg): + return chown_re.sub("chown UID:GID", msg) + +def log(msg, filters=[]): + for flt in filters: + msg = flt(msg) + print msg + # Test if 'match' is a recursive subset of 'event' def event_match(event, match=None): if match is None:
Signature · 1 line
2.5.0
Re: [Qemu-devel] [PATCH v4 18/26] tests: add output filter to python I/O tests helper
Quoted 4 lines · Daniel P. Berrange
Add a 'log' method to
iotests.pywhich prints messages to stdout, with optional filtering of data. Port over some standard filters for present in the shell common.filter code.
I'm not sure what you meant by 'for present'.
Quoted 6 lines
Signed-off-by Daniel P. Berrange <[email protected]>--- tests/qemu-iotests/iotests.py | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-)
But the patch itself looks reasonable.
Signature · 2 lines
Eric Blake eblake redhat com +1-919-301-3266 Libvirt virtualization library http://libvirt.org
Re: [Qemu-devel] [PATCH v4 18/26] tests: add output filter to python I/O tests helper
Quoted 7 lines · Eric Blake
Quoted 4 lines · Daniel P. Berrange
Add a 'log' method to
iotests.pywhich prints messages to stdout, with optional filtering of data. Port over some standard filters for present in the shell common.filter code.I'm not sure what you meant by 'for present'.
Nor am I :-)
Perhaps I meant to say 'already present'
Quoted 14 lines
Quoted 6 lines
Signed-off-by Daniel P. Berrange <[email protected]>--- tests/qemu-iotests/iotests.py | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-)But the patch itself looks reasonable.
Reviewed-by Eric Blake <[email protected]>Signature · 2 lines
Eric Blake eblake redhat com +1-919-301-3266 Libvirt virtualization library http://libvirt.org
Regards,
Daniel
Signature · 4 lines
|: 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 :|
PATCH v4 19/26 block: add generic full disk encryption driver
In reply to Daniel P. BerrangeAdd a block driver that is capable of supporting any full disk encryption format. This utilizes the previously added block encryption code, and at this time supports the LUKS format.
The driver code is capable of supporting any format supported by the QCryptoBlock module, so it registers one block driver for each format.
At this time, the "luks" driver is registered. New LUKS compatible volume can be formatted using qemu-img with defaults for all settings.
$ qemu-img create --object secret,data=123456,id=sec0 \
-f luks -o key-secret=sec0 demo.luks 10GAlternatively the cryptographic settings can explicitly set
$ qemu-img create --object secret,data=123456,id=sec0 \
-f luks -o key-secret=sec0,cipher-alg=aes-256,\
cipher-mode=cbc,ivgen-alg=plain64,hash-alg=sha256 \
demo.luks 10GAnd query its size
$ qemu-img info demo.img image: demo.img file format: luks virtual size: 10G (10737418240 bytes) disk size: 132K encrypted: yes
Note that it was not neccessary to provide the password when querying info for the volume. The password is only required when performing I/O on the volume
All volumes created by this new 'luks' driver should be capable of being opened by the kernel dm-crypt driver.
The only algorithms listed in the LUKS spec that are not currently supported by this impl are sha512 and ripemd160 hashes and cast6 cipher.
A new I/O test is added which is used to validate the interoperability of the QEMU implementation of LUKS, with the dm-crypt/cryptsetup implementation. Due to the need to run cryptsetup as root, this test requires that the user have password-less sudo configured.
--- block/Makefile.objs | 2 + block/crypto.c | 579 ++++++++++++ qapi/block-core.json | 22 +- tests/qemu-iotests/146 | 521 ++++++++++ tests/qemu-iotests/146.out | 2252 ++++++++++++++++++++++++++++++++++++++++++++ tests/qemu-iotests/common | 7 + tests/qemu-iotests/group | 1 + 7 files changed, 3382 insertions(+), 2 deletions(-) create mode 100644 block/crypto.c create mode 100755 tests/qemu-iotests/146 create mode 100644 tests/qemu-iotests/146.out
block/Makefile.objs +2 -0
@@ -23,6 +23,8 @@ block-obj-$(CONFIG_LIBSSH2) += ssh.o block-obj-y += accounting.o block-obj-y += write-threshold.o +block-obj-y += crypto.o + common-obj-y += stream.o common-obj-y += commit.o common-obj-y += backup.o
block/crypto.c new file +579 -0
579 lines not on this page · raw message
qapi/block-core.json +20 -2
@@ -242,11 +242,12 @@ # @drv: the name of the block format used to open the backing device. As of # 0.14.0 this can be: 'blkdebug', 'bochs', 'cloop', 'cow', 'dmg', # 'file', 'file', 'ftp', 'ftps', 'host_cdrom', 'host_device', -# 'http', 'https', 'nbd', 'parallels', 'qcow', +# 'http', 'https', 'luks', 'nbd', 'parallels', 'qcow', # 'qcow2', 'raw', 'tftp', 'vdi', 'vmdk', 'vpc', 'vvfat' # 2.2: 'archipelago' added, 'cow' dropped # 2.3: 'host_floppy' deprecated # 2.5: 'host_floppy' dropped +# 2.6: 'luks' added # # @backing_file: #optional the name of the backing file (for copy-on-write) #
@@ -1639,7 +1640,7 @@ { 'enum': 'BlockdevDriver', 'data': [ 'archipelago', 'blkdebug', 'blkverify', 'bochs', 'cloop', 'dmg', 'file', 'ftp', 'ftps', 'host_cdrom', 'host_device', - 'http', 'https', 'null-aio', 'null-co', 'parallels', + 'http', 'https', 'luks', 'null-aio', 'null-co', 'parallels', 'qcow', 'qcow2', 'qed', 'quorum', 'raw', 'tftp', 'vdi', 'vhdx', 'vmdk', 'vpc', 'vvfat' ] }
@@ -1757,6 +1758,22 @@ 'data': { 'file': 'BlockdevRef' } } ## +# @BlockdevOptionsLUKS +# +# Driver specific block device options for LUKS. +# +# @key-secret: #optional the ID of a QCryptoSecret object providing +# the decryption key (since 2.6). Mandatory except when +# doing a metadata-only probe of the image. +# +# Since: 2.6 +## +{ 'struct': 'BlockdevOptionsLUKS', + 'base': 'BlockdevOptionsGenericFormat', + 'data': { '*key-secret': 'str' } } + + +## # @BlockdevOptionsGenericCOWFormat # # Driver specific block device options for image format that have no option
@@ -2093,6 +2110,7 @@ 'http': 'BlockdevOptionsFile', 'https': 'BlockdevOptionsFile', # TODO iscsi: Wait for structured options + 'luks': 'BlockdevOptionsLUKS', # TODO nbd: Should take InetSocketAddress for 'host'? # TODO nfs: Wait for structured options 'null-aio': 'BlockdevOptionsNull',
tests/qemu-iotests/146 new file +521 -0
521 lines not on this page · raw message
tests/qemu-iotests/146.out new file +2252 -0
1,842 lines not on this page · raw message
The rest of this diff is not shown. View the raw message.
Signature · 1 line
2.5.0
Part of the diff is not shown here. View the raw message.
Re: [Qemu-devel] [PATCH v4 19/26] block: add generic full disk encryption driver
Quoted 11 lines · Daniel P. Berrange
Add a block driver that is capable of supporting any full disk encryption format. This utilizes the previously added block encryption code, and at this time supports the LUKS format.
The driver code is capable of supporting any format supported by the QCryptoBlock module, so it registers one block driver for each format.
At this time, the "luks" driver is registered. New LUKS compatible volume can be formatted using qemu-img with defaults for all settings.
Sounds a bit redundant between the 1st and 3rd paragraph; but I'm not sure if I have any suggestions on shortening it for only a single mention that LUKS is the first (and so far only) supported driver.
Quoted 14 lines
$ qemu-img create --object secret,data=123456,id=sec0 \ -f luks -o key-secret=sec0 demo.luks 10GAlternatively the cryptographic settings can explicitly set
$ qemu-img create --object secret,data=123456,id=sec0 \ -f luks -o key-secret=sec0,cipher-alg=aes-256,\ cipher-mode=cbc,ivgen-alg=plain64,hash-alg=sha256 \ demo.luks 10GAnd query its size
Quoted 8 lines
$ qemu-img info demo.img image: demo.img file format: luks virtual size: 10G (10737418240 bytes) disk size: 132K encrypted: yesNote that it was not neccessary to provide the password
s/neccessary/necessary/
Quoted 10 lines
when querying info for the volume. The password is only required when performing I/O on the volume
All volumes created by this new 'luks' driver should be capable of being opened by the kernel dm-crypt driver.
The only algorithms listed in the LUKS spec that are not currently supported by this impl are sha512 and ripemd160 hashes and cast6 cipher.
Quoted 5 lines
A new I/O test is added which is used to validate the interoperability of the QEMU implementation of LUKS, with the dm-crypt/cryptsetup implementation. Due to the need to run cryptsetup as root, this test requires that the user have password-less sudo configured.
and therefore, the test better not be run by default, but by an explicit target. Worth spelling out what that target is? [1]
Quoted 17 lines
Signed-off-by Daniel P. Berrange <[email protected]>---
block/crypto.c new file +14
-0+ +static QCryptoBlockOpenOptions * +block_crypto_open_opts_init (QCryptoBlockFormat format, +QemuOpts *opts, +Error **errp) +{ +OptsVisitor *ov; +QCryptoBlockOpenOptions *ret; +QCryptoBlockOptionsLUKS *tmp; +Error *local_err =NULL ; + + ret =g_new0 (QCryptoBlockOpenOptions,1 ); + ret->format = format; +
block/crypto.c line 213
Quoted 10 lines
block/crypto.c new file +10
-0+ ov =opts_visitor_new (opts); + +switch (format) { +case Q_CRYPTO_BLOCK_FORMAT_LUKS : +visit_type_QCryptoBlockOptionsLUKS (opts_get_visitor (ov),"luks" , + &tmp, &local_err); +if (!local_err) { +memcpy (&ret->u.luks, tmp,sizeof (*tmp)); +g_free (tmp); + }
Commit 4d91e911 has landed; you should be using visit_type_QCryptoBlockOptionsLUKS_members() here rather than tmp and memcpy().
Quoted 31 lines
block/crypto.c new file +31
-0+break ; + +default : +error_setg (&local_err,"Unsupported block format %d" , format); +break ; + } + +if (local_err) { +error_propagate (errp, local_err); +opts_visitor_cleanup (ov); +qapi_free_QCryptoBlockOpenOptions (ret); +return NULL ; + } + +opts_visitor_cleanup (ov); +return ret; +} + + +static QCryptoBlockCreateOptions * +block_crypto_create_opts_init (QCryptoBlockFormat format, +QemuOpts *opts, +Error **errp) +{ +OptsVisitor *ov; +QCryptoBlockCreateOptions *ret; +QCryptoBlockCreateOptionsLUKS *tmp; +Error *local_err =NULL ; + + ret =g_new0 (QCryptoBlockCreateOptions,1 ); + ret->format = format;
block/crypto.c line 254
Quoted 10 lines
block/crypto.c new file +10
-0+ + ov =opts_visitor_new (opts); + +switch (format) { +case Q_CRYPTO_BLOCK_FORMAT_LUKS : +visit_type_QCryptoBlockCreateOptionsLUKS (opts_get_visitor (ov),"luks" , + &tmp, &local_err); +if (!local_err) { +memcpy (&ret->u.luks, tmp,sizeof (*tmp)); +g_free (tmp);
And again.
block/crypto.c line 316
Quoted 11 lines
block/crypto.c new file +10
-0+static int block_crypto_open_generic (QCryptoBlockFormat format, +QemuOptsList *opts_spec, +BlockDriverState *bs, +QDict *options, +int flags, +Error **errp) +{ + + bs->encrypted =1 ; + bs->valid_key =1 ;
These look like they should be bool; but then again, I think you are getting rid of them later in the series, so it's not worth the churn.
qapi/block-core.json line 250
Quoted 12 lines
+++
b/qapi/block-core.jsonqapi/block-core.json +2
-1@@ -242,11 +242,12 @@ # @drv: the name of the block format used to open the backing device. As of # 0.14.0 this can be: 'blkdebug', 'bochs', 'cloop', 'cow', 'dmg', # 'file', 'file', 'ftp', 'ftps', 'host_cdrom', 'host_device', -# 'http', 'https', 'nbd', 'parallels', 'qcow', +# 'http', 'https', 'luks', 'nbd', 'parallels', 'qcow', # 'qcow2', 'raw', 'tftp', 'vdi', 'vmdk', 'vpc', 'vvfat' # 2.2: 'archipelago' added, 'cow' dropped # 2.3: 'host_floppy' deprecated # 2.5: 'host_floppy' dropped +# 2.6: 'luks' added
Nice - you remembered docs.
Quoted 9 lines
tests/qemu-iotests/146 new file +7
-0+++ b/tests/qemu-iotests/146@@ -0,0 +1,521 @@ + +def verify_passwordless_sudo(): + """Check whether sudo is configured to allow + password-less access to commands""" + + args = ["sudo", "-n", "/bin/true"]
tests/qemu-iotests/146 line 107
Quoted 10 lines
tests/qemu-iotests/146 new file +10
-0+ + proc = subprocess.Popen(args, + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT) + + msg = proc.communicate()[0] + + if proc.returncode != 0: + iotests.notrun('requires password-less sudo access: %s' % msg)
[1] Okay, the check is part of qemu-iotests (not run as part of 'make check', but independently run), and looks like this should do the job of making it obvious whether the test was skipped due to setup reasons.
Overall looks like a nice test. The changes above about using the more efficient _members() visit could be done as a followup if desired, so I'm okay if you fix the commit message typo and add:
Signature · 2 lines
Eric Blake eblake redhat com +1-919-301-3266 Libvirt virtualization library http://libvirt.org
Re: [Qemu-devel] [PATCH v4 19/26] block: add generic full disk encryption driver
Quoted 52 lines · Eric Blake
Quoted 11 lines · Daniel P. Berrange
Add a block driver that is capable of supporting any full disk encryption format. This utilizes the previously added block encryption code, and at this time supports the LUKS format.
The driver code is capable of supporting any format supported by the QCryptoBlock module, so it registers one block driver for each format.
At this time, the "luks" driver is registered. New LUKS compatible volume can be formatted using qemu-img with defaults for all settings.
Sounds a bit redundant between the 1st and 3rd paragraph; but I'm not sure if I have any suggestions on shortening it for only a single mention that LUKS is the first (and so far only) supported driver.
Quoted 14 lines
$ qemu-img create --object secret,data=123456,id=sec0 \ -f luks -o key-secret=sec0 demo.luks 10GAlternatively the cryptographic settings can explicitly set
$ qemu-img create --object secret,data=123456,id=sec0 \ -f luks -o key-secret=sec0,cipher-alg=aes-256,\ cipher-mode=cbc,ivgen-alg=plain64,hash-alg=sha256 \ demo.luks 10GAnd query its size
Quoted 8 lines
$ qemu-img info demo.img image: demo.img file format: luks virtual size: 10G (10737418240 bytes) disk size: 132K encrypted: yesNote that it was not neccessary to provide the password
s/neccessary/necessary/
Quoted 10 lines
when querying info for the volume. The password is only required when performing I/O on the volume
All volumes created by this new 'luks' driver should be capable of being opened by the kernel dm-crypt driver.
The only algorithms listed in the LUKS spec that are not currently supported by this impl are sha512 and ripemd160 hashes and cast6 cipher.
Quoted 8 lines
Quoted 5 lines
A new I/O test is added which is used to validate the interoperability of the QEMU implementation of LUKS, with the dm-crypt/cryptsetup implementation. Due to the need to run cryptsetup as root, this test requires that the user have password-less sudo configured.
and therefore, the test better not be run by default, but by an explicit target. Worth spelling out what that target is? [1]
Yes, for reference it is
cd tests/qemu-iotests
./check -luks 146
...and then wait a long time :-)
In theory the other pre-existing I/O tests should also pass, but the current I/O test infrastructure isn't clever enough to provide the key secrets needed when creating the images. I'll be working on fixing this test suite limitation later...
Regards,
Daniel
Signature · 4 lines
|: 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 :|
PATCH v4 20/26 qcow2: make qcow2_encrypt_sectors encrypt in place
In reply to Daniel P. BerrangeInstead of requiring separate input/output buffers for encrypting data, change qcow2_encrypt_sectors() to assume use of a single buffer, encrypting in place. The current callers all used the same buffer for input/output already.
--- block/qcow2-cluster.c | 17 +++++------------ block/qcow2.c | 5 ++--- block/qcow2.h | 3 +-- 3 files changed, 8 insertions(+), 17 deletions(-)
block/qcow2-cluster.c +5 -12
@@ -342,12 +342,8 @@ static int count_contiguous_clusters_by_type(int nb_clusters,return i; } -/* The crypt function is compatible with the linux cryptoloop -algorithm for < 4 GB images. NOTE: out_buf == in_buf is -supported */ int qcow2_encrypt_sectors (BDRVQcow2State *s,int64_t sector_num, -uint8_t *out_buf,const uint8_t *in_buf, -int nb_sectors,bool enc, +uint8_t *buf,int nb_sectors,bool enc,Error **errp) {union {
@@ -367,14 +363,12 @@ int qcow2_encrypt_sectors(BDRVQcow2State *s, int64_t sector_num, }if (enc) { ret =qcrypto_cipher_encrypt (s->cipher, - in_buf, - out_buf, + buf, buf,512 , errp); }else { ret =qcrypto_cipher_decrypt (s->cipher, - in_buf, - out_buf, + buf, buf,512 , errp); }
@@ -382,8 +376,7 @@ int qcow2_encrypt_sectors(BDRVQcow2State *s, int64_t sector_num,return -1 ; } sector_num++; - in_buf +=512 ; - out_buf +=512 ; + buf +=512 ; }return 0 ; }
@@ -431,7 +424,7 @@ static int coroutine_fn copy_sectors(BlockDriverState *bs,Error *err =NULL ;assert (s->cipher);if (qcow2_encrypt_sectors (s, start_sect + n_start, - iov.iov_base, iov.iov_base, n, + iov.iov_base, n, true, &err) <0 ) { ret = -EIO ;error_free (err);
block/qcow2.c +2 -3
@@ -1506,7 +1506,7 @@ static coroutine_fn int qcow2_co_readv(BlockDriverState *bs, int64_t sector_num,assert (s->cipher);Error *err =NULL ;if (qcow2_encrypt_sectors (s, sector_num, cluster_data, - cluster_data, cur_nr_sectors, false, + cur_nr_sectors, false, &err) <0 ) {error_free (err); ret = -EIO ;
@@ -1606,8 +1606,7 @@ static coroutine_fn int qcow2_co_writev(BlockDriverState *bs,qemu_iovec_to_buf (&hd_qiov,0 , cluster_data, hd_qiov.size);if (qcow2_encrypt_sectors (s, sector_num, cluster_data, - cluster_data, cur_nr_sectors, - true, &err) <0 ) { + cur_nr_sectors, true, &err) <0 ) {error_free (err); ret = -EIO ; goto fail;
block/qcow2.h +1 -2
@@ -540,8 +540,7 @@ int qcow2_write_l1_entry(BlockDriverState *bs, int l1_index);void qcow2_l2_cache_reset (BlockDriverState *bs);int qcow2_decompress_cluster (BlockDriverState *bs,uint64_t cluster_offset);int qcow2_encrypt_sectors (BDRVQcow2State *s,int64_t sector_num, -uint8_t *out_buf,const uint8_t *in_buf, -int nb_sectors,bool enc,Error **errp); +uint8_t *buf,int nb_sectors,bool enc,Error **errp);int qcow2_get_cluster_offset (BlockDriverState *bs,uint64_t offset,int *num,uint64_t *cluster_offset);
Signature · 1 line
2.5.0
PATCH v4 21/26 qcow2: convert QCow2 to use QCryptoBlock for encryption
In reply to Daniel P. BerrangeThis converts the qcow2 driver to make use of the QCryptoBlock APIs for encrypting image content. As well as continued support for the legacy QCow2 encryption format, the appealing benefit is that it enables support for the LUKS format inside qcow2.
With the LUKS format it is necessary to store the LUKS partition header and key material in the QCow2 file. This data can be many MB in size, so cannot go into the QCow2 header region directly. Thus the spec defines a FDE (Full Disk Encryption) header extension that specifies the offset of a set of clusters to hold the FDE headers, as well as the length of that region. The LUKS header is thus stored in these extra allocated clusters before the main image payload.
With this change it is now required to use the QCryptoSecret object for providing passwords, instead of the current block password APIs / interactive prompting.
$QEMU \
-object secret,id=sec0,filename=/home/berrange/encrypted.pw \
-drive file=/home/berrange/encrypted.qcow2,key-secret=sec0The new LUKS format is set as the new default format when creating encrypted images. ie
# qemu-img create --object secret,data=123456,id=sec0 \
-f qcow2 -o encryption,key-secret=sec0 \
test.qcow2 10Gresults in the creation of an image using the LUKS format.
For compatibility the old qcow2 AES format can still be used via the 'encryption-format' parameter which accepts the values 'luks' or 'qcow'.
# qemu-img create --object secret,data=123456,id=sec0 \
-f qcow2 -o encryption,key-secret=sec0,encryption-format=qcow \
test.qcow2 10G--- block/qcow2-cluster.c | 46 +--- block/qcow2-refcount.c | 10 + block/qcow2.c | 511 ++++++++++++++++++++++++++++++++++++++------- block/qcow2.h | 21 +- docs/specs/qcow2.txt | 76 +++++++ qapi/block-core.json | 7 +- tests/qemu-iotests/049 | 2 +- tests/qemu-iotests/049.out | 7 +- tests/qemu-iotests/082.out | 189 +++++++++++++++++ tests/qemu-iotests/087 | 28 ++- tests/qemu-iotests/087.out | 16 +- tests/qemu-iotests/134 | 18 +- tests/qemu-iotests/134.out | 21 +- tests/qemu-iotests/common | 1 + 14 files changed, 788 insertions(+), 165 deletions(-)
block/qcow2-cluster.c +3 -43
@@ -342,45 +342,6 @@ static int count_contiguous_clusters_by_type(int nb_clusters,return i; } -int qcow2_encrypt_sectors (BDRVQcow2State *s,int64_t sector_num, -uint8_t *buf,int nb_sectors,bool enc, -Error **errp) -{ -union { -uint64_t ll[2 ]; -uint8_t b[16 ]; - } ivec; -int i; -int ret; - -for (i =0 ; i < nb_sectors; i++) { - ivec.ll[0 ] =cpu_to_le64 (sector_num); - ivec.ll[1 ] =0 ; -if (qcrypto_cipher_setiv (s->cipher, - ivec.b,G_N_ELEMENTS (ivec.b), - errp) <0 ) { -return -1 ; - } -if (enc) { - ret =qcrypto_cipher_encrypt (s->cipher, - buf, buf, -512 , - errp); - }else { - ret =qcrypto_cipher_decrypt (s->cipher, - buf, buf, -512 , - errp); - } -if (ret <0 ) { -return -1 ; - } - sector_num++; - buf +=512 ; - } -return 0 ; -} - static int coroutine_fn copy_sectors(BlockDriverState *bs, uint64_t start_sect, uint64_t cluster_offset,
@@ -422,10 +383,9 @@ static int coroutine_fn copy_sectors(BlockDriverState *bs,if (bs->encrypted) {Error *err =NULL ; -assert (s->cipher); -if (qcow2_encrypt_sectors (s, start_sect + n_start, - iov.iov_base, n, - true, &err) <0 ) { +assert (s->crypto); +if (qcrypto_block_encrypt (s->crypto, start_sect + n_start, + iov.iov_base, n, &err) <0 ) { ret = -EIO ;error_free (err); goto out;
block/qcow2-refcount.c +10 -0
@@ -1848,6 +1848,16 @@ static int calculate_refcounts(BlockDriverState *bs, BdrvCheckResult *res,return ret; } +/* encryption */ +if (s->crypto_header.length) { + ret =inc_refcounts (bs, res, refcount_table, nb_clusters, + s->crypto_header.offset, + s->crypto_header.length); +if (ret <0 ) { +return ret; + } + } +return check_refblocks (bs, res, fix, rebuild, refcount_table, nb_clusters); }
block/qcow2.c +436 -75
722 lines not on this page · raw message
block/qcow2.h +19 -2
@@ -25,7 +25,7 @@#ifndef BLOCK_QCOW2_H #define BLOCK_QCOW2_H -#include "crypto/cipher.h" +#include "crypto/block.h" #include "qemu/coroutine.h" //#define DEBUG_ALLOC
@@ -36,6 +36,7 @@#define QCOW_CRYPT_NONE 0#define QCOW_CRYPT_AES 1 +#define QCOW_CRYPT_LUKS 2#define QCOW_MAX_CRYPT_CLUSTERS 32#define QCOW_MAX_SNAPSHOTS 65536
@@ -98,6 +99,15 @@#define QCOW2_OPT_REFCOUNT_CACHE_SIZE "refcount-cache-size"#define QCOW2_OPT_CACHE_CLEAN_INTERVAL "cache-clean-interval" +#define QCOW2_OPT_CRYPTO_FORMAT "encryption-format" +#define QCOW2_OPT_KEY_SECRET "key-secret" +#define QCOW2_OPT_CIPHER_ALG "cipher-alg" +#define QCOW2_OPT_CIPHER_MODE "cipher-mode" +#define QCOW2_OPT_IVGEN_ALG "ivgen-alg" +#define QCOW2_OPT_IVGEN_HASH_ALG "ivgen-hash-alg" +#define QCOW2_OPT_HASH_ALG "hash-alg" + + typedef struct QCowHeader { uint32_t magic; uint32_t version;
@@ -163,6 +173,11 @@ typedef struct QCowSnapshot {struct Qcow2Cache ;typedef struct Qcow2Cache Qcow2Cache ; +typedef struct Qcow2CryptoHeaderExtension { +uint64_t offset; +uint64_t length; +} QEMU_PACKED Qcow2CryptoHeaderExtension; + typedef struct Qcow2UnknownHeaderExtension { uint32_t magic; uint32_t len;
@@ -256,7 +271,9 @@ typedef struct BDRVQcow2State {CoMutex lock; -QCryptoCipher *cipher;/* current cipher, NULL if no key yet */ +Qcow2CryptoHeaderExtension crypto_header;/* QCow2 header extension */ +QCryptoBlockOpenOptions *crypto_opts;/* Disk encryption runtime options */ +QCryptoBlock *crypto;/* Disk encryption format driver */ uint32_t crypt_method_header;uint64_t snapshots_offset;int snapshots_size;
docs/specs/qcow2.txt +76 -0
94 lines not on this page · raw message
qapi/block-core.json +5 -2
@@ -1884,6 +1884,9 @@ # @cache-clean-interval: #optional clean unused entries in the L2 and refcount # caches. The interval is in seconds. The default value # is 0 and it disables this feature (since 2.5) +# @key-secret: #optional the ID of a QCryptoSecret object providing +# the decryption key (since 2.6) Mandatory except when +# doing a metadata-only probe of the image. # # Since: 1.7 ##
@@ -1897,8 +1900,8 @@ '*cache-size': 'int', '*l2-cache-size': 'int', '*refcount-cache-size': 'int', - '*cache-clean-interval': 'int' } } - + '*cache-clean-interval': 'int', + '*key-secret': 'str' } } ## # @BlockdevOptionsArchipelago
tests/qemu-iotests/049 +1 -1
@@ -107,7 +107,7 @@ test_qemu_img create -f $IMGFMT -o preallocation=1234 "$TEST_IMG" 64M echo "== Check encryption option ==" echo test_qemu_img create -f $IMGFMT -o encryption=off "$TEST_IMG" 64M -test_qemu_img create -f $IMGFMT -o encryption=on "$TEST_IMG" 64M +test_qemu_img create -f $IMGFMT --object secret,id=sec0,data=123456 -o encryption=on,key-secret=sec0 "$TEST_IMG" 64M echo "== Check lazy_refcounts option (only with v3) ==" echo
tests/qemu-iotests/049.out +2 -5
@@ -186,14 +186,11 @@ Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_si qemu-img create -f qcow2 -o encryption=off TEST_DIR/t.qcow2 64M Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16 -qemu-img create -f qcow2 -o encryption=on TEST_DIR/t.qcow2 64M +qemu-img create -f qcow2 --object secret,id=sec0,data=123456 -o encryption=on,key-secret=sec0 TEST_DIR/t.qcow2 64M qemu-img: Encrypted images are deprecated Support for them will be removed in a future release. You can use 'qemu-img convert' to convert your image to an unencrypted one. -qemu-img: Encrypted images are deprecated -Support for them will be removed in a future release. -You can use 'qemu-img convert' to convert your image to an unencrypted one. -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=on cluster_size=65536 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=on cluster_size=65536 lazy_refcounts=off refcount_bits=16 key-secret=sec0 == Check lazy_refcounts option (only with v3) ==
tests/qemu-iotests/082.out +189 -0
351 lines not on this page · raw message
tests/qemu-iotests/087 +24 -4
@@ -184,9 +184,18 @@ echo echo === Encrypted image === echo -_make_test_img -o encryption=on $size +_make_test_img --object secret,id=sec0,data=123456 -o encryption=on,key-secret=sec0 $size run_qemu -S <<EOF { "execute": "qmp_capabilities" } +{ "execute": "object-add", + "arguments": { + "qom-type": "secret", + "id": "sec0", + "props": { + "data": "123456" + } + } +} { "execute": "blockdev-add", "arguments": { "options": {
@@ -195,7 +204,8 @@ run_qemu -S <<EOF "file": { "driver": "file", "filename": "$TEST_IMG" - } + }, + "key-secret": "sec0" } } }
@@ -204,6 +214,15 @@ EOF run_qemu <<EOF { "execute": "qmp_capabilities" } +{ "execute": "object-add", + "arguments": { + "qom-type": "secret", + "id": "sec0", + "props": { + "data": "123456" + } + } +} { "execute": "blockdev-add", "arguments": { "options": {
@@ -212,7 +231,8 @@ run_qemu <<EOF "file": { "driver": "file", "filename": "$TEST_IMG" - } + }, + "key-secret": "sec0" } } }
@@ -223,7 +243,7 @@ echo echo === Missing driver === echo -_make_test_img -o encryption=on $size +_make_test_img --object secret,id=sec0,data=123456 -o encryption=on,key-secret=sec0 $size run_qemu -S <<EOF { "execute": "qmp_capabilities" } { "execute": "blockdev-add",
tests/qemu-iotests/087.out +6 -10
@@ -41,27 +41,26 @@ QMP_VERSION qemu-img: Encrypted images are deprecated Support for them will be removed in a future release. You can use 'qemu-img convert' to convert your image to an unencrypted one. -qemu-img: Encrypted images are deprecated -Support for them will be removed in a future release. -You can use 'qemu-img convert' to convert your image to an unencrypted one. -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 encryption=on +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 encryption=on key-secret=sec0 Testing: -S QMP_VERSION {"return": {}} +{"return": {}} Encrypted images are deprecated Support for them will be removed in a future release. You can use 'qemu-img convert' to convert your image to an unencrypted one. -{"error": {"class": "GenericError", "desc": "blockdev-add doesn't support encrypted devices"}} +{"return": {}} {"return": {}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN"} Testing: QMP_VERSION {"return": {}} +{"return": {}} Encrypted images are deprecated Support for them will be removed in a future release. You can use 'qemu-img convert' to convert your image to an unencrypted one. -{"error": {"class": "GenericError", "desc": "Guest must be stopped for opening of encrypted image"}} +{"return": {}} {"return": {}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN"}
@@ -71,10 +70,7 @@ You can use 'qemu-img convert' to convert your image to an unencrypted one. qemu-img: Encrypted images are deprecated Support for them will be removed in a future release. You can use 'qemu-img convert' to convert your image to an unencrypted one. -qemu-img: Encrypted images are deprecated -Support for them will be removed in a future release. -You can use 'qemu-img convert' to convert your image to an unencrypted one. -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 encryption=on +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 encryption=on key-secret=sec0 Testing: -S QMP_VERSION {"return": {}}
tests/qemu-iotests/134 +13 -5
@@ -44,23 +44,31 @@ _supported_os Linux size=128M -IMGOPTS="encryption=on" _make_test_img $size + +SECRET="secret,id=sec0,data=astrochicken" +SECRETALT="secret,id=sec0,data=platypus" + +_make_test_img --object $SECRET -o "encryption=on,key-secret=sec0" $size + +IMGSPEC="driver=$IMGFMT,file.filename=$TEST_IMG,key-secret=sec0" + +QEMU_IO_OPTIONS=$QEMU_IO_OPTIONS_NO_FMT echo echo "== reading whole image ==" -echo "astrochicken" | $QEMU_IO -c "read 0 $size" "$TEST_IMG" | _filter_qemu_io | _filter_testdir +$QEMU_IO --object $SECRET -c "read 0 $size" --options $IMGSPEC | _filter_qemu_io | _filter_testdir echo echo "== rewriting whole image ==" -echo "astrochicken" | $QEMU_IO -c "write -P 0xa 0 $size" "$TEST_IMG" | _filter_qemu_io | _filter_testdir +$QEMU_IO --object $SECRET -c "write -P 0xa 0 $size" --options $IMGSPEC | _filter_qemu_io | _filter_testdir echo echo "== verify pattern ==" -echo "astrochicken" | $QEMU_IO -c "read -P 0xa 0 $size" "$TEST_IMG" | _filter_qemu_io | _filter_testdir +$QEMU_IO --object $SECRET -c "read -P 0xa 0 $size" --options $IMGSPEC | _filter_qemu_io | _filter_testdir echo echo "== verify pattern failure with wrong password ==" -echo "platypus" | $QEMU_IO -c "read -P 0xa 0 $size" "$TEST_IMG" | _filter_qemu_io | _filter_testdir +$QEMU_IO --object $SECRETALT -c "read -P 0xa 0 $size" --options $IMGSPEC | _filter_qemu_io | _filter_testdir # success, all done
tests/qemu-iotests/134.out +3 -18
@@ -2,17 +2,12 @@ QA output created by 134 qemu-img: Encrypted images are deprecated Support for them will be removed in a future release. You can use 'qemu-img convert' to convert your image to an unencrypted one. -qemu-img: Encrypted images are deprecated -Support for them will be removed in a future release. -You can use 'qemu-img convert' to convert your image to an unencrypted one. -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 encryption=on +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 encryption=on key-secret=sec0 == reading whole image == Encrypted images are deprecated Support for them will be removed in a future release. You can use 'qemu-img convert' to convert your image to an unencrypted one. -Disk image 'TEST_DIR/t.qcow2' is encrypted. -password: read 134217728/134217728 bytes at offset 0 128 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@@ -20,8 +15,6 @@ read 134217728/134217728 bytes at offset 0 Encrypted images are deprecated Support for them will be removed in a future release. You can use 'qemu-img convert' to convert your image to an unencrypted one. -Disk image 'TEST_DIR/t.qcow2' is encrypted. -password: wrote 134217728/134217728 bytes at offset 0 128 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@@ -29,18 +22,10 @@ wrote 134217728/134217728 bytes at offset 0 Encrypted images are deprecated Support for them will be removed in a future release. You can use 'qemu-img convert' to convert your image to an unencrypted one. -Disk image 'TEST_DIR/t.qcow2' is encrypted. -password: read 134217728/134217728 bytes at offset 0 128 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) == verify pattern failure with wrong password == -Encrypted images are deprecated -Support for them will be removed in a future release. -You can use 'qemu-img convert' to convert your image to an unencrypted one. -Disk image 'TEST_DIR/t.qcow2' is encrypted. -password: -Pattern verification failed at offset 0, 134217728 bytes -read 134217728/134217728 bytes at offset 0 -128 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +can't open: Invalid password, cannot unlock any keyslot +no file open, try 'help open' *** done
tests/qemu-iotests/common +1 -0
@@ -405,6 +405,7 @@ BEGIN { for (t='$start'; t<='$end'; t++) printf "%03d\n",t }' \ done # Set qemu-io cache mode with $CACHEMODE we have +QEMU_IO_OPTIONS_NO_FMT="$QEMU_IO_OPTIONS --cache $CACHEMODE" QEMU_IO_OPTIONS="$QEMU_IO_OPTIONS -f $IMGFMT --cache $CACHEMODE" # Set default options for qemu-img create -o if they were not specified
Signature · 1 line
2.5.0
PATCH v4 22/26 qcow: make encrypt_sectors encrypt in place
In reply to Daniel P. BerrangeInstead of requiring separate input/output buffers for encrypting data, change encrypt_sectors() to assume use of a single buffer, encrypting in place. One current caller all uses the same buffer for input/output already and the other two callers are easily converted todo so.
--- block/qcow.c | 36 ++++++++++-------------------------- 1 file changed, 10 insertions(+), 26 deletions(-)
block/qcow.c +10 -26
@@ -294,12 +294,9 @@ static int qcow_set_key(BlockDriverState *bs, const char *key)return 0 ; } -/* The crypt function is compatible with the linux cryptoloop -algorithm for < 4 GB images. NOTE: out_buf == in_buf is -supported */ static int encrypt_sectors (BDRVQcowState *s,int64_t sector_num, -uint8_t *out_buf,const uint8_t *in_buf, -int nb_sectors,bool enc,Error **errp) +uint8_t *buf,int nb_sectors,bool enc, +Error **errp) {union {uint64_t ll[2 ];
@@ -318,14 +315,12 @@ static int encrypt_sectors(BDRVQcowState *s, int64_t sector_num, }if (enc) { ret =qcrypto_cipher_encrypt (s->cipher, - in_buf, - out_buf, + buf, buf,512 , errp); }else { ret =qcrypto_cipher_decrypt (s->cipher, - in_buf, - out_buf, + buf, buf,512 , errp); }
@@ -333,8 +328,7 @@ static int encrypt_sectors(BDRVQcowState *s, int64_t sector_num,return -1 ; } sector_num++; - in_buf +=512 ; - out_buf +=512 ; + buf +=512 ; }return 0 ; }
@@ -454,13 +448,12 @@ static uint64_t get_cluster_offset(BlockDriverState *bs,uint64_t start_sect;assert (s->cipher); start_sect = (offset & ~(s->cluster_size -1 )) >>9 ; -memset (s->cluster_data +512 ,0x00 ,512 ); +memset (s->cluster_data,0x00 ,512 );for (i =0 ; i < s->cluster_sectors; i++) {if (i < n_start || i >= n_end) {Error *err =NULL ;if (encrypt_sectors (s, start_sect + i, - s->cluster_data, - s->cluster_data +512 ,1 , + s->cluster_data,1 , true, &err) <0 ) {error_free (err); errno =EIO ;
@@ -639,7 +632,7 @@ static coroutine_fn int qcow_co_readv(BlockDriverState *bs, int64_t sector_num, }if (bs->encrypted) {assert (s->cipher); -if (encrypt_sectors (s, sector_num, buf, buf, +if (encrypt_sectors (s, sector_num, buf, n, false, &err) <0 ) { goto fail; }
@@ -674,9 +667,7 @@ static coroutine_fn int qcow_co_writev(BlockDriverState *bs, int64_t sector_num,BDRVQcowState *s = bs->opaque;int index_in_cluster;uint64_t cluster_offset; -const uint8_t *src_buf;int ret =0 , n; -uint8_t *cluster_data =NULL ;struct iovec hd_iov;QEMUIOVector hd_qiov;uint8_t *buf;
@@ -714,21 +705,15 @@ static coroutine_fn int qcow_co_writev(BlockDriverState *bs, int64_t sector_num,if (bs->encrypted) {Error *err =NULL ;assert (s->cipher); -if (!cluster_data) { - cluster_data =g_malloc0 (s->cluster_size); - } -if (encrypt_sectors (s, sector_num, cluster_data, buf, +if (encrypt_sectors (s, sector_num, buf, n, true, &err) <0 ) {error_free (err); ret = -EIO ;break ; } - src_buf = cluster_data; - }else { - src_buf = buf; } - hd_iov.iov_base = (void *)src_buf; + hd_iov.iov_base = (void *)buf; hd_iov.iov_len = n *512 ;qemu_iovec_init_external (&hd_qiov, &hd_iov,1 );qemu_co_mutex_unlock (&s->lock);
@@ -750,7 +735,6 @@ static coroutine_fn int qcow_co_writev(BlockDriverState *bs, int64_t sector_num,if (qiov->niov >1 ) {qemu_vfree (orig_buf); } -g_free (cluster_data);return ret; }
Signature · 1 line
2.5.0
PATCH v4 23/26 qcow: convert QCow to use QCryptoBlock for encryption
In reply to Daniel P. BerrangeThis converts the qcow2 driver to make use of the QCryptoBlock APIs for encrypting image content. This is only wired up to permit use of the legacy QCow encryption format. Users who wish to have the strong LUKS format should switch to qcow2 instead.
With this change it is now required to use the QCryptoSecret object for providing passwords, instead of the current block password APIs / interactive prompting.
$QEMU \
-object secret,id=sec0,filename=/home/berrange/encrypted.pw \
-drive file=/home/berrange/encrypted.qcow,key-secret=sec0--- block/qcow.c | 176 +++++++++++++++++++++++---------------------------- qapi/block-core.json | 17 ++++- 2 files changed, 96 insertions(+), 97 deletions(-)
block/qcow.c +80 -96
@@ -27,7 +27,9 @@#include "qemu/module.h" #include <zlib.h> #include "qapi/qmp/qerror.h" -#include "crypto/cipher.h" +#include "crypto/block.h" +#include "qapi/opts-visitor.h" +#include "qapi-visit.h" #include "migration/migration.h" /**************************************************************/
@@ -41,6 +43,8 @@#define QCOW_OFLAG_COMPRESSED (1LL << 63) +#define QCOW_OPT_KEY_SECRET "key-secret" + typedef struct QCowHeader { uint32_t magic; uint32_t version;
@@ -73,7 +77,7 @@ typedef struct BDRVQcowState {uint8_t *cluster_cache;uint8_t *cluster_data;uint64_t cluster_cache_offset; -QCryptoCipher *cipher;/* NULL if no key yet */ +QCryptoBlock *crypto;/* Disk encryption format driver */ uint32_t crypt_method_header;CoMutex lock;Error *migration_blocker;
@@ -93,6 +97,19 @@ static int qcow_probe(const uint8_t *buf, int buf_size, const char *filename)return 0 ; } +static QemuOptsList qcow_runtime_opts = { + .name ="qcow" , + .head =QTAILQ_HEAD_INITIALIZER (qcow_runtime_opts.head), + .desc = { + { + .name =QCOW_OPT_KEY_SECRET , + .type =QEMU_OPT_STRING , + .help ="ID of the secret that provides the encryption key" , + }, + {/* end of list */ } + }, +}; +static int qcow_open (BlockDriverState *bs,QDict *options,int flags,Error **errp) {
@@ -100,6 +117,11 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags,unsigned int len, i, shift;int ret;QCowHeader header; +QemuOpts *opts =NULL ; +Error *local_err =NULL ; +QCryptoBlockOpenOptions *crypto_opts =NULL ; +unsigned int cflags =0 ; +OptsVisitor *ov; ret =bdrv_pread (bs->file->bs,0 , &header,sizeof (header));if (ret <0 ) {
@@ -148,19 +170,53 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags, goto fail; } -if (header.crypt_method >QCOW_CRYPT_AES ) { -error_setg (errp,"invalid encryption method in qcow header" ); - ret = -EINVAL ; - goto fail; - } -if (!qcrypto_cipher_supports (QCRYPTO_CIPHER_ALG_AES_128 )) { -error_setg (errp,"AES cipher not available" ); + opts =qemu_opts_create (&qcow_runtime_opts,NULL ,0 , &error_abort); +qemu_opts_absorb_qdict (opts, options, &local_err); +if (local_err) { +error_propagate (errp, local_err); ret = -EINVAL ; goto fail; } + s->crypt_method_header = header.crypt_method;if (s->crypt_method_header) { +if (s->crypt_method_header ==QCOW_CRYPT_AES ) { +QCryptoBlockOptionsQCow *tmp; + ov =opts_visitor_new (opts); + + crypto_opts =g_new0 (QCryptoBlockOpenOptions,1 ); + crypto_opts->format =Q_CRYPTO_BLOCK_FORMAT_QCOW ; +visit_type_QCryptoBlockOptionsQCow (opts_get_visitor (ov), +"qcow" , &tmp, + &local_err); +if (local_err) { +error_propagate (errp, local_err); +opts_visitor_cleanup (ov); + ret = -EINVAL ; + goto fail; + }else { +memcpy (&crypto_opts->u.qcow, tmp,sizeof (*tmp)); +g_free (tmp); + } +opts_visitor_cleanup (ov); + +if (flags &BDRV_O_NO_IO ) { + cflags |=QCRYPTO_BLOCK_OPEN_NO_IO ; + } + s->crypto =qcrypto_block_open (crypto_opts,NULL ,NULL , + cflags, errp); +if (!s->crypto) { +error_setg (errp,"Could not setup encryption layer" ); + ret = -EINVAL ; + goto fail; + } + }else { +error_setg (errp,"invalid encryption method in qcow header" ); + ret = -EINVAL ; + goto fail; + } bs->encrypted =1 ; + bs->valid_key =1 ; } s->cluster_bits = header.cluster_bits; s->cluster_size =1 << s->cluster_bits;
@@ -239,6 +295,7 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags, bdrv_get_device_or_node_name(bs));migrate_add_blocker (s->migration_blocker); +qapi_free_QCryptoBlockOpenOptions (crypto_opts);qemu_co_mutex_init (&s->lock);return 0 ;
@@ -247,6 +304,7 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags,qemu_vfree (s->l2_cache);g_free (s->cluster_cache);g_free (s->cluster_data); +qapi_free_QCryptoBlockOpenOptions (crypto_opts);return ret; }
@@ -259,79 +317,6 @@ static int qcow_reopen_prepare(BDRVReopenState *state,return 0 ; } -static int qcow_set_key (BlockDriverState *bs,const char *key) -{ -BDRVQcowState *s = bs->opaque; -uint8_t keybuf[16 ]; -int len, i; -Error *err; - -memset (keybuf,0 ,16 ); - len =strlen (key); -if (len >16 ) - len =16 ; -/* XXX: we could compress the chars to 7 bits to increase -entropy */ -for (i =0 ;i < len;i++) { - keybuf[i] = key[i]; - } -assert (bs->encrypted); - -qcrypto_cipher_free (s->cipher); - s->cipher =qcrypto_cipher_new ( -QCRYPTO_CIPHER_ALG_AES_128 , -QCRYPTO_CIPHER_MODE_CBC , - keybuf,G_N_ELEMENTS (keybuf), - &err); - -if (!s->cipher) { -/* XXX would be nice if errors in this method could -* be properly propagate to the caller. Would need -* the bdrv_set_key() API signature to be fixed. */ -error_free (err); -return -1 ; - } -return 0 ; -} - -static int encrypt_sectors (BDRVQcowState *s,int64_t sector_num, -uint8_t *buf,int nb_sectors,bool enc, -Error **errp) -{ -union { -uint64_t ll[2 ]; -uint8_t b[16 ]; - } ivec; -int i; -int ret; - -for (i =0 ; i < nb_sectors; i++) { - ivec.ll[0 ] =cpu_to_le64 (sector_num); - ivec.ll[1 ] =0 ; -if (qcrypto_cipher_setiv (s->cipher, - ivec.b,G_N_ELEMENTS (ivec.b), - errp) <0 ) { -return -1 ; - } -if (enc) { - ret =qcrypto_cipher_encrypt (s->cipher, - buf, buf, -512 , - errp); - }else { - ret =qcrypto_cipher_decrypt (s->cipher, - buf, buf, -512 , - errp); - } -if (ret <0 ) { -return -1 ; - } - sector_num++; - buf +=512 ; - } -return 0 ; -}/* 'allocate' is: *
@@ -446,15 +431,15 @@ static uint64_t get_cluster_offset(BlockDriverState *bs,if (bs->encrypted && (n_end - n_start) < s->cluster_sectors) {uint64_t start_sect; -assert (s->cipher); +assert (s->crypto); start_sect = (offset & ~(s->cluster_size -1 )) >>9 ;memset (s->cluster_data,0x00 ,512 );for (i =0 ; i < s->cluster_sectors; i++) {if (i < n_start || i >= n_end) {Error *err =NULL ; -if (encrypt_sectors (s, start_sect + i, - s->cluster_data,1 , - true, &err) <0 ) { +if (qcrypto_block_encrypt (s->crypto, start_sect + i, + s->cluster_data,1 , + &err) <0 ) {error_free (err); errno =EIO ;return -1 ;
@@ -499,7 +484,7 @@ static int64_t coroutine_fn qcow_co_get_block_status(BlockDriverState *bs,if (!cluster_offset) {return 0 ; } -if ((cluster_offset &QCOW_OFLAG_COMPRESSED ) || s->cipher) { +if ((cluster_offset &QCOW_OFLAG_COMPRESSED ) || s->crypto) {return BDRV_BLOCK_DATA ; } cluster_offset |= (index_in_cluster <<BDRV_SECTOR_BITS );
@@ -631,9 +616,9 @@ static coroutine_fn int qcow_co_readv(BlockDriverState *bs, int64_t sector_num,break ; }if (bs->encrypted) { -assert (s->cipher); -if (encrypt_sectors (s, sector_num, buf, - n, false, &err) <0 ) { +assert (s->crypto); +if (qcrypto_block_decrypt (s->crypto, sector_num, buf, + n, &err) <0 ) { goto fail; } }
@@ -704,9 +689,9 @@ static coroutine_fn int qcow_co_writev(BlockDriverState *bs, int64_t sector_num, }if (bs->encrypted) {Error *err =NULL ; -assert (s->cipher); -if (encrypt_sectors (s, sector_num, buf, - n, true, &err) <0 ) { +assert (s->crypto); +if (qcrypto_block_encrypt (s->crypto, sector_num, buf, + n, &err) <0 ) {error_free (err); ret = -EIO ;break ;
@@ -743,8 +728,8 @@ static void qcow_close(BlockDriverState *bs) {BDRVQcowState *s = bs->opaque; -qcrypto_cipher_free (s->cipher); - s->cipher =NULL ; +qcrypto_block_free (s->crypto); + s->crypto =NULL ;g_free (s->l1_table);qemu_vfree (s->l2_cache);g_free (s->cluster_cache);
@@ -1009,7 +994,6 @@ static BlockDriver bdrv_qcow = { .bdrv_co_writev = qcow_co_writev, .bdrv_co_get_block_status = qcow_co_get_block_status, - .bdrv_set_key = qcow_set_key, .bdrv_make_empty = qcow_make_empty, .bdrv_write_compressed = qcow_write_compressed, .bdrv_get_info = qcow_get_info,
qapi/block-core.json +16 -1
@@ -1851,6 +1851,21 @@ 'mode': 'Qcow2OverlapCheckMode' } } ## +# @BlockdevOptionsQcow +# +# Driver specific block device options for qcow. +# +# @key-secret: #optional ID of the "secret" object providing the +# AES decryption key. +# +# Since: 2.6 +## +{ 'struct': 'BlockdevOptionsQcow', + 'base': 'BlockdevOptionsGenericCOWFormat', + 'data': { '*key-secret': 'str' } } + + +## # @BlockdevOptionsQcow2 # # Driver specific block device options for qcow2.
@@ -2120,7 +2135,7 @@ 'null-co': 'BlockdevOptionsNull', 'parallels': 'BlockdevOptionsGenericFormat', 'qcow2': 'BlockdevOptionsQcow2', - 'qcow': 'BlockdevOptionsGenericCOWFormat', + 'qcow': 'BlockdevOptionsQcow', 'qed': 'BlockdevOptionsGenericCOWFormat', 'quorum': 'BlockdevOptionsQuorum', 'raw': 'BlockdevOptionsGenericFormat',
Signature · 1 line
2.5.0
PATCH v4 24/26 block: rip out all traces of password prompting
In reply to Daniel P. BerrangeNow that qcow & qcow2 are wired up to get encryption keys via the QCryptoSecret object, nothing is relying on the interactive prompting for passwords. All the code related to password prompting can thus be ripped out.
--- hmp.c | 31 --------------------- hw/usb/dev-storage.c | 34 ------------------------ include/monitor/monitor.h | 7 ----- include/qemu/osdep.h | 2 -- monitor.c | 68 ----------------------------------------------- qemu-img.c | 31 --------------------- qemu-io.c | 21 --------------- qmp.c | 10 +------ tests/qemu-iotests/087 | 2 ++ util/oslib-posix.c | 66 --------------------------------------------- util/oslib-win32.c | 24 ----------------- 11 files changed, 3 insertions(+), 293 deletions(-)
hmp.c +0 -31
@@ -969,37 +969,12 @@ void hmp_ringbuf_read(Monitor *mon, const QDict *qdict)g_free (data); } -static void hmp_cont_cb (void *opaque,int err) -{ -if (!err) { -qmp_cont (NULL ); - } -} - -static bool key_is_missing (const BlockInfo *bdev) -{ -return (bdev->inserted && bdev->inserted->encryption_key_missing); -} -void hmp_cont (Monitor *mon,const QDict *qdict) { -BlockInfoList *bdev_list, *bdev;Error *err =NULL ; - bdev_list =qmp_query_block (NULL ); -for (bdev = bdev_list; bdev; bdev = bdev->next) { -if (key_is_missing (bdev->value)) { -monitor_read_block_device_key (mon, bdev->value->device, - hmp_cont_cb,NULL ); - goto out; - } - } -qmp_cont (&err);hmp_handle_error (mon, &err); - -out: -qapi_free_BlockInfoList (bdev_list); }void hmp_system_wakeup (Monitor *mon,const QDict *qdict)
@@ -1380,12 +1355,6 @@ void hmp_change(Monitor *mon, const QDict *qdict)qmp_blockdev_change_medium (device, target, !!arg, arg, !!read_only, read_only_mode, &err); -if (err && -error_get_class (err) ==ERROR_CLASS_DEVICE_ENCRYPTED ) { -error_free (err); -monitor_read_block_device_key (mon, device,NULL ,NULL ); -return ; - } }hmp_handle_error (mon, &err);
hw/usb/dev-storage.c +0 -34
@@ -554,21 +554,6 @@ static void usb_msd_handle_data(USBDevice *dev, USBPacket *p) } } -static void usb_msd_password_cb (void *opaque,int err) -{ -MSDState *s = opaque; -Error *local_err =NULL ; - -if (!err) { -usb_device_attach (&s->dev, &local_err); - } - -if (local_err) { -error_report_err (local_err); -qdev_unplug (&s->dev.qdev,NULL ); - } -} -static void *usb_msd_load_request (QEMUFile *f,SCSIRequest *req) {MSDState *s =DO_UPCAST (MSDState, dev.qdev, req->bus->qbus.parent);
@@ -614,25 +599,6 @@ static void usb_msd_realize_storage(USBDevice *dev, Error **errp)return ; } -if (blk_bs (blk)) { -bdrv_add_key (blk_bs (blk),NULL , &err); -if (err) { -if (monitor_cur_is_qmp ()) { -error_propagate (errp, err); -return ; - } -error_free (err); - err =NULL ; -if (cur_mon) { -monitor_read_bdrv_key_start (cur_mon,blk_bs (blk), - usb_msd_password_cb, s); - s->dev.auto_attach =0 ; - }else { - autostart =0 ; - } - } - } -blkconf_serial (&s->conf, &dev->serial);blkconf_blocksizes (&s->conf);
include/monitor/monitor.h +0 -7
@@ -21,13 +21,6 @@ void monitor_init(CharDriverState *chr, int flags);int monitor_suspend (Monitor *mon);void monitor_resume (Monitor *mon); -int monitor_read_bdrv_key_start (Monitor *mon,BlockDriverState *bs, -BlockCompletionFunc *completion_cb, -void *opaque); -int monitor_read_block_device_key (Monitor *mon,const char *device, -BlockCompletionFunc *completion_cb, -void *opaque); -int monitor_get_fd (Monitor *mon,const char *fdname,Error **errp);int monitor_fd_param (Monitor *mon,const char *fdname,Error **errp);
include/qemu/osdep.h +0 -2
@@ -322,8 +322,6 @@ void qemu_set_tty_echo(int fd, bool echo);void os_mem_prealloc (int fd,char *area,size_t sz); -int qemu_read_password (char *buf,int buf_size); -/** * qemu_fork: *
monitor.c +0 -68
74 lines not on this page · raw message
qemu-img.c +0 -31
@@ -223,29 +223,6 @@ static int print_block_option_help(const char *filename, const char *fmt) } -static int img_open_password (BlockBackend *blk,const char *filename, -int flags,bool quiet) -{ -BlockDriverState *bs; -char password[256 ]; - - bs =blk_bs (blk); -if (bdrv_is_encrypted (bs) &&bdrv_key_required (bs) && - !(flags &BDRV_O_NO_IO )) { -qprintf (quiet,"Disk image '%s' is encrypted.\n" , filename); -if (qemu_read_password (password,sizeof (password)) <0 ) { -error_report ("No password given" ); -return -1 ; - } -if (bdrv_set_key (bs, password) <0 ) { -error_report ("invalid password" ); -return -1 ; - } - } -return 0 ; -} - - static BlockBackend *img_open_opts(const char *id, const char *optstr, QemuOpts *opts, int flags,
@@ -261,10 +238,6 @@ static BlockBackend *img_open_opts(const char *id,return NULL ; } -if (img_open_password (blk, optstr, flags, quiet) <0 ) { -blk_unref (blk); -return NULL ; - }return blk; }
@@ -287,10 +260,6 @@ static BlockBackend *img_open_file(const char *id, const char *filename,return NULL ; } -if (img_open_password (blk, filename, flags, quiet) <0 ) { -blk_unref (blk); -return NULL ; - }return blk; }
qemu-io.c +0 -21
@@ -53,7 +53,6 @@ static const cmdinfo_t close_cmd = {static int openfile (char *name,int flags,QDict *opts) {Error *local_err =NULL ; -BlockDriverState *bs;if (qemuio_blk) {error_report ("file open already, try 'help close'" );
@@ -68,27 +67,7 @@ static int openfile(char *name, int flags, QDict *opts)return 1 ; } - bs =blk_bs (qemuio_blk); -if (bdrv_is_encrypted (bs) &&bdrv_key_required (bs)) { -char password[256 ]; -printf ("Disk image '%s' is encrypted.\n" , name); -if (qemu_read_password (password,sizeof (password)) <0 ) { -error_report ("No password given" ); - goto error; - } -if (bdrv_set_key (bs, password) <0 ) { -error_report ("invalid password" ); - goto error; - } - } - -return 0 ; - - error: -blk_unref (qemuio_blk); - qemuio_blk =NULL ; -return 1 ; }static void open_help (void )
qmp.c +1 -9
@@ -178,9 +178,8 @@ SpiceInfo *qmp_query_spice(Error **errp)void qmp_cont (Error **errp) { -Error *local_err =NULL ;BlockBackend *blk; -BlockDriverState *bs; +Error *local_err =NULL ;/* if there is a dump in background, we should wait until the dump * finished */
@@ -199,13 +198,6 @@ void qmp_cont(Error **errp)for (blk =blk_next (NULL ); blk; blk =blk_next (blk)) {blk_iostatus_reset (blk); } -for (bs =bdrv_next (NULL ); bs; bs =bdrv_next (bs)) { -bdrv_add_key (bs,NULL , &local_err); -if (local_err) { -error_propagate (errp, local_err); -return ; - } - }/* Continuing after completed migration. Images have been inactivated to * allow the destination to take control. Need to get control back now. */
tests/qemu-iotests/087 +2 -0
@@ -201,6 +201,7 @@ run_qemu -S <<EOF "options": { "driver": "$IMGFMT", "id": "disk", + "key-secret": "sec0", "file": { "driver": "file", "filename": "$TEST_IMG"
@@ -228,6 +229,7 @@ run_qemu <<EOF "options": { "driver": "$IMGFMT", "id": "disk", + "key-secret": "sec0", "file": { "driver": "file", "filename": "$TEST_IMG"
util/oslib-posix.c +0 -66
72 lines not on this page · raw message
util/oslib-win32.c +0 -24
@@ -473,30 +473,6 @@ void os_mem_prealloc(int fd, char *area, size_t memory) } -/* XXX: put correct support for win32 */ -int qemu_read_password (char *buf,int buf_size) -{ -int c, i; - -printf ("Password: " ); -fflush (stdout); - i =0 ; -for (;;) { - c =getchar (); -if (c <0 ) { - buf[i] ='\0' ; -return -1 ; - }else if (c =='\n' ) { -break ; - }else if (i < (buf_size -1 )) { - buf[i++] = c; - } - } - buf[i] ='\0' ; -return 0 ; -} - -pid_t qemu_fork (Error **errp) { errno =ENOSYS ;
Signature · 1 line
2.5.0
Re: [Qemu-devel] [PATCH v4 24/26] block: rip out all traces of password prompting
Quoted 6 lines · Daniel P. Berrange
Now that qcow & qcow2 are wired up to get encryption keys via the QCryptoSecret object, nothing is relying on the interactive prompting for passwords. All the code related to password prompting can thus be ripped out.
Signed-off-by Daniel P. Berrange <[email protected]>
Quoted 13 lines
--- hmp.c | 31 --------------------- hw/usb/dev-storage.c | 34 ------------------------ include/monitor/monitor.h | 7 ----- include/qemu/osdep.h | 2 -- monitor.c | 68 ----------------------------------------------- qemu-img.c | 31 --------------------- qemu-io.c | 21 --------------- qmp.c | 10 +------ tests/qemu-iotests/087 | 2 ++ util/oslib-posix.c | 66 --------------------------------------------- util/oslib-win32.c | 24 ----------------- 11 files changed, 3 insertions(+), 293 deletions(-)
Missed a spot: in qapi-schema.json, human-monitor-command states:
# Notes: This command only exists as a stop-gap. Its use is highly
# discouraged. The semantics of this command are not guaranteed.
...
# o Commands that prompt the user for data (eg. 'cont' when the block
# device is encrypted) don't currently work
but after your series, cont no longer prompts for passwords so the comment is (or will be) stale and worth removing.
Signature · 2 lines
Eric Blake eblake redhat com +1-919-301-3266 Libvirt virtualization library http://libvirt.org
PATCH v4 25/26 block: remove all encryption handling APIs
In reply to Daniel P. BerrangeNow that all encryption keys must be provided upfront via the QCryptoSecret API and associated block driver properties there is no need for any explicit encryption handling APIs in the block layer. Encryption can be handled transparently within the block driver. We only retain an API for querying whether an image is encrypted or not, since that is a potentially useful piece of metadata to report to the user.
--- block.c | 82 ++--------------------------------------------- block/crypto.c | 1 - block/qapi.c | 2 +- block/qcow.c | 1 - block/qcow2.c | 1 - blockdev.c | 41 ++---------------------- include/block/block.h | 4 --- include/block/block_int.h | 1 - 8 files changed, 5 insertions(+), 128 deletions(-)
block.c +2 -80
@@ -1691,17 +1691,8 @@ static int bdrv_open_inherit(BlockDriverState **pbs, const char *filename, goto close_and_fail; } -if (!bdrv_key_required (bs)) { -if (bs->blk) { -blk_dev_change_media_cb (bs->blk, true); - } - }else if (!runstate_check (RUN_STATE_PRELAUNCH ) - && !runstate_check (RUN_STATE_INMIGRATE ) - && !runstate_check (RUN_STATE_PAUSED )) {/* HACK */ -error_setg (errp, -"Guest must be stopped for opening of encrypted image" ); - ret = -EBUSY ; - goto close_and_fail; +if (bs->blk) { +blk_dev_change_media_cb (bs->blk, true); }QDECREF (options);
@@ -2187,7 +2178,6 @@ static void bdrv_close(BlockDriverState *bs) bs->backing_format[0 ] ='\0' ; bs->total_sectors =0 ; bs->encrypted =0 ; - bs->valid_key =0 ; bs->sg =0 ; bs->zero_beyond_eof = false;QDECREF (bs->options);
@@ -2796,74 +2786,6 @@ int bdrv_is_encrypted(BlockDriverState *bs)return bs->encrypted; } -int bdrv_key_required (BlockDriverState *bs) -{ -BdrvChild *backing = bs->backing; - -if (backing && backing->bs->encrypted && !backing->bs->valid_key) { -return 1 ; - } -return (bs->encrypted && !bs->valid_key); -} - -int bdrv_set_key (BlockDriverState *bs,const char *key) -{ -int ret; -if (bs->backing && bs->backing->bs->encrypted) { - ret =bdrv_set_key (bs->backing->bs, key); -if (ret <0 ) -return ret; -if (!bs->encrypted) -return 0 ; - } -if (!bs->encrypted) { -return -EINVAL ; - }else if (!bs->drv || !bs->drv->bdrv_set_key) { -return -ENOMEDIUM ; - } - ret = bs->drv->bdrv_set_key (bs, key); -if (ret <0 ) { - bs->valid_key =0 ; - }else if (!bs->valid_key) { - bs->valid_key =1 ; -if (bs->blk) { -/* call the change callback now, we skipped it on open */ -blk_dev_change_media_cb (bs->blk, true); - } - } -return ret; -} - -/* -* Provide an encryption key for @bs. -* If @key is non-null: -* If @bs is not encrypted, fail. -* Else if the key is invalid, fail. -* Else set @bs's key to @key, replacing the existing key, if any. -* If @key is null: -* If @bs is encrypted and still lacks a key, fail. -* Else do nothing. -* On failure, store an error object through @errp if non-null. -*/ -void bdrv_add_key (BlockDriverState *bs,const char *key,Error **errp) -{ -if (key) { -if (!bdrv_is_encrypted (bs)) { -error_setg (errp,"Node '%s' is not encrypted" , -bdrv_get_device_or_node_name (bs)); - }else if (bdrv_set_key (bs, key) <0 ) { -error_setg (errp,QERR_INVALID_PASSWORD ); - } - }else { -if (bdrv_key_required (bs)) { -error_set (errp,ERROR_CLASS_DEVICE_ENCRYPTED , -"'%s' (%s) is encrypted" , -bdrv_get_device_or_node_name (bs), -bdrv_get_encrypted_filename (bs)); - } - } -} -const char *bdrv_get_format_name (BlockDriverState *bs) {return bs->drv ? bs->drv->format_name :NULL ;
block/crypto.c +0 -1
@@ -313,7 +313,6 @@ static int block_crypto_open_generic(QCryptoBlockFormat format, } bs->encrypted =1 ; - bs->valid_key =1 ;qemu_co_mutex_init (&crypto->lock);
block/qapi.c +1 -1
@@ -43,7 +43,7 @@ BlockDeviceInfo *bdrv_block_device_info(BlockDriverState *bs, Error **errp) info->ro = bs->read_only; info->drv =g_strdup (bs->drv->format_name); info->encrypted = bs->encrypted; - info->encryption_key_missing =bdrv_key_required (bs); + info->encryption_key_missing = false; info->cache =g_new (BlockdevCacheInfo,1 ); *info->cache = (BlockdevCacheInfo ) {
block/qcow.c +0 -1
@@ -216,7 +216,6 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags, goto fail; } bs->encrypted =1 ; - bs->valid_key =1 ; } s->cluster_bits = header.cluster_bits; s->cluster_size =1 << s->cluster_bits;
block/qcow2.c +0 -1
@@ -1224,7 +1224,6 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags, s->crypt_method_header = header.crypt_method;if (s->crypt_method_header) { bs->encrypted =1 ; - bs->valid_key =1 ; } s->l2_bits = s->cluster_bits -3 ;/* L2 is always one cluster */
blockdev.c +2 -39
65 lines not on this page · raw message
include/block/block.h +0 -4
@@ -417,10 +417,6 @@ bool bdrv_chain_contains(BlockDriverState *top, BlockDriverState *base);BlockDriverState *bdrv_next_node (BlockDriverState *bs);BlockDriverState *bdrv_next (BlockDriverState *bs);int bdrv_is_encrypted (BlockDriverState *bs); -int bdrv_key_required (BlockDriverState *bs); -int bdrv_set_key (BlockDriverState *bs,const char *key); -void bdrv_add_key (BlockDriverState *bs,const char *key,Error **errp); -int bdrv_query_missing_keys (void );void bdrv_iterate_format (void (*it)(void *opaque,const char *name),void *opaque);const char *bdrv_get_node_name (const BlockDriverState *bs);
include/block/block_int.h +0 -1
@@ -376,7 +376,6 @@ struct BlockDriverState {int read_only;/* if true, the media is read only */ int open_flags;/* flags used to open the file, re-used for re-open */ int encrypted;/* if true, the media is encrypted */ -int valid_key;/* if true, a valid encryption key has been set */ int sg;/* if true, the device is a /dev/sg* */ int copy_on_read;/* if true, copy read backing sectors into image note this is a reference count */
Signature · 1 line
2.5.0
PATCH v4 26/26 block: remove support for legecy AES qcow/qcow2 encryption
In reply to Daniel P. BerrangeRefuse to use images with the legacy AES-CBC encryption format in the system emulators. They are still fully supported in the qemu-img, qemu-io & qemu-nbd tools in order to allow data to be liberated and for compatibility with older QEMU versions. Continued support in these tools is not a notable burden with the new FDE framework.
--- block.c | 12 +++++------- block/qcow.c | 9 +++++++++ block/qcow2.c | 8 ++++++++ include/block/block.h | 1 + tests/qemu-iotests/049.out | 3 --- tests/qemu-iotests/087.out | 12 ------------ tests/qemu-iotests/134.out | 12 ------------ 7 files changed, 23 insertions(+), 34 deletions(-)
block.c +5 -7
@@ -313,6 +313,11 @@ static int bdrv_is_whitelisted(BlockDriver *drv, bool read_only)return 0 ; } +bool bdrv_uses_whitelist (void ) +{ +return use_bdrv_whitelist; +} + typedef struct CreateCo { BlockDriver *drv; char *filename;
@@ -1023,13 +1028,6 @@ static int bdrv_open_common(BlockDriverState *bs, BdrvChild *file, goto free_and_fail; } -if (bs->encrypted) { -error_report ("Encrypted images are deprecated" ); -error_printf ("Support for them will be removed in a future release.\n" -"You can use 'qemu-img convert' to convert your image" -" to an unencrypted one.\n" ); - } - ret =refresh_total_sectors (bs, bs->total_sectors);if (ret <0 ) {error_setg_errno (errp, -ret,"Could not refresh total sector count" );
block/qcow.c +9 -0
@@ -182,6 +182,15 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags,if (s->crypt_method_header) {if (s->crypt_method_header ==QCOW_CRYPT_AES ) {QCryptoBlockOptionsQCow *tmp; + +if (bdrv_uses_whitelist ()) { +error_setg (errp, +"Use of AES-CBC encrypted qcow images is no longer " +"supported. Please use the qcow2 LUKS format instead." ); + ret = -ENOSYS ; + goto fail; + } + ov =opts_visitor_new (opts); crypto_opts =g_new0 (QCryptoBlockOpenOptions,1 );
block/qcow2.c +8 -0
@@ -1223,6 +1223,14 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags, s->crypt_method_header = header.crypt_method;if (s->crypt_method_header) { +if (bdrv_uses_whitelist () && + s->crypt_method_header ==QCOW_CRYPT_AES ) { +error_setg (errp, +"Use of AES-CBC encrypted qcow2 images is no longer " +"supported. Please use the qcow2 LUKS format instead." ); + ret = -ENOSYS ; + goto fail; + } bs->encrypted =1 ; }
include/block/block.h +1 -0
@@ -191,6 +191,7 @@ void bdrv_io_limits_update_group(BlockDriverState *bs, const char *group);void bdrv_init (void );void bdrv_init_with_whitelist (void ); +bool bdrv_uses_whitelist (void );BlockDriver *bdrv_find_protocol (const char *filename,bool allow_protocol_prefix,Error **errp);
tests/qemu-iotests/049.out +0 -3
@@ -187,9 +187,6 @@ qemu-img create -f qcow2 -o encryption=off TEST_DIR/t.qcow2 64M Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16 qemu-img create -f qcow2 --object secret,id=sec0,data=123456 -o encryption=on,key-secret=sec0 TEST_DIR/t.qcow2 64M -qemu-img: Encrypted images are deprecated -Support for them will be removed in a future release. -You can use 'qemu-img convert' to convert your image to an unencrypted one. Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=on cluster_size=65536 lazy_refcounts=off refcount_bits=16 key-secret=sec0 == Check lazy_refcounts option (only with v3) ==
tests/qemu-iotests/087.out +0 -12
@@ -38,17 +38,11 @@ QMP_VERSION === Encrypted image === -qemu-img: Encrypted images are deprecated -Support for them will be removed in a future release. -You can use 'qemu-img convert' to convert your image to an unencrypted one. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 encryption=on key-secret=sec0 Testing: -S QMP_VERSION {"return": {}} {"return": {}} -Encrypted images are deprecated -Support for them will be removed in a future release. -You can use 'qemu-img convert' to convert your image to an unencrypted one. {"return": {}} {"return": {}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN"}
@@ -57,9 +51,6 @@ Testing: QMP_VERSION {"return": {}} {"return": {}} -Encrypted images are deprecated -Support for them will be removed in a future release. -You can use 'qemu-img convert' to convert your image to an unencrypted one. {"return": {}} {"return": {}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN"}
@@ -67,9 +58,6 @@ You can use 'qemu-img convert' to convert your image to an unencrypted one. === Missing driver === -qemu-img: Encrypted images are deprecated -Support for them will be removed in a future release. -You can use 'qemu-img convert' to convert your image to an unencrypted one. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 encryption=on key-secret=sec0 Testing: -S QMP_VERSION
tests/qemu-iotests/134.out +0 -12
@@ -1,27 +1,15 @@ QA output created by 134 -qemu-img: Encrypted images are deprecated -Support for them will be removed in a future release. -You can use 'qemu-img convert' to convert your image to an unencrypted one. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 encryption=on key-secret=sec0 == reading whole image == -Encrypted images are deprecated -Support for them will be removed in a future release. -You can use 'qemu-img convert' to convert your image to an unencrypted one. read 134217728/134217728 bytes at offset 0 128 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) == rewriting whole image == -Encrypted images are deprecated -Support for them will be removed in a future release. -You can use 'qemu-img convert' to convert your image to an unencrypted one. wrote 134217728/134217728 bytes at offset 0 128 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) == verify pattern == -Encrypted images are deprecated -Support for them will be removed in a future release. -You can use 'qemu-img convert' to convert your image to an unencrypted one. read 134217728/134217728 bytes at offset 0 128 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
Signature · 1 line
2.5.0