public inbox for linux-crypto@vger.kernel.org
 help / color / mirror / Atom feed
From: Holger Dengler <dengler@linux.ibm.com>
To: Eric Biggers <ebiggers@kernel.org>,
	David Laight <david.laight.linux@gmail.com>
Cc: Ard Biesheuvel <ardb@kernel.org>,
	"Jason A . Donenfeld" <Jason@zx2c4.com>,
	Herbert Xu <herbert@gondor.apana.org.au>,
	Harald Freudenberger <freude@linux.ibm.com>,
	Holger Dengler <dengler@linux.ibm.com>,
	linux-kernel@vger.kernel.org, linux-crypto@vger.kernel.org
Subject: [PATCH v2 1/1] lib/crypto: tests: Add KUnit tests for AES
Date: Mon, 19 Jan 2026 13:12:10 +0100	[thread overview]
Message-ID: <20260119121210.2662-2-dengler@linux.ibm.com> (raw)
In-Reply-To: <20260119121210.2662-1-dengler@linux.ibm.com>

Add a KUnit test suite for AES library functions, including KAT and
benchmarks. The functional tests do a very minimal verification of the
AES operation for each key-size. The benchmarks, which are also part
of the test-suite, can be used to get some rough performance
measurements of the AES operations. The key preparation API
performance is not covered by the benchmarks.

Signed-off-by: Holger Dengler <dengler@linux.ibm.com>
---
 lib/crypto/tests/Kconfig        |  12 +++
 lib/crypto/tests/Makefile       |   1 +
 lib/crypto/tests/aes-testvecs.h |  77 ++++++++++++++++
 lib/crypto/tests/aes_kunit.c    | 150 ++++++++++++++++++++++++++++++++
 4 files changed, 240 insertions(+)
 create mode 100644 lib/crypto/tests/aes-testvecs.h
 create mode 100644 lib/crypto/tests/aes_kunit.c

diff --git a/lib/crypto/tests/Kconfig b/lib/crypto/tests/Kconfig
index 4970463ea0aa..8ac06b6e2f12 100644
--- a/lib/crypto/tests/Kconfig
+++ b/lib/crypto/tests/Kconfig
@@ -1,5 +1,17 @@
 # SPDX-License-Identifier: GPL-2.0-or-later
 
+config CRYPTO_LIB_AES_KUNIT_TEST
+	tristate "KUnit tests for AES" if !KUNIT_ALL_TESTS
+	depends on KUNIT
+	default KUNIT_ALL_TESTS || CRYPTO_SELFTESTS
+	select CRYPTO_LIB_BENCHMARK_VISIBLE
+	select CRYPTO_LIB_AES
+	help
+	  KUnit tests for the AES library functions, including known answer
+	  tests and benchmarks for encrypt/decrypt with all key sizes. The
+	  test suite does not contain any key generation test, nor any error
+	  cases.
+
 config CRYPTO_LIB_BLAKE2B_KUNIT_TEST
 	tristate "KUnit tests for BLAKE2b" if !KUNIT_ALL_TESTS
 	depends on KUNIT
diff --git a/lib/crypto/tests/Makefile b/lib/crypto/tests/Makefile
index f4262379f56c..e0a30bdc02ac 100644
--- a/lib/crypto/tests/Makefile
+++ b/lib/crypto/tests/Makefile
@@ -1,5 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0-or-later
 
+obj-$(CONFIG_CRYPTO_LIB_AES_KUNIT_TEST) += aes_kunit.o
 obj-$(CONFIG_CRYPTO_LIB_BLAKE2B_KUNIT_TEST) += blake2b_kunit.o
 obj-$(CONFIG_CRYPTO_LIB_BLAKE2S_KUNIT_TEST) += blake2s_kunit.o
 obj-$(CONFIG_CRYPTO_LIB_CURVE25519_KUNIT_TEST) += curve25519_kunit.o
diff --git a/lib/crypto/tests/aes-testvecs.h b/lib/crypto/tests/aes-testvecs.h
new file mode 100644
index 000000000000..fd52d8ad7760
--- /dev/null
+++ b/lib/crypto/tests/aes-testvecs.h
@@ -0,0 +1,77 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _AES_TESTVECS_H
+#define _AES_TESTVECS_H
+
+#include <crypto/aes.h>
+
+struct aes_testvector {
+	u8 plain[AES_BLOCK_SIZE];
+	u8 cipher[AES_BLOCK_SIZE];
+	struct {
+		size_t len;
+		u8 b[32];
+	} key;
+};
+
+/*
+ * KAT test vectors from NIST.
+ * https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/examples/aes_ecb.pdf
+ */
+static const struct aes_testvector aes128_kat = {
+	.plain = {
+		0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
+		0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
+	},
+	.cipher = {
+		0x3a, 0xd7, 0x7b, 0xb4, 0x0d, 0x7a, 0x36, 0x60,
+		0xa8, 0x9e, 0xca, 0xf3, 0x24, 0x66, 0xef, 0x97,
+	},
+	.key = {
+		.len = 16,
+		.b = {
+			0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
+			0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c,
+		},
+	},
+};
+
+static const struct aes_testvector aes192_kat = {
+	.plain = {
+		0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
+		0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
+	},
+	.cipher = {
+		0xbd, 0x33, 0x4f, 0x1d, 0x6e, 0x45, 0xf2, 0x5f,
+		0xf7, 0x12, 0xa2, 0x14, 0x57, 0x1f, 0xa5, 0xcc,
+	},
+	.key = {
+		.len = 24,
+		.b = {
+			0x8e, 0x73, 0xb0, 0xf7, 0xda, 0x0e, 0x64, 0x52,
+			0xc8, 0x10, 0xf3, 0x2b, 0x80, 0x90, 0x79, 0xe5,
+			0x62, 0xf8, 0xea, 0xd2, 0x52, 0x2c, 0x6b, 0x7b,
+		},
+	},
+};
+
+static const struct aes_testvector aes256_kat = {
+	.plain = {
+		0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
+		0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
+	},
+	.cipher = {
+		0xf3, 0xee, 0xd1, 0xbd, 0xb5, 0xd2, 0xa0, 0x3c,
+		0x06, 0x4b, 0x5a, 0x7e, 0x3d, 0xb1, 0x81, 0xf8,
+	},
+	.key = {
+		.len = 32,
+		.b = {
+			0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe,
+			0x2b, 0x73, 0xae, 0xf0, 0x85, 0x7d, 0x77, 0x81,
+			0x1f, 0x35, 0x2c, 0x07, 0x3b, 0x61, 0x08, 0xd7,
+			0x2d, 0x98, 0x10, 0xa3, 0x09, 0x14, 0xdf, 0xf4,
+		},
+	},
+};
+
+#endif /* _AES_TESTVECS_H */
diff --git a/lib/crypto/tests/aes_kunit.c b/lib/crypto/tests/aes_kunit.c
new file mode 100644
index 000000000000..8110d3718085
--- /dev/null
+++ b/lib/crypto/tests/aes_kunit.c
@@ -0,0 +1,150 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <kunit/test.h>
+#include <linux/preempt.h>
+#include "aes-testvecs.h"
+
+static void test_aes(struct kunit *test, const struct aes_testvector *tv,
+		     bool enc)
+{
+	struct aes_key aes_key;
+	u8 out[AES_BLOCK_SIZE];
+	const u8 *input, *expect;
+	int rc;
+
+	rc = aes_preparekey(&aes_key, tv->key.b, tv->key.len);
+	KUNIT_ASSERT_EQ(test, 0, rc);
+
+	if (enc) {
+		input = tv->plain;
+		expect = tv->cipher;
+		aes_encrypt(&aes_key, out, input);
+	} else {
+		input = tv->cipher;
+		expect = tv->plain;
+		aes_decrypt(&aes_key, out, input);
+	}
+	KUNIT_ASSERT_MEMEQ(test, out, expect, sizeof(out));
+}
+
+static __always_inline u64 time_aes_op(bool encrypt, struct aes_key *aes_key,
+				       u8 *out, const u8 *in)
+{
+	void (*aes_op)(const struct aes_key *key, u8 *out, const u8 *in);
+	u64 t;
+
+	aes_op = encrypt ? &aes_encrypt : &aes_decrypt;
+
+	preempt_disable();
+	t = ktime_get_ns();
+	aes_op(aes_key, out, in);
+	t = ktime_get_ns() - t;
+	preempt_enable();
+
+	return t;
+}
+
+static void benchmark_aes(struct kunit *test, const struct aes_testvector *tv)
+{
+	const size_t num_iters = 100;
+	struct aes_key aes_key;
+	u8 out[AES_BLOCK_SIZE];
+	u64 t, t_enc, t_dec;
+	int rc;
+
+	if (!IS_ENABLED(CONFIG_CRYPTO_LIB_BENCHMARK))
+		kunit_skip(test, "not enabled");
+
+	rc = aes_preparekey(&aes_key, tv->key.b, tv->key.len);
+	KUNIT_ASSERT_EQ(test, 0, rc);
+
+	/* warm-up */
+	for (size_t i = 0; i < num_iters; i++) {
+		aes_encrypt(&aes_key, out, tv->plain);
+		aes_decrypt(&aes_key, out, tv->cipher);
+	}
+
+	t_enc = NSEC_PER_SEC;
+	t_dec = NSEC_PER_SEC;
+	for (size_t i = 0; i < num_iters; i++) {
+		t = time_aes_op(true, &aes_key, out, tv->plain);
+		t_enc = MIN_T(u64, t, t_enc);
+
+		t = time_aes_op(false, &aes_key, out, tv->cipher);
+		t_dec = MIN_T(u64, t, t_dec);
+	}
+
+	kunit_info(test, "enc (len=%zu): %llu MB/s", (size_t)AES_BLOCK_SIZE,
+		   div64_u64(AES_BLOCK_SIZE * NSEC_PER_SEC / 1000000,
+			     (t_enc ?: 1)));
+	kunit_info(test, "dec (len=%zu): %llu MB/s", (size_t)AES_BLOCK_SIZE,
+		   div64_u64(AES_BLOCK_SIZE * NSEC_PER_SEC / 1000000,
+			     (t_dec ?: 1)));
+}
+
+static void test_aes128_encrypt(struct kunit *test)
+{
+	test_aes(test, &aes128_kat, true);
+}
+
+static void test_aes128_decrypt(struct kunit *test)
+{
+	test_aes(test, &aes128_kat, false);
+}
+
+static void test_aes192_encrypt(struct kunit *test)
+{
+	test_aes(test, &aes192_kat, true);
+}
+
+static void test_aes192_decrypt(struct kunit *test)
+{
+	test_aes(test, &aes192_kat, false);
+}
+
+static void test_aes256_encrypt(struct kunit *test)
+{
+	test_aes(test, &aes256_kat, true);
+}
+
+static void test_aes256_decrypt(struct kunit *test)
+{
+	test_aes(test, &aes256_kat, false);
+}
+
+static void benchmark_aes128(struct kunit *test)
+{
+	benchmark_aes(test, &aes128_kat);
+}
+
+static void benchmark_aes192(struct kunit *test)
+{
+	benchmark_aes(test, &aes192_kat);
+}
+
+static void benchmark_aes256(struct kunit *test)
+{
+	benchmark_aes(test, &aes256_kat);
+}
+
+static struct kunit_case aes_test_cases[] = {
+	KUNIT_CASE(test_aes128_encrypt),
+	KUNIT_CASE(test_aes128_decrypt),
+	KUNIT_CASE(test_aes192_encrypt),
+	KUNIT_CASE(test_aes192_decrypt),
+	KUNIT_CASE(test_aes256_encrypt),
+	KUNIT_CASE(test_aes256_decrypt),
+	KUNIT_CASE(benchmark_aes128),
+	KUNIT_CASE(benchmark_aes192),
+	KUNIT_CASE(benchmark_aes256),
+	{},
+};
+
+static struct kunit_suite aes_test_suite = {
+	.name = "aes",
+	.test_cases = aes_test_cases,
+};
+
+kunit_test_suite(aes_test_suite);
+
+MODULE_DESCRIPTION("KUnit tests and benchmark AES library");
+MODULE_LICENSE("GPL");
-- 
2.51.0


  reply	other threads:[~2026-01-19 12:12 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-01-19 12:12 [PATCH v2 0/1] lib/crypto: tests: KUnit test-suite for AES Holger Dengler
2026-01-19 12:12 ` Holger Dengler [this message]
2026-01-19 16:39   ` [PATCH v2 1/1] lib/crypto: tests: Add KUnit tests " kernel test robot
2026-01-19 17:22   ` kernel test robot
2026-01-19 20:31   ` kernel test robot
2026-01-29  1:18   ` Eric Biggers
2026-01-30 10:54     ` Holger Dengler

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=20260119121210.2662-2-dengler@linux.ibm.com \
    --to=dengler@linux.ibm.com \
    --cc=Jason@zx2c4.com \
    --cc=ardb@kernel.org \
    --cc=david.laight.linux@gmail.com \
    --cc=ebiggers@kernel.org \
    --cc=freude@linux.ibm.com \
    --cc=herbert@gondor.apana.org.au \
    --cc=linux-crypto@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    /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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox