RE: [PATCH v2 16/17] tests/qtest/aspeed-hace: Test the crypto command on the AST2700

Kane Chen <[email protected]>
Newsgroups org.nongnu.qemu-arm,org.nongnu.qemu-devel
Message-ID <SI6PR06MB76314A70BFA943E4C80912E7F7DE2@SI6PR06MB7631.apcprd06.prod.outlook.com>
> -----Original Message-----
> From: Jamin Lin <[email protected]>
> Sent: Wednesday, July 15, 2026 11:34 AM
> To: Daniel P. Berrangé <[email protected]>; Cédric Le Goater
> <[email protected]>; Peter Maydell <[email protected]>; Steven Lee
> <[email protected]>; Troy Lee <[email protected]>; Kane Chen
> <[email protected]>; Andrew Jeffery
> <[email protected]>; Joel Stanley <[email protected]>; Eric Blake
> <[email protected]>; Markus Armbruster <[email protected]>; Fabiano
> Rosas <[email protected]>; Laurent Vivier <[email protected]>; Paolo Bonzini
> <[email protected]>; open list:All patches CC here
> <[email protected]>; open list:ASPEED BMCs
> <[email protected]>
> Cc: Jamin Lin <[email protected]>; Troy Lee
> <[email protected]>
> 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 <[email protected]>
> ---
>  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 <[email protected]>
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.