@samitouri / QOSamiQemu / commits / b0f7e8cc97

crypto/cipher-nettle: Implement AES-GCM

Add the AES-GCM AEAD mode to the nettle backend so it is available when QEMU is built with nettle instead of gcrypt. GCM is driven through nettle's generic gcm_* interface, using the AES encrypt function for both directions: gcm_set_iv() sets the (typically 96-bit) nonce, gcm_update() feeds the associated data, gcm_encrypt()/gcm_decrypt() need not be block aligned, and gcm_digest() produces the authentication tag. Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com> Reviewed-by: Daniel P. Berrangé <berrange@redhat.com> Link: https://lore.kernel.org/qemu-devel/20260811060115.1849266-11-jamin_lin@aspeedtech.com Signed-off-by: Cédric Le Goater <clg@redhat.com>

Jamin Lin committed Aug 11, 2026 at 06:01 UTC b0f7e8cc97d16133bfd7ce344b525188d68e30f1
1 file changed +128
crypto/cipher-nettle.c.inc
+128
@@ -27,6 +27,7 @@
27 #include <nettle/twofish.h>
28 #include <nettle/ctr.h>
29 #include <nettle/xts.h>
30 +#include <nettle/gcm.h>
31 #ifdef CONFIG_CRYPTO_SM4
32 #include <nettle/sm4.h>
33 #endif
@@ -410,6 +411,125 @@ DEFINE_ECB(qcrypto_nettle_sm4,
411 sm4_encrypt_native, sm4_decrypt_native)
412 #endif
413
414 +/*
415 + * GCM is an AEAD mode built on AES (128-bit block only). Drive it through the
416 + * generic gcm_* interface, using the block cipher's encrypt function for both
417 + * directions; associated data is fed with gcm_update() and the authentication
418 + * tag is produced by gcm_digest().
419 + */
420 +typedef struct QCryptoNettleAESGCM {
421 + QCryptoCipher base;
422 + struct gcm_key gcm_key;
423 + struct gcm_ctx gcm_ctx;
424 + union {
425 + struct aes128_ctx aes128;
426 + struct aes192_ctx aes192;
427 + struct aes256_ctx aes256;
428 + } cipher;
429 + nettle_cipher_func *encrypt;
430 +} QCryptoNettleAESGCM;
431 +
432 +static int qcrypto_nettle_aes_gcm_setiv(QCryptoCipher *cipher,
433 + const uint8_t *iv, size_t niv,
434 + Error **errp)
435 +{
436 + QCryptoNettleAESGCM *ctx = container_of(cipher, QCryptoNettleAESGCM, base);
437 +
438 + gcm_set_iv(&ctx->gcm_ctx, &ctx->gcm_key, niv, iv);
439 + return 0;
440 +}
441 +
442 +static int qcrypto_nettle_aes_gcm_setaad(QCryptoCipher *cipher,
443 + const uint8_t *aad, size_t len,
444 + Error **errp)
445 +{
446 + QCryptoNettleAESGCM *ctx = container_of(cipher, QCryptoNettleAESGCM, base);
447 +
448 + gcm_update(&ctx->gcm_ctx, &ctx->gcm_key, len, aad);
449 + return 0;
450 +}
451 +
452 +static int qcrypto_nettle_aes_gcm_encrypt(QCryptoCipher *cipher,
453 + const void *in, void *out,
454 + size_t len, Error **errp)
455 +{
456 + QCryptoNettleAESGCM *ctx = container_of(cipher, QCryptoNettleAESGCM, base);
457 +
458 + gcm_encrypt(&ctx->gcm_ctx, &ctx->gcm_key, &ctx->cipher, ctx->encrypt,
459 + len, out, in);
460 + return 0;
461 +}
462 +
463 +static int qcrypto_nettle_aes_gcm_decrypt(QCryptoCipher *cipher,
464 + const void *in, void *out,
465 + size_t len, Error **errp)
466 +{
467 + QCryptoNettleAESGCM *ctx = container_of(cipher, QCryptoNettleAESGCM, base);
468 +
469 + gcm_decrypt(&ctx->gcm_ctx, &ctx->gcm_key, &ctx->cipher, ctx->encrypt,
470 + len, out, in);
471 + return 0;
472 +}
473 +
474 +static int qcrypto_nettle_aes_gcm_gettag(QCryptoCipher *cipher,
475 + uint8_t *tag, size_t len,
476 + Error **errp)
477 +{
478 + QCryptoNettleAESGCM *ctx = container_of(cipher, QCryptoNettleAESGCM, base);
479 +
480 + gcm_digest(&ctx->gcm_ctx, &ctx->gcm_key, &ctx->cipher, ctx->encrypt,
481 + len, tag);
482 + return 0;
483 +}
484 +
485 +static const struct QCryptoCipherDriver qcrypto_nettle_aes_gcm_driver = {
486 + .cipher_encrypt = qcrypto_nettle_aes_gcm_encrypt,
487 + .cipher_decrypt = qcrypto_nettle_aes_gcm_decrypt,
488 + .cipher_setiv = qcrypto_nettle_aes_gcm_setiv,
489 + .cipher_setaad = qcrypto_nettle_aes_gcm_setaad,
490 + .cipher_gettag = qcrypto_nettle_aes_gcm_gettag,
491 + .cipher_free = qcrypto_cipher_ctx_free,
492 +};
493 +
494 +static QCryptoCipher *qcrypto_nettle_aes_gcm_ctx_new(QCryptoCipherAlgo alg,
495 + const uint8_t *key,
496 + size_t nkey,
497 + Error **errp)
498 +{
499 + QCryptoNettleAESGCM *ctx;
500 +
501 + if (!qcrypto_cipher_validate_key_length(alg, QCRYPTO_CIPHER_MODE_GCM,
502 + nkey, errp)) {
503 + return NULL;
504 + }
505 +
506 + ctx = g_new0(QCryptoNettleAESGCM, 1);
507 + ctx->base.driver = &qcrypto_nettle_aes_gcm_driver;
508 +
509 + switch (alg) {
510 + case QCRYPTO_CIPHER_ALGO_AES_128:
511 + aes128_set_encrypt_key(&ctx->cipher.aes128, key);
512 + ctx->encrypt = aes128_encrypt_native;
513 + break;
514 + case QCRYPTO_CIPHER_ALGO_AES_192:
515 + aes192_set_encrypt_key(&ctx->cipher.aes192, key);
516 + ctx->encrypt = aes192_encrypt_native;
517 + break;
518 + case QCRYPTO_CIPHER_ALGO_AES_256:
519 + aes256_set_encrypt_key(&ctx->cipher.aes256, key);
520 + ctx->encrypt = aes256_encrypt_native;
521 + break;
522 + default:
523 + error_setg(errp, "Unsupported cipher algorithm %s with GCM mode",
524 + QCryptoCipherAlgo_str(alg));
525 + g_free(ctx);
526 + return NULL;
527 + }
528 +
529 + gcm_set_key(&ctx->gcm_key, &ctx->cipher, ctx->encrypt);
530 + return &ctx->base;
531 +}
532 +
533 bool qcrypto_cipher_supports(QCryptoCipherAlgo alg,
534 QCryptoCipherMode mode)
535 {
@@ -440,6 +560,10 @@ bool qcrypto_cipher_supports(QCryptoCipherAlgo alg,
560 case QCRYPTO_CIPHER_MODE_XTS:
561 case QCRYPTO_CIPHER_MODE_CTR:
562 return true;
563 + case QCRYPTO_CIPHER_MODE_GCM:
564 + return alg == QCRYPTO_CIPHER_ALGO_AES_128 ||
565 + alg == QCRYPTO_CIPHER_ALGO_AES_192 ||
566 + alg == QCRYPTO_CIPHER_ALGO_AES_256;
567 default:
568 return false;
569 }
@@ -451,6 +575,10 @@ static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgo alg,
575 size_t nkey,
576 Error **errp)
577 {
578 + if (mode == QCRYPTO_CIPHER_MODE_GCM) {
579 + return qcrypto_nettle_aes_gcm_ctx_new(alg, key, nkey, errp);
580 + }
581 +
582 switch (mode) {
583 case QCRYPTO_CIPHER_MODE_ECB:
584 case QCRYPTO_CIPHER_MODE_CBC: