qemu with hax to log dma reads & writes jcs.org/2018/11/12/vfio

crypto: add support for gcrypt's native XTS impl

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>

+88 -35
+22
configure
··· 474 474 nettle="" 475 475 gcrypt="" 476 476 gcrypt_hmac="no" 477 + gcrypt_xts="no" 478 + qemu_private_xts="yes" 477 479 auth_pam="" 478 480 vte="" 479 481 virglrenderer="" ··· 2910 2912 EOF 2911 2913 if compile_prog "$gcrypt_cflags" "$gcrypt_libs" ; then 2912 2914 gcrypt_hmac=yes 2915 + fi 2916 + cat > $TMPC << EOF 2917 + #include <gcrypt.h> 2918 + int main(void) { 2919 + gcry_cipher_hd_t handle; 2920 + gcry_cipher_open(&handle, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_XTS, 0); 2921 + return 0; 2922 + } 2923 + EOF 2924 + if compile_prog "$gcrypt_cflags" "$gcrypt_libs" ; then 2925 + gcrypt_xts=yes 2926 + qemu_private_xts=no 2913 2927 fi 2914 2928 elif test "$gcrypt" = "yes"; then 2915 2929 feature_not_found "gcrypt" "Install gcrypt devel >= 1.5.0" ··· 6326 6340 echo "TLS priority $tls_priority" 6327 6341 echo "GNUTLS support $gnutls" 6328 6342 echo "libgcrypt $gcrypt" 6343 + if test "$gcrypt" = "yes" 6344 + then 6345 + echo " hmac $gcrypt_hmac" 6346 + echo " XTS $gcrypt_xts" 6347 + fi 6329 6348 echo "nettle $nettle $(echo_version $nettle $nettle_version)" 6330 6349 echo "libtasn1 $tasn1" 6331 6350 echo "PAM $auth_pam" ··· 6803 6822 if test "$nettle" = "yes" ; then 6804 6823 echo "CONFIG_NETTLE=y" >> $config_host_mak 6805 6824 echo "CONFIG_NETTLE_VERSION_MAJOR=${nettle_version%%.*}" >> $config_host_mak 6825 + fi 6826 + if test "$qemu_private_xts" = "yes" ; then 6827 + echo "CONFIG_QEMU_PRIVATE_XTS=y" >> $config_host_mak 6806 6828 fi 6807 6829 if test "$tasn1" = "yes" ; then 6808 6830 echo "CONFIG_TASN1=y" >> $config_host_mak
+1 -1
crypto/Makefile.objs
··· 31 31 crypto-obj-y += ivgen-plain.o 32 32 crypto-obj-y += ivgen-plain64.o 33 33 crypto-obj-y += afsplit.o 34 - crypto-obj-y += xts.o 34 + crypto-obj-$(CONFIG_QEMU_PRIVATE_XTS) += xts.o 35 35 crypto-obj-y += block.o 36 36 crypto-obj-y += block-qcow.o 37 37 crypto-obj-y += block-luks.o
+64 -33
crypto/cipher-gcrypt.c
··· 19 19 */ 20 20 21 21 #include "qemu/osdep.h" 22 + #ifdef CONFIG_QEMU_PRIVATE_XTS 22 23 #include "crypto/xts.h" 24 + #endif 23 25 #include "cipherpriv.h" 24 26 25 27 #include <gcrypt.h> ··· 59 61 typedef struct QCryptoCipherGcrypt QCryptoCipherGcrypt; 60 62 struct QCryptoCipherGcrypt { 61 63 gcry_cipher_hd_t handle; 62 - gcry_cipher_hd_t tweakhandle; 63 64 size_t blocksize; 65 + #ifdef CONFIG_QEMU_PRIVATE_XTS 66 + gcry_cipher_hd_t tweakhandle; 64 67 /* Initialization vector or Counter */ 65 68 uint8_t *iv; 69 + #endif 66 70 }; 67 71 68 72 static void ··· 74 78 } 75 79 76 80 gcry_cipher_close(ctx->handle); 81 + #ifdef CONFIG_QEMU_PRIVATE_XTS 77 82 if (mode == QCRYPTO_CIPHER_MODE_XTS) { 78 83 gcry_cipher_close(ctx->tweakhandle); 79 84 } 80 85 g_free(ctx->iv); 86 + #endif 81 87 g_free(ctx); 82 88 } 83 89 ··· 94 100 95 101 switch (mode) { 96 102 case QCRYPTO_CIPHER_MODE_ECB: 103 + gcrymode = GCRY_CIPHER_MODE_ECB; 104 + break; 97 105 case QCRYPTO_CIPHER_MODE_XTS: 106 + #ifdef CONFIG_QEMU_PRIVATE_XTS 98 107 gcrymode = GCRY_CIPHER_MODE_ECB; 108 + #else 109 + gcrymode = GCRY_CIPHER_MODE_XTS; 110 + #endif 99 111 break; 100 112 case QCRYPTO_CIPHER_MODE_CBC: 101 113 gcrymode = GCRY_CIPHER_MODE_CBC; ··· 172 184 gcry_strerror(err)); 173 185 goto error; 174 186 } 187 + #ifdef CONFIG_QEMU_PRIVATE_XTS 175 188 if (mode == QCRYPTO_CIPHER_MODE_XTS) { 176 189 err = gcry_cipher_open(&ctx->tweakhandle, gcryalg, gcrymode, 0); 177 190 if (err != 0) { ··· 180 193 goto error; 181 194 } 182 195 } 196 + #endif 183 197 184 198 if (alg == QCRYPTO_CIPHER_ALG_DES_RFB) { 185 199 /* We're using standard DES cipher from gcrypt, so we need ··· 191 205 g_free(rfbkey); 192 206 ctx->blocksize = 8; 193 207 } else { 208 + #ifdef CONFIG_QEMU_PRIVATE_XTS 194 209 if (mode == QCRYPTO_CIPHER_MODE_XTS) { 195 210 nkey /= 2; 196 211 err = gcry_cipher_setkey(ctx->handle, key, nkey); ··· 201 216 } 202 217 err = gcry_cipher_setkey(ctx->tweakhandle, key + nkey, nkey); 203 218 } else { 219 + #endif 204 220 err = gcry_cipher_setkey(ctx->handle, key, nkey); 221 + #ifdef CONFIG_QEMU_PRIVATE_XTS 205 222 } 223 + #endif 206 224 if (err != 0) { 207 225 error_setg(errp, "Cannot set key: %s", 208 226 gcry_strerror(err)); ··· 228 246 } 229 247 } 230 248 249 + #ifdef CONFIG_QEMU_PRIVATE_XTS 231 250 if (mode == QCRYPTO_CIPHER_MODE_XTS) { 232 251 if (ctx->blocksize != XTS_BLOCK_SIZE) { 233 252 error_setg(errp, ··· 237 256 } 238 257 ctx->iv = g_new0(uint8_t, ctx->blocksize); 239 258 } 259 + #endif 240 260 241 261 return ctx; 242 262 ··· 253 273 } 254 274 255 275 276 + #ifdef CONFIG_QEMU_PRIVATE_XTS 256 277 static void qcrypto_gcrypt_xts_encrypt(const void *ctx, 257 278 size_t length, 258 279 uint8_t *dst, ··· 272 293 err = gcry_cipher_decrypt((gcry_cipher_hd_t)ctx, dst, length, src, length); 273 294 g_assert(err == 0); 274 295 } 296 + #endif 275 297 276 298 static int 277 299 qcrypto_gcrypt_cipher_encrypt(QCryptoCipher *cipher, ··· 289 311 return -1; 290 312 } 291 313 314 + #ifdef CONFIG_QEMU_PRIVATE_XTS 292 315 if (cipher->mode == QCRYPTO_CIPHER_MODE_XTS) { 293 316 xts_encrypt(ctx->handle, ctx->tweakhandle, 294 317 qcrypto_gcrypt_xts_encrypt, 295 318 qcrypto_gcrypt_xts_decrypt, 296 319 ctx->iv, len, out, in); 297 - } else { 298 - err = gcry_cipher_encrypt(ctx->handle, 299 - out, len, 300 - in, len); 301 - if (err != 0) { 302 - error_setg(errp, "Cannot encrypt data: %s", 303 - gcry_strerror(err)); 304 - return -1; 305 - } 320 + return 0; 321 + } 322 + #endif 323 + 324 + err = gcry_cipher_encrypt(ctx->handle, 325 + out, len, 326 + in, len); 327 + if (err != 0) { 328 + error_setg(errp, "Cannot encrypt data: %s", 329 + gcry_strerror(err)); 330 + return -1; 306 331 } 307 332 308 333 return 0; ··· 325 350 return -1; 326 351 } 327 352 353 + #ifdef CONFIG_QEMU_PRIVATE_XTS 328 354 if (cipher->mode == QCRYPTO_CIPHER_MODE_XTS) { 329 355 xts_decrypt(ctx->handle, ctx->tweakhandle, 330 356 qcrypto_gcrypt_xts_encrypt, 331 357 qcrypto_gcrypt_xts_decrypt, 332 358 ctx->iv, len, out, in); 333 - } else { 334 - err = gcry_cipher_decrypt(ctx->handle, 335 - out, len, 336 - in, len); 337 - if (err != 0) { 338 - error_setg(errp, "Cannot decrypt data: %s", 339 - gcry_strerror(err)); 340 - return -1; 341 - } 359 + return 0; 360 + } 361 + #endif 362 + 363 + err = gcry_cipher_decrypt(ctx->handle, 364 + out, len, 365 + in, len); 366 + if (err != 0) { 367 + error_setg(errp, "Cannot decrypt data: %s", 368 + gcry_strerror(err)); 369 + return -1; 342 370 } 343 371 344 372 return 0; ··· 358 386 return -1; 359 387 } 360 388 389 + #ifdef CONFIG_QEMU_PRIVATE_XTS 361 390 if (ctx->iv) { 362 391 memcpy(ctx->iv, iv, niv); 363 - } else { 364 - if (cipher->mode == QCRYPTO_CIPHER_MODE_CTR) { 365 - err = gcry_cipher_setctr(ctx->handle, iv, niv); 366 - if (err != 0) { 367 - error_setg(errp, "Cannot set Counter: %s", 392 + return 0; 393 + } 394 + #endif 395 + 396 + if (cipher->mode == QCRYPTO_CIPHER_MODE_CTR) { 397 + err = gcry_cipher_setctr(ctx->handle, iv, niv); 398 + if (err != 0) { 399 + error_setg(errp, "Cannot set Counter: %s", 368 400 gcry_strerror(err)); 369 - return -1; 370 - } 371 - } else { 372 - gcry_cipher_reset(ctx->handle); 373 - err = gcry_cipher_setiv(ctx->handle, iv, niv); 374 - if (err != 0) { 375 - error_setg(errp, "Cannot set IV: %s", 401 + return -1; 402 + } 403 + } else { 404 + gcry_cipher_reset(ctx->handle); 405 + err = gcry_cipher_setiv(ctx->handle, iv, niv); 406 + if (err != 0) { 407 + error_setg(errp, "Cannot set IV: %s", 376 408 gcry_strerror(err)); 377 - return -1; 378 - } 409 + return -1; 379 410 } 380 411 } 381 412
+1 -1
tests/Makefile.include
··· 140 140 check-unit-$(call land,$(CONFIG_BLOCK),$(if $(CONFIG_NETTLE),y,$(CONFIG_GCRYPT))) += tests/test-crypto-pbkdf$(EXESUF) 141 141 check-unit-$(CONFIG_BLOCK) += tests/test-crypto-ivgen$(EXESUF) 142 142 check-unit-$(CONFIG_BLOCK) += tests/test-crypto-afsplit$(EXESUF) 143 - check-unit-$(CONFIG_BLOCK) += tests/test-crypto-xts$(EXESUF) 143 + check-unit-$(if $(CONFIG_BLOCK),$(CONFIG_QEMU_PRIVATE_XTS)) += tests/test-crypto-xts$(EXESUF) 144 144 check-unit-$(CONFIG_BLOCK) += tests/test-crypto-block$(EXESUF) 145 145 check-unit-y += tests/test-logging$(EXESUF) 146 146 check-unit-$(call land,$(CONFIG_BLOCK),$(CONFIG_REPLICATION)) += tests/test-replication$(EXESUF)