From: Jamin Lin <jamin_lin@aspeedtech.com>
To: "Daniel P. Berrangé" <berrange@redhat.com>,
"Cédric Le Goater" <clg@kaod.org>,
"Peter Maydell" <peter.maydell@linaro.org>,
"Steven Lee" <steven_lee@aspeedtech.com>,
"Troy Lee" <leetroy@gmail.com>,
"Kane Chen" <kane_chen@aspeedtech.com>,
"Andrew Jeffery" <andrew@codeconstruct.com.au>,
"Joel Stanley" <joel@jms.id.au>, "Eric Blake" <eblake@redhat.com>,
"Markus Armbruster" <armbru@redhat.com>,
"Fabiano Rosas" <farosas@suse.de>,
"Laurent Vivier" <lvivier@redhat.com>,
"Paolo Bonzini" <pbonzini@redhat.com>,
"open list:All patches CC here" <qemu-devel@nongnu.org>,
"open list:ASPEED BMCs" <qemu-arm@nongnu.org>
Cc: Jamin Lin <jamin_lin@aspeedtech.com>, Troy Lee <troy_lee@aspeedtech.com>
Subject: [PATCH v2 11/17] crypto/cipher-gnutls: Implement AES-GCM
Date: Wed, 15 Jul 2026 03:33:31 +0000 [thread overview]
Message-ID: <20260715033311.1648424-12-jamin_lin@aspeedtech.com> (raw)
In-Reply-To: <20260715033311.1648424-1-jamin_lin@aspeedtech.com>
Add the AES-GCM AEAD mode to the gnutls backend so it is available when
QEMU is built with gnutls (neither gcrypt nor nettle). GCM uses the
incremental gnutls_cipher_* API with the GNUTLS_CIPHER_AES_*_GCM
algorithms: gnutls_cipher_set_iv() sets the nonce, gnutls_cipher_add_auth()
feeds the associated data, gnutls_cipher_encrypt2()/decrypt2() process the
message, and gnutls_cipher_tag() reads back the authentication tag.
Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
---
crypto/cipher-gnutls.c.inc | 154 +++++++++++++++++++++++++++++++++++++
1 file changed, 154 insertions(+)
diff --git a/crypto/cipher-gnutls.c.inc b/crypto/cipher-gnutls.c.inc
index a8263fff6d..963b328fa1 100644
--- a/crypto/cipher-gnutls.c.inc
+++ b/crypto/cipher-gnutls.c.inc
@@ -48,6 +48,15 @@ bool qcrypto_cipher_supports(QCryptoCipherAlgo alg,
default:
return false;
}
+ case QCRYPTO_CIPHER_MODE_GCM:
+ switch (alg) {
+ case QCRYPTO_CIPHER_ALGO_AES_128:
+ case QCRYPTO_CIPHER_ALGO_AES_192:
+ case QCRYPTO_CIPHER_ALGO_AES_256:
+ return true;
+ default:
+ return false;
+ }
default:
return false;
}
@@ -223,6 +232,147 @@ static struct QCryptoCipherDriver gnutls_driver = {
.cipher_free = qcrypto_gnutls_cipher_free,
};
+/*
+ * GCM is an AEAD stream mode: the nonce need not match the block size, the
+ * message length need not be a multiple of the block size, associated data is
+ * fed with gnutls_cipher_add_auth() and the authentication tag is read back
+ * with gnutls_cipher_tag().
+ */
+static int
+qcrypto_gnutls_cipher_encrypt_gcm(QCryptoCipher *cipher,
+ const void *in, void *out,
+ size_t len, Error **errp)
+{
+ QCryptoCipherGnutls *ctx = container_of(cipher, QCryptoCipherGnutls, base);
+ int err;
+
+ err = gnutls_cipher_encrypt2(ctx->handle, in, len, out, len);
+ if (err != 0) {
+ error_setg(errp, "Cannot encrypt data: %s", gnutls_strerror(err));
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+qcrypto_gnutls_cipher_decrypt_gcm(QCryptoCipher *cipher,
+ const void *in, void *out,
+ size_t len, Error **errp)
+{
+ QCryptoCipherGnutls *ctx = container_of(cipher, QCryptoCipherGnutls, base);
+ int err;
+
+ err = gnutls_cipher_decrypt2(ctx->handle, in, len, out, len);
+ if (err != 0) {
+ error_setg(errp, "Cannot decrypt data: %s", gnutls_strerror(err));
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+qcrypto_gnutls_cipher_setiv_gcm(QCryptoCipher *cipher,
+ const uint8_t *iv, size_t niv,
+ Error **errp)
+{
+ QCryptoCipherGnutls *ctx = container_of(cipher, QCryptoCipherGnutls, base);
+
+ gnutls_cipher_set_iv(ctx->handle, (void *)iv, niv);
+
+ return 0;
+}
+
+static int
+qcrypto_gnutls_cipher_setaad_gcm(QCryptoCipher *cipher,
+ const uint8_t *aad, size_t len,
+ Error **errp)
+{
+ QCryptoCipherGnutls *ctx = container_of(cipher, QCryptoCipherGnutls, base);
+ int err;
+
+ err = gnutls_cipher_add_auth(ctx->handle, aad, len);
+ if (err != 0) {
+ error_setg(errp, "Cannot add associated data: %s",
+ gnutls_strerror(err));
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+qcrypto_gnutls_cipher_gettag_gcm(QCryptoCipher *cipher,
+ uint8_t *tag, size_t len,
+ Error **errp)
+{
+ QCryptoCipherGnutls *ctx = container_of(cipher, QCryptoCipherGnutls, base);
+ int err;
+
+ err = gnutls_cipher_tag(ctx->handle, tag, len);
+ if (err != 0) {
+ error_setg(errp, "Cannot get authentication tag: %s",
+ gnutls_strerror(err));
+ return -1;
+ }
+
+ return 0;
+}
+
+static struct QCryptoCipherDriver gnutls_gcm_driver = {
+ .cipher_encrypt = qcrypto_gnutls_cipher_encrypt_gcm,
+ .cipher_decrypt = qcrypto_gnutls_cipher_decrypt_gcm,
+ .cipher_setiv = qcrypto_gnutls_cipher_setiv_gcm,
+ .cipher_setaad = qcrypto_gnutls_cipher_setaad_gcm,
+ .cipher_gettag = qcrypto_gnutls_cipher_gettag_gcm,
+ .cipher_free = qcrypto_gnutls_cipher_free,
+};
+
+static QCryptoCipher *
+qcrypto_gnutls_aes_gcm_ctx_new(QCryptoCipherAlgo alg, const uint8_t *key,
+ size_t nkey, Error **errp)
+{
+ gnutls_datum_t gkey = { (unsigned char *)key, nkey };
+ gnutls_cipher_algorithm_t galg = GNUTLS_CIPHER_UNKNOWN;
+ QCryptoCipherGnutls *ctx;
+ int err;
+
+ switch (alg) {
+ case QCRYPTO_CIPHER_ALGO_AES_128:
+ galg = GNUTLS_CIPHER_AES_128_GCM;
+ break;
+ case QCRYPTO_CIPHER_ALGO_AES_192:
+ galg = GNUTLS_CIPHER_AES_192_GCM;
+ break;
+ case QCRYPTO_CIPHER_ALGO_AES_256:
+ galg = GNUTLS_CIPHER_AES_256_GCM;
+ break;
+ default:
+ error_setg(errp, "Unsupported cipher algorithm %s with GCM mode",
+ QCryptoCipherAlgo_str(alg));
+ return NULL;
+ }
+
+ if (!qcrypto_cipher_validate_key_length(alg, QCRYPTO_CIPHER_MODE_GCM,
+ nkey, errp)) {
+ return NULL;
+ }
+
+ ctx = g_new0(QCryptoCipherGnutls, 1);
+ ctx->base.driver = &gnutls_gcm_driver;
+ ctx->blocksize = 16;
+
+ err = gnutls_cipher_init(&ctx->handle, galg, &gkey, NULL);
+ if (err != 0) {
+ error_setg(errp, "Cannot initialize cipher: %s", gnutls_strerror(err));
+ g_free(ctx);
+ return NULL;
+ }
+
+ return &ctx->base;
+}
+
static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgo alg,
QCryptoCipherMode mode,
const uint8_t *key,
@@ -234,6 +384,10 @@ static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgo alg,
gnutls_cipher_algorithm_t galg = GNUTLS_CIPHER_UNKNOWN;
int err;
+ if (mode == QCRYPTO_CIPHER_MODE_GCM) {
+ return qcrypto_gnutls_aes_gcm_ctx_new(alg, key, nkey, errp);
+ }
+
switch (mode) {
case QCRYPTO_CIPHER_MODE_XTS:
switch (alg) {
--
2.43.0
next prev parent reply other threads:[~2026-07-15 3:36 UTC|newest]
Thread overview: 19+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-15 3:33 [PATCH v2 00/17] Support the ASPEED HACE crypto command Jamin Lin
2026-07-15 3:33 ` [PATCH v2 01/17] hw/misc/aspeed_hace: Support the crypto command in direct access mode Jamin Lin
2026-07-15 3:33 ` [PATCH v2 02/17] tests/qtest/aspeed-hace: Test the crypto command on the AST2500 Jamin Lin
2026-07-15 3:33 ` [PATCH v2 03/17] hw/misc/aspeed_hace: Support scatter-gather mode for the crypto command Jamin Lin
2026-07-15 3:33 ` [PATCH v2 04/17] hw/misc/aspeed_hace: Support the CTR " Jamin Lin
2026-07-15 3:33 ` [PATCH v2 05/17] tests/qtest/aspeed-hace: Test the crypto command on the AST2600 Jamin Lin
2026-07-15 3:33 ` [PATCH v2 06/17] tests/qtest/aspeed-hace: Test the crypto command on the AST1030 Jamin Lin
2026-07-15 3:33 ` [PATCH v2 07/17] crypto/cipher: Add GCM to QCryptoCipherMode Jamin Lin
2026-07-15 4:51 ` Markus Armbruster
2026-07-15 3:33 ` [PATCH v2 08/17] crypto/cipher: Add setaad/gettag for AEAD modes Jamin Lin
2026-07-15 3:33 ` [PATCH v2 09/17] crypto/cipher-gcrypt: Implement AES-GCM Jamin Lin
2026-07-15 3:33 ` [PATCH v2 10/17] crypto/cipher-nettle: " Jamin Lin
2026-07-15 3:33 ` Jamin Lin [this message]
2026-07-15 3:33 ` [PATCH v2 12/17] tests/unit/test-crypto-cipher: Test AES-GCM mode Jamin Lin
2026-07-15 3:33 ` [PATCH v2 13/17] hw/misc/aspeed_hace: Support 64-bit DMA for the crypto command Jamin Lin
2026-07-15 3:33 ` [PATCH v2 14/17] hw/misc/aspeed_hace: Support the AES-GCM mode " Jamin Lin
2026-07-15 3:33 ` [PATCH v2 15/17] hw/misc/aspeed_hace: Enable the crypto command on the AST2700 Jamin Lin
2026-07-15 3:33 ` [PATCH v2 16/17] tests/qtest/aspeed-hace: Test " Jamin Lin
2026-07-15 3:33 ` [PATCH v2 17/17] tests/functional/aarch64/test_aspeed_ast2700: Drop the AST2700 crypto self-test workaround Jamin Lin
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260715033311.1648424-12-jamin_lin@aspeedtech.com \
--to=jamin_lin@aspeedtech.com \
--cc=andrew@codeconstruct.com.au \
--cc=armbru@redhat.com \
--cc=berrange@redhat.com \
--cc=clg@kaod.org \
--cc=eblake@redhat.com \
--cc=farosas@suse.de \
--cc=joel@jms.id.au \
--cc=kane_chen@aspeedtech.com \
--cc=leetroy@gmail.com \
--cc=lvivier@redhat.com \
--cc=pbonzini@redhat.com \
--cc=peter.maydell@linaro.org \
--cc=qemu-arm@nongnu.org \
--cc=qemu-devel@nongnu.org \
--cc=steven_lee@aspeedtech.com \
--cc=troy_lee@aspeedtech.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.