Cover the AST2700 crypto engine, which drives 64-bit scatter-gather DMA
and adds AES-GCM on top of the ECB/CBC/CTR modes shared with the AST2600.
Add AES-128 and AES-256 GCM known-answer vectors (GCM specification /
NIST SP 800-38D, no associated data) and a dedicated GCM runner that
programs the tag buffer and reads the tag back, checking it after both
encryption and decryption. Register the AST2700 with all four modes.
Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
---
tests/qtest/aspeed-hace-utils.h | 1 +
tests/qtest/aspeed-hace-utils.c | 163 +++++++++++++++++++++++++++++++-
tests/qtest/ast2700-hace-test.c | 9 ++
3 files changed, 172 insertions(+), 1 deletion(-)
diff --git a/tests/qtest/aspeed-hace-utils.h b/tests/qtest/aspeed-hace-utils.h
index 82b0b3f93d..a5601a3d65 100644
--- a/tests/qtest/aspeed-hace-utils.h
+++ b/tests/qtest/aspeed-hace-utils.h
@@ -86,6 +86,7 @@ enum {
CRYPT_MODE_ECB = 1 << 0,
CRYPT_MODE_CBC = 1 << 1,
CRYPT_MODE_CTR = 1 << 2,
+ CRYPT_MODE_GCM = 1 << 3,
};
/*
diff --git a/tests/qtest/aspeed-hace-utils.c b/tests/qtest/aspeed-hace-utils.c
index f582c88ef5..260eec043c 100644
--- a/tests/qtest/aspeed-hace-utils.c
+++ b/tests/qtest/aspeed-hace-utils.c
@@ -654,6 +654,8 @@ void aspeed_test_addresses(const char *machine, const uint32_t base,
#define HACE_CRYPTO_CONTEXT 0x08
#define HACE_CRYPTO_DATA_LEN 0x0c
#define HACE_CRYPTO_CMD 0x10
+#define HACE_CRYPTO_GCM_ADD_LEN 0x14
+#define HACE_CRYPTO_GCM_TAG 0x18
/* Crypto command bits */
#define HACE_CMD_ENCRYPT BIT(7)
@@ -666,7 +668,9 @@ void aspeed_test_addresses(const char *machine, const uint32_t base,
#define HACE_CMD_ECB (0x0 << 4)
#define HACE_CMD_CBC (0x1 << 4)
#define HACE_CMD_CTR (0x4 << 4)
+#define HACE_CMD_GCM (0x5 << 4)
#define HACE_CMD_AES128 (0x0 << 2)
+#define HACE_CMD_AES256 (0x2 << 2)
/* Context buffer layout: IV (DES at +8), key at +0x10 */
#define HACE_CTX_KEY_OFFSET 0x10
@@ -794,6 +798,59 @@ static const uint8_t tdes_ctr_ctext[8] = {
static const uint8_t tdes_ctr_ivout[8] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+/*
+ * aes_gcm_tv_template[2] (AES-128) and [9] (AES-256), from the McGrew & Viega
+ * GCM spec (also NIST SP 800-38D), no AAD. Both cases share this plaintext/IV.
+ */
+static const uint8_t aes_gcm_ptext[64] = {
+ 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5,
+ 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a,
+ 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda,
+ 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72,
+ 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53,
+ 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25,
+ 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57,
+ 0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x55 };
+static const uint8_t aes_gcm_iv[12] = {
+ 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad,
+ 0xde, 0xca, 0xf8, 0x88 };
+
+/* aes_gcm_tv_template[2] (AES-128) */
+static const uint8_t aes128_gcm_key[16] = {
+ 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c,
+ 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08 };
+static const uint8_t aes128_gcm_ctext[64] = {
+ 0x42, 0x83, 0x1e, 0xc2, 0x21, 0x77, 0x74, 0x24,
+ 0x4b, 0x72, 0x21, 0xb7, 0x84, 0xd0, 0xd4, 0x9c,
+ 0xe3, 0xaa, 0x21, 0x2f, 0x2c, 0x02, 0xa4, 0xe0,
+ 0x35, 0xc1, 0x7e, 0x23, 0x29, 0xac, 0xa1, 0x2e,
+ 0x21, 0xd5, 0x14, 0xb2, 0x54, 0x66, 0x93, 0x1c,
+ 0x7d, 0x8f, 0x6a, 0x5a, 0xac, 0x84, 0xaa, 0x05,
+ 0x1b, 0xa3, 0x0b, 0x39, 0x6a, 0x0a, 0xac, 0x97,
+ 0x3d, 0x58, 0xe0, 0x91, 0x47, 0x3f, 0x59, 0x85 };
+static const uint8_t aes128_gcm_tag[16] = {
+ 0x4d, 0x5c, 0x2a, 0xf3, 0x27, 0xcd, 0x64, 0xa6,
+ 0x2c, 0xf3, 0x5a, 0xbd, 0x2b, 0xa6, 0xfa, 0xb4 };
+
+/* aes_gcm_tv_template[9] (AES-256) */
+static const uint8_t aes256_gcm_key[32] = {
+ 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c,
+ 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08,
+ 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c,
+ 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08 };
+static const uint8_t aes256_gcm_ctext[64] = {
+ 0x52, 0x2d, 0xc1, 0xf0, 0x99, 0x56, 0x7d, 0x07,
+ 0xf4, 0x7f, 0x37, 0xa3, 0x2a, 0x84, 0x42, 0x7d,
+ 0x64, 0x3a, 0x8c, 0xdc, 0xbf, 0xe5, 0xc0, 0xc9,
+ 0x75, 0x98, 0xa2, 0xbd, 0x25, 0x55, 0xd1, 0xaa,
+ 0x8c, 0xb0, 0x8e, 0x48, 0x59, 0x0d, 0xbb, 0x3d,
+ 0xa7, 0xb0, 0x8b, 0x10, 0x56, 0x82, 0x88, 0x38,
+ 0xc5, 0xf6, 0x1e, 0x63, 0x93, 0xba, 0x7a, 0x0a,
+ 0xbc, 0xc9, 0xf6, 0x62, 0x89, 0x80, 0x15, 0xad };
+static const uint8_t aes256_gcm_tag[16] = {
+ 0xb0, 0x94, 0xda, 0xc5, 0xd9, 0x34, 0x71, 0xbd,
+ 0xec, 0x1a, 0x50, 0x22, 0x70, 0xe3, 0xcc, 0x6c };
+
typedef struct CryptTest {
QCryptoCipherMode mode;
QCryptoCipherAlgo alg;
@@ -801,10 +858,13 @@ typedef struct CryptTest {
const uint8_t *iv_out;
const uint8_t *ptext;
const uint8_t *ctext;
+ /* expected GCM authentication tag, or NULL for non-AEAD modes */
+ const uint8_t *tag;
const uint8_t *key;
const uint8_t *iv;
const char *name;
size_t keylen;
+ size_t taglen;
/* algorithm | mode | key size selection */
uint32_t cmd;
size_t ivlen;
@@ -927,6 +987,36 @@ static const CryptTest crypt_tests[] = {
.iv_out = tdes_ctr_ivout,
.len = sizeof(tdes_ctr_ptext),
},
+ {
+ .name = "aes128-gcm",
+ .cmd = HACE_CMD_AES128 | HACE_CMD_GCM,
+ .alg = QCRYPTO_CIPHER_ALGO_AES_128,
+ .mode = QCRYPTO_CIPHER_MODE_GCM,
+ .key = aes128_gcm_key,
+ .keylen = sizeof(aes128_gcm_key),
+ .iv = aes_gcm_iv,
+ .ivlen = sizeof(aes_gcm_iv),
+ .ptext = aes_gcm_ptext,
+ .ctext = aes128_gcm_ctext,
+ .tag = aes128_gcm_tag,
+ .taglen = sizeof(aes128_gcm_tag),
+ .len = sizeof(aes_gcm_ptext),
+ },
+ {
+ .name = "aes256-gcm",
+ .cmd = HACE_CMD_AES256 | HACE_CMD_GCM,
+ .alg = QCRYPTO_CIPHER_ALGO_AES_256,
+ .mode = QCRYPTO_CIPHER_MODE_GCM,
+ .key = aes256_gcm_key,
+ .keylen = sizeof(aes256_gcm_key),
+ .iv = aes_gcm_iv,
+ .ivlen = sizeof(aes_gcm_iv),
+ .ptext = aes_gcm_ptext,
+ .ctext = aes256_gcm_ctext,
+ .tag = aes256_gcm_tag,
+ .taglen = sizeof(aes256_gcm_tag),
+ .len = sizeof(aes_gcm_ptext),
+ },
};
/* DRAM offsets for the crypto test source, destination and context buffers. */
@@ -944,6 +1034,8 @@ static const CryptTest crypt_tests[] = {
*/
#define CRYPT_SG_FRAGS 3
#define CRYPT_SG_FRAG_STRIDE 0x1000
+/* DRAM offset for the AES-GCM authentication tag write buffer. */
+#define CRYPT_OFF_TAG 0x60000
/* Describes one registered crypto test (qtest_add_data_func() data pointer). */
typedef struct AspeedCryptoTest {
@@ -964,6 +1056,8 @@ static uint32_t crypt_mode_flag(uint32_t cmd)
return CRYPT_MODE_CBC;
case HACE_CMD_CTR:
return CRYPT_MODE_CTR;
+ case HACE_CMD_GCM:
+ return CRYPT_MODE_GCM;
default:
return 0;
}
@@ -1109,6 +1203,47 @@ static void crypt_run_sg(QTestState *s, uint32_t base, uint64_t dram,
crypt_gather_sg(s, dram, CRYPT_OFF_DST, out, t->len);
}
+/*
+ * Run one AES-GCM operation in scatter-gather mode: like crypt_run_sg() but
+ * also program the tag write buffer (HACE18) with no associated data, and read
+ * the authentication tag back into @out_tag.
+ */
+static void crypt_run_gcm(QTestState *s, uint32_t base, uint64_t dram,
+ const CryptTest *t, bool encrypt, uint8_t *out,
+ uint8_t *out_tag)
+{
+ const uint8_t *in = encrypt ? t->ptext : t->ctext;
+ uint64_t src_sg = dram + CRYPT_OFF_SRC_SG;
+ uint64_t dst_sg = dram + CRYPT_OFF_DST_SG;
+ uint64_t ctx = dram + CRYPT_OFF_CTX;
+ uint32_t cmd = t->cmd | HACE_CMD_ISR_EN | HACE_CMD_SRC_SG_CTRL |
+ HACE_CMD_DST_SG_CTRL;
+
+ if (encrypt) {
+ cmd |= HACE_CMD_ENCRYPT;
+ }
+
+ crypt_write_ctx(s, ctx, t);
+ crypt_make_sg(s, dram, CRYPT_OFF_SRC, src_sg, in, t->len);
+ crypt_make_sg(s, dram, CRYPT_OFF_DST, dst_sg, NULL, t->len);
+
+ qtest_writel(s, base + HACE_CRYPTO_SRC, (uint32_t)src_sg);
+ qtest_writel(s, base + HACE_CRYPTO_DEST, (uint32_t)dst_sg);
+ qtest_writel(s, base + HACE_CRYPTO_CONTEXT, (uint32_t)ctx);
+ qtest_writel(s, base + HACE_CRYPTO_DATA_LEN, t->len);
+ qtest_writel(s, base + HACE_CRYPTO_GCM_ADD_LEN, 0);
+ qtest_writel(s, base + HACE_CRYPTO_GCM_TAG,
+ (uint32_t)(dram + CRYPT_OFF_TAG));
+ qtest_writel(s, base + HACE_CRYPTO_CMD, cmd);
+
+ g_assert_cmphex(qtest_readl(s, base + HACE_STS) & HACE_CRYPTO_ISR, ==,
+ HACE_CRYPTO_ISR);
+ qtest_writel(s, base + HACE_STS, HACE_CRYPTO_ISR);
+
+ crypt_gather_sg(s, dram, CRYPT_OFF_DST, out, t->len);
+ qtest_memread(s, dram + CRYPT_OFF_TAG, out_tag, t->taglen);
+}
+
static void aspeed_test_crypto(const void *data)
{
const AspeedCryptoTest *c = data;
@@ -1145,6 +1280,29 @@ static void aspeed_test_crypto(const void *data)
qtest_quit(s);
}
+static void aspeed_test_crypto_gcm(const void *data)
+{
+ const AspeedCryptoTest *c = data;
+ const CryptTest *t = &crypt_tests[c->index];
+ QTestState *s = qtest_init(c->machine);
+ uint8_t out[64];
+ uint8_t tag[16];
+
+ g_assert_cmpuint(t->len, <=, sizeof(out));
+
+ /* Encrypt: ptext -> ctext, then check the authentication tag. */
+ crypt_run_gcm(s, c->base, c->dram, t, true, out, tag);
+ g_assert_cmpmem(out, t->len, t->ctext, t->len);
+ g_assert_cmpmem(tag, t->taglen, t->tag, t->taglen);
+
+ /* Decrypt: ctext -> ptext, the recomputed tag must match. */
+ crypt_run_gcm(s, c->base, c->dram, t, false, out, tag);
+ g_assert_cmpmem(out, t->len, t->ptext, t->len);
+ g_assert_cmpmem(tag, t->taglen, t->tag, t->taglen);
+
+ qtest_quit(s);
+}
+
void aspeed_add_crypto_tests(const char *prefix, const char *machine,
uint32_t base, uint64_t dram, uint32_t modes,
bool sg)
@@ -1152,6 +1310,7 @@ void aspeed_add_crypto_tests(const char *prefix, const char *machine,
int i;
for (i = 0; i < ARRAY_SIZE(crypt_tests); i++) {
+ bool is_gcm = crypt_tests[i].mode == QCRYPTO_CIPHER_MODE_GCM;
g_autofree char *path = NULL;
AspeedCryptoTest *t;
@@ -1173,7 +1332,9 @@ void aspeed_add_crypto_tests(const char *prefix, const char *machine,
t->dram = dram;
t->index = i;
t->sg = sg;
- qtest_add_data_func_full(path, t, aspeed_test_crypto, g_free);
+ qtest_add_data_func_full(path, t,
+ is_gcm ? aspeed_test_crypto_gcm :
+ aspeed_test_crypto, g_free);
}
}
diff --git a/tests/qtest/ast2700-hace-test.c b/tests/qtest/ast2700-hace-test.c
index 508a34dd6c..3f0217d635 100644
--- a/tests/qtest/ast2700-hace-test.c
+++ b/tests/qtest/ast2700-hace-test.c
@@ -94,5 +94,14 @@ int main(int argc, char **argv)
qtest_add_func("ast2700/hace/sha384_accum", test_sha384_accum_ast2700);
qtest_add_func("ast2700/hace/sha256_accum", test_sha256_accum_ast2700);
+ /*
+ * The AST2700 crypto engine uses scatter-gather with 64-bit DMA and adds
+ * AES-GCM on top of the ECB/CBC/CTR modes shared with the AST2600.
+ */
+ aspeed_add_crypto_tests("ast2700", "-machine ast2700-evb", 0x12070000,
+ 0x400000000,
+ CRYPT_MODE_ECB | CRYPT_MODE_CBC | CRYPT_MODE_CTR |
+ CRYPT_MODE_GCM, true);
+
return g_test_run();
}
--
2.43.0
> -----Original Message-----
> From: Jamin Lin <jamin_lin@aspeedtech.com>
> Sent: Wednesday, July 15, 2026 11:34 AM
> 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 16/17] tests/qtest/aspeed-hace: Test the crypto command
> on the AST2700
>
> Cover the AST2700 crypto engine, which drives 64-bit scatter-gather DMA and
> adds AES-GCM on top of the ECB/CBC/CTR modes shared with the AST2600.
> Add AES-128 and AES-256 GCM known-answer vectors (GCM specification /
> NIST SP 800-38D, no associated data) and a dedicated GCM runner that
> programs the tag buffer and reads the tag back, checking it after both
> encryption and decryption. Register the AST2700 with all four modes.
>
> Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
> ---
> tests/qtest/aspeed-hace-utils.h | 1 +
> tests/qtest/aspeed-hace-utils.c | 163 +++++++++++++++++++++++++++++++-
> tests/qtest/ast2700-hace-test.c | 9 ++
> 3 files changed, 172 insertions(+), 1 deletion(-)
>
> diff --git a/tests/qtest/aspeed-hace-utils.h b/tests/qtest/aspeed-hace-utils.h
> index 82b0b3f93d..a5601a3d65 100644
> --- a/tests/qtest/aspeed-hace-utils.h
> +++ b/tests/qtest/aspeed-hace-utils.h
> @@ -86,6 +86,7 @@ enum {
> CRYPT_MODE_ECB = 1 << 0,
> CRYPT_MODE_CBC = 1 << 1,
> CRYPT_MODE_CTR = 1 << 2,
> + CRYPT_MODE_GCM = 1 << 3,
> };
>
> /*
> diff --git a/tests/qtest/aspeed-hace-utils.c b/tests/qtest/aspeed-hace-utils.c
> index f582c88ef5..260eec043c 100644
> --- a/tests/qtest/aspeed-hace-utils.c
> +++ b/tests/qtest/aspeed-hace-utils.c
> @@ -654,6 +654,8 @@ void aspeed_test_addresses(const char *machine,
> const uint32_t base,
> #define HACE_CRYPTO_CONTEXT 0x08
> #define HACE_CRYPTO_DATA_LEN 0x0c
> #define HACE_CRYPTO_CMD 0x10
> +#define HACE_CRYPTO_GCM_ADD_LEN 0x14
> +#define HACE_CRYPTO_GCM_TAG 0x18
>
> /* Crypto command bits */
> #define HACE_CMD_ENCRYPT BIT(7)
> @@ -666,7 +668,9 @@ void aspeed_test_addresses(const char *machine,
> const uint32_t base,
> #define HACE_CMD_ECB (0x0 << 4)
> #define HACE_CMD_CBC (0x1 << 4)
> #define HACE_CMD_CTR (0x4 << 4)
> +#define HACE_CMD_GCM (0x5 << 4)
> #define HACE_CMD_AES128 (0x0 << 2)
> +#define HACE_CMD_AES256 (0x2 << 2)
>
> /* Context buffer layout: IV (DES at +8), key at +0x10 */
> #define HACE_CTX_KEY_OFFSET 0x10
> @@ -794,6 +798,59 @@ static const uint8_t tdes_ctr_ctext[8] = { static const
> uint8_t tdes_ctr_ivout[8] = {
> 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
>
> +/*
> + * aes_gcm_tv_template[2] (AES-128) and [9] (AES-256), from the McGrew
> +& Viega
> + * GCM spec (also NIST SP 800-38D), no AAD. Both cases share this
> plaintext/IV.
> + */
> +static const uint8_t aes_gcm_ptext[64] = {
> + 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5,
> + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a,
> + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda,
> + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72,
> + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53,
> + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25,
> + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57,
> + 0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x55 }; static const
> +uint8_t aes_gcm_iv[12] = {
> + 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad,
> + 0xde, 0xca, 0xf8, 0x88 };
> +
> +/* aes_gcm_tv_template[2] (AES-128) */
> +static const uint8_t aes128_gcm_key[16] = {
> + 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c,
> + 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08 }; static const
> +uint8_t aes128_gcm_ctext[64] = {
> + 0x42, 0x83, 0x1e, 0xc2, 0x21, 0x77, 0x74, 0x24,
> + 0x4b, 0x72, 0x21, 0xb7, 0x84, 0xd0, 0xd4, 0x9c,
> + 0xe3, 0xaa, 0x21, 0x2f, 0x2c, 0x02, 0xa4, 0xe0,
> + 0x35, 0xc1, 0x7e, 0x23, 0x29, 0xac, 0xa1, 0x2e,
> + 0x21, 0xd5, 0x14, 0xb2, 0x54, 0x66, 0x93, 0x1c,
> + 0x7d, 0x8f, 0x6a, 0x5a, 0xac, 0x84, 0xaa, 0x05,
> + 0x1b, 0xa3, 0x0b, 0x39, 0x6a, 0x0a, 0xac, 0x97,
> + 0x3d, 0x58, 0xe0, 0x91, 0x47, 0x3f, 0x59, 0x85 }; static const
> +uint8_t aes128_gcm_tag[16] = {
> + 0x4d, 0x5c, 0x2a, 0xf3, 0x27, 0xcd, 0x64, 0xa6,
> + 0x2c, 0xf3, 0x5a, 0xbd, 0x2b, 0xa6, 0xfa, 0xb4 };
> +
> +/* aes_gcm_tv_template[9] (AES-256) */
> +static const uint8_t aes256_gcm_key[32] = {
> + 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c,
> + 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08,
> + 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c,
> + 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08 }; static const
> +uint8_t aes256_gcm_ctext[64] = {
> + 0x52, 0x2d, 0xc1, 0xf0, 0x99, 0x56, 0x7d, 0x07,
> + 0xf4, 0x7f, 0x37, 0xa3, 0x2a, 0x84, 0x42, 0x7d,
> + 0x64, 0x3a, 0x8c, 0xdc, 0xbf, 0xe5, 0xc0, 0xc9,
> + 0x75, 0x98, 0xa2, 0xbd, 0x25, 0x55, 0xd1, 0xaa,
> + 0x8c, 0xb0, 0x8e, 0x48, 0x59, 0x0d, 0xbb, 0x3d,
> + 0xa7, 0xb0, 0x8b, 0x10, 0x56, 0x82, 0x88, 0x38,
> + 0xc5, 0xf6, 0x1e, 0x63, 0x93, 0xba, 0x7a, 0x0a,
> + 0xbc, 0xc9, 0xf6, 0x62, 0x89, 0x80, 0x15, 0xad }; static const
> +uint8_t aes256_gcm_tag[16] = {
> + 0xb0, 0x94, 0xda, 0xc5, 0xd9, 0x34, 0x71, 0xbd,
> + 0xec, 0x1a, 0x50, 0x22, 0x70, 0xe3, 0xcc, 0x6c };
> +
> typedef struct CryptTest {
> QCryptoCipherMode mode;
> QCryptoCipherAlgo alg;
> @@ -801,10 +858,13 @@ typedef struct CryptTest {
> const uint8_t *iv_out;
> const uint8_t *ptext;
> const uint8_t *ctext;
> + /* expected GCM authentication tag, or NULL for non-AEAD modes */
> + const uint8_t *tag;
> const uint8_t *key;
> const uint8_t *iv;
> const char *name;
> size_t keylen;
> + size_t taglen;
> /* algorithm | mode | key size selection */
> uint32_t cmd;
> size_t ivlen;
> @@ -927,6 +987,36 @@ static const CryptTest crypt_tests[] = {
> .iv_out = tdes_ctr_ivout,
> .len = sizeof(tdes_ctr_ptext),
> },
> + {
> + .name = "aes128-gcm",
> + .cmd = HACE_CMD_AES128 | HACE_CMD_GCM,
> + .alg = QCRYPTO_CIPHER_ALGO_AES_128,
> + .mode = QCRYPTO_CIPHER_MODE_GCM,
> + .key = aes128_gcm_key,
> + .keylen = sizeof(aes128_gcm_key),
> + .iv = aes_gcm_iv,
> + .ivlen = sizeof(aes_gcm_iv),
> + .ptext = aes_gcm_ptext,
> + .ctext = aes128_gcm_ctext,
> + .tag = aes128_gcm_tag,
> + .taglen = sizeof(aes128_gcm_tag),
> + .len = sizeof(aes_gcm_ptext),
> + },
> + {
> + .name = "aes256-gcm",
> + .cmd = HACE_CMD_AES256 | HACE_CMD_GCM,
> + .alg = QCRYPTO_CIPHER_ALGO_AES_256,
> + .mode = QCRYPTO_CIPHER_MODE_GCM,
> + .key = aes256_gcm_key,
> + .keylen = sizeof(aes256_gcm_key),
> + .iv = aes_gcm_iv,
> + .ivlen = sizeof(aes_gcm_iv),
> + .ptext = aes_gcm_ptext,
> + .ctext = aes256_gcm_ctext,
> + .tag = aes256_gcm_tag,
> + .taglen = sizeof(aes256_gcm_tag),
> + .len = sizeof(aes_gcm_ptext),
> + },
> };
>
> /* DRAM offsets for the crypto test source, destination and context buffers. */
> @@ -944,6 +1034,8 @@ static const CryptTest crypt_tests[] = {
> */
> #define CRYPT_SG_FRAGS 3
> #define CRYPT_SG_FRAG_STRIDE 0x1000
> +/* DRAM offset for the AES-GCM authentication tag write buffer. */
> +#define CRYPT_OFF_TAG 0x60000
>
> /* Describes one registered crypto test (qtest_add_data_func() data pointer).
> */ typedef struct AspeedCryptoTest { @@ -964,6 +1056,8 @@ static uint32_t
> crypt_mode_flag(uint32_t cmd)
> return CRYPT_MODE_CBC;
> case HACE_CMD_CTR:
> return CRYPT_MODE_CTR;
> + case HACE_CMD_GCM:
> + return CRYPT_MODE_GCM;
> default:
> return 0;
> }
> @@ -1109,6 +1203,47 @@ static void crypt_run_sg(QTestState *s, uint32_t
> base, uint64_t dram,
> crypt_gather_sg(s, dram, CRYPT_OFF_DST, out, t->len); }
>
> +/*
> + * Run one AES-GCM operation in scatter-gather mode: like
> +crypt_run_sg() but
> + * also program the tag write buffer (HACE18) with no associated data,
> +and read
> + * the authentication tag back into @out_tag.
> + */
> +static void crypt_run_gcm(QTestState *s, uint32_t base, uint64_t dram,
> + const CryptTest *t, bool encrypt, uint8_t *out,
> + uint8_t *out_tag) {
> + const uint8_t *in = encrypt ? t->ptext : t->ctext;
> + uint64_t src_sg = dram + CRYPT_OFF_SRC_SG;
> + uint64_t dst_sg = dram + CRYPT_OFF_DST_SG;
> + uint64_t ctx = dram + CRYPT_OFF_CTX;
> + uint32_t cmd = t->cmd | HACE_CMD_ISR_EN |
> HACE_CMD_SRC_SG_CTRL |
> + HACE_CMD_DST_SG_CTRL;
> +
> + if (encrypt) {
> + cmd |= HACE_CMD_ENCRYPT;
> + }
> +
> + crypt_write_ctx(s, ctx, t);
> + crypt_make_sg(s, dram, CRYPT_OFF_SRC, src_sg, in, t->len);
> + crypt_make_sg(s, dram, CRYPT_OFF_DST, dst_sg, NULL, t->len);
> +
> + qtest_writel(s, base + HACE_CRYPTO_SRC, (uint32_t)src_sg);
> + qtest_writel(s, base + HACE_CRYPTO_DEST, (uint32_t)dst_sg);
> + qtest_writel(s, base + HACE_CRYPTO_CONTEXT, (uint32_t)ctx);
> + qtest_writel(s, base + HACE_CRYPTO_DATA_LEN, t->len);
> + qtest_writel(s, base + HACE_CRYPTO_GCM_ADD_LEN, 0);
> + qtest_writel(s, base + HACE_CRYPTO_GCM_TAG,
> + (uint32_t)(dram + CRYPT_OFF_TAG));
> + qtest_writel(s, base + HACE_CRYPTO_CMD, cmd);
> +
> + g_assert_cmphex(qtest_readl(s, base + HACE_STS) & HACE_CRYPTO_ISR,
> ==,
> + HACE_CRYPTO_ISR);
> + qtest_writel(s, base + HACE_STS, HACE_CRYPTO_ISR);
> +
> + crypt_gather_sg(s, dram, CRYPT_OFF_DST, out, t->len);
> + qtest_memread(s, dram + CRYPT_OFF_TAG, out_tag, t->taglen); }
> +
> static void aspeed_test_crypto(const void *data) {
> const AspeedCryptoTest *c = data;
> @@ -1145,6 +1280,29 @@ static void aspeed_test_crypto(const void *data)
> qtest_quit(s);
> }
>
> +static void aspeed_test_crypto_gcm(const void *data) {
> + const AspeedCryptoTest *c = data;
> + const CryptTest *t = &crypt_tests[c->index];
> + QTestState *s = qtest_init(c->machine);
> + uint8_t out[64];
> + uint8_t tag[16];
> +
> + g_assert_cmpuint(t->len, <=, sizeof(out));
> +
> + /* Encrypt: ptext -> ctext, then check the authentication tag. */
> + crypt_run_gcm(s, c->base, c->dram, t, true, out, tag);
> + g_assert_cmpmem(out, t->len, t->ctext, t->len);
> + g_assert_cmpmem(tag, t->taglen, t->tag, t->taglen);
> +
> + /* Decrypt: ctext -> ptext, the recomputed tag must match. */
> + crypt_run_gcm(s, c->base, c->dram, t, false, out, tag);
> + g_assert_cmpmem(out, t->len, t->ptext, t->len);
> + g_assert_cmpmem(tag, t->taglen, t->tag, t->taglen);
> +
> + qtest_quit(s);
> +}
> +
> void aspeed_add_crypto_tests(const char *prefix, const char *machine,
> uint32_t base, uint64_t dram, uint32_t
> modes,
> bool sg)
> @@ -1152,6 +1310,7 @@ void aspeed_add_crypto_tests(const char *prefix,
> const char *machine,
> int i;
>
> for (i = 0; i < ARRAY_SIZE(crypt_tests); i++) {
> + bool is_gcm = crypt_tests[i].mode ==
> QCRYPTO_CIPHER_MODE_GCM;
> g_autofree char *path = NULL;
> AspeedCryptoTest *t;
>
> @@ -1173,7 +1332,9 @@ void aspeed_add_crypto_tests(const char *prefix,
> const char *machine,
> t->dram = dram;
> t->index = i;
> t->sg = sg;
> - qtest_add_data_func_full(path, t, aspeed_test_crypto, g_free);
> + qtest_add_data_func_full(path, t,
> + is_gcm ? aspeed_test_crypto_gcm :
> + aspeed_test_crypto, g_free);
> }
> }
>
> diff --git a/tests/qtest/ast2700-hace-test.c b/tests/qtest/ast2700-hace-test.c
> index 508a34dd6c..3f0217d635 100644
> --- a/tests/qtest/ast2700-hace-test.c
> +++ b/tests/qtest/ast2700-hace-test.c
> @@ -94,5 +94,14 @@ int main(int argc, char **argv)
> qtest_add_func("ast2700/hace/sha384_accum",
> test_sha384_accum_ast2700);
> qtest_add_func("ast2700/hace/sha256_accum",
> test_sha256_accum_ast2700);
>
> + /*
> + * The AST2700 crypto engine uses scatter-gather with 64-bit DMA and
> adds
> + * AES-GCM on top of the ECB/CBC/CTR modes shared with the
> AST2600.
> + */
> + aspeed_add_crypto_tests("ast2700", "-machine ast2700-evb",
> 0x12070000,
> + 0x400000000,
> + CRYPT_MODE_ECB | CRYPT_MODE_CBC |
> CRYPT_MODE_CTR |
> + CRYPT_MODE_GCM, true);
> +
> return g_test_run();
> }
> --
> 2.43.0
Reviewed-by: Kane Chen <kane_chen@aspeedtech.com>
© 2016 - 2026 Red Hat, Inc.