347 lines
11 KiB
Diff
347 lines
11 KiB
Diff
|
|
From 84352558eec97cfb0e4517fbb53d75d9f15cbcf9 Mon Sep 17 00:00:00 2001
|
||
|
|
From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= <berrange@redhat.com>
|
||
|
|
Date: Mon, 14 Oct 2019 17:28:27 +0100
|
||
|
|
Subject: [PATCH] crypto: add support for gcrypt's native XTS impl
|
||
|
|
MIME-Version: 1.0
|
||
|
|
Content-Type: text/plain; charset=UTF-8
|
||
|
|
Content-Transfer-Encoding: 8bit
|
||
|
|
|
||
|
|
Libgcrypt 1.8.0 added support for the XTS mode. Use this because long
|
||
|
|
term we wish to delete QEMU's XTS impl to avoid carrying private crypto
|
||
|
|
algorithm impls.
|
||
|
|
|
||
|
|
As an added benefit, using this improves performance from 531 MB/sec to
|
||
|
|
670 MB/sec, since we are avoiding several layers of function call
|
||
|
|
indirection.
|
||
|
|
|
||
|
|
This is even more noticable with the gcrypt builds in Fedora or RHEL-8
|
||
|
|
which have a non-upstream patch for FIPS mode which does mutex locking.
|
||
|
|
This is catastrophic for encryption performance with small block sizes,
|
||
|
|
meaning this patch improves encryption from 240 MB/sec to 670 MB/sec.
|
||
|
|
|
||
|
|
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
|
||
|
|
Reviewed-by: Stefano Garzarella <sgarzare@redhat.com>
|
||
|
|
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
|
||
|
|
---
|
||
|
|
configure | 22 ++++++++++
|
||
|
|
crypto/Makefile.objs | 2 +-
|
||
|
|
crypto/cipher-gcrypt.c | 97 ++++++++++++++++++++++++++++--------------
|
||
|
|
tests/Makefile.include | 2 +-
|
||
|
|
4 files changed, 88 insertions(+), 35 deletions(-)
|
||
|
|
|
||
|
|
diff --git a/configure b/configure
|
||
|
|
index 5dcaac3b95..a88cdd5109 100755
|
||
|
|
--- a/configure
|
||
|
|
+++ b/configure
|
||
|
|
@@ -476,6 +476,8 @@ nettle=""
|
||
|
|
nettle_xts="no"
|
||
|
|
gcrypt=""
|
||
|
|
gcrypt_hmac="no"
|
||
|
|
+gcrypt_xts="no"
|
||
|
|
+qemu_private_xts="yes"
|
||
|
|
auth_pam=""
|
||
|
|
vte=""
|
||
|
|
virglrenderer=""
|
||
|
|
@@ -2974,6 +2976,18 @@ EOF
|
||
|
|
if compile_prog "$gcrypt_cflags" "$gcrypt_libs" ; then
|
||
|
|
gcrypt_hmac=yes
|
||
|
|
fi
|
||
|
|
+ cat > $TMPC << EOF
|
||
|
|
+#include <gcrypt.h>
|
||
|
|
+int main(void) {
|
||
|
|
+ gcry_cipher_hd_t handle;
|
||
|
|
+ gcry_cipher_open(&handle, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_XTS, 0);
|
||
|
|
+ return 0;
|
||
|
|
+}
|
||
|
|
+EOF
|
||
|
|
+ if compile_prog "$gcrypt_cflags" "$gcrypt_libs" ; then
|
||
|
|
+ gcrypt_xts=yes
|
||
|
|
+ qemu_private_xts=no
|
||
|
|
+ fi
|
||
|
|
elif test "$gcrypt" = "yes"; then
|
||
|
|
feature_not_found "gcrypt" "Install gcrypt devel >= 1.5.0"
|
||
|
|
else
|
||
|
|
@@ -6404,6 +6418,11 @@ echo "VTE support $vte $(echo_version $vte $vteversion)"
|
||
|
|
echo "TLS priority $tls_priority"
|
||
|
|
echo "GNUTLS support $gnutls"
|
||
|
|
echo "libgcrypt $gcrypt"
|
||
|
|
+if test "$gcrypt" = "yes"
|
||
|
|
+then
|
||
|
|
+ echo " hmac $gcrypt_hmac"
|
||
|
|
+ echo " XTS $gcrypt_xts"
|
||
|
|
+fi
|
||
|
|
echo "nettle $nettle $(echo_version $nettle $nettle_version)"
|
||
|
|
if test "$nettle" = "yes"
|
||
|
|
then
|
||
|
|
@@ -6889,6 +6908,9 @@ if test "$nettle" = "yes" ; then
|
||
|
|
echo "CONFIG_NETTLE=y" >> $config_host_mak
|
||
|
|
echo "CONFIG_NETTLE_VERSION_MAJOR=${nettle_version%%.*}" >> $config_host_mak
|
||
|
|
fi
|
||
|
|
+if test "$qemu_private_xts" = "yes" ; then
|
||
|
|
+ echo "CONFIG_QEMU_PRIVATE_XTS=y" >> $config_host_mak
|
||
|
|
+fi
|
||
|
|
if test "$tasn1" = "yes" ; then
|
||
|
|
echo "CONFIG_TASN1=y" >> $config_host_mak
|
||
|
|
fi
|
||
|
|
diff --git a/crypto/Makefile.objs b/crypto/Makefile.objs
|
||
|
|
index 7fe2fa9da2..cdb01f9de9 100644
|
||
|
|
--- a/crypto/Makefile.objs
|
||
|
|
+++ b/crypto/Makefile.objs
|
||
|
|
@@ -31,7 +31,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
|
||
|
|
+crypto-obj-$(CONFIG_QEMU_PRIVATE_XTS) += xts.o
|
||
|
|
crypto-obj-y += block.o
|
||
|
|
crypto-obj-y += block-qcow.o
|
||
|
|
crypto-obj-y += block-luks.o
|
||
|
|
diff --git a/crypto/cipher-gcrypt.c b/crypto/cipher-gcrypt.c
|
||
|
|
index 5cece9b244..2864099527 100644
|
||
|
|
--- a/crypto/cipher-gcrypt.c
|
||
|
|
+++ b/crypto/cipher-gcrypt.c
|
||
|
|
@@ -19,7 +19,9 @@
|
||
|
|
*/
|
||
|
|
|
||
|
|
#include "qemu/osdep.h"
|
||
|
|
+#ifdef CONFIG_QEMU_PRIVATE_XTS
|
||
|
|
#include "crypto/xts.h"
|
||
|
|
+#endif
|
||
|
|
#include "cipherpriv.h"
|
||
|
|
|
||
|
|
#include <gcrypt.h>
|
||
|
|
@@ -59,10 +61,12 @@ bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg,
|
||
|
|
typedef struct QCryptoCipherGcrypt QCryptoCipherGcrypt;
|
||
|
|
struct QCryptoCipherGcrypt {
|
||
|
|
gcry_cipher_hd_t handle;
|
||
|
|
- gcry_cipher_hd_t tweakhandle;
|
||
|
|
size_t blocksize;
|
||
|
|
+#ifdef CONFIG_QEMU_PRIVATE_XTS
|
||
|
|
+ gcry_cipher_hd_t tweakhandle;
|
||
|
|
/* Initialization vector or Counter */
|
||
|
|
uint8_t *iv;
|
||
|
|
+#endif
|
||
|
|
};
|
||
|
|
|
||
|
|
static void
|
||
|
|
@@ -74,10 +78,12 @@ qcrypto_gcrypt_cipher_free_ctx(QCryptoCipherGcrypt *ctx,
|
||
|
|
}
|
||
|
|
|
||
|
|
gcry_cipher_close(ctx->handle);
|
||
|
|
+#ifdef CONFIG_QEMU_PRIVATE_XTS
|
||
|
|
if (mode == QCRYPTO_CIPHER_MODE_XTS) {
|
||
|
|
gcry_cipher_close(ctx->tweakhandle);
|
||
|
|
}
|
||
|
|
g_free(ctx->iv);
|
||
|
|
+#endif
|
||
|
|
g_free(ctx);
|
||
|
|
}
|
||
|
|
|
||
|
|
@@ -94,8 +100,14 @@ static QCryptoCipherGcrypt *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
|
||
|
|
|
||
|
|
switch (mode) {
|
||
|
|
case QCRYPTO_CIPHER_MODE_ECB:
|
||
|
|
+ gcrymode = GCRY_CIPHER_MODE_ECB;
|
||
|
|
+ break;
|
||
|
|
case QCRYPTO_CIPHER_MODE_XTS:
|
||
|
|
+#ifdef CONFIG_QEMU_PRIVATE_XTS
|
||
|
|
gcrymode = GCRY_CIPHER_MODE_ECB;
|
||
|
|
+#else
|
||
|
|
+ gcrymode = GCRY_CIPHER_MODE_XTS;
|
||
|
|
+#endif
|
||
|
|
break;
|
||
|
|
case QCRYPTO_CIPHER_MODE_CBC:
|
||
|
|
gcrymode = GCRY_CIPHER_MODE_CBC;
|
||
|
|
@@ -172,6 +184,7 @@ static QCryptoCipherGcrypt *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
|
||
|
|
gcry_strerror(err));
|
||
|
|
goto error;
|
||
|
|
}
|
||
|
|
+#ifdef CONFIG_QEMU_PRIVATE_XTS
|
||
|
|
if (mode == QCRYPTO_CIPHER_MODE_XTS) {
|
||
|
|
err = gcry_cipher_open(&ctx->tweakhandle, gcryalg, gcrymode, 0);
|
||
|
|
if (err != 0) {
|
||
|
|
@@ -180,6 +193,7 @@ static QCryptoCipherGcrypt *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
|
||
|
|
goto error;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
+#endif
|
||
|
|
|
||
|
|
if (alg == QCRYPTO_CIPHER_ALG_DES_RFB) {
|
||
|
|
/* We're using standard DES cipher from gcrypt, so we need
|
||
|
|
@@ -191,6 +205,7 @@ static QCryptoCipherGcrypt *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
|
||
|
|
g_free(rfbkey);
|
||
|
|
ctx->blocksize = 8;
|
||
|
|
} else {
|
||
|
|
+#ifdef CONFIG_QEMU_PRIVATE_XTS
|
||
|
|
if (mode == QCRYPTO_CIPHER_MODE_XTS) {
|
||
|
|
nkey /= 2;
|
||
|
|
err = gcry_cipher_setkey(ctx->handle, key, nkey);
|
||
|
|
@@ -201,8 +216,11 @@ static QCryptoCipherGcrypt *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
|
||
|
|
}
|
||
|
|
err = gcry_cipher_setkey(ctx->tweakhandle, key + nkey, nkey);
|
||
|
|
} else {
|
||
|
|
+#endif
|
||
|
|
err = gcry_cipher_setkey(ctx->handle, key, nkey);
|
||
|
|
+#ifdef CONFIG_QEMU_PRIVATE_XTS
|
||
|
|
}
|
||
|
|
+#endif
|
||
|
|
if (err != 0) {
|
||
|
|
error_setg(errp, "Cannot set key: %s",
|
||
|
|
gcry_strerror(err));
|
||
|
|
@@ -228,6 +246,7 @@ static QCryptoCipherGcrypt *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
+#ifdef CONFIG_QEMU_PRIVATE_XTS
|
||
|
|
if (mode == QCRYPTO_CIPHER_MODE_XTS) {
|
||
|
|
if (ctx->blocksize != XTS_BLOCK_SIZE) {
|
||
|
|
error_setg(errp,
|
||
|
|
@@ -237,6 +256,7 @@ static QCryptoCipherGcrypt *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
|
||
|
|
}
|
||
|
|
ctx->iv = g_new0(uint8_t, ctx->blocksize);
|
||
|
|
}
|
||
|
|
+#endif
|
||
|
|
|
||
|
|
return ctx;
|
||
|
|
|
||
|
|
@@ -253,6 +273,7 @@ qcrypto_gcrypt_cipher_ctx_free(QCryptoCipher *cipher)
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
+#ifdef CONFIG_QEMU_PRIVATE_XTS
|
||
|
|
static void qcrypto_gcrypt_xts_encrypt(const void *ctx,
|
||
|
|
size_t length,
|
||
|
|
uint8_t *dst,
|
||
|
|
@@ -272,6 +293,7 @@ static void qcrypto_gcrypt_xts_decrypt(const void *ctx,
|
||
|
|
err = gcry_cipher_decrypt((gcry_cipher_hd_t)ctx, dst, length, src, length);
|
||
|
|
g_assert(err == 0);
|
||
|
|
}
|
||
|
|
+#endif
|
||
|
|
|
||
|
|
static int
|
||
|
|
qcrypto_gcrypt_cipher_encrypt(QCryptoCipher *cipher,
|
||
|
|
@@ -289,20 +311,23 @@ qcrypto_gcrypt_cipher_encrypt(QCryptoCipher *cipher,
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
|
||
|
|
+#ifdef CONFIG_QEMU_PRIVATE_XTS
|
||
|
|
if (cipher->mode == QCRYPTO_CIPHER_MODE_XTS) {
|
||
|
|
xts_encrypt(ctx->handle, ctx->tweakhandle,
|
||
|
|
qcrypto_gcrypt_xts_encrypt,
|
||
|
|
qcrypto_gcrypt_xts_decrypt,
|
||
|
|
ctx->iv, len, out, in);
|
||
|
|
- } else {
|
||
|
|
- err = gcry_cipher_encrypt(ctx->handle,
|
||
|
|
- out, len,
|
||
|
|
- in, len);
|
||
|
|
- if (err != 0) {
|
||
|
|
- error_setg(errp, "Cannot encrypt data: %s",
|
||
|
|
- gcry_strerror(err));
|
||
|
|
- return -1;
|
||
|
|
- }
|
||
|
|
+ return 0;
|
||
|
|
+ }
|
||
|
|
+#endif
|
||
|
|
+
|
||
|
|
+ err = gcry_cipher_encrypt(ctx->handle,
|
||
|
|
+ out, len,
|
||
|
|
+ in, len);
|
||
|
|
+ if (err != 0) {
|
||
|
|
+ error_setg(errp, "Cannot encrypt data: %s",
|
||
|
|
+ gcry_strerror(err));
|
||
|
|
+ return -1;
|
||
|
|
}
|
||
|
|
|
||
|
|
return 0;
|
||
|
|
@@ -325,20 +350,23 @@ qcrypto_gcrypt_cipher_decrypt(QCryptoCipher *cipher,
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
|
||
|
|
+#ifdef CONFIG_QEMU_PRIVATE_XTS
|
||
|
|
if (cipher->mode == QCRYPTO_CIPHER_MODE_XTS) {
|
||
|
|
xts_decrypt(ctx->handle, ctx->tweakhandle,
|
||
|
|
qcrypto_gcrypt_xts_encrypt,
|
||
|
|
qcrypto_gcrypt_xts_decrypt,
|
||
|
|
ctx->iv, len, out, in);
|
||
|
|
- } else {
|
||
|
|
- err = gcry_cipher_decrypt(ctx->handle,
|
||
|
|
- out, len,
|
||
|
|
- in, len);
|
||
|
|
- if (err != 0) {
|
||
|
|
- error_setg(errp, "Cannot decrypt data: %s",
|
||
|
|
- gcry_strerror(err));
|
||
|
|
- return -1;
|
||
|
|
- }
|
||
|
|
+ return 0;
|
||
|
|
+ }
|
||
|
|
+#endif
|
||
|
|
+
|
||
|
|
+ err = gcry_cipher_decrypt(ctx->handle,
|
||
|
|
+ out, len,
|
||
|
|
+ in, len);
|
||
|
|
+ if (err != 0) {
|
||
|
|
+ error_setg(errp, "Cannot decrypt data: %s",
|
||
|
|
+ gcry_strerror(err));
|
||
|
|
+ return -1;
|
||
|
|
}
|
||
|
|
|
||
|
|
return 0;
|
||
|
|
@@ -358,24 +386,27 @@ qcrypto_gcrypt_cipher_setiv(QCryptoCipher *cipher,
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
|
||
|
|
+#ifdef CONFIG_QEMU_PRIVATE_XTS
|
||
|
|
if (ctx->iv) {
|
||
|
|
memcpy(ctx->iv, iv, niv);
|
||
|
|
- } else {
|
||
|
|
- if (cipher->mode == QCRYPTO_CIPHER_MODE_CTR) {
|
||
|
|
- err = gcry_cipher_setctr(ctx->handle, iv, niv);
|
||
|
|
- if (err != 0) {
|
||
|
|
- error_setg(errp, "Cannot set Counter: %s",
|
||
|
|
+ return 0;
|
||
|
|
+ }
|
||
|
|
+#endif
|
||
|
|
+
|
||
|
|
+ if (cipher->mode == QCRYPTO_CIPHER_MODE_CTR) {
|
||
|
|
+ err = gcry_cipher_setctr(ctx->handle, iv, niv);
|
||
|
|
+ if (err != 0) {
|
||
|
|
+ error_setg(errp, "Cannot set Counter: %s",
|
||
|
|
gcry_strerror(err));
|
||
|
|
- return -1;
|
||
|
|
- }
|
||
|
|
- } else {
|
||
|
|
- gcry_cipher_reset(ctx->handle);
|
||
|
|
- err = gcry_cipher_setiv(ctx->handle, iv, niv);
|
||
|
|
- if (err != 0) {
|
||
|
|
- error_setg(errp, "Cannot set IV: %s",
|
||
|
|
+ return -1;
|
||
|
|
+ }
|
||
|
|
+ } else {
|
||
|
|
+ gcry_cipher_reset(ctx->handle);
|
||
|
|
+ err = gcry_cipher_setiv(ctx->handle, iv, niv);
|
||
|
|
+ if (err != 0) {
|
||
|
|
+ error_setg(errp, "Cannot set IV: %s",
|
||
|
|
gcry_strerror(err));
|
||
|
|
- return -1;
|
||
|
|
- }
|
||
|
|
+ return -1;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
diff --git a/tests/Makefile.include b/tests/Makefile.include
|
||
|
|
index d6de4e1042..3be60ab999 100644
|
||
|
|
--- a/tests/Makefile.include
|
||
|
|
+++ b/tests/Makefile.include
|
||
|
|
@@ -132,7 +132,7 @@ check-unit-y += tests/test-base64$(EXESUF)
|
||
|
|
check-unit-$(call land,$(CONFIG_BLOCK),$(if $(CONFIG_NETTLE),y,$(CONFIG_GCRYPT))) += tests/test-crypto-pbkdf$(EXESUF)
|
||
|
|
check-unit-$(CONFIG_BLOCK) += tests/test-crypto-ivgen$(EXESUF)
|
||
|
|
check-unit-$(CONFIG_BLOCK) += tests/test-crypto-afsplit$(EXESUF)
|
||
|
|
-check-unit-$(CONFIG_BLOCK) += tests/test-crypto-xts$(EXESUF)
|
||
|
|
+check-unit-$(if $(CONFIG_BLOCK),$(CONFIG_QEMU_PRIVATE_XTS)) += tests/test-crypto-xts$(EXESUF)
|
||
|
|
check-unit-$(CONFIG_BLOCK) += tests/test-crypto-block$(EXESUF)
|
||
|
|
check-unit-y += tests/test-logging$(EXESUF)
|
||
|
|
check-unit-$(call land,$(CONFIG_BLOCK),$(CONFIG_REPLICATION)) += tests/test-replication$(EXESUF)
|
||
|
|
--
|
||
|
|
2.27.0
|
||
|
|
|