Commit 4599cb95 authored by Peter Maydell's avatar Peter Maydell
Browse files

Merge remote-tracking branch 'remotes/berrange/tags/crypto-luks-pull-request' into staging



crypto: improve performance of ciphers in XTS mode

Currently QEMU uses its own XTS cipher mode, however, this has
relatively poor performance.

Gcrypt now includes its own XTS cipher which is at least x2 faster than
what we get with QEMU's on Fedora/RHEL hosts. With gcrypt git master, a
further x5-6 speed up is seen.

This is essential for QEMU's LUKS performance to be viable.

# gpg: Signature made Mon 28 Oct 2019 15:48:38 GMT
# gpg:                using RSA key DAF3A6FDB26B62912D0E8E3FBE86EBB415104FDF
# gpg: Good signature from "Daniel P. Berrange <dan@berrange.com>" [full]
# gpg:                 aka "Daniel P. Berrange <berrange@redhat.com>" [full]
# Primary key fingerprint: DAF3 A6FD B26B 6291 2D0E  8E3F BE86 EBB4 1510 4FDF

* remotes/berrange/tags/crypto-luks-pull-request:
  crypto: add support for nettle's native XTS impl
  crypto: add support for gcrypt's native XTS impl
  tests: benchmark crypto with fixed data size, not time period
  tests: allow filtering crypto cipher benchmark tests

Signed-off-by: default avatarPeter Maydell <peter.maydell@linaro.org>
parents 8c68ff25 dc2207af
Loading
Loading
Loading
Loading
+40 −0
Original line number Diff line number Diff line
@@ -472,8 +472,11 @@ gtk_gl="no"
tls_priority="NORMAL"
gnutls=""
nettle=""
nettle_xts="no"
gcrypt=""
gcrypt_hmac="no"
gcrypt_xts="no"
qemu_private_xts="yes"
auth_pam=""
vte=""
virglrenderer=""
@@ -2869,6 +2872,19 @@ if test "$nettle" != "no"; then
            pass="yes"
        fi
    fi
    if test "$pass" = "yes"
    then
        cat > $TMPC << EOF
#include <nettle/xts.h>
int main(void) {
  return 0;
}
EOF
        if compile_prog "$nettle_cflags" "$nettle_libs" ; then
            nettle_xts=yes
            qemu_private_xts=no
        fi
    fi
    if test "$pass" = "no" && test "$nettle" = "yes"; then
        feature_not_found "nettle" "Install nettle devel >= 2.7.1"
    else
@@ -2911,6 +2927,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
@@ -6341,7 +6369,16 @@ 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
   echo "  XTS             $nettle_xts"
fi
echo "libtasn1          $tasn1"
echo "PAM               $auth_pam"
echo "iconv support     $iconv"
@@ -6819,6 +6856,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
+1 −1
Original line number Diff line number Diff line
@@ -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
+64 −33
Original line number Diff line number Diff line
@@ -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,12 +311,16 @@ 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 {
        return 0;
    }
#endif

    err = gcry_cipher_encrypt(ctx->handle,
                              out, len,
                              in, len);
@@ -303,7 +329,6 @@ qcrypto_gcrypt_cipher_encrypt(QCryptoCipher *cipher,
                   gcry_strerror(err));
        return -1;
    }
    }

    return 0;
}
@@ -325,12 +350,16 @@ 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 {
        return 0;
    }
#endif

    err = gcry_cipher_decrypt(ctx->handle,
                              out, len,
                              in, len);
@@ -339,7 +368,6 @@ qcrypto_gcrypt_cipher_decrypt(QCryptoCipher *cipher,
                   gcry_strerror(err));
        return -1;
    }
    }

    return 0;
}
@@ -358,9 +386,13 @@ qcrypto_gcrypt_cipher_setiv(QCryptoCipher *cipher,
        return -1;
    }

#ifdef CONFIG_QEMU_PRIVATE_XTS
    if (ctx->iv) {
        memcpy(ctx->iv, iv, niv);
    } else {
        return 0;
    }
#endif

    if (cipher->mode == QCRYPTO_CIPHER_MODE_CTR) {
        err = gcry_cipher_setctr(ctx->handle, iv, niv);
        if (err != 0) {
@@ -377,7 +409,6 @@ qcrypto_gcrypt_cipher_setiv(QCryptoCipher *cipher,
            return -1;
        }
    }
    }

    return 0;
}
+18 −0
Original line number Diff line number Diff line
@@ -19,7 +19,9 @@
 */

#include "qemu/osdep.h"
#ifdef CONFIG_QEMU_PRIVATE_XTS
#include "crypto/xts.h"
#endif
#include "cipherpriv.h"

#include <nettle/nettle-types.h>
@@ -30,6 +32,9 @@
#include <nettle/serpent.h>
#include <nettle/twofish.h>
#include <nettle/ctr.h>
#ifndef CONFIG_QEMU_PRIVATE_XTS
#include <nettle/xts.h>
#endif

typedef void (*QCryptoCipherNettleFuncWrapper)(const void *ctx,
                                               size_t length,
@@ -626,9 +631,15 @@ qcrypto_nettle_cipher_encrypt(QCryptoCipher *cipher,
        break;

    case QCRYPTO_CIPHER_MODE_XTS:
#ifdef CONFIG_QEMU_PRIVATE_XTS
        xts_encrypt(ctx->ctx, ctx->ctx_tweak,
                    ctx->alg_encrypt_wrapper, ctx->alg_encrypt_wrapper,
                    ctx->iv, len, out, in);
#else
        xts_encrypt_message(ctx->ctx, ctx->ctx_tweak,
                            ctx->alg_encrypt_native,
                            ctx->iv, len, out, in);
#endif
        break;

    case QCRYPTO_CIPHER_MODE_CTR:
@@ -673,9 +684,16 @@ qcrypto_nettle_cipher_decrypt(QCryptoCipher *cipher,
        break;

    case QCRYPTO_CIPHER_MODE_XTS:
#ifdef CONFIG_QEMU_PRIVATE_XTS
        xts_decrypt(ctx->ctx, ctx->ctx_tweak,
                    ctx->alg_encrypt_wrapper, ctx->alg_decrypt_wrapper,
                    ctx->iv, len, out, in);
#else
        xts_decrypt_message(ctx->ctx, ctx->ctx_tweak,
                            ctx->alg_decrypt_native,
                            ctx->alg_encrypt_native,
                            ctx->iv, len, out, in);
#endif
        break;
    case QCRYPTO_CIPHER_MODE_CTR:
        ctr_crypt(ctx->ctx, ctx->alg_encrypt_native,
+1 −1
Original line number Diff line number Diff line
@@ -140,7 +140,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)
Loading