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: