diff --git a/crypto-add-support-for-gcrypt-s-native-XTS-impl.patch b/crypto-add-support-for-gcrypt-s-native-XTS-impl.patch new file mode 100644 index 0000000..d204f01 --- /dev/null +++ b/crypto-add-support-for-gcrypt-s-native-XTS-impl.patch @@ -0,0 +1,346 @@ +From 84352558eec97cfb0e4517fbb53d75d9f15cbcf9 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= +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é +Reviewed-by: Stefano Garzarella +Signed-off-by: Daniel P. Berrangé +--- + 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 ++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 +@@ -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 +