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. -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEE2vOm/bJrYpEtDo4/vobrtBUQT98FAl23DdYACgkQvobrtBUQ T99bzQ//dEr62GzFSjfxiVu4GTvhWQ2VAg3U/Mcpp/xx3zEFX7YY6lQmBRCMtOF8 HMPEIop50coY55SnNLtiZaesBP/QW3MgUAer4tyMxDpgMo7Xspc00duB0CZx6UCp I7B8/OF6J27OSnii3+49IO9b0MNQ8yG1w0NuuvhaB4Syyp3u1flV4ZKEnMDCFN2I jAti4UcXmMjWZxWQNe95S6nmJLXpODhHG9ie3gxTtTTZyJkwnyF0lalelj5NMFiF /7Smnzy3cxx3e409TlRoPlA+47ZsfxjfN7HkV9zmxdI95Bhzh1ludhtSLsVhxdfW 1JarQT6eUjJg9GrrrQJFmofcnDKTYGFJMZnPIydtfGfdEvQH0FBs4tuZ2cgklxCo kPISXgbriMdB5x8QRP1b6JHRupjbfKNkD9P63Ze7+0wpn7HyDfGSPebJNNFDl1um 5Xkj5Sv+CuA+1VqRvpcDxaRhyNDI2sFmjd6vXyMNLLEyk5XujInjXfSobXk2HozB wmWEn+2aVDVz58FWlI8hTnJXTDwemkpPtxAQECou98I8S6gK25Ga1Mkkg7aUoyrM UovsisAIcHZuDSTRVZVyVfTp02JHZaiFiQZO9rBKfAwMNYOxoFPNJkAqJoOMDY8V GxVrT2DRvMetFyMk3AUmlVtbR/brYkBfr0jNCuvg8PgnLZEHIJk= =fkwe -----END PGP SIGNATURE----- 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: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
4599cb953c
40
configure
vendored
40
configure
vendored
|
@ -472,8 +472,11 @@ gtk_gl="no"
|
||||||
tls_priority="NORMAL"
|
tls_priority="NORMAL"
|
||||||
gnutls=""
|
gnutls=""
|
||||||
nettle=""
|
nettle=""
|
||||||
|
nettle_xts="no"
|
||||||
gcrypt=""
|
gcrypt=""
|
||||||
gcrypt_hmac="no"
|
gcrypt_hmac="no"
|
||||||
|
gcrypt_xts="no"
|
||||||
|
qemu_private_xts="yes"
|
||||||
auth_pam=""
|
auth_pam=""
|
||||||
vte=""
|
vte=""
|
||||||
virglrenderer=""
|
virglrenderer=""
|
||||||
|
@ -2869,6 +2872,19 @@ if test "$nettle" != "no"; then
|
||||||
pass="yes"
|
pass="yes"
|
||||||
fi
|
fi
|
||||||
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
|
if test "$pass" = "no" && test "$nettle" = "yes"; then
|
||||||
feature_not_found "nettle" "Install nettle devel >= 2.7.1"
|
feature_not_found "nettle" "Install nettle devel >= 2.7.1"
|
||||||
else
|
else
|
||||||
|
@ -2911,6 +2927,18 @@ EOF
|
||||||
if compile_prog "$gcrypt_cflags" "$gcrypt_libs" ; then
|
if compile_prog "$gcrypt_cflags" "$gcrypt_libs" ; then
|
||||||
gcrypt_hmac=yes
|
gcrypt_hmac=yes
|
||||||
fi
|
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
|
elif test "$gcrypt" = "yes"; then
|
||||||
feature_not_found "gcrypt" "Install gcrypt devel >= 1.5.0"
|
feature_not_found "gcrypt" "Install gcrypt devel >= 1.5.0"
|
||||||
else
|
else
|
||||||
|
@ -6341,7 +6369,16 @@ echo "VTE support $vte $(echo_version $vte $vteversion)"
|
||||||
echo "TLS priority $tls_priority"
|
echo "TLS priority $tls_priority"
|
||||||
echo "GNUTLS support $gnutls"
|
echo "GNUTLS support $gnutls"
|
||||||
echo "libgcrypt $gcrypt"
|
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)"
|
echo "nettle $nettle $(echo_version $nettle $nettle_version)"
|
||||||
|
if test "$nettle" = "yes"
|
||||||
|
then
|
||||||
|
echo " XTS $nettle_xts"
|
||||||
|
fi
|
||||||
echo "libtasn1 $tasn1"
|
echo "libtasn1 $tasn1"
|
||||||
echo "PAM $auth_pam"
|
echo "PAM $auth_pam"
|
||||||
echo "iconv support $iconv"
|
echo "iconv support $iconv"
|
||||||
|
@ -6819,6 +6856,9 @@ if test "$nettle" = "yes" ; then
|
||||||
echo "CONFIG_NETTLE=y" >> $config_host_mak
|
echo "CONFIG_NETTLE=y" >> $config_host_mak
|
||||||
echo "CONFIG_NETTLE_VERSION_MAJOR=${nettle_version%%.*}" >> $config_host_mak
|
echo "CONFIG_NETTLE_VERSION_MAJOR=${nettle_version%%.*}" >> $config_host_mak
|
||||||
fi
|
fi
|
||||||
|
if test "$qemu_private_xts" = "yes" ; then
|
||||||
|
echo "CONFIG_QEMU_PRIVATE_XTS=y" >> $config_host_mak
|
||||||
|
fi
|
||||||
if test "$tasn1" = "yes" ; then
|
if test "$tasn1" = "yes" ; then
|
||||||
echo "CONFIG_TASN1=y" >> $config_host_mak
|
echo "CONFIG_TASN1=y" >> $config_host_mak
|
||||||
fi
|
fi
|
||||||
|
|
|
@ -31,7 +31,7 @@ crypto-obj-y += ivgen-essiv.o
|
||||||
crypto-obj-y += ivgen-plain.o
|
crypto-obj-y += ivgen-plain.o
|
||||||
crypto-obj-y += ivgen-plain64.o
|
crypto-obj-y += ivgen-plain64.o
|
||||||
crypto-obj-y += afsplit.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.o
|
||||||
crypto-obj-y += block-qcow.o
|
crypto-obj-y += block-qcow.o
|
||||||
crypto-obj-y += block-luks.o
|
crypto-obj-y += block-luks.o
|
||||||
|
|
|
@ -19,7 +19,9 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "qemu/osdep.h"
|
#include "qemu/osdep.h"
|
||||||
|
#ifdef CONFIG_QEMU_PRIVATE_XTS
|
||||||
#include "crypto/xts.h"
|
#include "crypto/xts.h"
|
||||||
|
#endif
|
||||||
#include "cipherpriv.h"
|
#include "cipherpriv.h"
|
||||||
|
|
||||||
#include <gcrypt.h>
|
#include <gcrypt.h>
|
||||||
|
@ -59,10 +61,12 @@ bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg,
|
||||||
typedef struct QCryptoCipherGcrypt QCryptoCipherGcrypt;
|
typedef struct QCryptoCipherGcrypt QCryptoCipherGcrypt;
|
||||||
struct QCryptoCipherGcrypt {
|
struct QCryptoCipherGcrypt {
|
||||||
gcry_cipher_hd_t handle;
|
gcry_cipher_hd_t handle;
|
||||||
gcry_cipher_hd_t tweakhandle;
|
|
||||||
size_t blocksize;
|
size_t blocksize;
|
||||||
|
#ifdef CONFIG_QEMU_PRIVATE_XTS
|
||||||
|
gcry_cipher_hd_t tweakhandle;
|
||||||
/* Initialization vector or Counter */
|
/* Initialization vector or Counter */
|
||||||
uint8_t *iv;
|
uint8_t *iv;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -74,10 +78,12 @@ qcrypto_gcrypt_cipher_free_ctx(QCryptoCipherGcrypt *ctx,
|
||||||
}
|
}
|
||||||
|
|
||||||
gcry_cipher_close(ctx->handle);
|
gcry_cipher_close(ctx->handle);
|
||||||
|
#ifdef CONFIG_QEMU_PRIVATE_XTS
|
||||||
if (mode == QCRYPTO_CIPHER_MODE_XTS) {
|
if (mode == QCRYPTO_CIPHER_MODE_XTS) {
|
||||||
gcry_cipher_close(ctx->tweakhandle);
|
gcry_cipher_close(ctx->tweakhandle);
|
||||||
}
|
}
|
||||||
g_free(ctx->iv);
|
g_free(ctx->iv);
|
||||||
|
#endif
|
||||||
g_free(ctx);
|
g_free(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,9 +100,15 @@ static QCryptoCipherGcrypt *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
|
||||||
|
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
case QCRYPTO_CIPHER_MODE_ECB:
|
case QCRYPTO_CIPHER_MODE_ECB:
|
||||||
case QCRYPTO_CIPHER_MODE_XTS:
|
|
||||||
gcrymode = GCRY_CIPHER_MODE_ECB;
|
gcrymode = GCRY_CIPHER_MODE_ECB;
|
||||||
break;
|
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:
|
case QCRYPTO_CIPHER_MODE_CBC:
|
||||||
gcrymode = GCRY_CIPHER_MODE_CBC;
|
gcrymode = GCRY_CIPHER_MODE_CBC;
|
||||||
break;
|
break;
|
||||||
|
@ -172,6 +184,7 @@ static QCryptoCipherGcrypt *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
|
||||||
gcry_strerror(err));
|
gcry_strerror(err));
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
#ifdef CONFIG_QEMU_PRIVATE_XTS
|
||||||
if (mode == QCRYPTO_CIPHER_MODE_XTS) {
|
if (mode == QCRYPTO_CIPHER_MODE_XTS) {
|
||||||
err = gcry_cipher_open(&ctx->tweakhandle, gcryalg, gcrymode, 0);
|
err = gcry_cipher_open(&ctx->tweakhandle, gcryalg, gcrymode, 0);
|
||||||
if (err != 0) {
|
if (err != 0) {
|
||||||
|
@ -180,6 +193,7 @@ static QCryptoCipherGcrypt *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (alg == QCRYPTO_CIPHER_ALG_DES_RFB) {
|
if (alg == QCRYPTO_CIPHER_ALG_DES_RFB) {
|
||||||
/* We're using standard DES cipher from gcrypt, so we need
|
/* 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);
|
g_free(rfbkey);
|
||||||
ctx->blocksize = 8;
|
ctx->blocksize = 8;
|
||||||
} else {
|
} else {
|
||||||
|
#ifdef CONFIG_QEMU_PRIVATE_XTS
|
||||||
if (mode == QCRYPTO_CIPHER_MODE_XTS) {
|
if (mode == QCRYPTO_CIPHER_MODE_XTS) {
|
||||||
nkey /= 2;
|
nkey /= 2;
|
||||||
err = gcry_cipher_setkey(ctx->handle, key, nkey);
|
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);
|
err = gcry_cipher_setkey(ctx->tweakhandle, key + nkey, nkey);
|
||||||
} else {
|
} else {
|
||||||
|
#endif
|
||||||
err = gcry_cipher_setkey(ctx->handle, key, nkey);
|
err = gcry_cipher_setkey(ctx->handle, key, nkey);
|
||||||
|
#ifdef CONFIG_QEMU_PRIVATE_XTS
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
if (err != 0) {
|
if (err != 0) {
|
||||||
error_setg(errp, "Cannot set key: %s",
|
error_setg(errp, "Cannot set key: %s",
|
||||||
gcry_strerror(err));
|
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 (mode == QCRYPTO_CIPHER_MODE_XTS) {
|
||||||
if (ctx->blocksize != XTS_BLOCK_SIZE) {
|
if (ctx->blocksize != XTS_BLOCK_SIZE) {
|
||||||
error_setg(errp,
|
error_setg(errp,
|
||||||
|
@ -237,6 +256,7 @@ static QCryptoCipherGcrypt *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
|
||||||
}
|
}
|
||||||
ctx->iv = g_new0(uint8_t, ctx->blocksize);
|
ctx->iv = g_new0(uint8_t, ctx->blocksize);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
return ctx;
|
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,
|
static void qcrypto_gcrypt_xts_encrypt(const void *ctx,
|
||||||
size_t length,
|
size_t length,
|
||||||
uint8_t *dst,
|
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);
|
err = gcry_cipher_decrypt((gcry_cipher_hd_t)ctx, dst, length, src, length);
|
||||||
g_assert(err == 0);
|
g_assert(err == 0);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static int
|
static int
|
||||||
qcrypto_gcrypt_cipher_encrypt(QCryptoCipher *cipher,
|
qcrypto_gcrypt_cipher_encrypt(QCryptoCipher *cipher,
|
||||||
|
@ -289,20 +311,23 @@ qcrypto_gcrypt_cipher_encrypt(QCryptoCipher *cipher,
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_QEMU_PRIVATE_XTS
|
||||||
if (cipher->mode == QCRYPTO_CIPHER_MODE_XTS) {
|
if (cipher->mode == QCRYPTO_CIPHER_MODE_XTS) {
|
||||||
xts_encrypt(ctx->handle, ctx->tweakhandle,
|
xts_encrypt(ctx->handle, ctx->tweakhandle,
|
||||||
qcrypto_gcrypt_xts_encrypt,
|
qcrypto_gcrypt_xts_encrypt,
|
||||||
qcrypto_gcrypt_xts_decrypt,
|
qcrypto_gcrypt_xts_decrypt,
|
||||||
ctx->iv, len, out, in);
|
ctx->iv, len, out, in);
|
||||||
} else {
|
return 0;
|
||||||
err = gcry_cipher_encrypt(ctx->handle,
|
}
|
||||||
out, len,
|
#endif
|
||||||
in, len);
|
|
||||||
if (err != 0) {
|
err = gcry_cipher_encrypt(ctx->handle,
|
||||||
error_setg(errp, "Cannot encrypt data: %s",
|
out, len,
|
||||||
gcry_strerror(err));
|
in, len);
|
||||||
return -1;
|
if (err != 0) {
|
||||||
}
|
error_setg(errp, "Cannot encrypt data: %s",
|
||||||
|
gcry_strerror(err));
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -325,20 +350,23 @@ qcrypto_gcrypt_cipher_decrypt(QCryptoCipher *cipher,
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_QEMU_PRIVATE_XTS
|
||||||
if (cipher->mode == QCRYPTO_CIPHER_MODE_XTS) {
|
if (cipher->mode == QCRYPTO_CIPHER_MODE_XTS) {
|
||||||
xts_decrypt(ctx->handle, ctx->tweakhandle,
|
xts_decrypt(ctx->handle, ctx->tweakhandle,
|
||||||
qcrypto_gcrypt_xts_encrypt,
|
qcrypto_gcrypt_xts_encrypt,
|
||||||
qcrypto_gcrypt_xts_decrypt,
|
qcrypto_gcrypt_xts_decrypt,
|
||||||
ctx->iv, len, out, in);
|
ctx->iv, len, out, in);
|
||||||
} else {
|
return 0;
|
||||||
err = gcry_cipher_decrypt(ctx->handle,
|
}
|
||||||
out, len,
|
#endif
|
||||||
in, len);
|
|
||||||
if (err != 0) {
|
err = gcry_cipher_decrypt(ctx->handle,
|
||||||
error_setg(errp, "Cannot decrypt data: %s",
|
out, len,
|
||||||
gcry_strerror(err));
|
in, len);
|
||||||
return -1;
|
if (err != 0) {
|
||||||
}
|
error_setg(errp, "Cannot decrypt data: %s",
|
||||||
|
gcry_strerror(err));
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -358,24 +386,27 @@ qcrypto_gcrypt_cipher_setiv(QCryptoCipher *cipher,
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_QEMU_PRIVATE_XTS
|
||||||
if (ctx->iv) {
|
if (ctx->iv) {
|
||||||
memcpy(ctx->iv, iv, niv);
|
memcpy(ctx->iv, iv, niv);
|
||||||
|
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 {
|
} else {
|
||||||
if (cipher->mode == QCRYPTO_CIPHER_MODE_CTR) {
|
gcry_cipher_reset(ctx->handle);
|
||||||
err = gcry_cipher_setctr(ctx->handle, iv, niv);
|
err = gcry_cipher_setiv(ctx->handle, iv, niv);
|
||||||
if (err != 0) {
|
if (err != 0) {
|
||||||
error_setg(errp, "Cannot set Counter: %s",
|
error_setg(errp, "Cannot set IV: %s",
|
||||||
gcry_strerror(err));
|
gcry_strerror(err));
|
||||||
return -1;
|
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,9 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "qemu/osdep.h"
|
#include "qemu/osdep.h"
|
||||||
|
#ifdef CONFIG_QEMU_PRIVATE_XTS
|
||||||
#include "crypto/xts.h"
|
#include "crypto/xts.h"
|
||||||
|
#endif
|
||||||
#include "cipherpriv.h"
|
#include "cipherpriv.h"
|
||||||
|
|
||||||
#include <nettle/nettle-types.h>
|
#include <nettle/nettle-types.h>
|
||||||
|
@ -30,6 +32,9 @@
|
||||||
#include <nettle/serpent.h>
|
#include <nettle/serpent.h>
|
||||||
#include <nettle/twofish.h>
|
#include <nettle/twofish.h>
|
||||||
#include <nettle/ctr.h>
|
#include <nettle/ctr.h>
|
||||||
|
#ifndef CONFIG_QEMU_PRIVATE_XTS
|
||||||
|
#include <nettle/xts.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
typedef void (*QCryptoCipherNettleFuncWrapper)(const void *ctx,
|
typedef void (*QCryptoCipherNettleFuncWrapper)(const void *ctx,
|
||||||
size_t length,
|
size_t length,
|
||||||
|
@ -626,9 +631,15 @@ qcrypto_nettle_cipher_encrypt(QCryptoCipher *cipher,
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case QCRYPTO_CIPHER_MODE_XTS:
|
case QCRYPTO_CIPHER_MODE_XTS:
|
||||||
|
#ifdef CONFIG_QEMU_PRIVATE_XTS
|
||||||
xts_encrypt(ctx->ctx, ctx->ctx_tweak,
|
xts_encrypt(ctx->ctx, ctx->ctx_tweak,
|
||||||
ctx->alg_encrypt_wrapper, ctx->alg_encrypt_wrapper,
|
ctx->alg_encrypt_wrapper, ctx->alg_encrypt_wrapper,
|
||||||
ctx->iv, len, out, in);
|
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;
|
break;
|
||||||
|
|
||||||
case QCRYPTO_CIPHER_MODE_CTR:
|
case QCRYPTO_CIPHER_MODE_CTR:
|
||||||
|
@ -673,9 +684,16 @@ qcrypto_nettle_cipher_decrypt(QCryptoCipher *cipher,
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case QCRYPTO_CIPHER_MODE_XTS:
|
case QCRYPTO_CIPHER_MODE_XTS:
|
||||||
|
#ifdef CONFIG_QEMU_PRIVATE_XTS
|
||||||
xts_decrypt(ctx->ctx, ctx->ctx_tweak,
|
xts_decrypt(ctx->ctx, ctx->ctx_tweak,
|
||||||
ctx->alg_encrypt_wrapper, ctx->alg_decrypt_wrapper,
|
ctx->alg_encrypt_wrapper, ctx->alg_decrypt_wrapper,
|
||||||
ctx->iv, len, out, in);
|
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;
|
break;
|
||||||
case QCRYPTO_CIPHER_MODE_CTR:
|
case QCRYPTO_CIPHER_MODE_CTR:
|
||||||
ctr_crypt(ctx->ctx, ctx->alg_encrypt_native,
|
ctr_crypt(ctx->ctx, ctx->alg_encrypt_native,
|
||||||
|
|
|
@ -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-$(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-ivgen$(EXESUF)
|
||||||
check-unit-$(CONFIG_BLOCK) += tests/test-crypto-afsplit$(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-$(CONFIG_BLOCK) += tests/test-crypto-block$(EXESUF)
|
||||||
check-unit-y += tests/test-logging$(EXESUF)
|
check-unit-y += tests/test-logging$(EXESUF)
|
||||||
check-unit-$(call land,$(CONFIG_BLOCK),$(CONFIG_REPLICATION)) += tests/test-replication$(EXESUF)
|
check-unit-$(call land,$(CONFIG_BLOCK),$(CONFIG_REPLICATION)) += tests/test-replication$(EXESUF)
|
||||||
|
|
|
@ -21,11 +21,12 @@ static void test_cipher_speed(size_t chunk_size,
|
||||||
{
|
{
|
||||||
QCryptoCipher *cipher;
|
QCryptoCipher *cipher;
|
||||||
Error *err = NULL;
|
Error *err = NULL;
|
||||||
double total = 0.0;
|
|
||||||
uint8_t *key = NULL, *iv = NULL;
|
uint8_t *key = NULL, *iv = NULL;
|
||||||
uint8_t *plaintext = NULL, *ciphertext = NULL;
|
uint8_t *plaintext = NULL, *ciphertext = NULL;
|
||||||
size_t nkey;
|
size_t nkey;
|
||||||
size_t niv;
|
size_t niv;
|
||||||
|
const size_t total = 2 * GiB;
|
||||||
|
size_t remain;
|
||||||
|
|
||||||
if (!qcrypto_cipher_supports(alg, mode)) {
|
if (!qcrypto_cipher_supports(alg, mode)) {
|
||||||
return;
|
return;
|
||||||
|
@ -58,33 +59,34 @@ static void test_cipher_speed(size_t chunk_size,
|
||||||
&err) == 0);
|
&err) == 0);
|
||||||
|
|
||||||
g_test_timer_start();
|
g_test_timer_start();
|
||||||
do {
|
remain = total;
|
||||||
|
while (remain) {
|
||||||
g_assert(qcrypto_cipher_encrypt(cipher,
|
g_assert(qcrypto_cipher_encrypt(cipher,
|
||||||
plaintext,
|
plaintext,
|
||||||
ciphertext,
|
ciphertext,
|
||||||
chunk_size,
|
chunk_size,
|
||||||
&err) == 0);
|
&err) == 0);
|
||||||
total += chunk_size;
|
remain -= chunk_size;
|
||||||
} while (g_test_timer_elapsed() < 1.0);
|
}
|
||||||
|
g_test_timer_elapsed();
|
||||||
|
|
||||||
total /= MiB;
|
|
||||||
g_print("Enc chunk %zu bytes ", chunk_size);
|
g_print("Enc chunk %zu bytes ", chunk_size);
|
||||||
g_print("%.2f MB/sec ", total / g_test_timer_last());
|
g_print("%.2f MB/sec ", (double)total / MiB / g_test_timer_last());
|
||||||
|
|
||||||
total = 0.0;
|
|
||||||
g_test_timer_start();
|
g_test_timer_start();
|
||||||
do {
|
remain = total;
|
||||||
|
while (remain) {
|
||||||
g_assert(qcrypto_cipher_decrypt(cipher,
|
g_assert(qcrypto_cipher_decrypt(cipher,
|
||||||
plaintext,
|
plaintext,
|
||||||
ciphertext,
|
ciphertext,
|
||||||
chunk_size,
|
chunk_size,
|
||||||
&err) == 0);
|
&err) == 0);
|
||||||
total += chunk_size;
|
remain -= chunk_size;
|
||||||
} while (g_test_timer_elapsed() < 1.0);
|
}
|
||||||
|
g_test_timer_elapsed();
|
||||||
|
|
||||||
total /= MiB;
|
|
||||||
g_print("Dec chunk %zu bytes ", chunk_size);
|
g_print("Dec chunk %zu bytes ", chunk_size);
|
||||||
g_print("%.2f MB/sec ", total / g_test_timer_last());
|
g_print("%.2f MB/sec ", (double)total / MiB / g_test_timer_last());
|
||||||
|
|
||||||
qcrypto_cipher_free(cipher);
|
qcrypto_cipher_free(cipher);
|
||||||
g_free(plaintext);
|
g_free(plaintext);
|
||||||
|
@ -161,15 +163,26 @@ static void test_cipher_speed_xts_aes_256(const void *opaque)
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
|
char *alg = NULL;
|
||||||
|
char *size = NULL;
|
||||||
g_test_init(&argc, &argv, NULL);
|
g_test_init(&argc, &argv, NULL);
|
||||||
g_assert(qcrypto_init(NULL) == 0);
|
g_assert(qcrypto_init(NULL) == 0);
|
||||||
|
|
||||||
#define ADD_TEST(mode, cipher, keysize, chunk) \
|
#define ADD_TEST(mode, cipher, keysize, chunk) \
|
||||||
g_test_add_data_func( \
|
if ((!alg || g_str_equal(alg, #mode)) && \
|
||||||
|
(!size || g_str_equal(size, #chunk))) \
|
||||||
|
g_test_add_data_func( \
|
||||||
"/crypto/cipher/" #mode "-" #cipher "-" #keysize "/chunk-" #chunk, \
|
"/crypto/cipher/" #mode "-" #cipher "-" #keysize "/chunk-" #chunk, \
|
||||||
(void *)chunk, \
|
(void *)chunk, \
|
||||||
test_cipher_speed_ ## mode ## _ ## cipher ## _ ## keysize)
|
test_cipher_speed_ ## mode ## _ ## cipher ## _ ## keysize)
|
||||||
|
|
||||||
|
if (argc >= 2) {
|
||||||
|
alg = argv[1];
|
||||||
|
}
|
||||||
|
if (argc >= 3) {
|
||||||
|
size = argv[2];
|
||||||
|
}
|
||||||
|
|
||||||
#define ADD_TESTS(chunk) \
|
#define ADD_TESTS(chunk) \
|
||||||
do { \
|
do { \
|
||||||
ADD_TEST(ecb, aes, 128, chunk); \
|
ADD_TEST(ecb, aes, 128, chunk); \
|
||||||
|
|
|
@ -20,7 +20,8 @@ static void test_hash_speed(const void *opaque)
|
||||||
size_t chunk_size = (size_t)opaque;
|
size_t chunk_size = (size_t)opaque;
|
||||||
uint8_t *in = NULL, *out = NULL;
|
uint8_t *in = NULL, *out = NULL;
|
||||||
size_t out_len = 0;
|
size_t out_len = 0;
|
||||||
double total = 0.0;
|
const size_t total = 2 * GiB;
|
||||||
|
size_t remain;
|
||||||
struct iovec iov;
|
struct iovec iov;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
@ -31,20 +32,20 @@ static void test_hash_speed(const void *opaque)
|
||||||
iov.iov_len = chunk_size;
|
iov.iov_len = chunk_size;
|
||||||
|
|
||||||
g_test_timer_start();
|
g_test_timer_start();
|
||||||
do {
|
remain = total;
|
||||||
|
while (remain) {
|
||||||
ret = qcrypto_hash_bytesv(QCRYPTO_HASH_ALG_SHA256,
|
ret = qcrypto_hash_bytesv(QCRYPTO_HASH_ALG_SHA256,
|
||||||
&iov, 1, &out, &out_len,
|
&iov, 1, &out, &out_len,
|
||||||
NULL);
|
NULL);
|
||||||
g_assert(ret == 0);
|
g_assert(ret == 0);
|
||||||
|
|
||||||
total += chunk_size;
|
remain -= chunk_size;
|
||||||
} while (g_test_timer_elapsed() < 5.0);
|
}
|
||||||
|
g_test_timer_elapsed();
|
||||||
|
|
||||||
total /= MiB;
|
|
||||||
g_print("sha256: ");
|
g_print("sha256: ");
|
||||||
g_print("Testing chunk_size %zu bytes ", chunk_size);
|
g_print("Hash %zu GB chunk size %zu bytes ", total / GiB, chunk_size);
|
||||||
g_print("done: %.2f MB in %.2f secs: ", total, g_test_timer_last());
|
g_print("%.2f MB/sec ", (double)total / MiB / g_test_timer_last());
|
||||||
g_print("%.2f MB/sec\n", total / g_test_timer_last());
|
|
||||||
|
|
||||||
g_free(out);
|
g_free(out);
|
||||||
g_free(in);
|
g_free(in);
|
||||||
|
|
Loading…
Reference in a new issue