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 v1 10/15] tests/unit/test-crypto-cipher: Test AES-GCM mode
Date: Tue, 14 Jul 2026 07:29:16 +0000 [thread overview]
Message-ID: <20260714072900.3023742-11-jamin_lin@aspeedtech.com> (raw)
In-Reply-To: <20260714072900.3023742-1-jamin_lin@aspeedtech.com>
Exercise the new GCM mode and the setaad/gettag helpers with the
canonical AES-GCM test vectors from the GCM specification (McGrew &
Viega, also NIST SP 800-38D): AES-128 and AES-256, with and without
associated data. Each vector is run through encrypt (checking the
ciphertext and the generated tag) and decrypt (checking the recovered
plaintext and the recomputed tag).
Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
---
tests/unit/test-crypto-cipher.c | 240 ++++++++++++++++++++++++++++++++
1 file changed, 240 insertions(+)
diff --git a/tests/unit/test-crypto-cipher.c b/tests/unit/test-crypto-cipher.c
index 1331d558cf..670262b39e 100644
--- a/tests/unit/test-crypto-cipher.c
+++ b/tests/unit/test-crypto-cipher.c
@@ -810,6 +810,230 @@ static void test_cipher_short_plaintext(void)
qcrypto_cipher_free(cipher);
}
+typedef struct QCryptoCipherGcmTestData QCryptoCipherGcmTestData;
+struct QCryptoCipherGcmTestData {
+ const char *path;
+ QCryptoCipherAlgo alg;
+ const char *key;
+ const char *iv;
+ /* associated data, or NULL for none */
+ const char *aad;
+ const char *plaintext;
+ const char *ciphertext;
+ const char *tag;
+};
+
+/*
+ * AES-GCM test vectors from "The Galois/Counter Mode of Operation (GCM)"
+ * (McGrew & Viega, also NIST SP 800-38D), with a 96-bit IV and a 128-bit
+ * tag. Each entry's "Test case N" label is the numbered test case from that
+ * document (Appendix B / the GCM specification's test vectors).
+ */
+static QCryptoCipherGcmTestData gcm_test_data[] = {
+ {
+ /* Test case 2 */
+ .path = "/crypto/cipher/aes-128-gcm/2",
+ .alg = QCRYPTO_CIPHER_ALGO_AES_128,
+ .key = "00000000000000000000000000000000",
+ .iv = "000000000000000000000000",
+ .plaintext = "00000000000000000000000000000000",
+ .ciphertext = "0388dace60b6a392f328c2b971b2fe78",
+ .tag = "ab6e47d42cec13bdf53a67b21257bddf",
+ },
+ {
+ /* Test case 3 (no AAD) */
+ .path = "/crypto/cipher/aes-128-gcm/3",
+ .alg = QCRYPTO_CIPHER_ALGO_AES_128,
+ .key = "feffe9928665731c6d6a8f9467308308",
+ .iv = "cafebabefacedbaddecaf888",
+ .plaintext =
+ "d9313225f88406e5a55909c5aff5269a"
+ "86a7a9531534f7da2e4c303d8a318a72"
+ "1c3c0c95956809532fcf0e2449a6b525"
+ "b16aedf5aa0de657ba637b391aafd255",
+ .ciphertext =
+ "42831ec2217774244b7221b784d0d49c"
+ "e3aa212f2c02a4e035c17e2329aca12e"
+ "21d514b25466931c7d8f6a5aac84aa05"
+ "1ba30b396a0aac973d58e091473f5985",
+ .tag = "4d5c2af327cd64a62cf35abd2ba6fab4",
+ },
+ {
+ /* Test case 4 (with AAD) */
+ .path = "/crypto/cipher/aes-128-gcm/4",
+ .alg = QCRYPTO_CIPHER_ALGO_AES_128,
+ .key = "feffe9928665731c6d6a8f9467308308",
+ .iv = "cafebabefacedbaddecaf888",
+ .aad = "feedfacedeadbeeffeedfacedeadbeefabaddad2",
+ .plaintext =
+ "d9313225f88406e5a55909c5aff5269a"
+ "86a7a9531534f7da2e4c303d8a318a72"
+ "1c3c0c95956809532fcf0e2449a6b525"
+ "b16aedf5aa0de657ba637b39",
+ .ciphertext =
+ "42831ec2217774244b7221b784d0d49c"
+ "e3aa212f2c02a4e035c17e2329aca12e"
+ "21d514b25466931c7d8f6a5aac84aa05"
+ "1ba30b396a0aac973d58e091",
+ .tag = "5bc94fbc3221a5db94fae95ae7121a47",
+ },
+ {
+ /* Test case 15 (AES-256, no AAD) */
+ .path = "/crypto/cipher/aes-256-gcm/15",
+ .alg = QCRYPTO_CIPHER_ALGO_AES_256,
+ .key =
+ "feffe9928665731c6d6a8f9467308308"
+ "feffe9928665731c6d6a8f9467308308",
+ .iv = "cafebabefacedbaddecaf888",
+ .plaintext =
+ "d9313225f88406e5a55909c5aff5269a"
+ "86a7a9531534f7da2e4c303d8a318a72"
+ "1c3c0c95956809532fcf0e2449a6b525"
+ "b16aedf5aa0de657ba637b391aafd255",
+ .ciphertext =
+ "522dc1f099567d07f47f37a32a84427d"
+ "643a8cdcbfe5c0c97598a2bd2555d1aa"
+ "8cb08e48590dbb3da7b08b1056828838"
+ "c5f61e6393ba7a0abcc9f662898015ad",
+ .tag = "b094dac5d93471bdec1a502270e3cc6c",
+ },
+ {
+ /* Test case 16 (AES-256, with AAD) */
+ .path = "/crypto/cipher/aes-256-gcm/16",
+ .alg = QCRYPTO_CIPHER_ALGO_AES_256,
+ .key =
+ "feffe9928665731c6d6a8f9467308308"
+ "feffe9928665731c6d6a8f9467308308",
+ .iv = "cafebabefacedbaddecaf888",
+ .aad = "feedfacedeadbeeffeedfacedeadbeefabaddad2",
+ .plaintext =
+ "d9313225f88406e5a55909c5aff5269a"
+ "86a7a9531534f7da2e4c303d8a318a72"
+ "1c3c0c95956809532fcf0e2449a6b525"
+ "b16aedf5aa0de657ba637b39",
+ .ciphertext =
+ "522dc1f099567d07f47f37a32a84427d"
+ "643a8cdcbfe5c0c97598a2bd2555d1aa"
+ "8cb08e48590dbb3da7b08b1056828838"
+ "c5f61e6393ba7a0abcc9f662",
+ .tag = "76fc6ece0f4e1768cddf8853bb2d551b",
+ },
+};
+
+static void test_cipher_gcm(const void *opaque)
+{
+ const QCryptoCipherGcmTestData *data = opaque;
+ g_autofree uint8_t *key = NULL;
+ g_autofree uint8_t *iv = NULL;
+ g_autofree uint8_t *aad = NULL;
+ g_autofree uint8_t *ptext = NULL;
+ g_autofree uint8_t *ctext = NULL;
+ g_autofree uint8_t *tagexp = NULL;
+ g_autofree uint8_t *out = NULL;
+ uint8_t tag[16];
+ size_t nkey;
+ size_t niv;
+ size_t naad = 0;
+ size_t nptext;
+ size_t nctext;
+ size_t ntag;
+ QCryptoCipher *cipher;
+
+ nkey = unhex_string(data->key, &key);
+ niv = unhex_string(data->iv, &iv);
+ nptext = unhex_string(data->plaintext, &ptext);
+ nctext = unhex_string(data->ciphertext, &ctext);
+ ntag = unhex_string(data->tag, &tagexp);
+ if (data->aad) {
+ naad = unhex_string(data->aad, &aad);
+ }
+
+ g_assert_cmpint(nptext, ==, nctext);
+ g_assert_cmpint(ntag, ==, sizeof(tag));
+ out = g_new0(uint8_t, nptext);
+
+ /* Encrypt: plaintext -> ciphertext, then read back the tag. */
+ cipher = qcrypto_cipher_new(data->alg, QCRYPTO_CIPHER_MODE_GCM,
+ key, nkey, &error_abort);
+ g_assert(cipher != NULL);
+ g_assert(qcrypto_cipher_setiv(cipher, iv, niv, &error_abort) == 0);
+ if (naad) {
+ g_assert(qcrypto_cipher_setaad(cipher, aad, naad, &error_abort) == 0);
+ }
+ g_assert(qcrypto_cipher_encrypt(cipher, ptext, out, nptext,
+ &error_abort) == 0);
+ g_assert_cmpmem(out, nptext, ctext, nctext);
+ g_assert(qcrypto_cipher_gettag(cipher, tag, sizeof(tag),
+ &error_abort) == 0);
+ g_assert_cmpmem(tag, sizeof(tag), tagexp, ntag);
+ qcrypto_cipher_free(cipher);
+
+ /* Decrypt: ciphertext -> plaintext, recomputed tag must match. */
+ memset(out, 0, nptext);
+ cipher = qcrypto_cipher_new(data->alg, QCRYPTO_CIPHER_MODE_GCM,
+ key, nkey, &error_abort);
+ g_assert(cipher != NULL);
+ g_assert(qcrypto_cipher_setiv(cipher, iv, niv, &error_abort) == 0);
+ if (naad) {
+ g_assert(qcrypto_cipher_setaad(cipher, aad, naad, &error_abort) == 0);
+ }
+ g_assert(qcrypto_cipher_decrypt(cipher, ctext, out, nctext,
+ &error_abort) == 0);
+ g_assert_cmpmem(out, nctext, ptext, nptext);
+ g_assert(qcrypto_cipher_gettag(cipher, tag, sizeof(tag),
+ &error_abort) == 0);
+ g_assert_cmpmem(tag, sizeof(tag), tagexp, ntag);
+ qcrypto_cipher_free(cipher);
+}
+
+/*
+ * Corrupt one ciphertext byte and confirm the recomputed GCM tag no longer
+ * matches: the authentication tag must detect tampering.
+ */
+static void test_cipher_gcm_tamper(const void *opaque)
+{
+ const QCryptoCipherGcmTestData *data = opaque;
+ g_autofree uint8_t *key = NULL;
+ g_autofree uint8_t *iv = NULL;
+ g_autofree uint8_t *aad = NULL;
+ g_autofree uint8_t *ctext = NULL;
+ g_autofree uint8_t *tagexp = NULL;
+ g_autofree uint8_t *out = NULL;
+ uint8_t tag[16];
+ size_t nkey;
+ size_t niv;
+ size_t naad = 0;
+ size_t nctext;
+ size_t ntag;
+ QCryptoCipher *cipher;
+
+ nkey = unhex_string(data->key, &key);
+ niv = unhex_string(data->iv, &iv);
+ nctext = unhex_string(data->ciphertext, &ctext);
+ ntag = unhex_string(data->tag, &tagexp);
+ if (data->aad) {
+ naad = unhex_string(data->aad, &aad);
+ }
+ out = g_new0(uint8_t, nctext);
+
+ /* Flip one ciphertext bit before decrypting. */
+ ctext[0] ^= 0x01;
+
+ cipher = qcrypto_cipher_new(data->alg, QCRYPTO_CIPHER_MODE_GCM,
+ key, nkey, &error_abort);
+ g_assert(cipher != NULL);
+ g_assert(qcrypto_cipher_setiv(cipher, iv, niv, &error_abort) == 0);
+ if (naad) {
+ g_assert(qcrypto_cipher_setaad(cipher, aad, naad, &error_abort) == 0);
+ }
+ g_assert(qcrypto_cipher_decrypt(cipher, ctext, out, nctext,
+ &error_abort) == 0);
+ g_assert(qcrypto_cipher_gettag(cipher, tag, sizeof(tag),
+ &error_abort) == 0);
+ g_assert(memcmp(tag, tagexp, ntag) != 0);
+ qcrypto_cipher_free(cipher);
+}
+
int main(int argc, char **argv)
{
size_t i;
@@ -828,6 +1052,22 @@ int main(int argc, char **argv)
}
}
+ for (i = 0; i < G_N_ELEMENTS(gcm_test_data); i++) {
+ if (qcrypto_cipher_supports(gcm_test_data[i].alg,
+ QCRYPTO_CIPHER_MODE_GCM)) {
+ g_autofree char *tamper = g_strdup_printf("%s/tamper",
+ gcm_test_data[i].path);
+
+ g_test_add_data_func(gcm_test_data[i].path, &gcm_test_data[i],
+ test_cipher_gcm);
+ g_test_add_data_func(tamper, &gcm_test_data[i],
+ test_cipher_gcm_tamper);
+ } else {
+ g_printerr("# skip unsupported %s:gcm\n",
+ QCryptoCipherAlgo_str(gcm_test_data[i].alg));
+ }
+ }
+
if (qcrypto_cipher_supports(QCRYPTO_CIPHER_ALGO_AES_256,
QCRYPTO_CIPHER_MODE_CBC)) {
g_test_add_func("/crypto/cipher/null-iv",
--
2.43.0
next prev parent reply other threads:[~2026-07-14 7:31 UTC|newest]
Thread overview: 23+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-14 7:29 [PATCH v1 00/15] Support the ASPEED HACE crypto command Jamin Lin
2026-07-14 7:29 ` [PATCH v1 01/15] hw/misc/aspeed_hace: Support the crypto command in direct access mode Jamin Lin
2026-07-14 7:29 ` [PATCH v1 02/15] tests/qtest/aspeed-hace: Test the crypto command on the AST2500 Jamin Lin
2026-07-14 7:29 ` [PATCH v1 03/15] hw/misc/aspeed_hace: Support scatter-gather mode for the crypto command Jamin Lin
2026-07-14 7:29 ` [PATCH v1 04/15] hw/misc/aspeed_hace: Support the CTR " Jamin Lin
2026-07-14 7:29 ` [PATCH v1 05/15] tests/qtest/aspeed-hace: Test the crypto command on the AST2600 Jamin Lin
2026-07-14 10:16 ` Cédric Le Goater
2026-07-14 7:29 ` [PATCH v1 06/15] tests/qtest/aspeed-hace: Test the crypto command on the AST1030 Jamin Lin
2026-07-14 7:29 ` [PATCH v1 07/15] crypto/cipher: Add GCM to QCryptoCipherMode Jamin Lin
2026-07-14 8:37 ` Daniel P. Berrangé
2026-07-14 7:29 ` [PATCH v1 08/15] crypto/cipher: Add setaad/gettag for AEAD modes Jamin Lin
2026-07-14 8:37 ` Daniel P. Berrangé
2026-07-14 7:29 ` [PATCH v1 09/15] crypto/cipher-gcrypt: Implement AES-GCM Jamin Lin
2026-07-14 8:39 ` Daniel P. Berrangé
2026-07-14 8:57 ` Jamin Lin
2026-07-14 9:31 ` Daniel P. Berrangé
2026-07-14 7:29 ` Jamin Lin [this message]
2026-07-14 7:29 ` [PATCH v1 11/15] hw/misc/aspeed_hace: Support 64-bit DMA for the crypto command Jamin Lin
2026-07-14 7:29 ` [PATCH v1 12/15] hw/misc/aspeed_hace: Support the AES-GCM mode " Jamin Lin
2026-07-14 7:29 ` [PATCH v1 13/15] hw/misc/aspeed_hace: Enable the crypto command on the AST2700 Jamin Lin
2026-07-14 7:29 ` [PATCH v1 14/15] tests/qtest/aspeed-hace: Test " Jamin Lin
2026-07-14 7:29 ` [PATCH v1 15/15] tests/functional/aarch64/test_aspeed_ast2700: Drop the AST2700 crypto self-test workaround Jamin Lin
2026-07-14 8:47 ` [PATCH v1 00/15] Support the ASPEED HACE crypto command Daniel P. Berrangé
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=20260714072900.3023742-11-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.