@samitouri / QOSamiQemu / commits / d566fb6b1e

tests/qtest/aspeed-hace: Test the crypto command on the AST2500

Add a crypto known-answer test harness and exercise the AST2500, which uses the crypto engine's direct access mode. Each mode (AES/DES/3DES in ECB and CBC) is a separate test that checks the ciphertext, the plaintext round-trip and, for CBC, the chaining IV written back to the context buffer. The key/IV/plaintext/ciphertext values are taken verbatim from the Linux kernel crypto self-test templates in crypto/testmgr.h. Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com> Reviewed-by: Kane Chen <kane_chen@aspeedtech.com> Link: https://lore.kernel.org/qemu-devel/20260811060115.1849266-3-jamin_lin@aspeedtech.com Signed-off-by: Cédric Le Goater <clg@redhat.com>

Jamin Lin committed Aug 11, 2026 at 06:01 UTC d566fb6b1e1fb68007e72c221a54fcc1d7bc056c
4 files changed +351 -2
tests/qtest/aspeed-hace-utils.c
+325
@@ -9,6 +9,7 @@
9 #include "libqtest.h"
10 #include "qemu/bitops.h"
11 #include "qemu/bswap.h"
12 +#include "crypto/cipher.h"
13 #include "aspeed-hace-utils.h"
14
15 /*
@@ -645,3 +646,327 @@ void aspeed_test_addresses(const char *machine, const uint32_t base,
646 qtest_quit(s);
647 }
648
649 +/*
650 + * Crypto engine register layout (offsets from the HACE base).
651 + */
652 +#define HACE_CRYPTO_SRC 0x00
653 +#define HACE_CRYPTO_DEST 0x04
654 +#define HACE_CRYPTO_CONTEXT 0x08
655 +#define HACE_CRYPTO_DATA_LEN 0x0c
656 +#define HACE_CRYPTO_CMD 0x10
657 +
658 +/* Crypto command bits */
659 +#define HACE_CMD_ENCRYPT BIT(7)
660 +#define HACE_CMD_ISR_EN BIT(12)
661 +#define HACE_CMD_DES_SELECT BIT(16)
662 +#define HACE_CMD_TRIPLE_DES BIT(17)
663 +#define HACE_CMD_SRC_SG_CTRL BIT(18)
664 +#define HACE_CMD_DST_SG_CTRL BIT(19)
665 +#define HACE_CMD_OP_MODE_MASK (0x7 << 4)
666 +#define HACE_CMD_ECB (0x0 << 4)
667 +#define HACE_CMD_CBC (0x1 << 4)
668 +#define HACE_CMD_AES128 (0x0 << 2)
669 +
670 +/* Context buffer layout: IV (DES at +8), key at +0x10 */
671 +#define HACE_CTX_KEY_OFFSET 0x10
672 +#define HACE_CTX_SIZE 0x30
673 +
674 +/*
675 + * Crypto known-answer test vectors, taken verbatim from the Linux kernel
676 + * crypto self-test templates in crypto/testmgr.h:
677 + *
678 + * https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/crypto/testmgr.h?h=v6.18
679 + *
680 + * The originating template is noted above each block. CTR and the longer CBC
681 + * vectors are truncated to a single block (still a valid known-answer test as
682 + * the first block only depends on the IV).
683 + */
684 +
685 +/* aes_tv_template[0] (FIPS-197) */
686 +static const uint8_t aes128_ecb_key[16] = {
687 + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
688 + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f };
689 +static const uint8_t aes128_ecb_ptext[16] = {
690 + 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
691 + 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff };
692 +static const uint8_t aes128_ecb_ctext[16] = {
693 + 0x69, 0xc4, 0xe0, 0xd8, 0x6a, 0x7b, 0x04, 0x30,
694 + 0xd8, 0xcd, 0xb7, 0x80, 0x70, 0xb4, 0xc5, 0x5a };
695 +
696 +/* aes_cbc_tv_template[0] (RFC 3602) */
697 +static const uint8_t aes128_cbc_key[16] = {
698 + 0x06, 0xa9, 0x21, 0x40, 0x36, 0xb8, 0xa1, 0x5b,
699 + 0x51, 0x2e, 0x03, 0xd5, 0x34, 0x12, 0x00, 0x06 };
700 +static const uint8_t aes128_cbc_iv[16] = {
701 + 0x3d, 0xaf, 0xba, 0x42, 0x9d, 0x9e, 0xb4, 0x30,
702 + 0xb4, 0x22, 0xda, 0x80, 0x2c, 0x9f, 0xac, 0x41 };
703 +static const uint8_t aes128_cbc_ptext[16] = {
704 + 0x53, 0x69, 0x6e, 0x67, 0x6c, 0x65, 0x20, 0x62,
705 + 0x6c, 0x6f, 0x63, 0x6b, 0x20, 0x6d, 0x73, 0x67 };
706 +static const uint8_t aes128_cbc_ctext[16] = {
707 + 0xe3, 0x53, 0x77, 0x9c, 0x10, 0x79, 0xae, 0xb8,
708 + 0x27, 0x08, 0x94, 0x2d, 0xbe, 0x77, 0x18, 0x1a };
709 +static const uint8_t aes128_cbc_ivout[16] = {
710 + 0xe3, 0x53, 0x77, 0x9c, 0x10, 0x79, 0xae, 0xb8,
711 + 0x27, 0x08, 0x94, 0x2d, 0xbe, 0x77, 0x18, 0x1a };
712 +
713 +/* des_tv_template[0] (Applied Cryptography) */
714 +static const uint8_t des_ecb_key[8] = {
715 + 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef };
716 +static const uint8_t des_ecb_ptext[8] = {
717 + 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xe7 };
718 +static const uint8_t des_ecb_ctext[8] = {
719 + 0xc9, 0x57, 0x44, 0x25, 0x6a, 0x5e, 0xd3, 0x1d };
720 +
721 +/* des_cbc_tv_template[0] (OpenSSL), first block */
722 +static const uint8_t des_cbc_key[8] = {
723 + 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef };
724 +static const uint8_t des_cbc_iv[8] = {
725 + 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 };
726 +static const uint8_t des_cbc_ptext[8] = {
727 + 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x20 };
728 +static const uint8_t des_cbc_ctext[8] = {
729 + 0xcc, 0xd1, 0x73, 0xff, 0xab, 0x20, 0x39, 0xf4 };
730 +
731 +/* des3_ede_tv_template[0] (OpenSSL) */
732 +static const uint8_t tdes_ecb_key[24] = {
733 + 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
734 + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
735 + 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 };
736 +static const uint8_t tdes_ecb_ptext[8] = {
737 + 0x73, 0x6f, 0x6d, 0x65, 0x64, 0x61, 0x74, 0x61 };
738 +static const uint8_t tdes_ecb_ctext[8] = {
739 + 0x18, 0xd7, 0x48, 0xe5, 0x63, 0x62, 0x05, 0x72 };
740 +
741 +/* des3_ede_cbc_tv_template[0] (OpenSSL), first block */
742 +static const uint8_t tdes_cbc_key[24] = {
743 + 0xe9, 0xc0, 0xff, 0x2e, 0x76, 0x0b, 0x64, 0x24,
744 + 0x44, 0x4d, 0x99, 0x5a, 0x12, 0xd6, 0x40, 0xc0,
745 + 0xea, 0xc2, 0x84, 0xe8, 0x14, 0x95, 0xdb, 0xe8 };
746 +static const uint8_t tdes_cbc_iv[8] = {
747 + 0x7d, 0x33, 0x88, 0x93, 0x0f, 0x93, 0xb2, 0x42 };
748 +static const uint8_t tdes_cbc_ptext[8] = {
749 + 0x6f, 0x54, 0x20, 0x6f, 0x61, 0x4d, 0x79, 0x6e };
750 +static const uint8_t tdes_cbc_ctext[8] = {
751 + 0x0e, 0x2d, 0xb6, 0x97, 0x3c, 0x56, 0x33, 0xf4 };
752 +
753 +typedef struct CryptTest {
754 + QCryptoCipherMode mode;
755 + QCryptoCipherAlgo alg;
756 + /* expected context IV after encrypt, or NULL */
757 + const uint8_t *iv_out;
758 + const uint8_t *ptext;
759 + const uint8_t *ctext;
760 + const uint8_t *key;
761 + const uint8_t *iv;
762 + const char *name;
763 + size_t keylen;
764 + /* algorithm | mode | key size selection */
765 + uint32_t cmd;
766 + size_t ivlen;
767 + size_t len;
768 +} CryptTest;
769 +
770 +static const CryptTest crypt_tests[] = {
771 + {
772 + .name = "aes128-ecb",
773 + .cmd = HACE_CMD_AES128 | HACE_CMD_ECB,
774 + .alg = QCRYPTO_CIPHER_ALGO_AES_128,
775 + .mode = QCRYPTO_CIPHER_MODE_ECB,
776 + .key = aes128_ecb_key,
777 + .keylen = sizeof(aes128_ecb_key),
778 + .ptext = aes128_ecb_ptext,
779 + .ctext = aes128_ecb_ctext,
780 + .len = sizeof(aes128_ecb_ptext),
781 + },
782 + {
783 + .name = "aes128-cbc",
784 + .cmd = HACE_CMD_AES128 | HACE_CMD_CBC,
785 + .alg = QCRYPTO_CIPHER_ALGO_AES_128,
786 + .mode = QCRYPTO_CIPHER_MODE_CBC,
787 + .key = aes128_cbc_key,
788 + .keylen = sizeof(aes128_cbc_key),
789 + .iv = aes128_cbc_iv,
790 + .ivlen = sizeof(aes128_cbc_iv),
791 + .ptext = aes128_cbc_ptext,
792 + .ctext = aes128_cbc_ctext,
793 + .iv_out = aes128_cbc_ivout,
794 + .len = sizeof(aes128_cbc_ptext),
795 + },
796 + {
797 + .name = "des-ecb",
798 + .cmd = HACE_CMD_DES_SELECT | HACE_CMD_ECB,
799 + .alg = QCRYPTO_CIPHER_ALGO_DES,
800 + .mode = QCRYPTO_CIPHER_MODE_ECB,
801 + .key = des_ecb_key,
802 + .keylen = sizeof(des_ecb_key),
803 + .ptext = des_ecb_ptext,
804 + .ctext = des_ecb_ctext,
805 + .len = sizeof(des_ecb_ptext),
806 + },
807 + {
808 + .name = "des-cbc",
809 + .cmd = HACE_CMD_DES_SELECT | HACE_CMD_CBC,
810 + .alg = QCRYPTO_CIPHER_ALGO_DES,
811 + .mode = QCRYPTO_CIPHER_MODE_CBC,
812 + .key = des_cbc_key,
813 + .keylen = sizeof(des_cbc_key),
814 + .iv = des_cbc_iv,
815 + .ivlen = sizeof(des_cbc_iv),
816 + .ptext = des_cbc_ptext,
817 + .ctext = des_cbc_ctext,
818 + .len = sizeof(des_cbc_ptext),
819 + },
820 + {
821 + .name = "des3_ede-ecb",
822 + .cmd = HACE_CMD_DES_SELECT | HACE_CMD_TRIPLE_DES | HACE_CMD_ECB,
823 + .alg = QCRYPTO_CIPHER_ALGO_3DES,
824 + .mode = QCRYPTO_CIPHER_MODE_ECB,
825 + .key = tdes_ecb_key,
826 + .keylen = sizeof(tdes_ecb_key),
827 + .ptext = tdes_ecb_ptext,
828 + .ctext = tdes_ecb_ctext,
829 + .len = sizeof(tdes_ecb_ptext),
830 + },
831 + {
832 + .name = "des3_ede-cbc",
833 + .cmd = HACE_CMD_DES_SELECT | HACE_CMD_TRIPLE_DES | HACE_CMD_CBC,
834 + .alg = QCRYPTO_CIPHER_ALGO_3DES,
835 + .mode = QCRYPTO_CIPHER_MODE_CBC,
836 + .key = tdes_cbc_key,
837 + .keylen = sizeof(tdes_cbc_key),
838 + .iv = tdes_cbc_iv,
839 + .ivlen = sizeof(tdes_cbc_iv),
840 + .ptext = tdes_cbc_ptext,
841 + .ctext = tdes_cbc_ctext,
842 + .len = sizeof(tdes_cbc_ptext),
843 + },
844 +};
845 +
846 +/* DRAM offsets for the crypto test source, destination and context buffers. */
847 +#define CRYPT_OFF_SRC 0x10000
848 +#define CRYPT_OFF_DST 0x20000
849 +#define CRYPT_OFF_CTX 0x30000
850 +
851 +/* Describes one registered crypto test (qtest_add_data_func() data pointer). */
852 +typedef struct AspeedCryptoTest {
853 + const char *machine;
854 + uint64_t dram;
855 + uint32_t base;
856 + int index;
857 +} AspeedCryptoTest;
858 +
859 +/* Map a command's operation mode (HACE10[6:4]) to a CRYPT_MODE_* flag. */
860 +static uint32_t crypt_mode_flag(uint32_t cmd)
861 +{
862 + switch (cmd & HACE_CMD_OP_MODE_MASK) {
863 + case HACE_CMD_ECB:
864 + return CRYPT_MODE_ECB;
865 + case HACE_CMD_CBC:
866 + return CRYPT_MODE_CBC;
867 + default:
868 + return 0;
869 + }
870 +}
871 +
872 +static void crypt_write_ctx(QTestState *s, uint64_t ctx_addr,
873 + const CryptTest *t)
874 +{
875 + size_t iv_off = (t->cmd & HACE_CMD_DES_SELECT) ? 8 : 0;
876 + uint8_t ctx[HACE_CTX_SIZE] = { 0 };
877 +
878 + if (t->iv) {
879 + memcpy(ctx + iv_off, t->iv, t->ivlen);
880 + }
881 + memcpy(ctx + HACE_CTX_KEY_OFFSET, t->key, t->keylen);
882 + qtest_memwrite(s, ctx_addr, ctx, sizeof(ctx));
883 +}
884 +
885 +/* Run one crypto operation in direct access mode and read back the result. */
886 +static void crypt_run_direct(QTestState *s, uint32_t base, uint64_t dram,
887 + const CryptTest *t, bool encrypt, uint8_t *out)
888 +{
889 + const uint8_t *in = encrypt ? t->ptext : t->ctext;
890 + uint32_t cmd = t->cmd | HACE_CMD_ISR_EN;
891 + uint64_t src = dram + CRYPT_OFF_SRC;
892 + uint64_t dst = dram + CRYPT_OFF_DST;
893 + uint64_t ctx = dram + CRYPT_OFF_CTX;
894 +
895 + if (encrypt) {
896 + cmd |= HACE_CMD_ENCRYPT;
897 + }
898 +
899 + crypt_write_ctx(s, ctx, t);
900 + qtest_memwrite(s, src, in, t->len);
901 +
902 + qtest_writel(s, base + HACE_CRYPTO_SRC, (uint32_t)src);
903 + qtest_writel(s, base + HACE_CRYPTO_DEST, (uint32_t)dst);
904 + qtest_writel(s, base + HACE_CRYPTO_CONTEXT, (uint32_t)ctx);
905 + qtest_writel(s, base + HACE_CRYPTO_DATA_LEN, t->len);
906 + qtest_writel(s, base + HACE_CRYPTO_CMD, cmd);
907 +
908 + g_assert_cmphex(qtest_readl(s, base + HACE_STS) & HACE_CRYPTO_ISR, ==,
909 + HACE_CRYPTO_ISR);
910 + qtest_writel(s, base + HACE_STS, HACE_CRYPTO_ISR);
911 +
912 + qtest_memread(s, dst, out, t->len);
913 +}
914 +
915 +static void aspeed_test_crypto_direct(const void *data)
916 +{
917 + const AspeedCryptoTest *c = data;
918 + const CryptTest *t = &crypt_tests[c->index];
919 + QTestState *s = qtest_init(c->machine);
920 + uint8_t out[64];
921 + uint8_t iv[16];
922 + size_t iv_off;
923 +
924 + g_assert_cmpuint(t->len, <=, sizeof(out));
925 +
926 + /* Encrypt: ptext -> ctext */
927 + crypt_run_direct(s, c->base, c->dram, t, true, out);
928 + g_assert_cmpmem(out, t->len, t->ctext, t->len);
929 +
930 + if (t->iv_out) {
931 + iv_off = (t->cmd & HACE_CMD_DES_SELECT) ? 8 : 0;
932 + qtest_memread(s, c->dram + CRYPT_OFF_CTX + iv_off, iv, t->ivlen);
933 + g_assert_cmpmem(iv, t->ivlen, t->iv_out, t->ivlen);
934 + }
935 +
936 + /* Decrypt: ctext -> ptext */
937 + crypt_run_direct(s, c->base, c->dram, t, false, out);
938 + g_assert_cmpmem(out, t->len, t->ptext, t->len);
939 +
940 + qtest_quit(s);
941 +}
942 +
943 +void aspeed_add_crypto_tests(const char *prefix, const char *machine,
944 + uint32_t base, uint64_t dram, uint32_t modes)
945 +{
946 + int i;
947 +
948 + for (i = 0; i < ARRAY_SIZE(crypt_tests); i++) {
949 + g_autofree char *path = NULL;
950 + AspeedCryptoTest *t;
951 +
952 + if (!(modes & crypt_mode_flag(crypt_tests[i].cmd))) {
953 + continue;
954 + }
955 +
956 + if (!qcrypto_cipher_supports(crypt_tests[i].alg,
957 + crypt_tests[i].mode)) {
958 + g_printerr("# skip unsupported %s\n", crypt_tests[i].name);
959 + continue;
960 + }
961 +
962 + path = g_strdup_printf("%s/hace/crypto/%s", prefix,
963 + crypt_tests[i].name);
964 + t = g_new0(AspeedCryptoTest, 1);
965 + t->machine = machine;
966 + t->base = base;
967 + t->dram = dram;
968 + t->index = i;
969 + qtest_add_data_func_full(path, t, aspeed_test_crypto_direct, g_free);
970 + }
971 +}
972 +
tests/qtest/aspeed-hace-utils.h
+16
@@ -79,5 +79,21 @@ void aspeed_test_sha512_accum(const char *machine, const uint32_t base,
79 void aspeed_test_addresses(const char *machine, const uint32_t base,
80 const struct AspeedMasks *expected);
81
82 +/*
83 + * Cipher modes a SoC's crypto engine supports, for aspeed_add_crypto_tests().
84 + */
85 +enum {
86 + CRYPT_MODE_ECB = 1 << 0,
87 + CRYPT_MODE_CBC = 1 << 1,
88 +};
89 +
90 +/*
91 + * Register the crypto known-answer tests that @modes selects (a mask of
92 + * CRYPT_MODE_*) for the given machine. Each test is named
93 + * "<prefix>/hace/crypto/<mode>".
94 + */
95 +void aspeed_add_crypto_tests(const char *prefix, const char *machine,
96 + uint32_t base, uint64_t dram, uint32_t modes);
97 +
98 #endif /* TESTS_ASPEED_HACE_UTILS_H */
99
tests/qtest/aspeed_hace-test.c
+6
@@ -229,6 +229,12 @@ int main(int argc, char **argv)
229 qtest_add_func("ast2500/hace/sha256", test_sha256_ast2500);
230 qtest_add_func("ast2500/hace/md5", test_md5_ast2500);
231
232 + /*
233 + * The AST2500 crypto engine uses direct access mode and supports ECB/CBC.
234 + */
235 + aspeed_add_crypto_tests("ast2500", "-machine ast2500-evb", 0x1e6e3000,
236 + 0x80000000, CRYPT_MODE_ECB | CRYPT_MODE_CBC);
237 +
238 qtest_add_func("ast2400/hace/addresses", test_addresses_ast2400);
239 qtest_add_func("ast2400/hace/sha512", test_sha512_ast2400);
240 qtest_add_func("ast2400/hace/sha256", test_sha256_ast2400);
tests/qtest/meson.build
+4 -2
@@ -392,9 +392,11 @@ if get_option('replication').allowed()
392 endif
393
394 qtests = {
395 - 'aspeed_hace-test': files('aspeed-hace-utils.c', 'aspeed_hace-test.c'),
395 + 'aspeed_hace-test': [files('aspeed-hace-utils.c', 'aspeed_hace-test.c'),
396 + crypto],
397 'aspeed_smc-test': files('aspeed-smc-utils.c', 'aspeed_smc-test.c'),
397 - 'ast2700-hace-test': files('aspeed-hace-utils.c', 'ast2700-hace-test.c'),
398 + 'ast2700-hace-test': [files('aspeed-hace-utils.c', 'ast2700-hace-test.c'),
399 + crypto],
400 'ast2700-smc-test': files('aspeed-smc-utils.c', 'ast2700-smc-test.c'),
401 'bios-tables-test': [io, 'boot-sector.c', 'acpi-utils.c', 'tpm-emu.c'],
402 'cdrom-test': files('boot-sector.c'),