* [Qemu-devel] [PULL 0/7] Final changes for 2.4-rc0
@ 2015-07-07 14:11 Paolo Bonzini
2015-07-07 14:11 ` [Qemu-devel] [PULL 1/7] vl: move rom_load_all after machine init done Paolo Bonzini
` (6 more replies)
0 siblings, 7 replies; 10+ messages in thread
From: Paolo Bonzini @ 2015-07-07 14:11 UTC (permalink / raw)
To: qemu-devel
The following changes since commit f6e3035f75e5c6a73485335765ae070304c7a110:
Merge remote-tracking branch 'remotes/bonzini/tags/for-upstream-smm' into staging (2015-07-06 23:37:53 +0100)
are available in the git repository at:
git://github.com/bonzini/qemu.git tags/for-upstream
for you to fetch changes up to 1a79902fb054ea9881c8008f77a861ef63f60152:
crypto: add a nettle cipher implementation (2015-07-07 16:10:27 +0200)
----------------------------------------------------------------
Bugfixes and Daniel Berrange's crypto library.
----------------------------------------------------------------
Daniel P. Berrange (6):
crypto: introduce new module for computing hash digests
crypto: move built-in AES implementation into crypto/
crypto: move built-in D3DES implementation into crypto/
crypto: introduce generic cipher API & built-in implementation
crypto: add a gcrypt cipher implementation
crypto: add a nettle cipher implementation
Eric Auger (1):
vl: move rom_load_all after machine init done
MAINTAINERS | 7 +
Makefile.objs | 1 +
block/qcow.c | 2 +-
block/qcow2.c | 1 -
block/qcow2.h | 2 +-
configure | 103 +++++++++
crypto/Makefile.objs | 5 +
{util => crypto}/aes.c | 2 +-
crypto/cipher-builtin.c | 398 ++++++++++++++++++++++++++++++++++
crypto/cipher-gcrypt.c | 195 +++++++++++++++++
crypto/cipher-nettle.c | 206 ++++++++++++++++++
crypto/cipher.c | 75 +++++++
ui/d3des.c => crypto/desrfb.c | 2 +-
crypto/hash.c | 200 +++++++++++++++++
crypto/init.c | 150 +++++++++++++
hw/core/loader.c | 8 +-
include/{qemu => crypto}/aes.h | 0
include/crypto/cipher.h | 210 ++++++++++++++++++
ui/d3des.h => include/crypto/desrfb.h | 0
include/crypto/hash.h | 189 ++++++++++++++++
include/crypto/init.h | 29 +++
include/hw/loader.h | 3 +-
target-arm/crypto_helper.c | 2 +-
target-i386/fpu_helper.c | 1 -
target-i386/ops_sse.h | 2 +-
target-ppc/int_helper.c | 2 +-
tests/.gitignore | 2 +
tests/Makefile | 4 +
tests/test-crypto-cipher.c | 290 +++++++++++++++++++++++++
tests/test-crypto-hash.c | 209 ++++++++++++++++++
ui/Makefile.objs | 2 +-
ui/vnc.c | 2 +-
util/Makefile.objs | 2 +-
vl.c | 18 +-
34 files changed, 2297 insertions(+), 27 deletions(-)
create mode 100644 crypto/Makefile.objs
rename {util => crypto}/aes.c (99%)
create mode 100644 crypto/cipher-builtin.c
create mode 100644 crypto/cipher-gcrypt.c
create mode 100644 crypto/cipher-nettle.c
create mode 100644 crypto/cipher.c
rename ui/d3des.c => crypto/desrfb.c (99%)
create mode 100644 crypto/hash.c
create mode 100644 crypto/init.c
rename include/{qemu => crypto}/aes.h (100%)
create mode 100644 include/crypto/cipher.h
rename ui/d3des.h => include/crypto/desrfb.h (100%)
create mode 100644 include/crypto/hash.h
create mode 100644 include/crypto/init.h
create mode 100644 tests/test-crypto-cipher.c
create mode 100644 tests/test-crypto-hash.c
--
2.4.3
^ permalink raw reply [flat|nested] 10+ messages in thread
* [Qemu-devel] [PULL 1/7] vl: move rom_load_all after machine init done
2015-07-07 14:11 [Qemu-devel] [PULL 0/7] Final changes for 2.4-rc0 Paolo Bonzini
@ 2015-07-07 14:11 ` Paolo Bonzini
2015-07-07 14:11 ` [Qemu-devel] [PULL 2/7] crypto: introduce new module for computing hash digests Paolo Bonzini
` (5 subsequent siblings)
6 siblings, 0 replies; 10+ messages in thread
From: Paolo Bonzini @ 2015-07-07 14:11 UTC (permalink / raw)
To: qemu-devel; +Cc: Eric Auger
From: Eric Auger <eric.auger@linaro.org>
On ARM, commit ac9d32e39664e060cd1b538ff190980d57ad69e4 postponed the
memory preparation for boot until the machine init done notifier. This
has for consequence to insert ROM at machine init done time.
However the rom_load_all function stayed called before the ROM are
inserted. As a consequence the rom_load_all function does not do
everything it is expected to do, on ARM.
It currently registers the ROM reset notifier but does not iterate through
the registered ROM list. the isrom field is not set properly. This latter
is used to report info in the monitor and also to decide whether the
rom->data can be freed on ROM reset notifier.
To fix that regression the patch moves the rom_load_all call after
machine init done. We also take the opportunity to rename the rom_load_all
function into rom_check_and_resgister_reset() and integrate the
rom_load_done in it.
Signed-off-by: Eric Auger <eric.auger@linaro.org>
Reported-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
Message-Id: <1434470874-22573-1-git-send-email-eric.auger@linaro.org>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
hw/core/loader.c | 8 ++------
include/hw/loader.h | 3 +--
vl.c | 11 ++++-------
3 files changed, 7 insertions(+), 15 deletions(-)
diff --git a/hw/core/loader.c b/hw/core/loader.c
index 7ee675c..216eeeb 100644
--- a/hw/core/loader.c
+++ b/hw/core/loader.c
@@ -933,7 +933,7 @@ static void rom_reset(void *unused)
}
}
-int rom_load_all(void)
+int rom_check_and_register_reset(void)
{
hwaddr addr = 0;
MemoryRegionSection section;
@@ -957,12 +957,8 @@ int rom_load_all(void)
memory_region_unref(section.mr);
}
qemu_register_reset(rom_reset, NULL);
- return 0;
-}
-
-void rom_load_done(void)
-{
roms_loaded = 1;
+ return 0;
}
void rom_set_fw(FWCfgState *f)
diff --git a/include/hw/loader.h b/include/hw/loader.h
index 485ff8f..f7b43ab 100644
--- a/include/hw/loader.h
+++ b/include/hw/loader.h
@@ -75,8 +75,7 @@ MemoryRegion *rom_add_blob(const char *name, const void *blob, size_t len,
void *callback_opaque);
int rom_add_elf_program(const char *name, void *data, size_t datasize,
size_t romsize, hwaddr addr);
-int rom_load_all(void);
-void rom_load_done(void);
+int rom_check_and_register_reset(void);
void rom_set_fw(FWCfgState *f);
int rom_copy(uint8_t *dest, hwaddr addr, size_t size);
void *rom_ptr(hwaddr addr);
diff --git a/vl.c b/vl.c
index 69ad90c..2991af6 100644
--- a/vl.c
+++ b/vl.c
@@ -4579,18 +4579,15 @@ int main(int argc, char **argv, char **envp)
qdev_machine_creation_done();
- if (rom_load_all() != 0) {
- fprintf(stderr, "rom loading failed\n");
- exit(1);
- }
-
/* TODO: once all bus devices are qdevified, this should be done
* when bus is created by qdev.c */
qemu_register_reset(qbus_reset_all_fn, sysbus_get_default());
qemu_run_machine_init_done_notifiers();
- /* Done notifiers can load ROMs */
- rom_load_done();
+ if (rom_check_and_register_reset() != 0) {
+ fprintf(stderr, "rom check and register reset failed\n");
+ exit(1);
+ }
qemu_system_reset(VMRESET_SILENT);
if (loadvm) {
--
2.4.3
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [Qemu-devel] [PULL 2/7] crypto: introduce new module for computing hash digests
2015-07-07 14:11 [Qemu-devel] [PULL 0/7] Final changes for 2.4-rc0 Paolo Bonzini
2015-07-07 14:11 ` [Qemu-devel] [PULL 1/7] vl: move rom_load_all after machine init done Paolo Bonzini
@ 2015-07-07 14:11 ` Paolo Bonzini
2015-07-07 14:11 ` [Qemu-devel] [PULL 3/7] crypto: move built-in AES implementation into crypto/ Paolo Bonzini
` (4 subsequent siblings)
6 siblings, 0 replies; 10+ messages in thread
From: Paolo Bonzini @ 2015-07-07 14:11 UTC (permalink / raw)
To: qemu-devel
From: "Daniel P. Berrange" <berrange@redhat.com>
Introduce a new crypto/ directory that will (eventually) contain
all the cryptographic related code. This initially defines a
wrapper for initializing gnutls and for computing hashes with
gnutls. The former ensures that gnutls is guaranteed to be
initialized exactly once in QEMU regardless of CLI args. The
block quorum code currently fails to initialize gnutls so it
only works by luck, if VNC server TLS is not requested. The
hash APIs avoids the need to litter the rest of the code with
preprocessor checks and simplifies callers by allocating the
correct amount of memory for the requested hash.
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
Message-Id: <1435770638-25715-2-git-send-email-berrange@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
MAINTAINERS | 7 ++
Makefile.objs | 1 +
configure | 45 ++++++++++
crypto/Makefile.objs | 2 +
crypto/hash.c | 200 +++++++++++++++++++++++++++++++++++++++++++++
crypto/init.c | 60 ++++++++++++++
include/crypto/hash.h | 189 ++++++++++++++++++++++++++++++++++++++++++
include/crypto/init.h | 29 +++++++
tests/.gitignore | 1 +
tests/Makefile | 2 +
tests/test-crypto-hash.c | 209 +++++++++++++++++++++++++++++++++++++++++++++++
vl.c | 7 ++
12 files changed, 752 insertions(+)
create mode 100644 crypto/Makefile.objs
create mode 100644 crypto/hash.c
create mode 100644 crypto/init.c
create mode 100644 include/crypto/hash.h
create mode 100644 include/crypto/init.h
create mode 100644 tests/test-crypto-hash.c
diff --git a/MAINTAINERS b/MAINTAINERS
index 3d48a6b..411da3c 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1052,6 +1052,13 @@ S: Supported
F: qemu-seccomp.c
F: include/sysemu/seccomp.h
+Cryptography
+M: Daniel P. Berrange <berrange@redhat.com>
+S: Maintained
+F: crypto/
+F: include/crypto/
+F: tests/test-crypto-*
+
Usermode Emulation
------------------
Overall
diff --git a/Makefile.objs b/Makefile.objs
index 4881d2c..f094eff 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -2,6 +2,7 @@
# Common libraries for tools and emulators
stub-obj-y = stubs/
util-obj-y = util/ qobject/ qapi/ qapi-types.o qapi-visit.o qapi-event.o
+util-obj-y += crypto/
#######################################################################
# block-obj-y is code used by both qemu system emulation and qemu-img
diff --git a/configure b/configure
index 3063739..61a749e 100755
--- a/configure
+++ b/configure
@@ -330,6 +330,8 @@ glusterfs_zerofill="no"
archipelago="no"
gtk=""
gtkabi=""
+gnutls=""
+gnutls_hash=""
vte=""
tpm="yes"
libssh2=""
@@ -1118,6 +1120,10 @@ for opt do
;;
--enable-gtk) gtk="yes"
;;
+ --disable-gnutls) gnutls="no"
+ ;;
+ --enable-gnutls) gnutls="yes"
+ ;;
--enable-rdma) rdma="yes"
;;
--disable-rdma) rdma="no"
@@ -1328,6 +1334,7 @@ disabled with --disable-FEATURE, default is enabled if available:
debug-info debugging information
sparse sparse checker
+ gnutls GNUTLS cryptography support
sdl SDL UI
--with-sdlabi select preferred SDL ABI 1.2 or 2.0
gtk gtk UI
@@ -2115,6 +2122,36 @@ if test "$gtk" != "no"; then
fi
fi
+
+##########################################
+# GNUTLS probe
+
+if test "$gnutls" != "no"; then
+ if $pkg_config --exists "gnutls"; then
+ gnutls_cflags=`$pkg_config --cflags gnutls`
+ gnutls_libs=`$pkg_config --libs gnutls`
+ libs_softmmu="$gnutls_libs $libs_softmmu"
+ libs_tools="$gnutls_libs $libs_tools"
+ QEMU_CFLAGS="$QEMU_CFLAGS $gnutls_cflags"
+ gnutls="yes"
+
+ # gnutls_hash_init requires >= 2.9.10
+ if $pkg_config --exists "gnutls >= 2.9.10"; then
+ gnutls_hash="yes"
+ else
+ gnutls_hash="no"
+ fi
+ elif test "$gnutls" = "yes"; then
+ feature_not_found "gnutls" "Install gnutls devel"
+ else
+ gnutls="no"
+ gnutls_hash="no"
+ fi
+else
+ gnutls_hash="no"
+fi
+
+
##########################################
# VTE probe
@@ -4424,6 +4461,8 @@ fi
echo "pixman $pixman"
echo "SDL support $sdl"
echo "GTK support $gtk"
+echo "GNUTLS support $gnutls"
+echo "GNUTLS hash $gnutls_hash"
echo "VTE support $vte"
echo "curses support $curses"
echo "curl support $curl"
@@ -4782,6 +4821,12 @@ if test "$gtk" = "yes" ; then
echo "CONFIG_GTKABI=$gtkabi" >> $config_host_mak
echo "GTK_CFLAGS=$gtk_cflags" >> $config_host_mak
fi
+if test "$gnutls" = "yes" ; then
+ echo "CONFIG_GNUTLS=y" >> $config_host_mak
+fi
+if test "$gnutls_hash" = "yes" ; then
+ echo "CONFIG_GNUTLS_HASH=y" >> $config_host_mak
+fi
if test "$vte" = "yes" ; then
echo "CONFIG_VTE=y" >> $config_host_mak
echo "VTE_CFLAGS=$vte_cflags" >> $config_host_mak
diff --git a/crypto/Makefile.objs b/crypto/Makefile.objs
new file mode 100644
index 0000000..03cc1b2
--- /dev/null
+++ b/crypto/Makefile.objs
@@ -0,0 +1,2 @@
+util-obj-y += init.o
+util-obj-y += hash.o
diff --git a/crypto/hash.c b/crypto/hash.c
new file mode 100644
index 0000000..81e74de
--- /dev/null
+++ b/crypto/hash.c
@@ -0,0 +1,200 @@
+/*
+ * QEMU Crypto hash algorithms
+ *
+ * Copyright (c) 2015 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "crypto/hash.h"
+
+#ifdef CONFIG_GNUTLS_HASH
+#include <gnutls/gnutls.h>
+#include <gnutls/crypto.h>
+
+static int qcrypto_hash_alg_map[QCRYPTO_HASH_ALG_LAST] = {
+ [QCRYPTO_HASH_ALG_MD5] = GNUTLS_DIG_MD5,
+ [QCRYPTO_HASH_ALG_SHA1] = GNUTLS_DIG_SHA1,
+ [QCRYPTO_HASH_ALG_SHA256] = GNUTLS_DIG_SHA256,
+};
+
+gboolean qcrypto_hash_supports(QCryptoHashAlgorithm alg)
+{
+ if (alg < G_N_ELEMENTS(qcrypto_hash_alg_map)) {
+ return true;
+ }
+ return false;
+}
+
+int qcrypto_hash_bytesv(QCryptoHashAlgorithm alg,
+ const struct iovec *iov,
+ size_t niov,
+ uint8_t **result,
+ size_t *resultlen,
+ Error **errp)
+{
+ int i, ret;
+ gnutls_hash_hd_t dig;
+
+ if (alg >= G_N_ELEMENTS(qcrypto_hash_alg_map)) {
+ error_setg(errp,
+ "Unknown hash algorithm %d",
+ alg);
+ return -1;
+ }
+
+ ret = gnutls_hash_init(&dig, qcrypto_hash_alg_map[alg]);
+
+ if (ret < 0) {
+ error_setg(errp,
+ "Unable to initialize hash algorithm: %s",
+ gnutls_strerror(ret));
+ return -1;
+ }
+
+ for (i = 0; i < niov; i++) {
+ ret = gnutls_hash(dig, iov[i].iov_base, iov[i].iov_len);
+ if (ret < 0) {
+ error_setg(errp,
+ "Unable process hash data: %s",
+ gnutls_strerror(ret));
+ goto error;
+ }
+ }
+
+ ret = gnutls_hash_get_len(qcrypto_hash_alg_map[alg]);
+ if (ret <= 0) {
+ error_setg(errp,
+ "Unable to get hash length: %s",
+ gnutls_strerror(ret));
+ goto error;
+ }
+ if (*resultlen == 0) {
+ *resultlen = ret;
+ *result = g_new0(uint8_t, *resultlen);
+ } else if (*resultlen != ret) {
+ error_setg(errp,
+ "Result buffer size %zu is smaller than hash %d",
+ *resultlen, ret);
+ goto error;
+ }
+
+ gnutls_hash_deinit(dig, *result);
+ return 0;
+
+ error:
+ gnutls_hash_deinit(dig, NULL);
+ return -1;
+}
+
+#else /* ! CONFIG_GNUTLS_HASH */
+
+gboolean qcrypto_hash_supports(QCryptoHashAlgorithm alg G_GNUC_UNUSED)
+{
+ return false;
+}
+
+int qcrypto_hash_bytesv(QCryptoHashAlgorithm alg,
+ const struct iovec *iov G_GNUC_UNUSED,
+ size_t niov G_GNUC_UNUSED,
+ uint8_t **result G_GNUC_UNUSED,
+ size_t *resultlen G_GNUC_UNUSED,
+ Error **errp)
+{
+ error_setg(errp,
+ "Hash algorithm %d not supported without GNUTLS",
+ alg);
+ return -1;
+}
+
+#endif /* ! CONFIG_GNUTLS_HASH */
+
+int qcrypto_hash_bytes(QCryptoHashAlgorithm alg,
+ const char *buf,
+ size_t len,
+ uint8_t **result,
+ size_t *resultlen,
+ Error **errp)
+{
+ struct iovec iov = { .iov_base = (char *)buf,
+ .iov_len = len };
+ return qcrypto_hash_bytesv(alg, &iov, 1, result, resultlen, errp);
+}
+
+static const char hex[] = "0123456789abcdef";
+
+int qcrypto_hash_digestv(QCryptoHashAlgorithm alg,
+ const struct iovec *iov,
+ size_t niov,
+ char **digest,
+ Error **errp)
+{
+ uint8_t *result = NULL;
+ size_t resultlen = 0;
+ size_t i;
+
+ if (qcrypto_hash_bytesv(alg, iov, niov, &result, &resultlen, errp) < 0) {
+ return -1;
+ }
+
+ *digest = g_new0(char, (resultlen * 2) + 1);
+ for (i = 0 ; i < resultlen ; i++) {
+ (*digest)[(i * 2)] = hex[(result[i] >> 4) & 0xf];
+ (*digest)[(i * 2) + 1] = hex[result[i] & 0xf];
+ }
+ (*digest)[resultlen * 2] = '\0';
+ g_free(result);
+ return 0;
+}
+
+int qcrypto_hash_digest(QCryptoHashAlgorithm alg,
+ const char *buf,
+ size_t len,
+ char **digest,
+ Error **errp)
+{
+ struct iovec iov = { .iov_base = (char *)buf, .iov_len = len };
+
+ return qcrypto_hash_digestv(alg, &iov, 1, digest, errp);
+}
+
+int qcrypto_hash_base64v(QCryptoHashAlgorithm alg,
+ const struct iovec *iov,
+ size_t niov,
+ char **base64,
+ Error **errp)
+{
+ uint8_t *result = NULL;
+ size_t resultlen = 0;
+
+ if (qcrypto_hash_bytesv(alg, iov, niov, &result, &resultlen, errp) < 0) {
+ return -1;
+ }
+
+ *base64 = g_base64_encode(result, resultlen);
+ g_free(result);
+ return 0;
+}
+
+int qcrypto_hash_base64(QCryptoHashAlgorithm alg,
+ const char *buf,
+ size_t len,
+ char **base64,
+ Error **errp)
+{
+ struct iovec iov = { .iov_base = (char *)buf, .iov_len = len };
+
+ return qcrypto_hash_base64v(alg, &iov, 1, base64, errp);
+}
diff --git a/crypto/init.c b/crypto/init.c
new file mode 100644
index 0000000..40f3d6e
--- /dev/null
+++ b/crypto/init.c
@@ -0,0 +1,60 @@
+/*
+ * QEMU Crypto initialization
+ *
+ * Copyright (c) 2015 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "crypto/init.h"
+
+#ifdef CONFIG_GNUTLS
+#include <gnutls/gnutls.h>
+#include <gnutls/crypto.h>
+
+/* #define DEBUG_GNUTLS */
+
+#ifdef DEBUG_GNUTLS
+static void qcrypto_gnutls_log(int level, const char *str)
+{
+ fprintf(stderr, "%d: %s", level, str);
+}
+#endif
+
+int qcrypto_init(Error **errp)
+{
+ int ret;
+ ret = gnutls_global_init();
+ if (ret < 0) {
+ error_setg(errp,
+ "Unable to initialize GNUTLS library: %s",
+ gnutls_strerror(ret));
+ return -1;
+ }
+#ifdef DEBUG_GNUTLS
+ gnutls_global_set_log_level(10);
+ gnutls_global_set_log_function(qcrypto_gnutls_log);
+#endif
+ return 0;
+}
+
+#else /* ! CONFIG_GNUTLS */
+
+int qcrypto_init(Error **errp G_GNUC_UNUSED)
+{
+ return 0;
+}
+
+#endif /* ! CONFIG_GNUTLS */
diff --git a/include/crypto/hash.h b/include/crypto/hash.h
new file mode 100644
index 0000000..b5acbf6
--- /dev/null
+++ b/include/crypto/hash.h
@@ -0,0 +1,189 @@
+/*
+ * QEMU Crypto hash algorithms
+ *
+ * Copyright (c) 2015 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef QCRYPTO_HASH_H__
+#define QCRYPTO_HASH_H__
+
+#include "qemu-common.h"
+#include "qapi/error.h"
+
+typedef enum {
+ QCRYPTO_HASH_ALG_MD5,
+ QCRYPTO_HASH_ALG_SHA1,
+ QCRYPTO_HASH_ALG_SHA256,
+
+ QCRYPTO_HASH_ALG_LAST
+} QCryptoHashAlgorithm;
+
+
+/**
+ * qcrypto_hash_supports:
+ * @alg: the hash algorithm
+ *
+ * Determine if @alg hash algorithm is supported by the
+ * current configured build.
+ *
+ * Returns: true if the algorithm is supported, false otherwise
+ */
+gboolean qcrypto_hash_supports(QCryptoHashAlgorithm alg);
+
+/**
+ * qcrypto_hash_bytesv:
+ * @alg: the hash algorithm
+ * @iov: the array of memory regions to hash
+ * @niov: the length of @iov
+ * @result: pointer to hold output hash
+ * @resultlen: pointer to hold length of @result
+ * @errp: pointer to uninitialized error object
+ *
+ * Computes the hash across all the memory regions
+ * present in @iov. The @result pointer will be
+ * filled with raw bytes representing the computed
+ * hash, which will have length @resultlen. The
+ * memory pointer in @result must be released
+ * with a call to g_free() when no longer required.
+ *
+ * Returns: 0 on success, -1 on error
+ */
+int qcrypto_hash_bytesv(QCryptoHashAlgorithm alg,
+ const struct iovec *iov,
+ size_t niov,
+ uint8_t **result,
+ size_t *resultlen,
+ Error **errp);
+
+/**
+ * qcrypto_hash_bytes:
+ * @alg: the hash algorithm
+ * @buf: the memory region to hash
+ * @len: the length of @buf
+ * @result: pointer to hold output hash
+ * @resultlen: pointer to hold length of @result
+ * @errp: pointer to uninitialized error object
+ *
+ * Computes the hash across all the memory region
+ * @buf of length @len. The @result pointer will be
+ * filled with raw bytes representing the computed
+ * hash, which will have length @resultlen. The
+ * memory pointer in @result must be released
+ * with a call to g_free() when no longer required.
+ *
+ * Returns: 0 on success, -1 on error
+ */
+int qcrypto_hash_bytes(QCryptoHashAlgorithm alg,
+ const char *buf,
+ size_t len,
+ uint8_t **result,
+ size_t *resultlen,
+ Error **errp);
+
+/**
+ * qcrypto_hash_digestv:
+ * @alg: the hash algorithm
+ * @iov: the array of memory regions to hash
+ * @niov: the length of @iov
+ * @digest: pointer to hold output hash
+ * @errp: pointer to uninitialized error object
+ *
+ * Computes the hash across all the memory regions
+ * present in @iov. The @digest pointer will be
+ * filled with the printable hex digest of the computed
+ * hash, which will be terminated by '\0'. The
+ * memory pointer in @digest must be released
+ * with a call to g_free() when no longer required.
+ *
+ * Returns: 0 on success, -1 on error
+ */
+int qcrypto_hash_digestv(QCryptoHashAlgorithm alg,
+ const struct iovec *iov,
+ size_t niov,
+ char **digest,
+ Error **errp);
+
+/**
+ * qcrypto_hash_digest:
+ * @alg: the hash algorithm
+ * @buf: the memory region to hash
+ * @len: the length of @buf
+ * @digest: pointer to hold output hash
+ * @errp: pointer to uninitialized error object
+ *
+ * Computes the hash across all the memory region
+ * @buf of length @len. The @digest pointer will be
+ * filled with the printable hex digest of the computed
+ * hash, which will be terminated by '\0'. The
+ * memory pointer in @digest must be released
+ * with a call to g_free() when no longer required.
+ *
+ * Returns: 0 on success, -1 on error
+ */
+int qcrypto_hash_digest(QCryptoHashAlgorithm alg,
+ const char *buf,
+ size_t len,
+ char **digest,
+ Error **errp);
+
+/**
+ * qcrypto_hash_base64v:
+ * @alg: the hash algorithm
+ * @iov: the array of memory regions to hash
+ * @niov: the length of @iov
+ * @base64: pointer to hold output hash
+ * @errp: pointer to uninitialized error object
+ *
+ * Computes the hash across all the memory regions
+ * present in @iov. The @base64 pointer will be
+ * filled with the base64 encoding of the computed
+ * hash, which will be terminated by '\0'. The
+ * memory pointer in @base64 must be released
+ * with a call to g_free() when no longer required.
+ *
+ * Returns: 0 on success, -1 on error
+ */
+int qcrypto_hash_base64v(QCryptoHashAlgorithm alg,
+ const struct iovec *iov,
+ size_t niov,
+ char **base64,
+ Error **errp);
+
+/**
+ * qcrypto_hash_base64:
+ * @alg: the hash algorithm
+ * @buf: the memory region to hash
+ * @len: the length of @buf
+ * @base64: pointer to hold output hash
+ * @errp: pointer to uninitialized error object
+ *
+ * Computes the hash across all the memory region
+ * @buf of length @len. The @base64 pointer will be
+ * filled with the base64 encoding of the computed
+ * hash, which will be terminated by '\0'. The
+ * memory pointer in @base64 must be released
+ * with a call to g_free() when no longer required.
+ *
+ * Returns: 0 on success, -1 on error
+ */
+int qcrypto_hash_base64(QCryptoHashAlgorithm alg,
+ const char *buf,
+ size_t len,
+ char **base64,
+ Error **errp);
+
+#endif /* QCRYPTO_HASH_H__ */
diff --git a/include/crypto/init.h b/include/crypto/init.h
new file mode 100644
index 0000000..5fc510c
--- /dev/null
+++ b/include/crypto/init.h
@@ -0,0 +1,29 @@
+/*
+ * QEMU Crypto initialization
+ *
+ * Copyright (c) 2015 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef QCRYPTO_INIT_H__
+#define QCRYPTO_INIT_H__
+
+#include "qemu-common.h"
+#include "qapi/error.h"
+
+int qcrypto_init(Error **errp);
+
+#endif /* QCRYPTO_INIT_H__ */
diff --git a/tests/.gitignore b/tests/.gitignore
index dc813c2..18f60f1 100644
--- a/tests/.gitignore
+++ b/tests/.gitignore
@@ -10,6 +10,7 @@ rcutorture
test-aio
test-bitops
test-coroutine
+test-crypto-hash
test-cutils
test-hbitmap
test-int128
diff --git a/tests/Makefile b/tests/Makefile
index eff5e11..8c7f1ac 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -74,6 +74,7 @@ check-unit-y += tests/test-qemu-opts$(EXESUF)
gcov-files-test-qemu-opts-y = qom/test-qemu-opts.c
check-unit-y += tests/test-write-threshold$(EXESUF)
gcov-files-test-write-threshold-y = block/write-threshold.c
+check-unit-$(CONFIG_GNUTLS_HASH) += tests/test-crypto-hash$(EXESUF)
check-block-$(CONFIG_POSIX) += tests/qemu-iotests-quick.sh
@@ -339,6 +340,7 @@ tests/test-opts-visitor$(EXESUF): tests/test-opts-visitor.o $(test-qapi-obj-y) l
tests/test-mul64$(EXESUF): tests/test-mul64.o libqemuutil.a
tests/test-bitops$(EXESUF): tests/test-bitops.o libqemuutil.a
+tests/test-crypto-hash$(EXESUF): tests/test-crypto-hash.o libqemuutil.a libqemustub.a
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
diff --git a/tests/test-crypto-hash.c b/tests/test-crypto-hash.c
new file mode 100644
index 0000000..911437e
--- /dev/null
+++ b/tests/test-crypto-hash.c
@@ -0,0 +1,209 @@
+/*
+ * QEMU Crypto hash algorithms
+ *
+ * Copyright (c) 2015 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <glib.h>
+
+#include "crypto/init.h"
+#include "crypto/hash.h"
+
+#define INPUT_TEXT "Hiss hisss Hissss hiss Hiss hisss Hiss hiss"
+#define INPUT_TEXT1 "Hiss hisss "
+#define INPUT_TEXT2 "Hissss hiss "
+#define INPUT_TEXT3 "Hiss hisss Hiss hiss"
+
+#define OUTPUT_MD5 "628d206371563035ab8ef62f492bdec9"
+#define OUTPUT_SHA1 "b2e74f26758a3a421e509cee045244b78753cc02"
+#define OUTPUT_SHA256 "bc757abb0436586f392b437e5dd24096" \
+ "f7f224de6b74d4d86e2abc6121b160d0"
+
+#define OUTPUT_MD5_B64 "Yo0gY3FWMDWrjvYvSSveyQ=="
+#define OUTPUT_SHA1_B64 "sudPJnWKOkIeUJzuBFJEt4dTzAI="
+#define OUTPUT_SHA256_B64 "vHV6uwQ2WG85K0N+XdJAlvfyJN5rdNTYbiq8YSGxYNA="
+
+static const char *expected_outputs[] = {
+ [QCRYPTO_HASH_ALG_MD5] = OUTPUT_MD5,
+ [QCRYPTO_HASH_ALG_SHA1] = OUTPUT_SHA1,
+ [QCRYPTO_HASH_ALG_SHA256] = OUTPUT_SHA256,
+};
+static const char *expected_outputs_b64[] = {
+ [QCRYPTO_HASH_ALG_MD5] = OUTPUT_MD5_B64,
+ [QCRYPTO_HASH_ALG_SHA1] = OUTPUT_SHA1_B64,
+ [QCRYPTO_HASH_ALG_SHA256] = OUTPUT_SHA256_B64,
+};
+static const int expected_lens[] = {
+ [QCRYPTO_HASH_ALG_MD5] = 16,
+ [QCRYPTO_HASH_ALG_SHA1] = 20,
+ [QCRYPTO_HASH_ALG_SHA256] = 32,
+};
+
+static const char hex[] = "0123456789abcdef";
+
+/* Test with dynamic allocation */
+static void test_hash_alloc(void)
+{
+ size_t i;
+
+ g_assert(qcrypto_init(NULL) == 0);
+
+ for (i = 0; i < G_N_ELEMENTS(expected_outputs) ; i++) {
+ uint8_t *result = NULL;
+ size_t resultlen = 0;
+ int ret;
+ size_t j;
+
+ ret = qcrypto_hash_bytes(i,
+ INPUT_TEXT,
+ strlen(INPUT_TEXT),
+ &result,
+ &resultlen,
+ NULL);
+ g_assert(ret == 0);
+ g_assert(resultlen == expected_lens[i]);
+
+ for (j = 0; j < resultlen; j++) {
+ g_assert(expected_outputs[i][j * 2] == hex[(result[j] >> 4) & 0xf]);
+ g_assert(expected_outputs[i][j * 2 + 1] == hex[result[j] & 0xf]);
+ }
+ g_free(result);
+ }
+}
+
+/* Test with caller preallocating */
+static void test_hash_prealloc(void)
+{
+ size_t i;
+
+ g_assert(qcrypto_init(NULL) == 0);
+
+ for (i = 0; i < G_N_ELEMENTS(expected_outputs) ; i++) {
+ uint8_t *result;
+ size_t resultlen;
+ int ret;
+ size_t j;
+
+ resultlen = expected_lens[i];
+ result = g_new0(uint8_t, resultlen);
+
+ ret = qcrypto_hash_bytes(i,
+ INPUT_TEXT,
+ strlen(INPUT_TEXT),
+ &result,
+ &resultlen,
+ NULL);
+ g_assert(ret == 0);
+
+ g_assert(resultlen == expected_lens[i]);
+ for (j = 0; j < resultlen; j++) {
+ g_assert(expected_outputs[i][j * 2] == hex[(result[j] >> 4) & 0xf]);
+ g_assert(expected_outputs[i][j * 2 + 1] == hex[result[j] & 0xf]);
+ }
+ g_free(result);
+ }
+}
+
+
+/* Test with dynamic allocation */
+static void test_hash_iov(void)
+{
+ size_t i;
+
+ g_assert(qcrypto_init(NULL) == 0);
+
+ for (i = 0; i < G_N_ELEMENTS(expected_outputs) ; i++) {
+ struct iovec iov[3] = {
+ { .iov_base = (char *)INPUT_TEXT1, .iov_len = strlen(INPUT_TEXT1) },
+ { .iov_base = (char *)INPUT_TEXT2, .iov_len = strlen(INPUT_TEXT2) },
+ { .iov_base = (char *)INPUT_TEXT3, .iov_len = strlen(INPUT_TEXT3) },
+ };
+ uint8_t *result = NULL;
+ size_t resultlen = 0;
+ int ret;
+ size_t j;
+
+ ret = qcrypto_hash_bytesv(i,
+ iov, 3,
+ &result,
+ &resultlen,
+ NULL);
+ g_assert(ret == 0);
+ g_assert(resultlen == expected_lens[i]);
+ for (j = 0; j < resultlen; j++) {
+ g_assert(expected_outputs[i][j * 2] == hex[(result[j] >> 4) & 0xf]);
+ g_assert(expected_outputs[i][j * 2 + 1] == hex[result[j] & 0xf]);
+ }
+ g_free(result);
+ }
+}
+
+
+/* Test with printable hashing */
+static void test_hash_digest(void)
+{
+ size_t i;
+
+ g_assert(qcrypto_init(NULL) == 0);
+
+ for (i = 0; i < G_N_ELEMENTS(expected_outputs) ; i++) {
+ int ret;
+ char *digest;
+
+ ret = qcrypto_hash_digest(i,
+ INPUT_TEXT,
+ strlen(INPUT_TEXT),
+ &digest,
+ NULL);
+ g_assert(ret == 0);
+ g_assert(g_str_equal(digest, expected_outputs[i]));
+ g_free(digest);
+ }
+}
+
+/* Test with base64 encoding */
+static void test_hash_base64(void)
+{
+ size_t i;
+
+ g_assert(qcrypto_init(NULL) == 0);
+
+ for (i = 0; i < G_N_ELEMENTS(expected_outputs) ; i++) {
+ int ret;
+ char *digest;
+
+ ret = qcrypto_hash_base64(i,
+ INPUT_TEXT,
+ strlen(INPUT_TEXT),
+ &digest,
+ NULL);
+ g_assert(ret == 0);
+ g_assert(g_str_equal(digest, expected_outputs_b64[i]));
+ g_free(digest);
+ }
+}
+
+int main(int argc, char **argv)
+{
+ g_test_init(&argc, &argv, NULL);
+ g_test_add_func("/crypto/hash/iov", test_hash_iov);
+ g_test_add_func("/crypto/hash/alloc", test_hash_alloc);
+ g_test_add_func("/crypto/hash/prealloc", test_hash_prealloc);
+ g_test_add_func("/crypto/hash/digest", test_hash_digest);
+ g_test_add_func("/crypto/hash/base64", test_hash_base64);
+ return g_test_run();
+}
diff --git a/vl.c b/vl.c
index 2991af6..3eea5c4 100644
--- a/vl.c
+++ b/vl.c
@@ -121,6 +121,7 @@ int main(int argc, char **argv)
#include "qom/object_interfaces.h"
#include "qapi-event.h"
#include "exec/semihost.h"
+#include "crypto/init.h"
#define MAX_VIRTIO_CONSOLES 1
#define MAX_SCLP_CONSOLES 1
@@ -2958,6 +2959,7 @@ int main(int argc, char **argv, char **envp)
uint64_t ram_slots = 0;
FILE *vmstate_dump_file = NULL;
Error *main_loop_err = NULL;
+ Error *err = NULL;
qemu_init_cpu_loop();
qemu_mutex_lock_iothread();
@@ -3001,6 +3003,11 @@ int main(int argc, char **argv, char **envp)
runstate_init();
+ if (qcrypto_init(&err) < 0) {
+ fprintf(stderr, "Cannot initialize crypto: %s\n",
+ error_get_pretty(err));
+ exit(1);
+ }
rtc_clock = QEMU_CLOCK_HOST;
QLIST_INIT (&vm_change_state_head);
--
2.4.3
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [Qemu-devel] [PULL 3/7] crypto: move built-in AES implementation into crypto/
2015-07-07 14:11 [Qemu-devel] [PULL 0/7] Final changes for 2.4-rc0 Paolo Bonzini
2015-07-07 14:11 ` [Qemu-devel] [PULL 1/7] vl: move rom_load_all after machine init done Paolo Bonzini
2015-07-07 14:11 ` [Qemu-devel] [PULL 2/7] crypto: introduce new module for computing hash digests Paolo Bonzini
@ 2015-07-07 14:11 ` Paolo Bonzini
2015-07-07 14:11 ` [Qemu-devel] [PULL 4/7] crypto: move built-in D3DES " Paolo Bonzini
` (3 subsequent siblings)
6 siblings, 0 replies; 10+ messages in thread
From: Paolo Bonzini @ 2015-07-07 14:11 UTC (permalink / raw)
To: qemu-devel
From: "Daniel P. Berrange" <berrange@redhat.com>
To prepare for a generic internal cipher API, move the
built-in AES implementation into the crypto/ directory
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
Message-Id: <1435770638-25715-3-git-send-email-berrange@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
block/qcow.c | 2 +-
block/qcow2.c | 1 -
block/qcow2.h | 2 +-
crypto/Makefile.objs | 1 +
{util => crypto}/aes.c | 2 +-
include/{qemu => crypto}/aes.h | 0
target-arm/crypto_helper.c | 2 +-
target-i386/fpu_helper.c | 1 -
target-i386/ops_sse.h | 2 +-
target-ppc/int_helper.c | 2 +-
util/Makefile.objs | 2 +-
11 files changed, 8 insertions(+), 9 deletions(-)
rename {util => crypto}/aes.c (99%)
rename include/{qemu => crypto}/aes.h (100%)
diff --git a/block/qcow.c b/block/qcow.c
index 733627f..bf5c570 100644
--- a/block/qcow.c
+++ b/block/qcow.c
@@ -26,7 +26,7 @@
#include "qemu/module.h"
#include <zlib.h>
#include "qapi/qmp/qerror.h"
-#include "qemu/aes.h"
+#include "crypto/aes.h"
#include "migration/migration.h"
/**************************************************************/
diff --git a/block/qcow2.c b/block/qcow2.c
index d522ec7..85e0731 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -25,7 +25,6 @@
#include "block/block_int.h"
#include "qemu/module.h"
#include <zlib.h>
-#include "qemu/aes.h"
#include "block/qcow2.h"
#include "qemu/error-report.h"
#include "qapi/qmp/qerror.h"
diff --git a/block/qcow2.h b/block/qcow2.h
index 5936d29..462147c 100644
--- a/block/qcow2.h
+++ b/block/qcow2.h
@@ -25,7 +25,7 @@
#ifndef BLOCK_QCOW2_H
#define BLOCK_QCOW2_H
-#include "qemu/aes.h"
+#include "crypto/aes.h"
#include "block/coroutine.h"
//#define DEBUG_ALLOC
diff --git a/crypto/Makefile.objs b/crypto/Makefile.objs
index 03cc1b2..9efc9b4 100644
--- a/crypto/Makefile.objs
+++ b/crypto/Makefile.objs
@@ -1,2 +1,3 @@
util-obj-y += init.o
util-obj-y += hash.o
+util-obj-y += aes.o
diff --git a/util/aes.c b/crypto/aes.c
similarity index 99%
rename from util/aes.c
rename to crypto/aes.c
index 3d7c4be..244a388 100644
--- a/util/aes.c
+++ b/crypto/aes.c
@@ -28,7 +28,7 @@
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "qemu-common.h"
-#include "qemu/aes.h"
+#include "crypto/aes.h"
typedef uint32_t u32;
typedef uint8_t u8;
diff --git a/include/qemu/aes.h b/include/crypto/aes.h
similarity index 100%
rename from include/qemu/aes.h
rename to include/crypto/aes.h
diff --git a/target-arm/crypto_helper.c b/target-arm/crypto_helper.c
index 1fe975d..5d22838 100644
--- a/target-arm/crypto_helper.c
+++ b/target-arm/crypto_helper.c
@@ -14,7 +14,7 @@
#include "cpu.h"
#include "exec/exec-all.h"
#include "exec/helper-proto.h"
-#include "qemu/aes.h"
+#include "crypto/aes.h"
union CRYPTO_STATE {
uint8_t bytes[16];
diff --git a/target-i386/fpu_helper.c b/target-i386/fpu_helper.c
index 30d34d5..280adba 100644
--- a/target-i386/fpu_helper.c
+++ b/target-i386/fpu_helper.c
@@ -20,7 +20,6 @@
#include <math.h>
#include "cpu.h"
#include "exec/helper-proto.h"
-#include "qemu/aes.h"
#include "qemu/host-utils.h"
#include "exec/cpu_ldst.h"
diff --git a/target-i386/ops_sse.h b/target-i386/ops_sse.h
index 0765073..bee134b 100644
--- a/target-i386/ops_sse.h
+++ b/target-i386/ops_sse.h
@@ -18,7 +18,7 @@
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
-#include "qemu/aes.h"
+#include "crypto/aes.h"
#if SHIFT == 0
#define Reg MMXReg
diff --git a/target-ppc/int_helper.c b/target-ppc/int_helper.c
index 4c2b71c..0a55d5e 100644
--- a/target-ppc/int_helper.c
+++ b/target-ppc/int_helper.c
@@ -19,7 +19,7 @@
#include "cpu.h"
#include "qemu/host-utils.h"
#include "exec/helper-proto.h"
-#include "qemu/aes.h"
+#include "crypto/aes.h"
#include "helper_regs.h"
/*****************************************************************************/
diff --git a/util/Makefile.objs b/util/Makefile.objs
index ceaba30..114d657 100644
--- a/util/Makefile.objs
+++ b/util/Makefile.objs
@@ -9,7 +9,7 @@ util-obj-y += acl.o
util-obj-y += error.o qemu-error.o
util-obj-$(CONFIG_POSIX) += compatfd.o
util-obj-y += id.o
-util-obj-y += iov.o aes.o qemu-config.o qemu-sockets.o uri.o notify.o
+util-obj-y += iov.o qemu-config.o qemu-sockets.o uri.o notify.o
util-obj-y += qemu-option.o qemu-progress.o
util-obj-y += hexdump.o
util-obj-y += crc32c.o
--
2.4.3
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [Qemu-devel] [PULL 4/7] crypto: move built-in D3DES implementation into crypto/
2015-07-07 14:11 [Qemu-devel] [PULL 0/7] Final changes for 2.4-rc0 Paolo Bonzini
` (2 preceding siblings ...)
2015-07-07 14:11 ` [Qemu-devel] [PULL 3/7] crypto: move built-in AES implementation into crypto/ Paolo Bonzini
@ 2015-07-07 14:11 ` Paolo Bonzini
2015-07-07 14:11 ` [Qemu-devel] [PULL 5/7] crypto: introduce generic cipher API & built-in implementation Paolo Bonzini
` (2 subsequent siblings)
6 siblings, 0 replies; 10+ messages in thread
From: Paolo Bonzini @ 2015-07-07 14:11 UTC (permalink / raw)
To: qemu-devel
From: "Daniel P. Berrange" <berrange@redhat.com>
To prepare for a generic internal cipher API, move the
built-in D3DES implementation into the crypto/ directory.
This is not in fact a normal D3DES implementation, it is
D3DES with double & triple length modes removed, and the
key bytes in reversed bit order. IOW it is crippled
specifically for the "benefit" of RFB, so call the new
files desrfb.c instead of d3des.c to make it clear that
it isn't a generally useful impl.
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
Message-Id: <1435770638-25715-4-git-send-email-berrange@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
crypto/Makefile.objs | 1 +
ui/d3des.c => crypto/desrfb.c | 2 +-
ui/d3des.h => include/crypto/desrfb.h | 0
ui/Makefile.objs | 2 +-
ui/vnc.c | 2 +-
5 files changed, 4 insertions(+), 3 deletions(-)
rename ui/d3des.c => crypto/desrfb.c (99%)
rename ui/d3des.h => include/crypto/desrfb.h (100%)
diff --git a/crypto/Makefile.objs b/crypto/Makefile.objs
index 9efc9b4..9f70294 100644
--- a/crypto/Makefile.objs
+++ b/crypto/Makefile.objs
@@ -1,3 +1,4 @@
util-obj-y += init.o
util-obj-y += hash.o
util-obj-y += aes.o
+util-obj-y += desrfb.o
diff --git a/ui/d3des.c b/crypto/desrfb.c
similarity index 99%
rename from ui/d3des.c
rename to crypto/desrfb.c
index 5bc99b8..fc20a30 100644
--- a/ui/d3des.c
+++ b/crypto/desrfb.c
@@ -26,7 +26,7 @@
* (GEnie : OUTER; CIS : [71755,204]) Graven Imagery, 1992.
*/
-#include "d3des.h"
+#include "crypto/desrfb.h"
static void scrunch(unsigned char *, unsigned long *);
static void unscrun(unsigned long *, unsigned char *);
diff --git a/ui/d3des.h b/include/crypto/desrfb.h
similarity index 100%
rename from ui/d3des.h
rename to include/crypto/desrfb.h
diff --git a/ui/Makefile.objs b/ui/Makefile.objs
index 023914c..dd1f8e4 100644
--- a/ui/Makefile.objs
+++ b/ui/Makefile.objs
@@ -1,4 +1,4 @@
-vnc-obj-y += vnc.o d3des.o
+vnc-obj-y += vnc.o
vnc-obj-y += vnc-enc-zlib.o vnc-enc-hextile.o
vnc-obj-y += vnc-enc-tight.o vnc-palette.o
vnc-obj-y += vnc-enc-zrle.o
diff --git a/ui/vnc.c b/ui/vnc.c
index 2ffd9e5..b216182 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -48,7 +48,7 @@ static const struct timeval VNC_REFRESH_STATS = { 0, 500000 };
static const struct timeval VNC_REFRESH_LOSSY = { 2, 0 };
#include "vnc_keysym.h"
-#include "d3des.h"
+#include "crypto/desrfb.h"
static QTAILQ_HEAD(, VncDisplay) vnc_displays =
QTAILQ_HEAD_INITIALIZER(vnc_displays);
--
2.4.3
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [Qemu-devel] [PULL 5/7] crypto: introduce generic cipher API & built-in implementation
2015-07-07 14:11 [Qemu-devel] [PULL 0/7] Final changes for 2.4-rc0 Paolo Bonzini
` (3 preceding siblings ...)
2015-07-07 14:11 ` [Qemu-devel] [PULL 4/7] crypto: move built-in D3DES " Paolo Bonzini
@ 2015-07-07 14:11 ` Paolo Bonzini
2015-07-07 14:11 ` [Qemu-devel] [PULL 6/7] crypto: add a gcrypt cipher implementation Paolo Bonzini
2015-07-07 14:27 ` [Qemu-devel] [PULL 0/7] Final changes for 2.4-rc0 Paolo Bonzini
6 siblings, 0 replies; 10+ messages in thread
From: Paolo Bonzini @ 2015-07-07 14:11 UTC (permalink / raw)
To: qemu-devel
From: "Daniel P. Berrange" <berrange@redhat.com>
Introduce a generic cipher API and an implementation of it that
supports only the built-in AES and DES-RFB algorithms.
The test suite checks the supported algorithms + modes to
validate that every backend implementation is actually correctly
complying with the specs.
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
Message-Id: <1435770638-25715-5-git-send-email-berrange@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
crypto/Makefile.objs | 1 +
crypto/cipher-builtin.c | 398 +++++++++++++++++++++++++++++++++++++++++++++
crypto/cipher.c | 50 ++++++
include/crypto/cipher.h | 210 ++++++++++++++++++++++++
tests/.gitignore | 1 +
tests/Makefile | 2 +
tests/test-crypto-cipher.c | 290 +++++++++++++++++++++++++++++++++
7 files changed, 952 insertions(+)
create mode 100644 crypto/cipher-builtin.c
create mode 100644 crypto/cipher.c
create mode 100644 include/crypto/cipher.h
create mode 100644 tests/test-crypto-cipher.c
diff --git a/crypto/Makefile.objs b/crypto/Makefile.objs
index 9f70294..b050138 100644
--- a/crypto/Makefile.objs
+++ b/crypto/Makefile.objs
@@ -2,3 +2,4 @@ util-obj-y += init.o
util-obj-y += hash.o
util-obj-y += aes.o
util-obj-y += desrfb.o
+util-obj-y += cipher.o
diff --git a/crypto/cipher-builtin.c b/crypto/cipher-builtin.c
new file mode 100644
index 0000000..c625cb4
--- /dev/null
+++ b/crypto/cipher-builtin.c
@@ -0,0 +1,398 @@
+/*
+ * QEMU Crypto cipher built-in algorithms
+ *
+ * Copyright (c) 2015 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "crypto/aes.h"
+#include "crypto/desrfb.h"
+
+typedef struct QCryptoCipherBuiltinAES QCryptoCipherBuiltinAES;
+struct QCryptoCipherBuiltinAES {
+ AES_KEY encrypt_key;
+ AES_KEY decrypt_key;
+ uint8_t *iv;
+ size_t niv;
+};
+typedef struct QCryptoCipherBuiltinDESRFB QCryptoCipherBuiltinDESRFB;
+struct QCryptoCipherBuiltinDESRFB {
+ uint8_t *key;
+ size_t nkey;
+};
+
+typedef struct QCryptoCipherBuiltin QCryptoCipherBuiltin;
+struct QCryptoCipherBuiltin {
+ union {
+ QCryptoCipherBuiltinAES aes;
+ QCryptoCipherBuiltinDESRFB desrfb;
+ } state;
+ void (*free)(QCryptoCipher *cipher);
+ int (*setiv)(QCryptoCipher *cipher,
+ const uint8_t *iv, size_t niv,
+ Error **errp);
+ int (*encrypt)(QCryptoCipher *cipher,
+ const void *in,
+ void *out,
+ size_t len,
+ Error **errp);
+ int (*decrypt)(QCryptoCipher *cipher,
+ const void *in,
+ void *out,
+ size_t len,
+ Error **errp);
+};
+
+
+static void qcrypto_cipher_free_aes(QCryptoCipher *cipher)
+{
+ QCryptoCipherBuiltin *ctxt = cipher->opaque;
+
+ g_free(ctxt->state.aes.iv);
+ g_free(ctxt);
+ cipher->opaque = NULL;
+}
+
+
+static int qcrypto_cipher_encrypt_aes(QCryptoCipher *cipher,
+ const void *in,
+ void *out,
+ size_t len,
+ Error **errp)
+{
+ 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 {
+ AES_cbc_encrypt(in, out, len,
+ &ctxt->state.aes.encrypt_key,
+ ctxt->state.aes.iv, 1);
+ }
+
+ return 0;
+}
+
+
+static int qcrypto_cipher_decrypt_aes(QCryptoCipher *cipher,
+ const void *in,
+ void *out,
+ size_t len,
+ Error **errp)
+{
+ 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.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_decrypt(tmp1, tmp2, &ctxt->state.aes.encrypt_key);
+ memcpy(outptr, tmp2, len);
+ len = 0;
+ }
+ }
+ } else {
+ AES_cbc_encrypt(in, out, len,
+ &ctxt->state.aes.encrypt_key,
+ ctxt->state.aes.iv, 1);
+ }
+
+ return 0;
+}
+
+static int qcrypto_cipher_setiv_aes(QCryptoCipher *cipher,
+ const uint8_t *iv, size_t niv,
+ Error **errp)
+{
+ QCryptoCipherBuiltin *ctxt = cipher->opaque;
+ if (niv != 16) {
+ error_setg(errp, "IV must be 16 bytes not %zu", niv);
+ return -1;
+ }
+
+ g_free(ctxt->state.aes.iv);
+ ctxt->state.aes.iv = g_new0(uint8_t, niv);
+ memcpy(ctxt->state.aes.iv, iv, niv);
+ ctxt->state.aes.niv = niv;
+
+ return 0;
+}
+
+
+
+
+static int qcrypto_cipher_init_aes(QCryptoCipher *cipher,
+ const uint8_t *key, size_t nkey,
+ Error **errp)
+{
+ QCryptoCipherBuiltin *ctxt;
+
+ if (cipher->mode != QCRYPTO_CIPHER_MODE_CBC &&
+ cipher->mode != QCRYPTO_CIPHER_MODE_ECB) {
+ 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.encrypt_key) != 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) {
+ error_setg(errp, "Failed to set decryption key");
+ goto error;
+ }
+
+ ctxt->free = qcrypto_cipher_free_aes;
+ ctxt->setiv = qcrypto_cipher_setiv_aes;
+ ctxt->encrypt = qcrypto_cipher_encrypt_aes;
+ ctxt->decrypt = qcrypto_cipher_decrypt_aes;
+
+ cipher->opaque = ctxt;
+
+ return 0;
+
+ error:
+ g_free(ctxt);
+ return -1;
+}
+
+
+static void qcrypto_cipher_free_des_rfb(QCryptoCipher *cipher)
+{
+ QCryptoCipherBuiltin *ctxt = cipher->opaque;
+
+ g_free(ctxt->state.desrfb.key);
+ g_free(ctxt);
+ cipher->opaque = NULL;
+}
+
+
+static int qcrypto_cipher_encrypt_des_rfb(QCryptoCipher *cipher,
+ const void *in,
+ void *out,
+ size_t len,
+ Error **errp)
+{
+ QCryptoCipherBuiltin *ctxt = cipher->opaque;
+ size_t i;
+
+ if (len % 8) {
+ error_setg(errp, "Buffer size must be multiple of 8 not %zu",
+ len);
+ return -1;
+ }
+
+ deskey(ctxt->state.desrfb.key, EN0);
+
+ for (i = 0; i < len; i += 8) {
+ des((void *)in + i, out + i);
+ }
+
+ return 0;
+}
+
+
+static int qcrypto_cipher_decrypt_des_rfb(QCryptoCipher *cipher,
+ const void *in,
+ void *out,
+ size_t len,
+ Error **errp)
+{
+ QCryptoCipherBuiltin *ctxt = cipher->opaque;
+ size_t i;
+
+ if (len % 8) {
+ error_setg(errp, "Buffer size must be multiple of 8 not %zu",
+ len);
+ return -1;
+ }
+
+ deskey(ctxt->state.desrfb.key, DE1);
+
+ for (i = 0; i < len; i += 8) {
+ des((void *)in + i, out + i);
+ }
+
+ return 0;
+}
+
+
+static int qcrypto_cipher_setiv_des_rfb(QCryptoCipher *cipher,
+ const uint8_t *iv, size_t niv,
+ Error **errp)
+{
+ error_setg(errp, "Setting IV is not supported");
+ return -1;
+}
+
+
+static int qcrypto_cipher_init_des_rfb(QCryptoCipher *cipher,
+ const uint8_t *key, size_t nkey,
+ Error **errp)
+{
+ QCryptoCipherBuiltin *ctxt;
+
+ if (cipher->mode != QCRYPTO_CIPHER_MODE_ECB) {
+ error_setg(errp, "Unsupported cipher mode %d", cipher->mode);
+ return -1;
+ }
+
+ ctxt = g_new0(QCryptoCipherBuiltin, 1);
+
+ ctxt->state.desrfb.key = g_new0(uint8_t, nkey);
+ memcpy(ctxt->state.desrfb.key, key, nkey);
+ ctxt->state.desrfb.nkey = nkey;
+
+ ctxt->free = qcrypto_cipher_free_des_rfb;
+ ctxt->setiv = qcrypto_cipher_setiv_des_rfb;
+ ctxt->encrypt = qcrypto_cipher_encrypt_des_rfb;
+ ctxt->decrypt = qcrypto_cipher_decrypt_des_rfb;
+
+ cipher->opaque = ctxt;
+
+ return 0;
+}
+
+
+bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg)
+{
+ switch (alg) {
+ case QCRYPTO_CIPHER_ALG_DES_RFB:
+ case QCRYPTO_CIPHER_ALG_AES_128:
+ case QCRYPTO_CIPHER_ALG_AES_192:
+ case QCRYPTO_CIPHER_ALG_AES_256:
+ return true;
+ default:
+ return false;
+ }
+}
+
+
+QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,
+ QCryptoCipherMode mode,
+ const uint8_t *key, size_t nkey,
+ Error **errp)
+{
+ QCryptoCipher *cipher;
+
+ cipher = g_new0(QCryptoCipher, 1);
+ cipher->alg = alg;
+ cipher->mode = mode;
+
+ if (!qcrypto_cipher_validate_key_length(alg, nkey, errp)) {
+ goto error;
+ }
+
+ switch (cipher->alg) {
+ case QCRYPTO_CIPHER_ALG_DES_RFB:
+ if (qcrypto_cipher_init_des_rfb(cipher, key, nkey, errp) < 0) {
+ goto error;
+ }
+ break;
+ case QCRYPTO_CIPHER_ALG_AES_128:
+ case QCRYPTO_CIPHER_ALG_AES_192:
+ case QCRYPTO_CIPHER_ALG_AES_256:
+ if (qcrypto_cipher_init_aes(cipher, key, nkey, errp) < 0) {
+ goto error;
+ }
+ break;
+ default:
+ error_setg(errp,
+ "Unsupported cipher algorithm %d", cipher->alg);
+ goto error;
+ }
+
+ return cipher;
+
+ error:
+ g_free(cipher);
+ return NULL;
+}
+
+void qcrypto_cipher_free(QCryptoCipher *cipher)
+{
+ QCryptoCipherBuiltin *ctxt = cipher->opaque;
+ if (!cipher) {
+ return;
+ }
+
+ ctxt->free(cipher);
+ g_free(cipher);
+}
+
+
+int qcrypto_cipher_encrypt(QCryptoCipher *cipher,
+ const void *in,
+ void *out,
+ size_t len,
+ Error **errp)
+{
+ QCryptoCipherBuiltin *ctxt = cipher->opaque;
+
+ return ctxt->encrypt(cipher, in, out, len, errp);
+}
+
+
+int qcrypto_cipher_decrypt(QCryptoCipher *cipher,
+ const void *in,
+ void *out,
+ size_t len,
+ Error **errp)
+{
+ QCryptoCipherBuiltin *ctxt = cipher->opaque;
+
+ return ctxt->decrypt(cipher, in, out, len, errp);
+}
+
+
+int qcrypto_cipher_setiv(QCryptoCipher *cipher,
+ const uint8_t *iv, size_t niv,
+ Error **errp)
+{
+ QCryptoCipherBuiltin *ctxt = cipher->opaque;
+
+ return ctxt->setiv(cipher, iv, niv, errp);
+}
diff --git a/crypto/cipher.c b/crypto/cipher.c
new file mode 100644
index 0000000..9af5af7
--- /dev/null
+++ b/crypto/cipher.c
@@ -0,0 +1,50 @@
+/*
+ * QEMU Crypto cipher algorithms
+ *
+ * Copyright (c) 2015 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "crypto/cipher.h"
+
+static size_t alg_key_len[QCRYPTO_CIPHER_ALG_LAST] = {
+ [QCRYPTO_CIPHER_ALG_AES_128] = 16,
+ [QCRYPTO_CIPHER_ALG_AES_192] = 24,
+ [QCRYPTO_CIPHER_ALG_AES_256] = 32,
+ [QCRYPTO_CIPHER_ALG_DES_RFB] = 8,
+};
+
+static bool
+qcrypto_cipher_validate_key_length(QCryptoCipherAlgorithm alg,
+ size_t nkey,
+ Error **errp)
+{
+ if (alg < 0 ||
+ alg >= QCRYPTO_CIPHER_ALG_LAST) {
+ error_setg(errp, "Cipher algorithm %d out of range",
+ alg);
+ return false;
+ }
+
+ if (alg_key_len[alg] != nkey) {
+ error_setg(errp, "Cipher key length %zu should be %zu",
+ alg_key_len[alg], nkey);
+ return false;
+ }
+ return true;
+}
+
+#include "crypto/cipher-builtin.c"
diff --git a/include/crypto/cipher.h b/include/crypto/cipher.h
new file mode 100644
index 0000000..b4d714f
--- /dev/null
+++ b/include/crypto/cipher.h
@@ -0,0 +1,210 @@
+/*
+ * QEMU Crypto cipher algorithms
+ *
+ * Copyright (c) 2015 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef QCRYPTO_CIPHER_H__
+#define QCRYPTO_CIPHER_H__
+
+#include "qemu-common.h"
+#include "qapi/error.h"
+
+typedef struct QCryptoCipher QCryptoCipher;
+
+typedef enum {
+ QCRYPTO_CIPHER_ALG_AES_128,
+ QCRYPTO_CIPHER_ALG_AES_192,
+ QCRYPTO_CIPHER_ALG_AES_256,
+ QCRYPTO_CIPHER_ALG_DES_RFB, /* A stupid variant on DES for VNC */
+
+ QCRYPTO_CIPHER_ALG_LAST
+} QCryptoCipherAlgorithm;
+
+typedef enum {
+ QCRYPTO_CIPHER_MODE_ECB,
+ QCRYPTO_CIPHER_MODE_CBC,
+
+ QCRYPTO_CIPHER_MODE_LAST
+} QCryptoCipherMode;
+
+/**
+ * QCryptoCipher:
+ *
+ * The QCryptoCipher object provides a way to perform encryption
+ * and decryption of data, with a standard API, regardless of the
+ * algorithm used. It further isolates the calling code from the
+ * details of the specific underlying implementation, whether
+ * built-in, libgcrypt or nettle.
+ *
+ * Each QCryptoCipher object is capable of performing both
+ * encryption and decryption, and can operate in a number
+ * or modes including ECB, CBC.
+ *
+ * <example>
+ * <title>Encrypting data with AES-128 in CBC mode</title>
+ * <programlisting>
+ * QCryptoCipher *cipher;
+ * uint8_t key = ....;
+ * size_t keylen = 16;
+ * uint8_t iv = ....;
+ *
+ * if (!qcrypto_cipher_supports(QCRYPTO_CIPHER_ALG_AES_128)) {
+ * error_report(errp, "Feature <blah> requires AES cipher support");
+ * return -1;
+ * }
+ *
+ * cipher = qcrypto_cipher_new(QCRYPTO_CIPHER_ALG_AES_128,
+ * QCRYPTO_CIPHER_MODE_CBC,
+ * key, keylen,
+ * errp);
+ * if (!cipher) {
+ * return -1;
+ * }
+ *
+ * if (qcrypto_cipher_set_iv(cipher, iv, keylen, errp) < 0) {
+ * return -1;
+ * }
+ *
+ * if (qcrypto_cipher_encrypt(cipher, rawdata, encdata, datalen, errp) < 0) {
+ * return -1;
+ * }
+ *
+ * qcrypto_cipher_free(cipher);
+ * </programlisting>
+ * </example>
+ *
+ */
+
+struct QCryptoCipher {
+ QCryptoCipherAlgorithm alg;
+ QCryptoCipherMode mode;
+ void *opaque;
+};
+
+/**
+ * qcrypto_cipher_supports:
+ * @alg: the cipher algorithm
+ *
+ * Determine if @alg cipher algorithm is supported by the
+ * current configured build
+ *
+ * Returns: true if the algorithm is supported, false otherwise
+ */
+bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg);
+
+
+/**
+ * qcrypto_cipher_new:
+ * @alg: the cipher algorithm
+ * @mode: the cipher usage mode
+ * @key: the private key bytes
+ * @nkey: the length of @key
+ * @errp: pointer to an uninitialized error object
+ *
+ * Creates a new cipher object for encrypting/decrypting
+ * data with the algorithm @alg in the usage mode @mode.
+ *
+ * The @key parameter provides the bytes representing
+ * the encryption/decryption key to use. The @nkey parameter
+ * specifies the length of @key in bytes. Each algorithm has
+ * one or more valid key lengths, and it is an error to provide
+ * a key of the incorrect length.
+ *
+ * The returned cipher object must be released with
+ * qcrypto_cipher_free() when no longer required
+ *
+ * Returns: a new cipher object, or NULL on error
+ */
+QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,
+ QCryptoCipherMode mode,
+ const uint8_t *key, size_t nkey,
+ Error **errp);
+
+/**
+ * qcrypto_cipher_free:
+ * @cipher: the cipher object
+ *
+ * Release the memory associated with @cipher that
+ * was previously allocated by qcrypto_cipher_new()
+ */
+void qcrypto_cipher_free(QCryptoCipher *cipher);
+
+/**
+ * qcrypto_cipher_encrypt:
+ * @cipher: the cipher object
+ * @in: buffer holding the plain text input data
+ * @out: buffer to fill with the cipher text output data
+ * @len: the length of @in and @out buffers
+ * @errp: pointer to an uninitialized error object
+ *
+ * Encrypts the plain text stored in @in, filling
+ * @out with the resulting ciphered text. Both the
+ * @in and @out buffers must have the same size,
+ * given by @len.
+ *
+ * Returns: 0 on success, or -1 on error
+ */
+int qcrypto_cipher_encrypt(QCryptoCipher *cipher,
+ const void *in,
+ void *out,
+ size_t len,
+ Error **errp);
+
+
+/**
+ * qcrypto_cipher_decrypt:
+ * @cipher: the cipher object
+ * @in: buffer holding the cipher text input data
+ * @out: buffer to fill with the plain text output data
+ * @len: the length of @in and @out buffers
+ * @errp: pointer to an uninitialized error object
+ *
+ * Decrypts the cipher text stored in @in, filling
+ * @out with the resulting plain text. Both the
+ * @in and @out buffers must have the same size,
+ * given by @len.
+ *
+ * Returns: 0 on success, or -1 on error
+ */
+int qcrypto_cipher_decrypt(QCryptoCipher *cipher,
+ const void *in,
+ void *out,
+ size_t len,
+ Error **errp);
+
+/**
+ * qcrypto_cipher_setiv:
+ * @cipher: the cipher object
+ * @iv: the initialization vector bytes
+ * @niv: the length of @iv
+ * @errpr: pointer to an uninitialized error object
+ *
+ * If the @cipher object is setup to use a mode that requires
+ * initialization vectors, this sets the initialization vector
+ * bytes. The @iv data should have the same length as the
+ * cipher key used when originally constructing the cipher
+ * object. It is an error to set an initialization vector
+ * if the cipher mode does not require one.
+ *
+ * Returns: 0 on success, -1 on error
+ */
+int qcrypto_cipher_setiv(QCryptoCipher *cipher,
+ const uint8_t *iv, size_t niv,
+ Error **errp);
+
+#endif /* QCRYPTO_CIPHER_H__ */
diff --git a/tests/.gitignore b/tests/.gitignore
index 18f60f1..ccc92e4 100644
--- a/tests/.gitignore
+++ b/tests/.gitignore
@@ -10,6 +10,7 @@ rcutorture
test-aio
test-bitops
test-coroutine
+test-crypto-cipher
test-crypto-hash
test-cutils
test-hbitmap
diff --git a/tests/Makefile b/tests/Makefile
index 8c7f1ac..09838ac 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -75,6 +75,7 @@ gcov-files-test-qemu-opts-y = qom/test-qemu-opts.c
check-unit-y += tests/test-write-threshold$(EXESUF)
gcov-files-test-write-threshold-y = block/write-threshold.c
check-unit-$(CONFIG_GNUTLS_HASH) += tests/test-crypto-hash$(EXESUF)
+check-unit-y += tests/test-crypto-cipher$(EXESUF)
check-block-$(CONFIG_POSIX) += tests/qemu-iotests-quick.sh
@@ -341,6 +342,7 @@ tests/test-opts-visitor$(EXESUF): tests/test-opts-visitor.o $(test-qapi-obj-y) l
tests/test-mul64$(EXESUF): tests/test-mul64.o libqemuutil.a
tests/test-bitops$(EXESUF): tests/test-bitops.o libqemuutil.a
tests/test-crypto-hash$(EXESUF): tests/test-crypto-hash.o libqemuutil.a libqemustub.a
+tests/test-crypto-cipher$(EXESUF): tests/test-crypto-cipher.o libqemuutil.a libqemustub.a
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
diff --git a/tests/test-crypto-cipher.c b/tests/test-crypto-cipher.c
new file mode 100644
index 0000000..f9b1a03
--- /dev/null
+++ b/tests/test-crypto-cipher.c
@@ -0,0 +1,290 @@
+/*
+ * QEMU Crypto cipher algorithms
+ *
+ * Copyright (c) 2015 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <glib.h>
+
+#include "crypto/init.h"
+#include "crypto/cipher.h"
+
+typedef struct QCryptoCipherTestData QCryptoCipherTestData;
+struct QCryptoCipherTestData {
+ const char *path;
+ QCryptoCipherAlgorithm alg;
+ QCryptoCipherMode mode;
+ const char *key;
+ const char *plaintext;
+ const char *ciphertext;
+ const char *iv;
+};
+
+/* AES test data comes from appendix F of:
+ *
+ * http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf
+ */
+static QCryptoCipherTestData test_data[] = {
+ {
+ /* NIST F.1.1 ECB-AES128.Encrypt */
+ .path = "/crypto/cipher/aes-ecb-128",
+ .alg = QCRYPTO_CIPHER_ALG_AES_128,
+ .mode = QCRYPTO_CIPHER_MODE_ECB,
+ .key = "2b7e151628aed2a6abf7158809cf4f3c",
+ .plaintext =
+ "6bc1bee22e409f96e93d7e117393172a"
+ "ae2d8a571e03ac9c9eb76fac45af8e51"
+ "30c81c46a35ce411e5fbc1191a0a52ef"
+ "f69f2445df4f9b17ad2b417be66c3710",
+ .ciphertext =
+ "3ad77bb40d7a3660a89ecaf32466ef97"
+ "f5d3d58503b9699de785895a96fdbaaf"
+ "43b1cd7f598ece23881b00e3ed030688"
+ "7b0c785e27e8ad3f8223207104725dd4"
+ },
+ {
+ /* NIST F.1.3 ECB-AES192.Encrypt */
+ .path = "/crypto/cipher/aes-ecb-192",
+ .alg = QCRYPTO_CIPHER_ALG_AES_192,
+ .mode = QCRYPTO_CIPHER_MODE_ECB,
+ .key = "8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b",
+ .plaintext =
+ "6bc1bee22e409f96e93d7e117393172a"
+ "ae2d8a571e03ac9c9eb76fac45af8e51"
+ "30c81c46a35ce411e5fbc1191a0a52ef"
+ "f69f2445df4f9b17ad2b417be66c3710",
+ .ciphertext =
+ "bd334f1d6e45f25ff712a214571fa5cc"
+ "974104846d0ad3ad7734ecb3ecee4eef"
+ "ef7afd2270e2e60adce0ba2face6444e"
+ "9a4b41ba738d6c72fb16691603c18e0e"
+ },
+ {
+ /* NIST F.1.5 ECB-AES256.Encrypt */
+ .path = "/crypto/cipher/aes-ecb-256",
+ .alg = QCRYPTO_CIPHER_ALG_AES_256,
+ .mode = QCRYPTO_CIPHER_MODE_ECB,
+ .key =
+ "603deb1015ca71be2b73aef0857d7781"
+ "1f352c073b6108d72d9810a30914dff4",
+ .plaintext =
+ "6bc1bee22e409f96e93d7e117393172a"
+ "ae2d8a571e03ac9c9eb76fac45af8e51"
+ "30c81c46a35ce411e5fbc1191a0a52ef"
+ "f69f2445df4f9b17ad2b417be66c3710",
+ .ciphertext =
+ "f3eed1bdb5d2a03c064b5a7e3db181f8"
+ "591ccb10d410ed26dc5ba74a31362870"
+ "b6ed21b99ca6f4f9f153e7b1beafed1d"
+ "23304b7a39f9f3ff067d8d8f9e24ecc7",
+ },
+ {
+ /* NIST F.2.1 CBC-AES128.Encrypt */
+ .path = "/crypto/cipher/aes-cbc-128",
+ .alg = QCRYPTO_CIPHER_ALG_AES_128,
+ .mode = QCRYPTO_CIPHER_MODE_CBC,
+ .key = "2b7e151628aed2a6abf7158809cf4f3c",
+ .iv = "000102030405060708090a0b0c0d0e0f",
+ .plaintext =
+ "6bc1bee22e409f96e93d7e117393172a"
+ "ae2d8a571e03ac9c9eb76fac45af8e51"
+ "30c81c46a35ce411e5fbc1191a0a52ef"
+ "f69f2445df4f9b17ad2b417be66c3710",
+ .ciphertext =
+ "7649abac8119b246cee98e9b12e9197d"
+ "5086cb9b507219ee95db113a917678b2"
+ "73bed6b8e3c1743b7116e69e22229516"
+ "3ff1caa1681fac09120eca307586e1a7",
+ },
+ {
+ /* NIST F.2.3 CBC-AES128.Encrypt */
+ .path = "/crypto/cipher/aes-cbc-192",
+ .alg = QCRYPTO_CIPHER_ALG_AES_192,
+ .mode = QCRYPTO_CIPHER_MODE_CBC,
+ .key = "8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b",
+ .iv = "000102030405060708090a0b0c0d0e0f",
+ .plaintext =
+ "6bc1bee22e409f96e93d7e117393172a"
+ "ae2d8a571e03ac9c9eb76fac45af8e51"
+ "30c81c46a35ce411e5fbc1191a0a52ef"
+ "f69f2445df4f9b17ad2b417be66c3710",
+ .ciphertext =
+ "4f021db243bc633d7178183a9fa071e8"
+ "b4d9ada9ad7dedf4e5e738763f69145a"
+ "571b242012fb7ae07fa9baac3df102e0"
+ "08b0e27988598881d920a9e64f5615cd",
+ },
+ {
+ /* NIST F.2.5 CBC-AES128.Encrypt */
+ .path = "/crypto/cipher/aes-cbc-256",
+ .alg = QCRYPTO_CIPHER_ALG_AES_256,
+ .mode = QCRYPTO_CIPHER_MODE_CBC,
+ .key =
+ "603deb1015ca71be2b73aef0857d7781"
+ "1f352c073b6108d72d9810a30914dff4",
+ .iv = "000102030405060708090a0b0c0d0e0f",
+ .plaintext =
+ "6bc1bee22e409f96e93d7e117393172a"
+ "ae2d8a571e03ac9c9eb76fac45af8e51"
+ "30c81c46a35ce411e5fbc1191a0a52ef"
+ "f69f2445df4f9b17ad2b417be66c3710",
+ .ciphertext =
+ "f58c4c04d6e5f1ba779eabfb5f7bfbd6"
+ "9cfc4e967edb808d679f777bc6702c7d"
+ "39f23369a9d9bacfa530e26304231461"
+ "b2eb05e2c39be9fcda6c19078c6a9d1b",
+ },
+ {
+ .path = "/crypto/cipher/des-rfb-ecb-56",
+ .alg = QCRYPTO_CIPHER_ALG_DES_RFB,
+ .mode = QCRYPTO_CIPHER_MODE_ECB,
+ .key = "0123456789abcdef",
+ .plaintext =
+ "6bc1bee22e409f96e93d7e117393172a"
+ "ae2d8a571e03ac9c9eb76fac45af8e51"
+ "30c81c46a35ce411e5fbc1191a0a52ef"
+ "f69f2445df4f9b17ad2b417be66c3710",
+ .ciphertext =
+ "8f346aaf64eaf24040720d80648c52e7"
+ "aefc616be53ab1a3d301e69d91e01838"
+ "ffd29f1bb5596ad94ea2d8e6196b7f09"
+ "30d8ed0bf2773af36dd82a6280c20926",
+ },
+};
+
+
+static inline int unhex(char c)
+{
+ if (c >= 'a' && c <= 'f') {
+ return 10 + (c - 'a');
+ }
+ if (c >= 'A' && c <= 'F') {
+ return 10 + (c - 'A');
+ }
+ return c - '0';
+}
+
+static inline char hex(int i)
+{
+ if (i < 10) {
+ return '0' + i;
+ }
+ return 'a' + (i - 10);
+}
+
+static size_t unhex_string(const char *hexstr,
+ uint8_t **data)
+{
+ size_t len;
+ size_t i;
+
+ if (!hexstr) {
+ *data = NULL;
+ return 0;
+ }
+
+ len = strlen(hexstr);
+ *data = g_new0(uint8_t, len / 2);
+
+ for (i = 0; i < len; i += 2) {
+ (*data)[i/2] = (unhex(hexstr[i]) << 4) | unhex(hexstr[i+1]);
+ }
+ return len / 2;
+}
+
+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_cipher(const void *opaque)
+{
+ const QCryptoCipherTestData *data = opaque;
+
+ QCryptoCipher *cipher;
+ Error *err = NULL;
+ uint8_t *key, *iv, *ciphertext, *plaintext, *outtext;
+ size_t nkey, niv, nciphertext, nplaintext;
+ char *outtexthex;
+
+ g_test_message("foo");
+ nkey = unhex_string(data->key, &key);
+ niv = unhex_string(data->iv, &iv);
+ nciphertext = unhex_string(data->ciphertext, &ciphertext);
+ nplaintext = unhex_string(data->plaintext, &plaintext);
+
+ g_assert(nciphertext == nplaintext);
+
+ outtext = g_new0(uint8_t, nciphertext);
+
+ cipher = qcrypto_cipher_new(
+ data->alg, data->mode,
+ key, nkey,
+ &err);
+ g_assert(cipher != NULL);
+ g_assert(err == NULL);
+
+
+ if (iv) {
+ g_assert(qcrypto_cipher_setiv(cipher,
+ iv, niv,
+ &err) == 0);
+ g_assert(err == NULL);
+ }
+ g_assert(qcrypto_cipher_encrypt(cipher,
+ plaintext,
+ outtext,
+ nplaintext,
+ &err) == 0);
+ g_assert(err == NULL);
+
+ outtexthex = hex_string(outtext, nciphertext);
+
+ g_assert_cmpstr(outtexthex, ==, data->ciphertext);
+
+ g_free(outtext);
+ g_free(outtexthex);
+ g_free(key);
+ g_free(iv);
+ g_free(ciphertext);
+ g_free(plaintext);
+ qcrypto_cipher_free(cipher);
+}
+
+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_cipher);
+ }
+ return g_test_run();
+}
--
2.4.3
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [Qemu-devel] [PULL 6/7] crypto: add a gcrypt cipher implementation
2015-07-07 14:11 [Qemu-devel] [PULL 0/7] Final changes for 2.4-rc0 Paolo Bonzini
` (4 preceding siblings ...)
2015-07-07 14:11 ` [Qemu-devel] [PULL 5/7] crypto: introduce generic cipher API & built-in implementation Paolo Bonzini
@ 2015-07-07 14:11 ` Paolo Bonzini
2015-07-07 14:27 ` [Qemu-devel] [PULL 0/7] Final changes for 2.4-rc0 Paolo Bonzini
6 siblings, 0 replies; 10+ messages in thread
From: Paolo Bonzini @ 2015-07-07 14:11 UTC (permalink / raw)
To: qemu-devel
From: "Daniel P. Berrange" <berrange@redhat.com>
If we are linking to gnutls already and gnutls is built against
gcrypt, then we should use gcrypt as a cipher backend in
preference to our built-in backend.
This will be used when linking against GNUTLS 1.x and many
GNUTLS 2.x versions.
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
Message-Id: <1435770638-25715-6-git-send-email-berrange@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
configure | 29 ++++++++
crypto/cipher-gcrypt.c | 195 +++++++++++++++++++++++++++++++++++++++++++++++++
crypto/cipher.c | 23 ++++++
crypto/init.c | 90 +++++++++++++++++++++++
4 files changed, 337 insertions(+)
create mode 100644 crypto/cipher-gcrypt.c
diff --git a/configure b/configure
index 61a749e..f3c7ca6 100755
--- a/configure
+++ b/configure
@@ -2126,6 +2126,7 @@ fi
##########################################
# GNUTLS probe
+gnutls_gcrypt=no
if test "$gnutls" != "no"; then
if $pkg_config --exists "gnutls"; then
gnutls_cflags=`$pkg_config --cflags gnutls`
@@ -2141,6 +2142,18 @@ if test "$gnutls" != "no"; then
else
gnutls_hash="no"
fi
+
+ if $pkg_config --exists 'gnutls >= 3.0'; then
+ gnutls_gcrypt=no
+ elif $pkg_config --exists 'gnutls >= 2.12'; then
+ case `$pkg_config --libs --static gnutls` in
+ *gcrypt*) gnutls_gcrypt=yes ;;
+ *nettle*) gnutls_gcrypt=no ;;
+ *) gnutls_gcrypt=yes ;;
+ esac
+ else
+ gnutls_gcrypt=yes
+ fi
elif test "$gnutls" = "yes"; then
feature_not_found "gnutls" "Install gnutls devel"
else
@@ -2151,6 +2164,18 @@ else
gnutls_hash="no"
fi
+if test "$gnutls_gcrypt" != "no"; then
+ if has "libgcrypt-config"; then
+ gcrypt_cflags=`libgcrypt-config --cflags`
+ gcrypt_libs=`libgcrypt-config --libs`
+ libs_softmmu="$gcrypt_libs $libs_softmmu"
+ libs_tools="$gcrypt_libs $libs_tools"
+ QEMU_CFLAGS="$QEMU_CFLAGS $gcrypt_cflags"
+ else
+ feature_not_found "gcrypt" "Install gcrypt devel"
+ fi
+fi
+
##########################################
# VTE probe
@@ -4463,6 +4488,7 @@ echo "SDL support $sdl"
echo "GTK support $gtk"
echo "GNUTLS support $gnutls"
echo "GNUTLS hash $gnutls_hash"
+echo "GNUTLS gcrypt $gnutls_gcrypt"
echo "VTE support $vte"
echo "curses support $curses"
echo "curl support $curl"
@@ -4827,6 +4853,9 @@ fi
if test "$gnutls_hash" = "yes" ; then
echo "CONFIG_GNUTLS_HASH=y" >> $config_host_mak
fi
+if test "$gnutls_gcrypt" = "yes" ; then
+ echo "CONFIG_GNUTLS_GCRYPT=y" >> $config_host_mak
+fi
if test "$vte" = "yes" ; then
echo "CONFIG_VTE=y" >> $config_host_mak
echo "VTE_CFLAGS=$vte_cflags" >> $config_host_mak
diff --git a/crypto/cipher-gcrypt.c b/crypto/cipher-gcrypt.c
new file mode 100644
index 0000000..8cfc562
--- /dev/null
+++ b/crypto/cipher-gcrypt.c
@@ -0,0 +1,195 @@
+/*
+ * QEMU Crypto cipher libgcrypt algorithms
+ *
+ * Copyright (c) 2015 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <gcrypt.h>
+
+
+bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg)
+{
+ switch (alg) {
+ case QCRYPTO_CIPHER_ALG_DES_RFB:
+ case QCRYPTO_CIPHER_ALG_AES_128:
+ case QCRYPTO_CIPHER_ALG_AES_192:
+ case QCRYPTO_CIPHER_ALG_AES_256:
+ return true;
+ default:
+ return false;
+ }
+}
+
+
+QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,
+ QCryptoCipherMode mode,
+ const uint8_t *key, size_t nkey,
+ Error **errp)
+{
+ QCryptoCipher *cipher;
+ gcry_cipher_hd_t handle;
+ gcry_error_t err;
+ int gcryalg, gcrymode;
+
+ switch (mode) {
+ case QCRYPTO_CIPHER_MODE_ECB:
+ gcrymode = GCRY_CIPHER_MODE_ECB;
+ break;
+ case QCRYPTO_CIPHER_MODE_CBC:
+ gcrymode = GCRY_CIPHER_MODE_CBC;
+ break;
+ default:
+ error_setg(errp, "Unsupported cipher mode %d", mode);
+ return NULL;
+ }
+
+ if (!qcrypto_cipher_validate_key_length(alg, nkey, errp)) {
+ return NULL;
+ }
+
+ switch (alg) {
+ case QCRYPTO_CIPHER_ALG_DES_RFB:
+ gcryalg = GCRY_CIPHER_DES;
+ break;
+
+ case QCRYPTO_CIPHER_ALG_AES_128:
+ gcryalg = GCRY_CIPHER_AES128;
+ break;
+
+ case QCRYPTO_CIPHER_ALG_AES_192:
+ gcryalg = GCRY_CIPHER_AES192;
+ break;
+
+ case QCRYPTO_CIPHER_ALG_AES_256:
+ gcryalg = GCRY_CIPHER_AES256;
+ break;
+
+ default:
+ error_setg(errp, "Unsupported cipher algorithm %d", alg);
+ return NULL;
+ }
+
+ cipher = g_new0(QCryptoCipher, 1);
+ cipher->alg = alg;
+ cipher->mode = mode;
+
+ err = gcry_cipher_open(&handle, gcryalg, gcrymode, 0);
+ if (err != 0) {
+ error_setg(errp, "Cannot initialize cipher: %s",
+ gcry_strerror(err));
+ goto error;
+ }
+
+ if (cipher->alg == QCRYPTO_CIPHER_ALG_DES_RFB) {
+ /* We're using standard DES cipher from gcrypt, so we need
+ * to munge the key so that the results are the same as the
+ * bizarre RFB variant of DES :-)
+ */
+ uint8_t *rfbkey = qcrypto_cipher_munge_des_rfb_key(key, nkey);
+ err = gcry_cipher_setkey(handle, rfbkey, nkey);
+ g_free(rfbkey);
+ } else {
+ err = gcry_cipher_setkey(handle, key, nkey);
+ }
+ if (err != 0) {
+ error_setg(errp, "Cannot set key: %s",
+ gcry_strerror(err));
+ goto error;
+ }
+
+ cipher->opaque = handle;
+ return cipher;
+
+ error:
+ gcry_cipher_close(handle);
+ g_free(cipher);
+ return NULL;
+}
+
+
+void qcrypto_cipher_free(QCryptoCipher *cipher)
+{
+ gcry_cipher_hd_t handle;
+ if (!cipher) {
+ return;
+ }
+ handle = cipher->opaque;
+ gcry_cipher_close(handle);
+ g_free(cipher);
+}
+
+
+int qcrypto_cipher_encrypt(QCryptoCipher *cipher,
+ const void *in,
+ void *out,
+ size_t len,
+ Error **errp)
+{
+ gcry_cipher_hd_t handle = cipher->opaque;
+ gcry_error_t err;
+
+ err = gcry_cipher_encrypt(handle,
+ out, len,
+ in, len);
+ if (err != 0) {
+ error_setg(errp, "Cannot encrypt data: %s",
+ gcry_strerror(err));
+ return -1;
+ }
+
+ return 0;
+}
+
+
+int qcrypto_cipher_decrypt(QCryptoCipher *cipher,
+ const void *in,
+ void *out,
+ size_t len,
+ Error **errp)
+{
+ gcry_cipher_hd_t handle = cipher->opaque;
+ gcry_error_t err;
+
+ err = gcry_cipher_decrypt(handle,
+ out, len,
+ in, len);
+ if (err != 0) {
+ error_setg(errp, "Cannot decrypt data: %s",
+ gcry_strerror(err));
+ return -1;
+ }
+
+ return 0;
+}
+
+int qcrypto_cipher_setiv(QCryptoCipher *cipher,
+ const uint8_t *iv, size_t niv,
+ Error **errp)
+{
+ gcry_cipher_hd_t handle = cipher->opaque;
+ gcry_error_t err;
+
+ gcry_cipher_reset(handle);
+ err = gcry_cipher_setiv(handle, iv, niv);
+ if (err != 0) {
+ error_setg(errp, "Cannot set IV: %s",
+ gcry_strerror(err));
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/crypto/cipher.c b/crypto/cipher.c
index 9af5af7..f38f542 100644
--- a/crypto/cipher.c
+++ b/crypto/cipher.c
@@ -20,6 +20,7 @@
#include "crypto/cipher.h"
+
static size_t alg_key_len[QCRYPTO_CIPHER_ALG_LAST] = {
[QCRYPTO_CIPHER_ALG_AES_128] = 16,
[QCRYPTO_CIPHER_ALG_AES_192] = 24,
@@ -47,4 +48,26 @@ qcrypto_cipher_validate_key_length(QCryptoCipherAlgorithm alg,
return true;
}
+#if defined(CONFIG_GNUTLS_GCRYPT)
+static uint8_t *
+qcrypto_cipher_munge_des_rfb_key(const uint8_t *key,
+ size_t nkey)
+{
+ uint8_t *ret = g_new0(uint8_t, nkey);
+ size_t i;
+ for (i = 0; i < nkey; i++) {
+ uint8_t r = key[i];
+ r = (r & 0xf0) >> 4 | (r & 0x0f) << 4;
+ r = (r & 0xcc) >> 2 | (r & 0x33) << 2;
+ r = (r & 0xaa) >> 1 | (r & 0x55) << 1;
+ ret[i] = r;
+ }
+ return ret;
+}
+#endif /* CONFIG_GNUTLS_GCRYPT */
+
+#ifdef CONFIG_GNUTLS_GCRYPT
+#include "crypto/cipher-gcrypt.c"
+#else
#include "crypto/cipher-builtin.c"
+#endif
diff --git a/crypto/init.c b/crypto/init.c
index 40f3d6e..7447882 100644
--- a/crypto/init.c
+++ b/crypto/init.c
@@ -19,13 +19,48 @@
*/
#include "crypto/init.h"
+#include "qemu/thread.h"
#ifdef CONFIG_GNUTLS
#include <gnutls/gnutls.h>
#include <gnutls/crypto.h>
+#ifdef CONFIG_GNUTLS_GCRYPT
+#include <gcrypt.h>
+#endif
+
/* #define DEBUG_GNUTLS */
+/*
+ * If GNUTLS is built against GCrypt then
+ *
+ * - When GNUTLS >= 2.12, we must not initialize gcrypt threading
+ * because GNUTLS will do that itself
+ * - When GNUTLS < 2.12 we must always initialize gcrypt threading
+ *
+ * But....
+ *
+ * When gcrypt >= 1.6.0 we must not initialize gcrypt threading
+ * because gcrypt will do that itself.
+ *
+ * So we need to init gcrypt threading if
+ *
+ * - gcrypt < 1.6.0
+ * AND
+ * - gnutls < 2.12
+ *
+ */
+
+#if (defined(CONFIG_GNUTLS_GCRYPT) && \
+ (!defined(GNUTLS_VERSION_NUMBER) || \
+ (GNUTLS_VERSION_NUMBER < 0x020c00)) && \
+ (!defined(GCRYPT_VERSION_NUMBER) || \
+ (GCRYPT_VERSION_NUMBER < 0x010600)))
+#define QCRYPTO_INIT_GCRYPT_THREADS
+#else
+#undef QCRYPTO_INIT_GCRYPT_THREADS
+#endif
+
#ifdef DEBUG_GNUTLS
static void qcrypto_gnutls_log(int level, const char *str)
{
@@ -33,6 +68,49 @@ static void qcrypto_gnutls_log(int level, const char *str)
}
#endif
+#ifdef QCRYPTO_INIT_GCRYPT_THREADS
+static int qcrypto_gcrypt_mutex_init(void **priv)
+{ \
+ QemuMutex *lock = NULL;
+ lock = g_new0(QemuMutex, 1);
+ qemu_mutex_init(lock);
+ *priv = lock;
+ return 0;
+}
+
+static int qcrypto_gcrypt_mutex_destroy(void **priv)
+{
+ QemuMutex *lock = *priv;
+ qemu_mutex_destroy(lock);
+ g_free(lock);
+ return 0;
+}
+
+static int qcrypto_gcrypt_mutex_lock(void **priv)
+{
+ QemuMutex *lock = *priv;
+ qemu_mutex_lock(lock);
+ return 0;
+}
+
+static int qcrypto_gcrypt_mutex_unlock(void **priv)
+{
+ QemuMutex *lock = *priv;
+ qemu_mutex_unlock(lock);
+ return 0;
+}
+
+static struct gcry_thread_cbs qcrypto_gcrypt_thread_impl = {
+ (GCRY_THREAD_OPTION_PTHREAD | (GCRY_THREAD_OPTION_VERSION << 8)),
+ NULL,
+ qcrypto_gcrypt_mutex_init,
+ qcrypto_gcrypt_mutex_destroy,
+ qcrypto_gcrypt_mutex_lock,
+ qcrypto_gcrypt_mutex_unlock,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
+};
+#endif /* QCRYPTO_INIT_GCRYPT */
+
int qcrypto_init(Error **errp)
{
int ret;
@@ -47,6 +125,18 @@ int qcrypto_init(Error **errp)
gnutls_global_set_log_level(10);
gnutls_global_set_log_function(qcrypto_gnutls_log);
#endif
+
+#ifdef CONFIG_GNUTLS_GCRYPT
+ if (!gcry_check_version(GCRYPT_VERSION)) {
+ error_setg(errp, "Unable to initialize gcrypt");
+ return -1;
+ }
+#ifdef QCRYPTO_INIT_GCRYPT_THREADS
+ gcry_control(GCRYCTL_SET_THREAD_CBS, &qcrypto_gcrypt_thread_impl);
+#endif /* QCRYPTO_INIT_GCRYPT_THREADS */
+ gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0);
+#endif
+
return 0;
}
--
2.4.3
^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [Qemu-devel] [PULL 0/7] Final changes for 2.4-rc0
2015-07-07 14:11 [Qemu-devel] [PULL 0/7] Final changes for 2.4-rc0 Paolo Bonzini
` (5 preceding siblings ...)
2015-07-07 14:11 ` [Qemu-devel] [PULL 6/7] crypto: add a gcrypt cipher implementation Paolo Bonzini
@ 2015-07-07 14:27 ` Paolo Bonzini
2015-07-07 16:08 ` Peter Maydell
6 siblings, 1 reply; 10+ messages in thread
From: Paolo Bonzini @ 2015-07-07 14:27 UTC (permalink / raw)
To: qemu-devel
On 07/07/2015 16:11, Paolo Bonzini wrote:
> The following changes since commit f6e3035f75e5c6a73485335765ae070304c7a110:
>
> Merge remote-tracking branch 'remotes/bonzini/tags/for-upstream-smm' into staging (2015-07-06 23:37:53 +0100)
>
> are available in the git repository at:
>
> git://github.com/bonzini/qemu.git tags/for-upstream
>
> for you to fetch changes up to 1a79902fb054ea9881c8008f77a861ef63f60152:
>
> crypto: add a nettle cipher implementation (2015-07-07 16:10:27 +0200)
>
> ----------------------------------------------------------------
> Bugfixes and Daniel Berrange's crypto library.
>
> ----------------------------------------------------------------
> Daniel P. Berrange (6):
> crypto: introduce new module for computing hash digests
> crypto: move built-in AES implementation into crypto/
> crypto: move built-in D3DES implementation into crypto/
> crypto: introduce generic cipher API & built-in implementation
> crypto: add a gcrypt cipher implementation
> crypto: add a nettle cipher implementation
>
> Eric Auger (1):
> vl: move rom_load_all after machine init done
>
> MAINTAINERS | 7 +
> Makefile.objs | 1 +
> block/qcow.c | 2 +-
> block/qcow2.c | 1 -
> block/qcow2.h | 2 +-
> configure | 103 +++++++++
> crypto/Makefile.objs | 5 +
> {util => crypto}/aes.c | 2 +-
> crypto/cipher-builtin.c | 398 ++++++++++++++++++++++++++++++++++
> crypto/cipher-gcrypt.c | 195 +++++++++++++++++
> crypto/cipher-nettle.c | 206 ++++++++++++++++++
> crypto/cipher.c | 75 +++++++
> ui/d3des.c => crypto/desrfb.c | 2 +-
> crypto/hash.c | 200 +++++++++++++++++
> crypto/init.c | 150 +++++++++++++
> hw/core/loader.c | 8 +-
> include/{qemu => crypto}/aes.h | 0
> include/crypto/cipher.h | 210 ++++++++++++++++++
> ui/d3des.h => include/crypto/desrfb.h | 0
> include/crypto/hash.h | 189 ++++++++++++++++
> include/crypto/init.h | 29 +++
> include/hw/loader.h | 3 +-
> target-arm/crypto_helper.c | 2 +-
> target-i386/fpu_helper.c | 1 -
> target-i386/ops_sse.h | 2 +-
> target-ppc/int_helper.c | 2 +-
> tests/.gitignore | 2 +
> tests/Makefile | 4 +
> tests/test-crypto-cipher.c | 290 +++++++++++++++++++++++++
> tests/test-crypto-hash.c | 209 ++++++++++++++++++
> ui/Makefile.objs | 2 +-
> ui/vnc.c | 2 +-
> util/Makefile.objs | 2 +-
> vl.c | 18 +-
> 34 files changed, 2297 insertions(+), 27 deletions(-)
> create mode 100644 crypto/Makefile.objs
> rename {util => crypto}/aes.c (99%)
> create mode 100644 crypto/cipher-builtin.c
> create mode 100644 crypto/cipher-gcrypt.c
> create mode 100644 crypto/cipher-nettle.c
> create mode 100644 crypto/cipher.c
> rename ui/d3des.c => crypto/desrfb.c (99%)
> create mode 100644 crypto/hash.c
> create mode 100644 crypto/init.c
> rename include/{qemu => crypto}/aes.h (100%)
> create mode 100644 include/crypto/cipher.h
> rename ui/d3des.h => include/crypto/desrfb.h (100%)
> create mode 100644 include/crypto/hash.h
> create mode 100644 include/crypto/init.h
> create mode 100644 tests/test-crypto-cipher.c
> create mode 100644 tests/test-crypto-hash.c
>
Please ignore this pull request.
Paolo
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [Qemu-devel] [PULL 0/7] Final changes for 2.4-rc0
2015-07-07 14:27 ` [Qemu-devel] [PULL 0/7] Final changes for 2.4-rc0 Paolo Bonzini
@ 2015-07-07 16:08 ` Peter Maydell
2015-07-07 16:10 ` Paolo Bonzini
0 siblings, 1 reply; 10+ messages in thread
From: Peter Maydell @ 2015-07-07 16:08 UTC (permalink / raw)
To: Paolo Bonzini; +Cc: QEMU Developers
On 7 July 2015 at 15:27, Paolo Bonzini <pbonzini@redhat.com> wrote:
>
>
> On 07/07/2015 16:11, Paolo Bonzini wrote:
>> The following changes since commit f6e3035f75e5c6a73485335765ae070304c7a110:
>>
>> Merge remote-tracking branch 'remotes/bonzini/tags/for-upstream-smm' into staging (2015-07-06 23:37:53 +0100)
>>
>> are available in the git repository at:
>>
>> git://github.com/bonzini/qemu.git tags/for-upstream
>>
>> for you to fetch changes up to 1a79902fb054ea9881c8008f77a861ef63f60152:
>>
>> crypto: add a nettle cipher implementation (2015-07-07 16:10:27 +0200)
>>
>> ----------------------------------------------------------------
>> Bugfixes and Daniel Berrange's crypto library.
>>
>> ----------------------------------------------------------------
>> Daniel P. Berrange (6):
>> crypto: introduce new module for computing hash digests
>> crypto: move built-in AES implementation into crypto/
>> crypto: move built-in D3DES implementation into crypto/
>> crypto: introduce generic cipher API & built-in implementation
>> crypto: add a gcrypt cipher implementation
>> crypto: add a nettle cipher implementation
>>
>> Eric Auger (1):
>> vl: move rom_load_all after machine init done
>>
>> MAINTAINERS | 7 +
>> Makefile.objs | 1 +
>> block/qcow.c | 2 +-
>> block/qcow2.c | 1 -
>> block/qcow2.h | 2 +-
>> configure | 103 +++++++++
>> crypto/Makefile.objs | 5 +
>> {util => crypto}/aes.c | 2 +-
>> crypto/cipher-builtin.c | 398 ++++++++++++++++++++++++++++++++++
>> crypto/cipher-gcrypt.c | 195 +++++++++++++++++
>> crypto/cipher-nettle.c | 206 ++++++++++++++++++
>> crypto/cipher.c | 75 +++++++
>> ui/d3des.c => crypto/desrfb.c | 2 +-
>> crypto/hash.c | 200 +++++++++++++++++
>> crypto/init.c | 150 +++++++++++++
>> hw/core/loader.c | 8 +-
>> include/{qemu => crypto}/aes.h | 0
>> include/crypto/cipher.h | 210 ++++++++++++++++++
>> ui/d3des.h => include/crypto/desrfb.h | 0
>> include/crypto/hash.h | 189 ++++++++++++++++
>> include/crypto/init.h | 29 +++
>> include/hw/loader.h | 3 +-
>> target-arm/crypto_helper.c | 2 +-
>> target-i386/fpu_helper.c | 1 -
>> target-i386/ops_sse.h | 2 +-
>> target-ppc/int_helper.c | 2 +-
>> tests/.gitignore | 2 +
>> tests/Makefile | 4 +
>> tests/test-crypto-cipher.c | 290 +++++++++++++++++++++++++
>> tests/test-crypto-hash.c | 209 ++++++++++++++++++
>> ui/Makefile.objs | 2 +-
>> ui/vnc.c | 2 +-
>> util/Makefile.objs | 2 +-
>> vl.c | 18 +-
>> 34 files changed, 2297 insertions(+), 27 deletions(-)
>> create mode 100644 crypto/Makefile.objs
>> rename {util => crypto}/aes.c (99%)
>> create mode 100644 crypto/cipher-builtin.c
>> create mode 100644 crypto/cipher-gcrypt.c
>> create mode 100644 crypto/cipher-nettle.c
>> create mode 100644 crypto/cipher.c
>> rename ui/d3des.c => crypto/desrfb.c (99%)
>> create mode 100644 crypto/hash.c
>> create mode 100644 crypto/init.c
>> rename include/{qemu => crypto}/aes.h (100%)
>> create mode 100644 include/crypto/cipher.h
>> rename ui/d3des.h => include/crypto/desrfb.h (100%)
>> create mode 100644 include/crypto/hash.h
>> create mode 100644 include/crypto/init.h
>> create mode 100644 tests/test-crypto-cipher.c
>> create mode 100644 tests/test-crypto-hash.c
>>
>
> Please ignore this pull request.
...but the 12-patch v2 pullreq is OK, yes?
thanks
-- PMM
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [Qemu-devel] [PULL 0/7] Final changes for 2.4-rc0
2015-07-07 16:08 ` Peter Maydell
@ 2015-07-07 16:10 ` Paolo Bonzini
0 siblings, 0 replies; 10+ messages in thread
From: Paolo Bonzini @ 2015-07-07 16:10 UTC (permalink / raw)
To: Peter Maydell; +Cc: QEMU Developers
On 07/07/2015 18:08, Peter Maydell wrote:
>> > Please ignore this pull request.
> ...but the 12-patch v2 pullreq is OK, yes?
Yes, that one is okay.
Paolo
^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2015-07-07 16:11 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-07-07 14:11 [Qemu-devel] [PULL 0/7] Final changes for 2.4-rc0 Paolo Bonzini
2015-07-07 14:11 ` [Qemu-devel] [PULL 1/7] vl: move rom_load_all after machine init done Paolo Bonzini
2015-07-07 14:11 ` [Qemu-devel] [PULL 2/7] crypto: introduce new module for computing hash digests Paolo Bonzini
2015-07-07 14:11 ` [Qemu-devel] [PULL 3/7] crypto: move built-in AES implementation into crypto/ Paolo Bonzini
2015-07-07 14:11 ` [Qemu-devel] [PULL 4/7] crypto: move built-in D3DES " Paolo Bonzini
2015-07-07 14:11 ` [Qemu-devel] [PULL 5/7] crypto: introduce generic cipher API & built-in implementation Paolo Bonzini
2015-07-07 14:11 ` [Qemu-devel] [PULL 6/7] crypto: add a gcrypt cipher implementation Paolo Bonzini
2015-07-07 14:27 ` [Qemu-devel] [PULL 0/7] Final changes for 2.4-rc0 Paolo Bonzini
2015-07-07 16:08 ` Peter Maydell
2015-07-07 16:10 ` Paolo Bonzini
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).