diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2026-08-17 19:29:41 -0700 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2026-08-17 19:29:41 -0700 |
| commit | fc8c78bce3335860ff4ae9fcfd3b2eb1f674efbb (patch) | |
| tree | 5997e1747226eb6d6bb16b78ea64d4a0c7f739c6 /lib | |
| parent | d47db9bf50d28647689e6743ee93c45cb755ffc3 (diff) | |
| parent | 561131a27f5533e6e63520b4bc43d9c832a27c09 (diff) | |
Merge tag 'libcrypto-tests-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ebiggers/linux
Pull crypto library test updates from Eric Biggers:
- Add comprehensive KUnit test suites for the new AES-GCM and AES-CCM
library APIs
- Add FIPS self-tests for all the AES encryption modes. This is needed
for parity with the traditional crypto API
- Fix a couple more issues in the IRQ test helper
* tag 'libcrypto-tests-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ebiggers/linux:
lib/crypto: aes-cmac: Use __cleanup() instead of memzero_explicit()
kunit: irq: Unregister on-stack timer and work from debugobjects
kunit: irq: Continue increasing hrtimer interval for longer
lib/crypto: tests: Add KUnit test suite for AES-GCM
lib/crypto: tests: Add KUnit test suite for AES-CCM
lib/crypto: tests: Add aead-test-template.h
lib/crypto: tests: Use per-test-case buffers in hash tests
lib/crypto: tests: Create test-utils.h
lib/crypto: aes: Add FIPS self-tests for GCM and CCM
lib/crypto: aes: Add FIPS self-tests for unauthenticated modes
lib/crypto: fips: Split fips.h into fips-aes.h and fips-sha.h
Diffstat (limited to 'lib')
32 files changed, 2533 insertions, 367 deletions
diff --git a/lib/crypto/.kunitconfig b/lib/crypto/.kunitconfig index 3efc854a2c08..60e0a77f9889 100644 --- a/lib/crypto/.kunitconfig +++ b/lib/crypto/.kunitconfig @@ -3,6 +3,8 @@ CONFIG_KUNIT=y CONFIG_CRYPTO_LIB_ENABLE_ALL_FOR_KUNIT=y CONFIG_CRYPTO_LIB_AES_CBC_MACS_KUNIT_TEST=y +CONFIG_CRYPTO_LIB_AES_CCM_KUNIT_TEST=y +CONFIG_CRYPTO_LIB_AES_GCM_KUNIT_TEST=y CONFIG_CRYPTO_LIB_BLAKE2B_KUNIT_TEST=y CONFIG_CRYPTO_LIB_BLAKE2S_KUNIT_TEST=y CONFIG_CRYPTO_LIB_CHACHA20POLY1305_KUNIT_TEST=y diff --git a/lib/crypto/aes.c b/lib/crypto/aes.c index 4222a4cec2f2..f1549839b3de 100644 --- a/lib/crypto/aes.c +++ b/lib/crypto/aes.c @@ -19,7 +19,7 @@ #include <linux/export.h> #include <linux/module.h> #include <linux/unaligned.h> -#include "fips.h" +#include "fips-aes.h" static const u8 ____cacheline_aligned aes_sbox[] = { 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, @@ -522,6 +522,26 @@ void aes_decrypt(const struct aes_key *key, u8 out[AES_BLOCK_SIZE], } EXPORT_SYMBOL(aes_decrypt); +/* FIPS cryptographic algorithm self-test for "bare" AES */ +static void __init aes_fips_test(void) +{ + struct aes_key key; + u8 data[AES_BLOCK_SIZE]; + + if (aes_preparekey(&key, fips_test_key, sizeof(fips_test_key)) != 0) + panic("aes: FIPS self-test failed (preparekey)\n"); + + aes_encrypt(&key, data, fips_test_data); + if (memcmp(fips_test_aes_ecb_ctext, data, sizeof(data)) != 0) + panic("aes: FIPS self-test failed (wrong ciphertext)\n"); + + aes_decrypt(&key, data, data); + if (memcmp(fips_test_data, data, sizeof(data)) != 0) + panic("aes: FIPS self-test failed (wrong plaintext)\n"); + + memzero_explicit(&key, sizeof(key)); +} + #if IS_ENABLED(CONFIG_CRYPTO_LIB_AES_CBC_MACS) #ifndef aes_cbcmac_blocks_arch @@ -717,17 +737,10 @@ void aes_cbcmac_final(struct aes_cbcmac_ctx *ctx, u8 out[AES_BLOCK_SIZE]) } EXPORT_SYMBOL_NS_GPL(aes_cbcmac_final, "CRYPTO_INTERNAL"); -/* - * FIPS cryptographic algorithm self-test for AES-CMAC. As per the FIPS 140-3 - * Implementation Guidance, a cryptographic algorithm self-test for at least one - * of AES-GCM, AES-CCM, AES-CMAC, or AES-GMAC is required if any of those modes - * is implemented. This fulfills that requirement via AES-CMAC. - * - * This is just for FIPS. The full tests are in the KUnit test suite. - */ +/* FIPS cryptographic algorithm self-test for AES-CMAC */ static void __init aes_cmac_fips_test(void) { - struct aes_cmac_key key; + struct aes_cmac_key key __cleanup(aes_cmac_zeroize_key); u8 mac[AES_BLOCK_SIZE]; if (aes_cmac_preparekey(&key, fips_test_key, sizeof(fips_test_key)) != @@ -736,7 +749,6 @@ static void __init aes_cmac_fips_test(void) aes_cmac(&key, fips_test_data, sizeof(fips_test_data), mac); if (memcmp(fips_test_aes_cmac_value, mac, sizeof(mac)) != 0) panic("aes: CMAC FIPS self-test failed (wrong MAC)\n"); - memzero_explicit(&key, sizeof(key)); } #else /* CONFIG_CRYPTO_LIB_AES_CBC_MACS */ static inline void aes_cmac_fips_test(void) @@ -797,7 +809,31 @@ void aes_ecb_decrypt(u8 *dst, const u8 *src, size_t len, aes_decrypt(key, &dst[i], &src[i]); } EXPORT_SYMBOL_GPL(aes_ecb_decrypt); -#endif /* CONFIG_CRYPTO_LIB_AES_ECB */ + +/* FIPS cryptographic algorithm self-test for AES-ECB */ +static void __init aes_ecb_fips_test(void) +{ + struct aes_key key; + u8 data[sizeof(fips_test_data)]; + + if (aes_preparekey(&key, fips_test_key, sizeof(fips_test_key)) != 0) + panic("aes: ECB FIPS self-test failed (preparekey)\n"); + + aes_ecb_encrypt(data, fips_test_data, sizeof(data), &key); + if (memcmp(fips_test_aes_ecb_ctext, data, sizeof(data)) != 0) + panic("aes: ECB FIPS self-test failed (wrong ciphertext)\n"); + + aes_ecb_decrypt(data, data, sizeof(data), &key); + if (memcmp(fips_test_data, data, sizeof(data)) != 0) + panic("aes: ECB FIPS self-test failed (wrong plaintext)\n"); + + memzero_explicit(&key, sizeof(key)); +} +#else /* CONFIG_CRYPTO_LIB_AES_ECB */ +static inline void aes_ecb_fips_test(void) +{ +} +#endif /* !CONFIG_CRYPTO_LIB_AES_ECB */ #if IS_ENABLED(CONFIG_CRYPTO_LIB_AES_CBC) /* @@ -983,7 +1019,66 @@ void aes_cbc_cts_decrypt(u8 *dst, const u8 *src, size_t len, crypto_xor(pad, iv, AES_BLOCK_SIZE); /* P[n - 1] */ } EXPORT_SYMBOL_GPL(aes_cbc_cts_decrypt); -#endif /* CONFIG_CRYPTO_LIB_AES_CBC */ + +/* FIPS cryptographic algorithm self-test for AES-CBC */ +static void __init aes_cbc_fips_test(void) +{ + struct aes_key key; + u8 iv[AES_BLOCK_SIZE]; + u8 data[sizeof(fips_test_data)]; + + if (aes_preparekey(&key, fips_test_key, sizeof(fips_test_key)) != 0) + panic("aes: CBC FIPS self-test failed (preparekey)\n"); + + memcpy(iv, fips_test_iv, sizeof(iv)); + aes_cbc_encrypt(data, fips_test_data, sizeof(data), iv, &key); + if (memcmp(fips_test_aes_cbc_ctext, data, sizeof(data)) != 0) + panic("aes: CBC FIPS self-test failed (wrong ciphertext)\n"); + + memcpy(iv, fips_test_iv, sizeof(iv)); + aes_cbc_decrypt(data, data, sizeof(data), iv, &key); + if (memcmp(fips_test_data, data, sizeof(data)) != 0) + panic("aes: CBC FIPS self-test failed (wrong plaintext)\n"); + + memzero_explicit(&key, sizeof(key)); +} + +/* FIPS cryptographic algorithm self-test for AES-CBC-CTS */ +static void __init aes_cbc_cts_fips_test(void) +{ + struct aes_key key; + u8 iv[AES_BLOCK_SIZE]; + const size_t data_len = 2 * AES_BLOCK_SIZE; + u8 ptext[2 * AES_BLOCK_SIZE]; + u8 data[2 * AES_BLOCK_SIZE]; + + /* ptext = fips_test_data || fips_test_data */ + memcpy(ptext, fips_test_data, AES_BLOCK_SIZE); + memcpy(&ptext[AES_BLOCK_SIZE], ptext, AES_BLOCK_SIZE); + + if (aes_preparekey(&key, fips_test_key, sizeof(fips_test_key)) != 0) + panic("aes: CBC-CTS FIPS self-test failed (preparekey)\n"); + + memcpy(iv, fips_test_iv, sizeof(iv)); + aes_cbc_cts_encrypt(data, ptext, data_len, iv, &key); + if (memcmp(fips_test_aes_cbc_cts_ctext, data, data_len) != 0) + panic("aes: CBC-CTS FIPS self-test failed (wrong ciphertext)\n"); + + memcpy(iv, fips_test_iv, sizeof(iv)); + aes_cbc_cts_decrypt(data, data, data_len, iv, &key); + if (memcmp(ptext, data, data_len) != 0) + panic("aes: CBC-CTS FIPS self-test failed (wrong plaintext)\n"); + + memzero_explicit(&key, sizeof(key)); +} +#else /* CONFIG_CRYPTO_LIB_AES_CBC */ +static inline void aes_cbc_fips_test(void) +{ +} +static inline void aes_cbc_cts_fips_test(void) +{ +} +#endif /* !CONFIG_CRYPTO_LIB_AES_CBC */ #if IS_ENABLED(CONFIG_CRYPTO_LIB_AES_CTR) /* @@ -1078,7 +1173,34 @@ void aes_xctr(u8 *dst, const u8 *src, size_t len, u64 *ctr, memzero_explicit(aes_input, sizeof(aes_input)); } EXPORT_SYMBOL_GPL(aes_xctr); -#endif /* CONFIG_CRYPTO_LIB_AES_CTR */ + +/* FIPS cryptographic algorithm self-test for AES-CTR */ +static void __init aes_ctr_fips_test(void) +{ + struct aes_enckey key; + u8 ctr[AES_BLOCK_SIZE]; + u8 data[sizeof(fips_test_data)]; + + if (aes_prepareenckey(&key, fips_test_key, sizeof(fips_test_key)) != 0) + panic("aes: CTR FIPS self-test failed (preparekey)\n"); + + memcpy(ctr, fips_test_iv, sizeof(ctr)); + aes_ctr(data, fips_test_data, sizeof(data), ctr, &key); + if (memcmp(fips_test_aes_ctr_ctext, data, sizeof(data)) != 0) + panic("aes: CTR FIPS self-test failed (wrong ciphertext)\n"); + + memcpy(ctr, fips_test_iv, sizeof(ctr)); + aes_ctr(data, data, sizeof(data), ctr, &key); + if (memcmp(fips_test_data, data, sizeof(data)) != 0) + panic("aes: CTR FIPS self-test failed (wrong plaintext)\n"); + + memzero_explicit(&key, sizeof(key)); +} +#else /* CONFIG_CRYPTO_LIB_AES_CTR */ +static inline void aes_ctr_fips_test(void) +{ +} +#endif /* !CONFIG_CRYPTO_LIB_AES_CTR */ #if IS_ENABLED(CONFIG_CRYPTO_LIB_AES_XTS) int aes_xts_preparekey(struct aes_xts_key *key, const u8 *in_key, @@ -1307,7 +1429,36 @@ void aes_xts_decrypt(u8 *dst, const u8 *src, size_t len, aes_xts_decrypt_nocts(dst, src, len, tweak, key, cont); } EXPORT_SYMBOL_GPL(aes_xts_decrypt); -#endif /* CONFIG_CRYPTO_LIB_AES_XTS */ + +/* FIPS cryptographic algorithm self-test for AES-XTS */ +static void __init aes_xts_fips_test(void) +{ + struct aes_xts_key *key __free(kfree_sensitive) = kmalloc_obj(*key); + u8 tweak[AES_BLOCK_SIZE]; + u8 data[sizeof(fips_test_data)]; + + if (key == NULL) + panic("aes: XTS FIPS self-test failed (kmalloc)\n"); + + if (aes_xts_preparekey(key, fips_test_xts_key, + sizeof(fips_test_xts_key), 0) != 0) + panic("aes: XTS FIPS self-test failed (preparekey)\n"); + + memcpy(tweak, fips_test_iv, sizeof(tweak)); + aes_xts_encrypt(data, fips_test_data, sizeof(data), tweak, key, false); + if (memcmp(fips_test_aes_xts_ctext, data, sizeof(data)) != 0) + panic("aes: XTS FIPS self-test failed (wrong ciphertext)\n"); + + memcpy(tweak, fips_test_iv, sizeof(tweak)); + aes_xts_decrypt(data, data, sizeof(data), tweak, key, false); + if (memcmp(fips_test_data, data, sizeof(data)) != 0) + panic("aes: XTS FIPS self-test failed (wrong plaintext)\n"); +} +#else /* CONFIG_CRYPTO_LIB_AES_XTS */ +static inline void aes_xts_fips_test(void) +{ +} +#endif /* !CONFIG_CRYPTO_LIB_AES_XTS */ #if IS_ENABLED(CONFIG_CRYPTO_LIB_AES_GCM) /* @@ -1586,7 +1737,37 @@ int aes_gcm_decrypt(u8 *dst, const u8 *src, size_t data_len, const u8 *authtag, } EXPORT_SYMBOL_GPL(aes_gcm_decrypt); -#endif /* CONFIG_CRYPTO_LIB_AES_GCM */ +/* FIPS cryptographic algorithm self-test for AES-GCM */ +static void __init aes_gcm_fips_test(void) +{ + const size_t data_len = sizeof(fips_test_data); + u8 buf[sizeof(fips_test_data) + AES_BLOCK_SIZE]; + struct aes_gcm_key key; + int err; + + if (aes_gcm_preparekey(&key, fips_test_key, sizeof(fips_test_key), + AES_BLOCK_SIZE) != 0) + panic("aes: GCM FIPS self-test failed (preparekey)\n"); + + aes_gcm_encrypt(buf, fips_test_data, data_len, &buf[data_len], + fips_test_ad, sizeof(fips_test_ad), fips_test_iv, &key); + if (memcmp(fips_test_aes_gcm_ctext_and_tag, buf, sizeof(buf)) != 0) + panic("aes: GCM FIPS self-test failed (wrong ciphertext and/or tag)\n"); + + err = aes_gcm_decrypt(buf, buf, data_len, &buf[data_len], fips_test_ad, + sizeof(fips_test_ad), fips_test_iv, &key); + if (err != 0) + panic("aes: GCM FIPS self-test failed (decryption failed)\n"); + if (memcmp(fips_test_data, buf, data_len) != 0) + panic("aes: GCM FIPS self-test failed (wrong plaintext)\n"); + + memzero_explicit(&key, sizeof(key)); +} +#else /* CONFIG_CRYPTO_LIB_AES_GCM */ +static inline void aes_gcm_fips_test(void) +{ +} +#endif /* !CONFIG_CRYPTO_LIB_AES_GCM */ #if IS_ENABLED(CONFIG_CRYPTO_LIB_AES_CCM) int aes_ccm_preparekey(struct aes_ccm_key *key, const u8 *in_key, @@ -1898,15 +2079,60 @@ int aes_ccm_decrypt(u8 *dst, const u8 *src, size_t data_len, const u8 *authtag, return err; } EXPORT_SYMBOL_GPL(aes_ccm_decrypt); -#endif /* CONFIG_CRYPTO_LIB_AES_CCM */ + +/* FIPS cryptographic algorithm self-test for AES-CCM */ +static void __init aes_ccm_fips_test(void) +{ + const size_t data_len = sizeof(fips_test_data); + const size_t nonce_len = 13; + u8 buf[sizeof(fips_test_data) + AES_BLOCK_SIZE]; + struct aes_ccm_key key; + int err; + + if (aes_ccm_preparekey(&key, fips_test_key, sizeof(fips_test_key), + AES_BLOCK_SIZE) != 0) + panic("aes: CCM FIPS self-test failed (preparekey)\n"); + + err = aes_ccm_encrypt(buf, fips_test_data, data_len, &buf[data_len], + fips_test_ad, sizeof(fips_test_ad), fips_test_iv, + nonce_len, &key); + if (err != 0) + panic("aes: CCM FIPS self-test failed (encryption failed)\n"); + if (memcmp(fips_test_aes_ccm_ctext_and_tag, buf, sizeof(buf)) != 0) + panic("aes: CCM FIPS self-test failed (wrong ciphertext and/or tag)\n"); + + err = aes_ccm_decrypt(buf, buf, data_len, &buf[data_len], fips_test_ad, + sizeof(fips_test_ad), fips_test_iv, nonce_len, + &key); + if (err != 0) + panic("aes: CCM FIPS self-test failed (decryption failed)\n"); + if (memcmp(fips_test_data, buf, data_len) != 0) + panic("aes: CCM FIPS self-test failed (wrong plaintext)\n"); + + memzero_explicit(&key, sizeof(key)); +} +#else /* CONFIG_CRYPTO_LIB_AES_CCM */ +static inline void aes_ccm_fips_test(void) +{ +} +#endif /* !CONFIG_CRYPTO_LIB_AES_CCM */ static int __init aes_mod_init(void) { #ifdef aes_mod_init_arch aes_mod_init_arch(); #endif - if (fips_enabled) + if (fips_enabled) { + aes_fips_test(); aes_cmac_fips_test(); + aes_ecb_fips_test(); + aes_cbc_fips_test(); + aes_cbc_cts_fips_test(); + aes_ctr_fips_test(); + aes_xts_fips_test(); + aes_gcm_fips_test(); + aes_ccm_fips_test(); + } return 0; } subsys_initcall(aes_mod_init); diff --git a/lib/crypto/fips-aes.h b/lib/crypto/fips-aes.h new file mode 100644 index 000000000000..2a1746606533 --- /dev/null +++ b/lib/crypto/fips-aes.h @@ -0,0 +1,78 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* This file was generated by: gen-fips-testvecs.py */ +/* clang-format off */ + +#include <linux/fips.h> + +static const u8 fips_test_data[] __initconst __maybe_unused = { + 0x66, 0x69, 0x70, 0x73, 0x20, 0x74, 0x65, 0x73, + 0x74, 0x20, 0x64, 0x61, 0x74, 0x61, 0x00, 0x00, +}; + +static const u8 fips_test_ad[] __initconst __maybe_unused = { + 0x66, 0x69, 0x70, 0x73, 0x20, 0x74, 0x65, 0x73, + 0x74, 0x20, 0x61, 0x64, 0x00, 0x00, 0x00, 0x00, +}; + +static const u8 fips_test_iv[] __initconst __maybe_unused = { + 0x66, 0x69, 0x70, 0x73, 0x20, 0x74, 0x65, 0x73, + 0x74, 0x20, 0x69, 0x76, 0x00, 0x00, 0x00, 0x00, +}; + +static const u8 fips_test_key[] __initconst __maybe_unused = { + 0x66, 0x69, 0x70, 0x73, 0x20, 0x74, 0x65, 0x73, + 0x74, 0x20, 0x6b, 0x65, 0x79, 0x00, 0x00, 0x00, +}; + +static const u8 fips_test_xts_key[] __initconst __maybe_unused = { + 0x6b, 0x65, 0x79, 0x31, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x6b, 0x65, 0x79, 0x32, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +static const u8 fips_test_aes_cmac_value[] __initconst __maybe_unused = { + 0xc5, 0x88, 0x28, 0x55, 0xd7, 0x2c, 0x00, 0xb6, + 0x6a, 0xa7, 0xfc, 0x82, 0x90, 0x81, 0xcf, 0x18, +}; + +static const u8 fips_test_aes_ecb_ctext[] __initconst __maybe_unused = { + 0x47, 0x76, 0x48, 0xaf, 0x1b, 0xd8, 0x4c, 0xe6, + 0xb5, 0xa7, 0x20, 0x8d, 0x64, 0x88, 0xbc, 0x3f, +}; + +static const u8 fips_test_aes_cbc_ctext[] __initconst __maybe_unused = { + 0xc8, 0x7d, 0x7c, 0x25, 0xba, 0x15, 0xf7, 0xe1, + 0x08, 0xa0, 0xd0, 0x7a, 0x20, 0x37, 0xaf, 0x5e, +}; + +static const u8 fips_test_aes_cbc_cts_ctext[] __initconst __maybe_unused = { + 0x36, 0x8e, 0x37, 0xb4, 0x78, 0xe2, 0x88, 0x59, + 0xd5, 0xe8, 0x17, 0x65, 0x5c, 0xa1, 0x25, 0xe6, + 0xc8, 0x7d, 0x7c, 0x25, 0xba, 0x15, 0xf7, 0xe1, + 0x08, 0xa0, 0xd0, 0x7a, 0x20, 0x37, 0xaf, 0x5e, +}; + +static const u8 fips_test_aes_ctr_ctext[] __initconst __maybe_unused = { + 0x95, 0xf4, 0xf4, 0x7a, 0xc8, 0xa2, 0x53, 0x73, + 0x53, 0x8f, 0x95, 0xfc, 0x18, 0xfe, 0x58, 0x2f, +}; + +static const u8 fips_test_aes_xts_ctext[] __initconst __maybe_unused = { + 0xd4, 0x51, 0x7f, 0x01, 0x14, 0x91, 0x16, 0x29, + 0x26, 0xbe, 0xec, 0x9b, 0x90, 0xed, 0x59, 0x30, +}; + +static const u8 fips_test_aes_gcm_ctext_and_tag[] __initconst __maybe_unused = { + 0x12, 0x0c, 0x5d, 0x03, 0x32, 0x93, 0x13, 0x44, + 0x06, 0x35, 0x26, 0x9d, 0xe0, 0xea, 0xbc, 0xe2, + 0x30, 0xa9, 0xa4, 0x15, 0xc5, 0x3d, 0xb3, 0xf9, + 0x30, 0x82, 0xdf, 0x9c, 0xd8, 0xc4, 0x3f, 0x2f, +}; + +static const u8 fips_test_aes_ccm_ctext_and_tag[] __initconst __maybe_unused = { + 0x11, 0x8e, 0x01, 0xcb, 0xb5, 0x22, 0x6d, 0xb4, + 0x66, 0x98, 0x97, 0x1d, 0x35, 0x53, 0x78, 0xdd, + 0xd1, 0xc5, 0xff, 0xb6, 0x90, 0xcf, 0xb1, 0xf2, + 0x87, 0x99, 0xd6, 0x1e, 0xd5, 0xd1, 0xed, 0x63, +}; diff --git a/lib/crypto/fips.h b/lib/crypto/fips-sha.h index 9fc49747db64..68af7e14e09c 100644 --- a/lib/crypto/fips.h +++ b/lib/crypto/fips-sha.h @@ -1,5 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ /* This file was generated by: gen-fips-testvecs.py */ +/* clang-format off */ #include <linux/fips.h> @@ -43,8 +44,3 @@ static const u8 fips_test_sha3_256_value[] __initconst __maybe_unused = { 0xba, 0x9b, 0xb6, 0xaa, 0x32, 0xa7, 0x97, 0x00, 0x98, 0xdb, 0xff, 0xe7, 0xc6, 0xde, 0xb5, 0x82, }; - -static const u8 fips_test_aes_cmac_value[] __initconst __maybe_unused = { - 0xc5, 0x88, 0x28, 0x55, 0xd7, 0x2c, 0x00, 0xb6, - 0x6a, 0xa7, 0xfc, 0x82, 0x90, 0x81, 0xcf, 0x18, -}; diff --git a/lib/crypto/sha1.c b/lib/crypto/sha1.c index daf18c862fdf..b687b89d97cb 100644 --- a/lib/crypto/sha1.c +++ b/lib/crypto/sha1.c @@ -12,7 +12,7 @@ #include <linux/string.h> #include <linux/unaligned.h> #include <linux/wordpart.h> -#include "fips.h" +#include "fips-sha.h" static const struct sha1_block_state sha1_iv = { .h = { SHA1_H0, SHA1_H1, SHA1_H2, SHA1_H3, SHA1_H4 }, diff --git a/lib/crypto/sha256.c b/lib/crypto/sha256.c index 5d6b77e7e141..e8c346f563c5 100644 --- a/lib/crypto/sha256.c +++ b/lib/crypto/sha256.c @@ -17,7 +17,7 @@ #include <linux/string.h> #include <linux/unaligned.h> #include <linux/wordpart.h> -#include "fips.h" +#include "fips-sha.h" static const struct sha256_block_state sha224_iv = { .h = { diff --git a/lib/crypto/sha3.c b/lib/crypto/sha3.c index 32b7074de792..286a2373c156 100644 --- a/lib/crypto/sha3.c +++ b/lib/crypto/sha3.c @@ -17,7 +17,7 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/unaligned.h> -#include "fips.h" +#include "fips-sha.h" /* * On some 32-bit architectures, such as h8300, GCC ends up using over 1 KB of diff --git a/lib/crypto/sha512.c b/lib/crypto/sha512.c index 605eab51aabd..0dd6fb4ca15b 100644 --- a/lib/crypto/sha512.c +++ b/lib/crypto/sha512.c @@ -17,7 +17,7 @@ #include <linux/string.h> #include <linux/unaligned.h> #include <linux/wordpart.h> -#include "fips.h" +#include "fips-sha.h" static const struct sha512_block_state sha384_iv = { .h = { diff --git a/lib/crypto/tests/Kconfig b/lib/crypto/tests/Kconfig index bc084dde424f..e121114624da 100644 --- a/lib/crypto/tests/Kconfig +++ b/lib/crypto/tests/Kconfig @@ -9,6 +9,24 @@ config CRYPTO_LIB_AES_CBC_MACS_KUNIT_TEST KUnit tests for the AES-CMAC, AES-XCBC-MAC, and AES-CBC-MAC message authentication codes. +config CRYPTO_LIB_AES_CCM_KUNIT_TEST + tristate "KUnit tests for AES-CCM" if !KUNIT_ALL_TESTS + depends on KUNIT && CRYPTO_LIB_AES_CCM + default KUNIT_ALL_TESTS + select CRYPTO_LIB_BENCHMARK_VISIBLE + # This test uses BLAKE2s, but that's always built-in. + help + KUnit tests for the AES-CCM authenticated encryption algorithm. + +config CRYPTO_LIB_AES_GCM_KUNIT_TEST + tristate "KUnit tests for AES-GCM" if !KUNIT_ALL_TESTS + depends on KUNIT && CRYPTO_LIB_AES_GCM + default KUNIT_ALL_TESTS + select CRYPTO_LIB_BENCHMARK_VISIBLE + # This test uses BLAKE2s, but that's always built-in. + help + KUnit tests for the AES-GCM authenticated encryption algorithm. + config CRYPTO_LIB_BLAKE2B_KUNIT_TEST tristate "KUnit tests for BLAKE2b" if !KUNIT_ALL_TESTS depends on KUNIT && CRYPTO_LIB_BLAKE2B diff --git a/lib/crypto/tests/Makefile b/lib/crypto/tests/Makefile index a739413500b6..c97c1d78784a 100644 --- a/lib/crypto/tests/Makefile +++ b/lib/crypto/tests/Makefile @@ -1,6 +1,8 @@ # SPDX-License-Identifier: GPL-2.0-or-later obj-$(CONFIG_CRYPTO_LIB_AES_CBC_MACS_KUNIT_TEST) += aes_cbc_macs_kunit.o +obj-$(CONFIG_CRYPTO_LIB_AES_CCM_KUNIT_TEST) += aes_ccm_kunit.o +obj-$(CONFIG_CRYPTO_LIB_AES_GCM_KUNIT_TEST) += aes_gcm_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_CHACHA20POLY1305_KUNIT_TEST) += chacha20poly1305_kunit.o diff --git a/lib/crypto/tests/aead-test-template.h b/lib/crypto/tests/aead-test-template.h new file mode 100644 index 000000000000..0c0138d2fa8a --- /dev/null +++ b/lib/crypto/tests/aead-test-template.h @@ -0,0 +1,1039 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Shared KUnit test cases for AEAD algorithms, including a benchmark + * + * Copyright 2026 Google LLC + */ + +/* + * This file implements KUnit test cases shared by the different KUnit test + * suites for Authenticated Encryption with Associated Data (AEAD) algorithms. + * + * Test suites including this file must #define the following: + * + * Data structs: + * - AEAD_KEY: name of key struct + * - AEAD_CTX: name of context for incremental computation + * + * Constants: + * - AEAD_VALID_KEY_LENS: array of all valid key lengths in bytes + * - AEAD_VALID_NONCE_LENS: array of all valid nonce lengths in bytes + * - AEAD_VALID_TAG_LENS: array of all valid authtag lengths in bytes + * - AEAD_MAX_KEY_LEN: max key length in bytes (assumed to fit on stack) + * - AEAD_MAX_NONCE_LEN: max nonce length in bytes (assumed to fit on stack) + * - AEAD_MAX_TAG_LEN: max authtag length in bytes (assumed to fit on stack) + * - AEAD_MONTE_CARLO_CHECKSUM: checksum of a deterministically generated series + * of (ciphertext, authtag) pairs (see test_aead_monte_carlo()) + * + * Functions: + * - AEAD_PREPAREKEY: key preparation + * - AEAD_ENCRYPT and AEAD_DECRYPT: one-shot encryption and decryption + * - AEAD_INIT, AEAD_AUTH_UPDATE, AEAD_ENCRYPT_UPDATE, AEAD_ENCRYPT_FINAL, + * AEAD_DECRYPT_UPDATE, AEAD_DECRYPT_FINAL: functions for incremental + * encryption and decryption + * + * Function prototypes and their behavior must match the AES-CCM API. + */ + +#include <crypto/blake2s.h> +#include <kunit/run-in-irq-context.h> +#include <kunit/test.h> +#include <linux/ktime.h> +#include <linux/preempt.h> +#include "test-utils.h" + +/* + * Allocate a KUnit-managed struct AEAD_KEY and prepare it with a random key, + * using a random key length and random authentication tag length. + */ +static struct AEAD_KEY *aead_alloc_random_key(struct kunit *test, + size_t *tag_len_ret) +{ + size_t key_len = + AEAD_VALID_KEY_LENS[rand32() % ARRAY_SIZE(AEAD_VALID_KEY_LENS)]; + size_t tag_len = + AEAD_VALID_TAG_LENS[rand32() % ARRAY_SIZE(AEAD_VALID_TAG_LENS)]; + u8 raw_key[AEAD_MAX_KEY_LEN]; + struct AEAD_KEY *key = alloc_buf(test, sizeof(*key)); + int err; + + rand_bytes(raw_key, key_len); + err = AEAD_PREPAREKEY(key, raw_key, key_len, tag_len); + KUNIT_ASSERT_EQ(test, 0, err); + *tag_len_ret = tag_len; + return key; +} + +/* + * Allocate a KUnit-managed slab buffer of length @len bytes and initialize it + * with random data. + */ +static u8 *aead_alloc_random_data(struct kunit *test, size_t len) +{ + u8 *buf = alloc_buf(test, len); + + rand_bytes(buf, len); + return buf; +} + +/* + * Allocate a KUnit-managed guarded buffer of length @len bytes and initialize + * it with random data. + */ +static u8 *aead_alloc_random_data_guarded(struct kunit *test, size_t len) +{ + u8 *buf = alloc_guarded_buf(test, len); + + rand_bytes(buf, len); + return buf; +} + +/* Process the given associated data using a random incremental strategy. */ +static size_t aead_auth_incrementally(struct AEAD_CTX *ctx, const u8 *ad, + size_t ad_len) +{ + size_t num_parts = 0; + size_t pos = 0; + + while (rand_bool()) { + size_t part_len = rand_length(ad_len - pos); + + AEAD_AUTH_UPDATE(ctx, &ad[pos], part_len); + pos += part_len; + num_parts++; + } + if (pos < ad_len || rand_bool()) { + AEAD_AUTH_UPDATE(ctx, &ad[pos], ad_len - pos); + num_parts++; + } + return num_parts; +} + +/* Process the given en/decrypted data using a random incremental strategy. */ +static size_t aead_crypt_incrementally(struct AEAD_CTX *ctx, u8 *dst, + const u8 *src, size_t data_len, bool enc) +{ + size_t num_parts = 0; + size_t pos = 0; + + while (rand_bool()) { + size_t part_len = rand_length(data_len - pos); + + if (enc) + AEAD_ENCRYPT_UPDATE(ctx, &dst[pos], &src[pos], + part_len); + else + AEAD_DECRYPT_UPDATE(ctx, &dst[pos], &src[pos], + part_len); + pos += part_len; + num_parts++; + } + if (pos < data_len || rand_bool()) { + if (enc) + AEAD_ENCRYPT_UPDATE(ctx, &dst[pos], &src[pos], + data_len - pos); + else + AEAD_DECRYPT_UPDATE(ctx, &dst[pos], &src[pos], + data_len - pos); + num_parts++; + } + return num_parts; +} + +struct aead_incremental_info { + size_t num_data_parts; + size_t num_ad_parts; +}; + +static const char *aead_incr_info_str(struct kunit *test, + const struct aead_incremental_info *info) +{ + const size_t max_str_len = 64; + char *str = alloc_buf(test, max_str_len); + + snprintf(str, max_str_len, "num_data_parts=%zu num_ad_parts=%zu", + info->num_data_parts, info->num_ad_parts); + return str; +} + +/* + * Encrypt data using a random incremental strategy. + * Return information about the incremental strategy used. + */ +static struct aead_incremental_info +aead_encrypt_incrementally(struct kunit *test, struct AEAD_CTX *ctx, u8 *dst, + const u8 *src, size_t data_len, u8 *tag, + const u8 *ad, size_t ad_len, const u8 *nonce, + size_t nonce_len, const struct AEAD_KEY *key) +{ + struct aead_incremental_info info; + int err; + + err = AEAD_INIT(ctx, data_len, ad_len, nonce, nonce_len, key); + KUNIT_ASSERT_EQ(test, 0, err); + info.num_ad_parts = aead_auth_incrementally(ctx, ad, ad_len); + info.num_data_parts = aead_crypt_incrementally(ctx, dst, src, data_len, + /* enc= */ true); + AEAD_ENCRYPT_FINAL(ctx, tag); + KUNIT_ASSERT_TRUE_MSG(test, mem_is_zero(ctx, sizeof(*ctx)), + "encrypt_final didn't zeroize context"); + return info; +} + +/* + * Decrypt authentic data using a random incremental strategy. + * Return information about the incremental strategy used. + */ +static struct aead_incremental_info +aead_decrypt_incrementally(struct kunit *test, struct AEAD_CTX *ctx, u8 *dst, + const u8 *src, size_t data_len, const u8 *tag, + const u8 *ad, size_t ad_len, const u8 *nonce, + size_t nonce_len, const struct AEAD_KEY *key) +{ + struct aead_incremental_info info; + int err; + + err = AEAD_INIT(ctx, data_len, ad_len, nonce, nonce_len, key); + KUNIT_ASSERT_EQ(test, 0, err); + info.num_ad_parts = aead_auth_incrementally(ctx, ad, ad_len); + info.num_data_parts = aead_crypt_incrementally(ctx, dst, src, data_len, + /* enc= */ false); + err = AEAD_DECRYPT_FINAL(ctx, tag); + KUNIT_ASSERT_EQ(test, 0, err); + KUNIT_ASSERT_TRUE_MSG(test, mem_is_zero(ctx, sizeof(*ctx)), + "decrypt_final didn't zeroize context"); + return info; +} + +/* Return true if key_len is declared to be a valid key length. */ +static bool aead_is_key_len_expected_valid(size_t key_len) +{ + for (size_t i = 0; i < ARRAY_SIZE(AEAD_VALID_KEY_LENS); i++) { + if (AEAD_VALID_KEY_LENS[i] == key_len) + return true; + } + return false; +} + +/* Return true if nonce_len is declared to be a valid nonce length. */ +static bool aead_is_nonce_len_expected_valid(size_t nonce_len) +{ + for (size_t i = 0; i < ARRAY_SIZE(AEAD_VALID_NONCE_LENS); i++) { + if (AEAD_VALID_NONCE_LENS[i] == nonce_len) + return true; + } + return false; +} + +/* Return true if tag_len is declared to be a valid tag length. */ +static bool aead_is_tag_len_expected_valid(size_t tag_len) +{ + for (size_t i = 0; i < ARRAY_SIZE(AEAD_VALID_TAG_LENS); i++) { + if (AEAD_VALID_TAG_LENS[i] == tag_len) + return true; + } + return false; +} + +struct aead_basic_validation_test_ctx { + struct AEAD_KEY key; + struct AEAD_CTX ctx; + u8 *raw_key_buf_end; + u8 *nonce_buf_end; + u8 *tag_buf_end; + u8 pt[64]; /* plaintext */ + u8 ct[64]; /* ciphertext */ + u8 decrypted[64]; + u8 ad[16]; /* associated data */ + u8 *unused_buf; + size_t data_len; + size_t ad_len; +}; + +static struct aead_basic_validation_test_ctx * +aead_alloc_basic_validation_test_ctx(struct kunit *test) +{ + struct aead_basic_validation_test_ctx *ctx = + alloc_buf(test, sizeof(*ctx)); + + memset(ctx, 0, sizeof(*ctx)); + ctx->raw_key_buf_end = + aead_alloc_random_data_guarded(test, AEAD_MAX_KEY_LEN) + + AEAD_MAX_KEY_LEN; + ctx->nonce_buf_end = + aead_alloc_random_data_guarded(test, AEAD_MAX_NONCE_LEN) + + AEAD_MAX_NONCE_LEN; + ctx->tag_buf_end = + aead_alloc_random_data_guarded(test, AEAD_MAX_TAG_LEN) + + AEAD_MAX_TAG_LEN; + + /* + * A pointer to this buffer is passed when passing a length that is + * expected to be invalid. It should never actually be accessed. + */ + ctx->unused_buf = + alloc_buf(test, max3(AEAD_MAX_KEY_LEN, AEAD_MAX_NONCE_LEN, + AEAD_MAX_TAG_LEN)); + + ctx->data_len = sizeof(ctx->pt); + ctx->ad_len = sizeof(ctx->ad); + return ctx; +} + +/* + * Given an expected-valid key_len, nonce_len, and tag_len, verify round-trip + * encryption and decryption with them. Use guarded buffers for each of the raw + * key, nonce, and tag to detect any buffer overruns in them. Also, verify that + * every byte of the tag is actually checked. + */ +static void aead_do_basic_checks(struct kunit *test, + struct aead_basic_validation_test_ctx *ctx, + size_t key_len, size_t nonce_len, + size_t tag_len) +{ + /* Set up exact-size guarded buffers for (raw_key, nonce, tag). */ + const u8 *raw_key = ctx->raw_key_buf_end - key_len; + const u8 *nonce = ctx->nonce_buf_end - nonce_len; + u8 *tag = ctx->tag_buf_end - tag_len; + int err; + + /* Key preparation should succeed. */ + err = AEAD_PREPAREKEY(&ctx->key, raw_key, key_len, tag_len); + KUNIT_ASSERT_EQ_MSG(test, 0, err, + "key_len=%zu, tag_len=%zu wasn't accepted", key_len, + tag_len); + + /* Encryption should succeed. */ + err = AEAD_ENCRYPT(ctx->ct, ctx->pt, ctx->data_len, tag, ctx->ad, + ctx->ad_len, nonce, nonce_len, &ctx->key); + KUNIT_ASSERT_EQ_MSG( + test, 0, err, + "Encryption failed with key_len=%zu, nonce_len=%zu, tag_len=%zu", + key_len, nonce_len, tag_len); + + /* Decryption should succeed and give the original data. */ + err = AEAD_DECRYPT(ctx->decrypted, ctx->ct, ctx->data_len, tag, ctx->ad, + ctx->ad_len, nonce, nonce_len, &ctx->key); + KUNIT_ASSERT_EQ_MSG( + test, 0, err, + "Decryption failed with key_len=%zu, nonce_len=%zu, tag_len=%zu", + key_len, nonce_len, tag_len); + KUNIT_ASSERT_MEMEQ_MSG( + test, ctx->pt, ctx->decrypted, ctx->data_len, + "Decryption gave wrong output with key_len=%zu, nonce_len=%zu, tag_len=%zu", + key_len, nonce_len, tag_len); + + /* + * Every byte of the tag should actually be checked. + * And on authentication failure, the dst buffer should be cleared. + */ + for (size_t i = 0; i < tag_len; i++) { + memset(ctx->decrypted, 0xff, ctx->data_len); + tag[i] ^= 1; + err = AEAD_DECRYPT(ctx->decrypted, ctx->ct, ctx->data_len, tag, + ctx->ad, ctx->ad_len, nonce, nonce_len, + &ctx->key); + KUNIT_ASSERT_EQ_MSG( + test, -EBADMSG, err, + "Decryption with bad auth tag with key_len=%zu, nonce_len=%zu, tag_len=%zu didn't fail with -EBADMSG", + key_len, nonce_len, tag_len); + KUNIT_ASSERT_TRUE_MSG( + test, mem_is_zero(ctx->decrypted, ctx->data_len), + "dst wasn't cleared on authentication failure"); + tag[i] ^= 1; + } +} + +/* Verify that the given expected-invalid key_len is actually rejected. */ +static void +aead_verify_invalid_key_len(struct kunit *test, + struct aead_basic_validation_test_ctx *ctx, + size_t key_len) +{ + int err; + + /* + * The preparekey function should reject the key_len. It should do so + * before writing to the key struct. + */ + memset(&ctx->key, 0, sizeof(ctx->key)); + err = AEAD_PREPAREKEY(&ctx->key, ctx->unused_buf, key_len, + AEAD_MAX_TAG_LEN); + KUNIT_ASSERT_EQ_MSG(test, -EINVAL, err, + "key_len=%zu wasn't rejected with -EINVAL", + key_len); + KUNIT_ASSERT_TRUE_MSG( + test, mem_is_zero(&ctx->key, sizeof(ctx->key)), + "Key struct was written to before length validation"); +} + +/* + * Test that every valid key length is accepted and basic checks pass with it, + * and test that invalid key lengths are rejected. + */ +static void test_aead_all_key_lens(struct kunit *test) +{ + struct aead_basic_validation_test_ctx *ctx = + aead_alloc_basic_validation_test_ctx(test); + + for (size_t key_len = 0; key_len <= AEAD_MAX_KEY_LEN; key_len++) { + if (aead_is_key_len_expected_valid(key_len)) + aead_do_basic_checks(test, ctx, key_len, + AEAD_MAX_NONCE_LEN, + AEAD_MAX_TAG_LEN); + else + aead_verify_invalid_key_len(test, ctx, key_len); + } + aead_verify_invalid_key_len(test, ctx, AEAD_MAX_KEY_LEN + 1); + aead_verify_invalid_key_len(test, ctx, AEAD_MAX_KEY_LEN * 2); + aead_verify_invalid_key_len(test, ctx, U32_MAX); + aead_verify_invalid_key_len(test, ctx, SIZE_MAX); +} + +/* Verify that the given expected-invalid nonce_len is actually rejected. */ +static void +aead_verify_invalid_nonce_len(struct kunit *test, + struct aead_basic_validation_test_ctx *ctx, + size_t nonce_len) +{ + static const u8 raw_key[AEAD_MAX_KEY_LEN]; + int err; + + /* Key preparation should succeed, as nonce_len isn't given yet. */ + err = AEAD_PREPAREKEY(&ctx->key, raw_key, sizeof(raw_key), + AEAD_MAX_TAG_LEN); + KUNIT_ASSERT_EQ(test, 0, err); + + /* The init function should reject the nonce_len. */ + memset(&ctx->ctx, 0, sizeof(ctx->ctx)); + err = AEAD_INIT(&ctx->ctx, ctx->data_len, ctx->ad_len, ctx->unused_buf, + nonce_len, &ctx->key); + KUNIT_ASSERT_EQ_MSG(test, -EINVAL, err, + "nonce_len=%zu wasn't rejected with -EINVAL (init)", + nonce_len); + KUNIT_ASSERT_TRUE_MSG( + test, mem_is_zero(&ctx->ctx, sizeof(ctx->ctx)), + "Context struct was written to before length validation"); + + /* The encrypt function should reject the nonce_len. */ + err = AEAD_ENCRYPT(ctx->ct, ctx->pt, ctx->data_len, ctx->unused_buf, + ctx->ad, ctx->ad_len, ctx->unused_buf, nonce_len, + &ctx->key); + KUNIT_ASSERT_EQ_MSG( + test, -EINVAL, err, + "nonce_len=%zu wasn't rejected with -EINVAL (encrypt)", + nonce_len); + + /* The decrypt function should reject the nonce_len. */ + err = AEAD_DECRYPT(ctx->pt, ctx->ct, ctx->data_len, ctx->unused_buf, + ctx->ad, ctx->ad_len, ctx->unused_buf, nonce_len, + &ctx->key); + KUNIT_ASSERT_EQ_MSG( + test, -EINVAL, err, + "nonce_len=%zu wasn't rejected with -EINVAL (decrypt)", + nonce_len); +} + +/* + * Test that every valid nonce length is accepted and basic checks pass with it, + * and test that invalid nonce lengths are rejected. + */ +static void test_aead_all_nonce_lens(struct kunit *test) +{ + struct aead_basic_validation_test_ctx *ctx = + aead_alloc_basic_validation_test_ctx(test); + + for (size_t nonce_len = 0; nonce_len <= AEAD_MAX_NONCE_LEN; + nonce_len++) { + if (aead_is_nonce_len_expected_valid(nonce_len)) + aead_do_basic_checks(test, ctx, AEAD_MAX_KEY_LEN, + nonce_len, AEAD_MAX_TAG_LEN); + else + aead_verify_invalid_nonce_len(test, ctx, nonce_len); + } + aead_verify_invalid_nonce_len(test, ctx, AEAD_MAX_NONCE_LEN + 1); + aead_verify_invalid_nonce_len(test, ctx, AEAD_MAX_NONCE_LEN * 2); + aead_verify_invalid_nonce_len(test, ctx, U32_MAX); + aead_verify_invalid_nonce_len(test, ctx, SIZE_MAX); +} + +/* Verify that the given expected-invalid tag_len is actually rejected. */ +static void +aead_verify_invalid_tag_len(struct kunit *test, + struct aead_basic_validation_test_ctx *ctx, + size_t tag_len) +{ + static const u8 raw_key[AEAD_MAX_KEY_LEN]; + int err; + + /* + * The preparekey function should reject the tag_len. It should do so + * before writing to the key struct. + */ + memset(&ctx->key, 0, sizeof(ctx->key)); + err = AEAD_PREPAREKEY(&ctx->key, raw_key, sizeof(raw_key), tag_len); + KUNIT_ASSERT_EQ_MSG(test, -EINVAL, err, + "tag_len=%zu wasn't rejected with -EINVAL", + tag_len); + KUNIT_ASSERT_TRUE_MSG( + test, mem_is_zero(&ctx->key, sizeof(ctx->key)), + "Key struct was written to before length validation"); +} + +/* + * Test that every valid authentication tag length is accepted and basic checks + * pass with it, and test that invalid authentication tag lengths are rejected. + */ +static void test_aead_all_tag_lens(struct kunit *test) +{ + struct aead_basic_validation_test_ctx *ctx = + aead_alloc_basic_validation_test_ctx(test); + + for (size_t tag_len = 0; tag_len <= AEAD_MAX_TAG_LEN; tag_len++) { + if (aead_is_tag_len_expected_valid(tag_len)) + aead_do_basic_checks(test, ctx, AEAD_MAX_KEY_LEN, + AEAD_MAX_NONCE_LEN, tag_len); + else + aead_verify_invalid_tag_len(test, ctx, tag_len); + } + aead_verify_invalid_tag_len(test, ctx, AEAD_MAX_TAG_LEN + 1); + aead_verify_invalid_tag_len(test, ctx, AEAD_MAX_TAG_LEN * 2); + aead_verify_invalid_tag_len(test, ctx, U32_MAX); + aead_verify_invalid_tag_len(test, ctx, SIZE_MAX); +} + +/* + * Test that one-shot encryption and decryption are consistent with each other + * and with incremental encryption and decryption. + */ +static void test_aead_incremental_updates(struct kunit *test) +{ + const size_t max_data_len = 1024; + const size_t max_ad_len = 512; + const size_t nonce_len = AEAD_MAX_NONCE_LEN; + size_t tag_len; + struct AEAD_KEY *key = aead_alloc_random_key(test, &tag_len); + struct AEAD_CTX *ctx = alloc_buf(test, sizeof(*ctx)); + u8 *pt = aead_alloc_random_data(test, max_data_len); + u8 *ad = aead_alloc_random_data(test, max_ad_len); + u8 *nonce = aead_alloc_random_data(test, nonce_len); + u8 *ct = alloc_buf(test, max_data_len); + u8 *ct2 = alloc_buf(test, max_data_len); + u8 *decrypted = alloc_buf(test, max_data_len); + u8 *tag = alloc_buf(test, tag_len); + u8 *tag2 = alloc_buf(test, tag_len); + int err; + + for (int i = 0; i < 500; i++) { + /* Select the lengths to test. */ + const size_t data_len = rand_length(max_data_len); + const size_t ad_len = rand_length(max_ad_len); + struct aead_incremental_info incr_info; + + /* Try one-shot encryption and decryption. */ + err = AEAD_ENCRYPT(ct, pt, data_len, tag, ad, ad_len, nonce, + nonce_len, key); + KUNIT_ASSERT_EQ(test, 0, err); + err = AEAD_DECRYPT(decrypted, ct, data_len, tag, ad, ad_len, + nonce, nonce_len, key); + KUNIT_ASSERT_EQ(test, 0, err); + KUNIT_ASSERT_MEMEQ_MSG( + test, pt, decrypted, data_len, + "Decryption didn't invert encryption; data_len=%zu, ad_len=%zu", + data_len, ad_len); + + /* Try incremental encryption and decryption. */ + incr_info = aead_encrypt_incrementally(test, ctx, ct2, pt, + data_len, tag2, ad, + ad_len, nonce, nonce_len, + key); + KUNIT_ASSERT_MEMEQ_MSG( + test, ct, ct2, data_len, + "One-shot and incremental encryption gave different ciphertexts; data_len=%zu ad_len=%zu %s", + data_len, ad_len, aead_incr_info_str(test, &incr_info)); + KUNIT_ASSERT_MEMEQ_MSG( + test, tag, tag2, tag_len, + "One-shot and incremental encryption gave different auth tags; data_len=%zu ad_len=%zu %s", + data_len, ad_len, aead_incr_info_str(test, &incr_info)); + incr_info = aead_decrypt_incrementally(test, ctx, decrypted, + ct2, data_len, tag2, ad, + ad_len, nonce, nonce_len, + key); + KUNIT_ASSERT_MEMEQ_MSG( + test, pt, decrypted, data_len, + "One-shot and incremental decryption gave different plaintexts; data_len=%zu ad_len=%zu %s", + data_len, ad_len, aead_incr_info_str(test, &incr_info)); + } +} + +/* + * Test using guarded buffers for the plaintext, ciphertext, and associated + * data. This detects out-of-bounds accesses, even in assembly code. + * + * Note: other test cases cover overrun of raw_key, nonce, and tag. + */ +static void test_aead_data_buffer_overruns(struct kunit *test) +{ + const size_t max_data_len = 1024; + const size_t max_ad_len = 512; + const size_t nonce_len = AEAD_MAX_NONCE_LEN; + size_t tag_len; + struct AEAD_KEY *key = aead_alloc_random_key(test, &tag_len); + const u8 *nonce = aead_alloc_random_data(test, nonce_len); + const u8 *pt_end = aead_alloc_random_data_guarded(test, max_data_len) + + max_data_len; + const u8 *ad_end = + aead_alloc_random_data_guarded(test, max_ad_len) + max_ad_len; + u8 *ct_end = alloc_guarded_buf(test, max_data_len) + max_data_len; + u8 *decrypted_end = + alloc_guarded_buf(test, max_data_len) + max_data_len; + u8 *tag = alloc_buf(test, tag_len); + + for (int i = 0; i < 200; i++) { + /* Select the lengths to test. */ + const size_t data_len = rand_length(max_data_len); + const size_t ad_len = rand_length(max_ad_len); + /* Set up exact-size guarded buffers. */ + const u8 *pt = pt_end - data_len; + const u8 *ad = ad_end - ad_len; + u8 *ct = ct_end - data_len; + u8 *decrypted = decrypted_end - data_len; + int err; + + /* Encrypt and decrypt. */ + err = AEAD_ENCRYPT(ct, pt, data_len, tag, ad, ad_len, nonce, + nonce_len, key); + KUNIT_ASSERT_EQ(test, 0, err); + err = AEAD_DECRYPT(decrypted, ct, data_len, tag, ad, ad_len, + nonce, nonce_len, key); + KUNIT_ASSERT_EQ(test, 0, err); + KUNIT_ASSERT_MEMEQ_MSG( + test, pt, decrypted, data_len, + "Decryption didn't invert encryption; data_len=%zu, ad_len=%zu", + data_len, ad_len); + } +} + +/* + * Test that encryption and decryption produce the same results regardless of + * how the buffers are aligned in memory. + */ +static void test_aead_alignment_consistency(struct kunit *test) +{ + const size_t max_data_len = 4096; + const size_t max_ad_len = 4096; + const size_t max_offset = 128; + const size_t nonce_len = AEAD_MAX_NONCE_LEN; + const size_t key_len = AEAD_MAX_KEY_LEN; + const size_t tag_len = AEAD_MAX_TAG_LEN; + u8 *raw_key1_buf = alloc_buf(test, key_len + max_offset); + u8 *raw_key2_buf = alloc_buf(test, key_len + max_offset); + u8 *nonce1_buf = alloc_buf(test, nonce_len + max_offset); + u8 *nonce2_buf = alloc_buf(test, nonce_len + max_offset); + u8 *pt1_buf = alloc_buf(test, max_data_len); + u8 *pt2_buf = alloc_buf(test, max_data_len); + u8 *ct1_buf = alloc_buf(test, max_data_len); + u8 *ct2_buf = alloc_buf(test, max_data_len); + u8 *ad1_buf = alloc_buf(test, max_ad_len); + u8 *ad2_buf = alloc_buf(test, max_ad_len); + u8 *tag1_buf = alloc_buf(test, tag_len + max_offset); + u8 *tag2_buf = alloc_buf(test, tag_len + max_offset); + struct AEAD_KEY *key = alloc_buf(test, sizeof(*key)); + int err; + + for (int i = 0; i < 100; i++) { + /* Generate lengths. */ + size_t data_len = rand_length(max_data_len); + size_t ad_len = rand_length(max_ad_len); + + /* Generate two sets of alignments. */ + u8 *raw_key1 = raw_key1_buf + rand_offset(max_offset); + u8 *raw_key2 = raw_key2_buf + rand_offset(max_offset); + u8 *nonce1 = nonce1_buf + rand_offset(max_offset); + u8 *nonce2 = nonce2_buf + rand_offset(max_offset); + u8 *pt1 = pt1_buf + rand_offset(max_data_len - data_len); + u8 *pt2 = pt2_buf + rand_offset(max_data_len - data_len); + u8 *ct1 = ct1_buf + rand_offset(max_data_len - data_len); + u8 *ct2 = ct2_buf + rand_offset(max_data_len - data_len); + u8 *ad1 = ad1_buf + rand_offset(max_ad_len - ad_len); + u8 *ad2 = ad2_buf + rand_offset(max_ad_len - ad_len); + u8 *tag1 = tag1_buf + rand_offset(max_offset); + u8 *tag2 = tag2_buf + rand_offset(max_offset); + + /* + * Generate inputs in the first set of buffers using the first + * set of alignments. + */ + rand_bytes(raw_key1, key_len); + rand_bytes(nonce1, nonce_len); + rand_bytes(pt1, data_len); + rand_bytes(ad1, ad_len); + + /* + * Copy the inputs to the second set of buffers using the second + * set of alignments. + */ + memcpy(raw_key2, raw_key1, key_len); + memcpy(nonce2, nonce1, nonce_len); + memcpy(pt2, pt1, data_len); + memcpy(ad2, ad1, ad_len); + + /* Verify encryption consistency. */ + + err = AEAD_PREPAREKEY(key, raw_key1, key_len, tag_len); + KUNIT_ASSERT_EQ(test, 0, err); + err = AEAD_ENCRYPT(ct1, pt1, data_len, tag1, ad1, ad_len, + nonce1, nonce_len, key); + KUNIT_ASSERT_EQ(test, 0, err); + + err = AEAD_PREPAREKEY(key, raw_key2, key_len, tag_len); + KUNIT_ASSERT_EQ(test, 0, err); + err = AEAD_ENCRYPT(ct2, pt2, data_len, tag2, ad2, ad_len, + nonce2, nonce_len, key); + KUNIT_ASSERT_EQ(test, 0, err); + + KUNIT_ASSERT_MEMEQ(test, ct1, ct2, data_len); + KUNIT_ASSERT_MEMEQ(test, tag1, tag2, tag_len); + + /* Verify decryption consistency. */ + + err = AEAD_PREPAREKEY(key, raw_key1, key_len, tag_len); + KUNIT_ASSERT_EQ(test, 0, err); + err = AEAD_DECRYPT(pt1, ct1, data_len, tag1, ad1, ad_len, + nonce1, nonce_len, key); + KUNIT_ASSERT_EQ(test, 0, err); + + err = AEAD_PREPAREKEY(key, raw_key2, key_len, tag_len); + KUNIT_ASSERT_EQ(test, 0, err); + err = AEAD_DECRYPT(pt2, ct2, data_len, tag2, ad2, ad_len, + nonce2, nonce_len, key); + KUNIT_ASSERT_EQ(test, 0, err); + + KUNIT_ASSERT_MEMEQ(test, pt1, pt2, data_len); + } +} + +static void test_aead_inplace(struct kunit *test) +{ + const size_t max_data_len = 1024; + const size_t max_ad_len = 512; + const size_t nonce_len = AEAD_MAX_NONCE_LEN; + size_t tag_len; + struct AEAD_KEY *key = aead_alloc_random_key(test, &tag_len); + u8 *data = aead_alloc_random_data(test, max_data_len + tag_len); + u8 *data2 = alloc_buf(test, max_data_len + tag_len); + u8 *ad = aead_alloc_random_data(test, max_ad_len); + const u8 *nonce = aead_alloc_random_data(test, nonce_len); + + for (int i = 0; i < 100; i++) { + size_t data_len = rand_length(max_data_len); + size_t ad_len = rand_length(max_ad_len); + int err; + + /* Encrypt out-of-place. */ + err = AEAD_ENCRYPT(data2, data, data_len, data2 + data_len, ad, + ad_len, nonce, nonce_len, key); + KUNIT_ASSERT_EQ(test, 0, err); + + /* Encrypt in-place. */ + err = AEAD_ENCRYPT(data, data, data_len, data + data_len, ad, + ad_len, nonce, nonce_len, key); + KUNIT_ASSERT_EQ(test, 0, err); + + /* Compare the results. */ + KUNIT_ASSERT_MEMEQ(test, data2, data, data_len + tag_len); + + /* Decrypt out-of-place. */ + err = AEAD_DECRYPT(data2, data, data_len, data + data_len, ad, + ad_len, nonce, nonce_len, key); + KUNIT_ASSERT_EQ(test, 0, err); + + /* Decrypt in-place. */ + err = AEAD_DECRYPT(data, data, data_len, data + data_len, ad, + ad_len, nonce, nonce_len, key); + KUNIT_ASSERT_EQ(test, 0, err); + + /* Compare the results. */ + KUNIT_ASSERT_MEMEQ(test, data2, data, data_len); + } +} + +/* + * Monte-Carlo test for AEAD algorithms. This deterministically generates + * random AEAD inputs, encrypts them, verifies decryption, and computes and + * verifies the checksum of all computed (ciphertext, tag) pairs. + */ +static void test_aead_monte_carlo(struct kunit *test) +{ + const size_t max_data_len = 1024; + const size_t max_ad_len = 293; + u8 raw_key[AEAD_MAX_KEY_LEN]; + u8 nonce[AEAD_MAX_NONCE_LEN]; + u8 tag[AEAD_MAX_TAG_LEN]; + u8 *pt = alloc_buf(test, max_data_len); + u8 *ct = alloc_buf(test, max_data_len); + u8 *decrypted = alloc_buf(test, max_data_len); + u8 *ad = alloc_buf(test, max_ad_len); + struct AEAD_KEY *key = alloc_buf(test, sizeof(*key)); + struct blake2s_ctx checksum_ctx; + u8 actual_checksum[BLAKE2S_HASH_SIZE]; + int err; + + blake2s_init(&checksum_ctx, BLAKE2S_HASH_SIZE); + + for (size_t data_len = 0; data_len <= max_data_len; data_len++) { + size_t ad_len = data_len % max_ad_len; + size_t key_len = + AEAD_VALID_KEY_LENS[data_len % + ARRAY_SIZE(AEAD_VALID_KEY_LENS)]; + size_t nonce_len = + AEAD_VALID_NONCE_LENS[data_len % + ARRAY_SIZE(AEAD_VALID_NONCE_LENS)]; + size_t tag_len = + AEAD_VALID_TAG_LENS[data_len % + ARRAY_SIZE(AEAD_VALID_TAG_LENS)]; + + rand_bytes_seeded_from_len(pt, data_len); + rand_bytes_seeded_from_len(ad, ad_len); + rand_bytes_seeded_from_len(raw_key, key_len); + rand_bytes_seeded_from_len(nonce, nonce_len); + + err = AEAD_PREPAREKEY(key, raw_key, key_len, tag_len); + KUNIT_ASSERT_EQ(test, 0, err); + + err = AEAD_ENCRYPT(ct, pt, data_len, tag, ad, ad_len, nonce, + nonce_len, key); + KUNIT_ASSERT_EQ_MSG( + test, 0, err, + "Encryption failed with data_len=%zu, ad_len=%zu", + data_len, ad_len); + err = AEAD_DECRYPT(decrypted, ct, data_len, tag, ad, ad_len, + nonce, nonce_len, key); + KUNIT_ASSERT_EQ_MSG( + test, 0, err, + "Decryption failed with data_len=%zu, ad_len=%zu", + data_len, ad_len); + KUNIT_ASSERT_MEMEQ_MSG( + test, pt, decrypted, data_len, + "Decryption didn't invert encryption; data_len=%zu, ad_len=%zu", + data_len, ad_len); + + blake2s_update(&checksum_ctx, ct, data_len); + blake2s_update(&checksum_ctx, tag, tag_len); + } + + blake2s_final(&checksum_ctx, actual_checksum); + KUNIT_EXPECT_MEMEQ_MSG(test, actual_checksum, AEAD_MONTE_CARLO_CHECKSUM, + BLAKE2S_HASH_SIZE, + "Monte-Carlo checksum mismatch"); +} + +#define IRQ_TEST_DATA_LEN 256 +#define IRQ_TEST_NUM_BUFFERS 3 /* matches max concurrency level */ + +struct aead_irq_test_slot { + /* Fields written only at test case initialization time */ + u8 raw_key[AEAD_MAX_KEY_LEN]; + u8 nonce[AEAD_MAX_NONCE_LEN]; + u8 pt[IRQ_TEST_DATA_LEN]; + u8 ct[IRQ_TEST_DATA_LEN + AEAD_MAX_TAG_LEN]; + u8 ad[IRQ_TEST_DATA_LEN]; + + /* Fields written throughout the test case */ + struct AEAD_KEY key; + u8 scratch_buf[IRQ_TEST_DATA_LEN + AEAD_MAX_TAG_LEN]; + int phase; + atomic_t in_use; +}; + +struct aead_irq_test_state { + struct aead_irq_test_slot slots[IRQ_TEST_NUM_BUFFERS]; +}; + +static bool aead_irq_test_func(void *state_) +{ + struct aead_irq_test_state *state = state_; + struct aead_irq_test_slot *slot; + size_t data_len; + bool ok = true; + + /* + * Find a free slot. This should always succeed, since the number of + * slots is equal to the max concurrency level of kunit_run_irq_test(). + */ + for (slot = &state->slots[0]; + slot < &state->slots[ARRAY_SIZE(state->slots)]; slot++) { + if (atomic_cmpxchg(&slot->in_use, 0, 1) == 0) + break; + } + if (WARN_ON_ONCE(slot == &state->slots[ARRAY_SIZE(state->slots)])) + return false; + /* + * This execution context now has exclusive access to 'slot'. + * Next, execute the next operation that the slot is set to perform. + */ + + data_len = sizeof(slot->pt); + if (slot->phase == 0) { + /* Phase 0: Prepare slot's key in current context. */ + ok = ok && AEAD_PREPAREKEY(&slot->key, slot->raw_key, + sizeof(slot->raw_key), + AEAD_MAX_TAG_LEN) == 0; + } else if (slot->phase == 1) { + /* + * Phase 1: Encrypt plaintext using key that may have been + * prepared in a different context. + */ + ok = ok && AEAD_ENCRYPT(slot->scratch_buf, slot->pt, data_len, + &slot->scratch_buf[data_len], slot->ad, + sizeof(slot->ad), slot->nonce, + sizeof(slot->nonce), &slot->key) == 0; + /* Verify the ciphertext (with concatenated auth tag) matches */ + ok = ok && + memcmp(slot->scratch_buf, slot->ct, sizeof(slot->ct)) == 0; + } else { + /* + * Phase 2: Decrypt ciphertext using key that may have been + * prepared in a different context. + */ + ok = ok && AEAD_DECRYPT(slot->scratch_buf, slot->ct, data_len, + &slot->ct[data_len], slot->ad, + sizeof(slot->ad), slot->nonce, + sizeof(slot->nonce), &slot->key) == 0; + /* Verify the plaintext matches. */ + ok = ok && memcmp(slot->scratch_buf, slot->pt, data_len) == 0; + } + slot->phase = (slot->phase + 1) % 3; + atomic_set_release(&slot->in_use, 0); + return ok; +} + +/* + * Test that encryption and decryption produce the correct results in task, + * softirq, and hardirq contexts running concurrently -- including with keys + * prepared in other contexts. This is needed to cover fallback code paths that + * execute in contexts where FPU or vector registers cannot be used. + */ +static void test_aead_interrupt_context(struct kunit *test) +{ + struct aead_irq_test_state *state = alloc_buf(test, sizeof(*state)); + + memset(state, 0, sizeof(*state)); + + /* + * For each slot, generate a set of AEAD inputs: a key, a nonce, a + * plaintext, and some associated data. Then generate the corresponding + * ciphertext with concatenated auth tag. + */ + for (int i = 0; i < IRQ_TEST_NUM_BUFFERS; i++) { + struct aead_irq_test_slot *slot = &state->slots[i]; + int err; + + rand_bytes(slot->raw_key, sizeof(slot->raw_key)); + rand_bytes(slot->nonce, sizeof(slot->nonce)); + rand_bytes(slot->pt, sizeof(slot->pt)); + rand_bytes(slot->ad, sizeof(slot->ad)); + err = AEAD_PREPAREKEY(&slot->key, slot->raw_key, + sizeof(slot->raw_key), AEAD_MAX_TAG_LEN); + KUNIT_ASSERT_EQ(test, 0, err); + err = AEAD_ENCRYPT(slot->ct, slot->pt, sizeof(slot->pt), + &slot->ct[sizeof(slot->pt)], slot->ad, + sizeof(slot->ad), slot->nonce, + sizeof(slot->nonce), &slot->key); + KUNIT_ASSERT_EQ(test, 0, err); + } + + kunit_run_irq_test(test, aead_irq_test_func, 100000, state); +} + +/* Benchmark AEAD encryption and decryption on various data lengths. */ +static void benchmark_aead(struct kunit *test) +{ + static const size_t data_lens_to_test[] = { + 16, 64, 128, 256, 512, 1024, 1420, 4096, 16384, + }; + const size_t max_data_len = 16384; + const size_t ad_len = 16; + const size_t key_len = AEAD_MAX_KEY_LEN; + const size_t nonce_len = AEAD_MAX_NONCE_LEN; + const size_t tag_len = AEAD_MAX_TAG_LEN; + const u8 *raw_key, *nonce, *ad; + u8 *pt, *ct, *tag; + struct AEAD_KEY *key; + int err; + + if (!IS_ENABLED(CONFIG_CRYPTO_LIB_BENCHMARK)) + kunit_skip(test, "not enabled"); + + raw_key = aead_alloc_random_data(test, key_len); + nonce = aead_alloc_random_data(test, nonce_len); + ad = aead_alloc_random_data(test, ad_len); + pt = aead_alloc_random_data(test, max_data_len); + ct = alloc_buf(test, max_data_len); + tag = alloc_buf(test, tag_len); + + key = alloc_buf(test, sizeof(*key)); + err = AEAD_PREPAREKEY(key, raw_key, key_len, tag_len); + KUNIT_ASSERT_EQ(test, 0, err); + + /* Warm-up */ + for (size_t i = 0; i < 10000000; i += max_data_len) { + err = AEAD_ENCRYPT(ct, pt, max_data_len, tag, ad, ad_len, nonce, + nonce_len, key); + KUNIT_ASSERT_EQ(test, 0, err); + err = AEAD_DECRYPT(pt, ct, max_data_len, tag, ad, ad_len, nonce, + nonce_len, key); + KUNIT_ASSERT_EQ(test, 0, err); + } + + for (size_t i = 0; i < ARRAY_SIZE(data_lens_to_test); i++) { + size_t data_len = data_lens_to_test[i]; + size_t num_iters = 10000000 / (data_len + 128); + u64 t_enc, t_dec; + bool ok = true; + + KUNIT_ASSERT_LE(test, data_len, max_data_len); + + preempt_disable(); + + t_enc = ktime_get_ns(); + for (size_t j = 0; j < num_iters; j++) { + err = AEAD_ENCRYPT(ct, pt, data_len, tag, ad, ad_len, + nonce, nonce_len, key); + ok &= (err == 0); + } + t_enc = ktime_get_ns() - t_enc; + + t_dec = ktime_get_ns(); + for (size_t j = 0; j < num_iters; j++) { + err = AEAD_DECRYPT(pt, ct, data_len, tag, ad, ad_len, + nonce, nonce_len, key); + ok &= (err == 0); + } + t_dec = ktime_get_ns() - t_dec; + + preempt_enable(); + + KUNIT_ASSERT_TRUE_MSG(test, ok, "data_len=%zu", data_len); + + kunit_info(test, "data_len=%zu: enc %llu MB/s, dec %llu MB/s", + data_len, + div64_u64((u64)data_len * num_iters * 1000, + t_enc ?: 1), + div64_u64((u64)data_len * num_iters * 1000, + t_dec ?: 1)); + } +} + +/* clang-format off */ +#define AEAD_KUNIT_CASES \ + KUNIT_CASE(test_aead_all_key_lens), \ + KUNIT_CASE(test_aead_all_nonce_lens), \ + KUNIT_CASE(test_aead_all_tag_lens), \ + KUNIT_CASE(test_aead_incremental_updates), \ + KUNIT_CASE(test_aead_data_buffer_overruns), \ + KUNIT_CASE(test_aead_alignment_consistency), \ + KUNIT_CASE(test_aead_inplace), \ + KUNIT_CASE(test_aead_monte_carlo), \ + KUNIT_CASE(test_aead_interrupt_context), \ + KUNIT_CASE(benchmark_aead) diff --git a/lib/crypto/tests/aes_cbc_macs_kunit.c b/lib/crypto/tests/aes_cbc_macs_kunit.c index ae3745212f03..6afdb3a04c17 100644 --- a/lib/crypto/tests/aes_cbc_macs_kunit.c +++ b/lib/crypto/tests/aes_cbc_macs_kunit.c @@ -34,18 +34,9 @@ static void aes_cmac_withtestkey(const u8 *data, size_t data_len, static int aes_cbc_macs_suite_init(struct kunit_suite *suite) { u8 raw_key[AES_KEYSIZE_256]; - int err; rand_bytes_seeded_from_len(raw_key, sizeof(raw_key)); - err = aes_cmac_preparekey(&test_key, raw_key, sizeof(raw_key)); - if (err) - return err; - return hash_suite_init(suite); -} - -static void aes_cbc_macs_suite_exit(struct kunit_suite *suite) -{ - hash_suite_exit(suite); + return aes_cmac_preparekey(&test_key, raw_key, sizeof(raw_key)); } /* Verify compatibility of the AES-CMAC implementation with RFC 4493. */ @@ -218,7 +209,6 @@ static struct kunit_suite aes_cbc_macs_test_suite = { .name = "aes_cbc_macs", .test_cases = aes_cbc_macs_test_cases, .suite_init = aes_cbc_macs_suite_init, - .suite_exit = aes_cbc_macs_suite_exit, }; kunit_test_suite(aes_cbc_macs_test_suite); diff --git a/lib/crypto/tests/aes_ccm_kunit.c b/lib/crypto/tests/aes_ccm_kunit.c new file mode 100644 index 000000000000..e8f2b3446017 --- /dev/null +++ b/lib/crypto/tests/aes_ccm_kunit.c @@ -0,0 +1,356 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * KUnit test suite for AES-CCM + * + * Copyright 2026 Google LLC + */ +#include <crypto/aes-ccm.h> +#include <crypto/blake2s.h> +#include "test-utils.h" + +/* AES-CCM test vectors from external sources */ +static const struct aes_ccm_testvec { + const char *name; + const char *key; + size_t key_len; + const char *nonce; + size_t nonce_len; + const char *ad; + size_t ad_len; + const char *ptext; + const char *ctext; + size_t data_len; + const char *tag; + size_t tag_len; +} aes_ccm_testvecs[] = { + { + .name = "RFC 3610 Packet Vector #1", + .key = "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7" + "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf", + .key_len = 16, + .nonce = "\x00\x00\x00\x03\x02\x01\x00\xa0" + "\xa1\xa2\xa3\xa4\xa5", + .nonce_len = 13, + .ad = "\x00\x01\x02\x03\x04\x05\x06\x07", + .ad_len = 8, + .ptext = "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" + "\x10\x11\x12\x13\x14\x15\x16\x17" + "\x18\x19\x1a\x1b\x1c\x1d\x1e", + .ctext = "\x58\x8c\x97\x9a\x61\xc6\x63\xd2" + "\xf0\x66\xd0\xc2\xc0\xf9\x89\x80" + "\x6d\x5f\x6b\x61\xda\xc3\x84", + .data_len = 23, + .tag = "\x17\xe8\xd1\x2c\xfd\xf9\x26\xe0", + .tag_len = 8, + }, + { + .name = "RFC 3610 Packet Vector #5", + .key = "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7" + "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf", + .key_len = 16, + .nonce = "\x00\x00\x00\x07\x06\x05\x04\xa0" + "\xa1\xa2\xa3\xa4\xa5", + .nonce_len = 13, + .ad = "\x00\x01\x02\x03\x04\x05\x06\x07" + "\x08\x09\x0a\x0b", + .ad_len = 12, + .ptext = "\x0c\x0d\x0e\x0f\x10\x11\x12\x13" + "\x14\x15\x16\x17\x18\x19\x1a\x1b" + "\x1c\x1d\x1e\x1f", + .ctext = "\xdc\xf1\xfb\x7b\x5d\x9e\x23\xfb" + "\x9d\x4e\x13\x12\x53\x65\x8a\xd8" + "\x6e\xbd\xca\x3e", + .data_len = 20, + .tag = "\x51\xe8\x3f\x07\x7d\x9c\x2d\x93", + .tag_len = 8, + }, + { + .name = "RFC 3610 Packet Vector #9", + .key = "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7" + "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf", + .key_len = 16, + .nonce = "\x00\x00\x00\x0b\x0a\x09\x08\xa0" + "\xa1\xa2\xa3\xa4\xa5", + .nonce_len = 13, + .ad = "\x00\x01\x02\x03\x04\x05\x06\x07", + .ad_len = 8, + .ptext = "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" + "\x10\x11\x12\x13\x14\x15\x16\x17" + "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" + "\x20", + .ctext = "\x82\x53\x1a\x60\xcc\x24\x94\x5a" + "\x4b\x82\x79\x18\x1a\xb5\xc8\x4d" + "\xf2\x1c\xe7\xf9\xb7\x3f\x42\xe1" + "\x97", + .data_len = 25, + .tag = "\xea\x9c\x07\xe5\x6b\x5e\xb1\x7e" + "\x5f\x4e", + .tag_len = 10, + }, + { + .name = "NIST SP 800-38C Example 1", + .key = "\x40\x41\x42\x43\x44\x45\x46\x47" + "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f", + .key_len = 16, + .nonce = "\x10\x11\x12\x13\x14\x15\x16", + .nonce_len = 7, + .ad = "\x00\x01\x02\x03\x04\x05\x06\x07", + .ad_len = 8, + .ptext = "\x20\x21\x22\x23", + .ctext = "\x71\x62\x01\x5b", + .data_len = 4, + .tag = "\x4d\xac\x25\x5d", + .tag_len = 4, + }, + { + .name = "NIST SP 800-38C Example 2", + .key = "\x40\x41\x42\x43\x44\x45\x46\x47" + "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f", + .key_len = 16, + .nonce = "\x10\x11\x12\x13\x14\x15\x16\x17", + .nonce_len = 8, + .ad = "\x00\x01\x02\x03\x04\x05\x06\x07" + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", + .ad_len = 16, + .ptext = "\x20\x21\x22\x23\x24\x25\x26\x27" + "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f", + .ctext = "\xd2\xa1\xf0\xe0\x51\xea\x5f\x62" + "\x08\x1a\x77\x92\x07\x3d\x59\x3d", + .data_len = 16, + .tag = "\x1f\xc6\x4f\xbf\xac\xcd", + .tag_len = 6, + }, + { + .name = "NIST SP 800-38C Example 3", + .key = "\x40\x41\x42\x43\x44\x45\x46\x47" + "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f", + .key_len = 16, + .nonce = "\x10\x11\x12\x13\x14\x15\x16\x17" + "\x18\x19\x1a\x1b", + .nonce_len = 12, + .ad = "\x00\x01\x02\x03\x04\x05\x06\x07" + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" + "\x10\x11\x12\x13", + .ad_len = 20, + .ptext = "\x20\x21\x22\x23\x24\x25\x26\x27" + "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f" + "\x30\x31\x32\x33\x34\x35\x36\x37", + .ctext = "\xe3\xb2\x01\xa9\xf5\xb7\x1a\x7a" + "\x9b\x1c\xea\xec\xcd\x97\xe7\x0b" + "\x61\x76\xaa\xd9\xa4\x42\x8a\xa5", + .data_len = 24, + .tag = "\x48\x43\x92\xfb\xc1\xb0\x99\x51", + .tag_len = 8, + }, +}; + +static void test_aes_ccm_one_test_vector(struct kunit *test, + const struct aes_ccm_testvec *tv) +{ + u8 *ctext = alloc_buf(test, tv->data_len); + u8 *decrypted = alloc_buf(test, tv->data_len); + u8 *tag = alloc_buf(test, tv->tag_len); + struct aes_ccm_key key; + int err; + + err = aes_ccm_preparekey(&key, tv->key, tv->key_len, tv->tag_len); + KUNIT_ASSERT_EQ_MSG(test, 0, err, "Failed to prepare key for %s", + tv->name); + + err = aes_ccm_encrypt(ctext, tv->ptext, tv->data_len, tag, tv->ad, + tv->ad_len, tv->nonce, tv->nonce_len, &key); + KUNIT_ASSERT_EQ_MSG(test, 0, err, "Encryption failed for %s", tv->name); + KUNIT_ASSERT_MEMEQ_MSG(test, tv->ctext, ctext, tv->data_len, + "Wrong ciphertext for %s", tv->name); + KUNIT_ASSERT_MEMEQ_MSG(test, tag, tv->tag, tv->tag_len, + "Wrong tag for %s", tv->name); + + err = aes_ccm_decrypt(decrypted, ctext, tv->data_len, tag, tv->ad, + tv->ad_len, tv->nonce, tv->nonce_len, &key); + KUNIT_ASSERT_EQ_MSG(test, 0, err, "Decryption failed for %s", tv->name); + KUNIT_ASSERT_MEMEQ_MSG(test, tv->ptext, decrypted, tv->data_len, + "Wrong plaintext for %s", tv->name); +} + +static void test_aes_ccm_test_vectors(struct kunit *test) +{ + for (size_t i = 0; i < ARRAY_SIZE(aes_ccm_testvecs); i++) + test_aes_ccm_one_test_vector(test, &aes_ccm_testvecs[i]); +} + +/* + * Test NIST SP 800-38C Example 4, which uses a deterministically-generated + * 65536-byte associated data string. + */ +static void test_aes_ccm_nist_sp800_38c_example4(struct kunit *test) +{ + struct aes_ccm_testvec tv = { + .name = "NIST SP 800-38C Example 4", + .key_len = 16, + .nonce_len = 13, + .ad_len = 65536, + .ctext = "\x69\x91\x5d\xad\x1e\x84\xc6\x37" + "\x6a\x68\xc2\x96\x7e\x4d\xab\x61" + "\x5a\xe0\xfd\x1f\xae\xc4\x4c\xc4" + "\x84\x82\x85\x29\x46\x3c\xcf\x72", + .data_len = 32, + .tag = "\xb4\xac\x6b\xec\x93\xe8\x59\x8e" + "\x7f\x0d\xad\xbc\xea\x5b", + .tag_len = 14, + }; + u8 *key, *nonce, *ad, *ptext; + + key = alloc_buf(test, tv.key_len); + for (size_t i = 0; i < tv.key_len; i++) + key[i] = 0x40 + i; + + nonce = alloc_guarded_buf(test, tv.nonce_len); + for (size_t i = 0; i < tv.nonce_len; i++) + nonce[i] = 0x10 + i; + + ad = alloc_guarded_buf(test, tv.ad_len); + for (size_t i = 0; i < tv.ad_len; i++) + ad[i] = (u8)i; + + ptext = alloc_guarded_buf(test, tv.data_len); + for (size_t i = 0; i < tv.data_len; i++) + ptext[i] = 0x20 + i; + + tv.key = key; + tv.nonce = nonce; + tv.ad = ad; + tv.ptext = ptext; + + test_aes_ccm_one_test_vector(test, &tv); +} + +static const size_t aes_ccm_valid_key_lens[] = { 16, 24, 32 }; +#define AEAD_MAX_KEY_LEN 32 +#define AEAD_VALID_KEY_LENS aes_ccm_valid_key_lens + +static const size_t aes_ccm_valid_nonce_lens[] = { 7, 8, 9, 10, 11, 12, 13 }; +#define AEAD_MAX_NONCE_LEN 13 +#define AEAD_VALID_NONCE_LENS aes_ccm_valid_nonce_lens + +static const size_t aes_ccm_valid_tag_lens[] = { 4, 6, 8, 10, 12, 14, 16 }; +#define AEAD_MAX_TAG_LEN 16 +#define AEAD_VALID_TAG_LENS aes_ccm_valid_tag_lens + +#define AEAD_KEY aes_ccm_key +#define AEAD_CTX aes_ccm_ctx +#define AEAD_PREPAREKEY aes_ccm_preparekey +#define AEAD_ENCRYPT aes_ccm_encrypt +#define AEAD_DECRYPT aes_ccm_decrypt + +#define AEAD_INIT aes_ccm_init +#define AEAD_AUTH_UPDATE aes_ccm_auth_update +#define AEAD_ENCRYPT_UPDATE aes_ccm_encrypt_update +#define AEAD_DECRYPT_UPDATE aes_ccm_decrypt_update +#define AEAD_ENCRYPT_FINAL aes_ccm_encrypt_final +#define AEAD_DECRYPT_FINAL aes_ccm_decrypt_final + +/* This value was generated by gen-aead-testvecs.py. */ +static const u8 aes_ccm_monte_carlo_checksum[BLAKE2S_HASH_SIZE] = { + 0x70, 0x1c, 0xde, 0xa4, 0xe2, 0x03, 0x50, 0xb2, 0xf5, 0x9e, 0x61, + 0x66, 0xe4, 0xe5, 0x13, 0x1a, 0x00, 0x95, 0x34, 0x03, 0xb7, 0x61, + 0x2c, 0xdb, 0xc3, 0x15, 0x36, 0x84, 0x93, 0x7f, 0xb4, 0x5b, +}; +#define AEAD_MONTE_CARLO_CHECKSUM aes_ccm_monte_carlo_checksum + +#include "aead-test-template.h" + +/* + * Test that for each AES-CCM nonce length, the message length is validated + * against the correct corresponding maximum message length. + */ +static void test_aes_ccm_data_len_too_large(struct kunit *test) +{ + static const struct { + size_t nonce_len; + u64 max_data_len; + } lens[] = { + /* clang-format off */ + { 7, 0xffffffffffffffff }, /* U64_MAX */ + { 8, 0xffffffffffffff }, + { 9, 0xffffffffffff }, + { 10, 0xffffffffff }, + { 11, 0xffffffff }, + { 12, 0xffffff }, + { 13, 0xffff }, + /* clang-format on */ + }; + u8 nonce[13] = {}; + u8 raw_key[AES_KEYSIZE_256] = {}; + int err; + struct aes_ccm_key *key = alloc_buf(test, sizeof(*key)); + struct aes_ccm_ctx ctx; + + err = aes_ccm_preparekey(key, raw_key, sizeof(raw_key), 16); + KUNIT_ASSERT_EQ(test, 0, err); + + for (size_t i = 0; i < ARRAY_SIZE(lens); i++) { + size_t nonce_len = lens[i].nonce_len; + u64 max_data_len = lens[i].max_data_len; + + /* data_len <= max_data_len should be accepted. */ + err = aes_ccm_init(&ctx, 0, 0, nonce, nonce_len, key); + KUNIT_ASSERT_EQ_MSG( + test, 0, err, + "data_len=0 wasn't accepted with nonce_len=%zu", + nonce_len); + err = aes_ccm_init(&ctx, max_data_len, 0, nonce, nonce_len, + key); + KUNIT_ASSERT_EQ_MSG( + test, 0, err, + "data_len=%llu wasn't accepted with nonce_len=%zu", + max_data_len, nonce_len); + + /* data_len > max_data_len should be rejected. */ + if (max_data_len == U64_MAX) + continue; + err = aes_ccm_init(&ctx, max_data_len + 1, 0, nonce, nonce_len, + key); + KUNIT_ASSERT_EQ_MSG( + test, -EOVERFLOW, err, + "data_len=%llu wasn't rejected with -EOVERFLOW with nonce_len=%zu (aes_ccm_init)", + max_data_len + 1, nonce_len); + if (max_data_len + 1 <= SIZE_MAX) { + err = aes_ccm_encrypt(NULL, NULL, max_data_len + 1, + NULL, NULL, 0, nonce, nonce_len, + key); + KUNIT_ASSERT_EQ_MSG( + test, -EOVERFLOW, err, + "data_len=%llu wasn't rejected with -EOVERFLOW with nonce_len=%zu (aes_ccm_encrypt)", + max_data_len + 1, nonce_len); + err = aes_ccm_decrypt(NULL, NULL, max_data_len + 1, + NULL, NULL, 0, nonce, nonce_len, + key); + KUNIT_ASSERT_EQ_MSG( + test, -EOVERFLOW, err, + "data_len=%llu wasn't rejected with -EOVERFLOW with nonce_len=%zu (aes_ccm_decrypt)", + max_data_len + 1, nonce_len); + } + err = aes_ccm_init(&ctx, U64_MAX, 0, nonce, nonce_len, key); + KUNIT_ASSERT_EQ_MSG( + test, -EOVERFLOW, err, + "data_len=U64_MAX wasn't rejected with -EOVERFLOW with nonce_len=%zu (aes_ccm_init)", + nonce_len); + } +} + +static struct kunit_case aes_ccm_test_cases[] = { + KUNIT_CASE(test_aes_ccm_test_vectors), + KUNIT_CASE(test_aes_ccm_nist_sp800_38c_example4), + KUNIT_CASE(test_aes_ccm_data_len_too_large), + AEAD_KUNIT_CASES, + {}, +}; + +static struct kunit_suite aes_ccm_test_suite = { + .name = "aes_ccm", + .test_cases = aes_ccm_test_cases, +}; +kunit_test_suite(aes_ccm_test_suite); + +MODULE_DESCRIPTION("KUnit tests and benchmark for AES-CCM"); +MODULE_LICENSE("GPL"); diff --git a/lib/crypto/tests/aes_gcm_kunit.c b/lib/crypto/tests/aes_gcm_kunit.c new file mode 100644 index 000000000000..6959d86b316a --- /dev/null +++ b/lib/crypto/tests/aes_gcm_kunit.c @@ -0,0 +1,472 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * KUnit test suite for AES-GCM + * + * Copyright 2026 Google LLC + */ +#include <crypto/aes-gcm.h> +#include <crypto/blake2s.h> +#include "test-utils.h" + +/* The kernel's AES-GCM implementation supports only 12-byte nonces. */ +#define AES_GCM_NONCE_LEN 12 + +/* + * AES-GCM test vectors from the original paper "The Galois/Counter Mode of + * Operation (GCM)" by McGrew & Viega. Vectors with nonce lengths other than 12 + * bytes are excluded. + */ +static const struct aes_gcm_testvec { + const char *name; + const char *key; + size_t key_len; + const char *nonce; + size_t nonce_len; + const char *ad; + size_t ad_len; + const char *ptext; + const char *ctext; + size_t data_len; + const char *tag; + size_t tag_len; +} aes_gcm_testvecs[] = { + /* AES-128 Test Vectors */ + { + .name = "McGrew & Viega Test Case 1", + .key = "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00", + .key_len = 16, + .nonce = "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00", + .nonce_len = 12, + .ptext = "", + .ctext = "", + .data_len = 0, + .ad = "", + .ad_len = 0, + .tag = "\x58\xe2\xfc\xce\xfa\x7e\x30\x61" + "\x36\x7f\x1d\x57\xa4\xe7\x45\x5a", + .tag_len = 16, + }, + { + .name = "McGrew & Viega Test Case 2", + .key = "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00", + .key_len = 16, + .nonce = "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00", + .nonce_len = 12, + .ptext = "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00", + .ctext = "\x03\x88\xda\xce\x60\xb6\xa3\x92" + "\xf3\x28\xc2\xb9\x71\xb2\xfe\x78", + .data_len = 16, + .ad = "", + .ad_len = 0, + .tag = "\xab\x6e\x47\xd4\x2c\xec\x13\xbd" + "\xf5\x3a\x67\xb2\x12\x57\xbd\xdf", + .tag_len = 16, + }, + { + .name = "McGrew & Viega Test Case 3", + .key = "\xfe\xff\xe9\x92\x86\x65\x73\x1c" + "\x6d\x6a\x8f\x94\x67\x30\x83\x08", + .key_len = 16, + .nonce = "\xca\xfe\xba\xbe\xfa\xce\xdb\xad" + "\xde\xca\xf8\x88", + .nonce_len = 12, + .ptext = "\xd9\x31\x32\x25\xf8\x84\x06\xe5" + "\xa5\x59\x09\xc5\xaf\xf5\x26\x9a" + "\x86\xa7\xa9\x53\x15\x34\xf7\xda" + "\x2e\x4c\x30\x3d\x8a\x31\x8a\x72" + "\x1c\x3c\x0c\x95\x95\x68\x09\x53" + "\x2f\xcf\x0e\x24\x49\xa6\xb5\x25" + "\xb1\x6a\xed\xf5\xaa\x0d\xe6\x57" + "\xba\x63\x7b\x39\x1a\xaf\xd2\x55", + .ctext = "\x42\x83\x1e\xc2\x21\x77\x74\x24" + "\x4b\x72\x21\xb7\x84\xd0\xd4\x9c" + "\xe3\xaa\x21\x2f\x2c\x02\xa4\xe0" + "\x35\xc1\x7e\x23\x29\xac\xa1\x2e" + "\x21\xd5\x14\xb2\x54\x66\x93\x1c" + "\x7d\x8f\x6a\x5a\xac\x84\xaa\x05" + "\x1b\xa3\x0b\x39\x6a\x0a\xac\x97" + "\x3d\x58\xe0\x91\x47\x3f\x59\x85", + .data_len = 64, + .ad = "", + .ad_len = 0, + .tag = "\x4d\x5c\x2a\xf3\x27\xcd\x64\xa6" + "\x2c\xf3\x5a\xbd\x2b\xa6\xfa\xb4", + .tag_len = 16, + }, + { + .name = "McGrew & Viega Test Case 4", + .key = "\xfe\xff\xe9\x92\x86\x65\x73\x1c" + "\x6d\x6a\x8f\x94\x67\x30\x83\x08", + .key_len = 16, + .nonce = "\xca\xfe\xba\xbe\xfa\xce\xdb\xad" + "\xde\xca\xf8\x88", + .nonce_len = 12, + .ptext = "\xd9\x31\x32\x25\xf8\x84\x06\xe5" + "\xa5\x59\x09\xc5\xaf\xf5\x26\x9a" + "\x86\xa7\xa9\x53\x15\x34\xf7\xda" + "\x2e\x4c\x30\x3d\x8a\x31\x8a\x72" + "\x1c\x3c\x0c\x95\x95\x68\x09\x53" + "\x2f\xcf\x0e\x24\x49\xa6\xb5\x25" + "\xb1\x6a\xed\xf5\xaa\x0d\xe6\x57" + "\xba\x63\x7b\x39", + .ctext = "\x42\x83\x1e\xc2\x21\x77\x74\x24" + "\x4b\x72\x21\xb7\x84\xd0\xd4\x9c" + "\xe3\xaa\x21\x2f\x2c\x02\xa4\xe0" + "\x35\xc1\x7e\x23\x29\xac\xa1\x2e" + "\x21\xd5\x14\xb2\x54\x66\x93\x1c" + "\x7d\x8f\x6a\x5a\xac\x84\xaa\x05" + "\x1b\xa3\x0b\x39\x6a\x0a\xac\x97" + "\x3d\x58\xe0\x91", + .data_len = 60, + .ad = "\xfe\xed\xfa\xce\xde\xad\xbe\xef" + "\xfe\xed\xfa\xce\xde\xad\xbe\xef" + "\xab\xad\xda\xd2", + .ad_len = 20, + .tag = "\x5b\xc9\x4f\xbc\x32\x21\xa5\xdb" + "\x94\xfa\xe9\x5a\xe7\x12\x1a\x47", + .tag_len = 16, + }, + + /* AES-192 Test Vectors */ + { + .name = "McGrew & Viega Test Case 7", + .key = "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00", + .key_len = 24, + .nonce = "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00", + .nonce_len = 12, + .ptext = "", + .ctext = "", + .data_len = 0, + .ad = "", + .ad_len = 0, + .tag = "\xcd\x33\xb2\x8a\xc7\x73\xf7\x4b" + "\xa0\x0e\xd1\xf3\x12\x57\x24\x35", + .tag_len = 16, + }, + { + .name = "McGrew & Viega Test Case 8", + .key = "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00", + .key_len = 24, + .nonce = "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00", + .nonce_len = 12, + .ptext = "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00", + .ctext = "\x98\xe7\x24\x7c\x07\xf0\xfe\x41" + "\x1c\x26\x7e\x43\x84\xb0\xf6\x00", + .data_len = 16, + .ad = "", + .ad_len = 0, + .tag = "\x2f\xf5\x8d\x80\x03\x39\x27\xab" + "\x8e\xf4\xd4\x58\x75\x14\xf0\xfb", + .tag_len = 16, + }, + { + .name = "McGrew & Viega Test Case 9", + .key = "\xfe\xff\xe9\x92\x86\x65\x73\x1c" + "\x6d\x6a\x8f\x94\x67\x30\x83\x08" + "\xfe\xff\xe9\x92\x86\x65\x73\x1c", + .key_len = 24, + .nonce = "\xca\xfe\xba\xbe\xfa\xce\xdb\xad" + "\xde\xca\xf8\x88", + .nonce_len = 12, + .ptext = "\xd9\x31\x32\x25\xf8\x84\x06\xe5" + "\xa5\x59\x09\xc5\xaf\xf5\x26\x9a" + "\x86\xa7\xa9\x53\x15\x34\xf7\xda" + "\x2e\x4c\x30\x3d\x8a\x31\x8a\x72" + "\x1c\x3c\x0c\x95\x95\x68\x09\x53" + "\x2f\xcf\x0e\x24\x49\xa6\xb5\x25" + "\xb1\x6a\xed\xf5\xaa\x0d\xe6\x57" + "\xba\x63\x7b\x39\x1a\xaf\xd2\x55", + .ctext = "\x39\x80\xca\x0b\x3c\x00\xe8\x41" + "\xeb\x06\xfa\xc4\x87\x2a\x27\x57" + "\x85\x9e\x1c\xea\xa6\xef\xd9\x84" + "\x62\x85\x93\xb4\x0c\xa1\xe1\x9c" + "\x7d\x77\x3d\x00\xc1\x44\xc5\x25" + "\xac\x61\x9d\x18\xc8\x4a\x3f\x47" + "\x18\xe2\x44\x8b\x2f\xe3\x24\xd9" + "\xcc\xda\x27\x10\xac\xad\xe2\x56", + .data_len = 64, + .ad = "", + .ad_len = 0, + .tag = "\x99\x24\xa7\xc8\x58\x73\x36\xbf" + "\xb1\x18\x02\x4d\xb8\x67\x4a\x14", + .tag_len = 16, + }, + { + .name = "McGrew & Viega Test Case 10", + .key = "\xfe\xff\xe9\x92\x86\x65\x73\x1c" + "\x6d\x6a\x8f\x94\x67\x30\x83\x08" + "\xfe\xff\xe9\x92\x86\x65\x73\x1c", + .key_len = 24, + .nonce = "\xca\xfe\xba\xbe\xfa\xce\xdb\xad" + "\xde\xca\xf8\x88", + .nonce_len = 12, + .ptext = "\xd9\x31\x32\x25\xf8\x84\x06\xe5" + "\xa5\x59\x09\xc5\xaf\xf5\x26\x9a" + "\x86\xa7\xa9\x53\x15\x34\xf7\xda" + "\x2e\x4c\x30\x3d\x8a\x31\x8a\x72" + "\x1c\x3c\x0c\x95\x95\x68\x09\x53" + "\x2f\xcf\x0e\x24\x49\xa6\xb5\x25" + "\xb1\x6a\xed\xf5\xaa\x0d\xe6\x57" + "\xba\x63\x7b\x39", + .ctext = "\x39\x80\xca\x0b\x3c\x00\xe8\x41" + "\xeb\x06\xfa\xc4\x87\x2a\x27\x57" + "\x85\x9e\x1c\xea\xa6\xef\xd9\x84" + "\x62\x85\x93\xb4\x0c\xa1\xe1\x9c" + "\x7d\x77\x3d\x00\xc1\x44\xc5\x25" + "\xac\x61\x9d\x18\xc8\x4a\x3f\x47" + "\x18\xe2\x44\x8b\x2f\xe3\x24\xd9" + "\xcc\xda\x27\x10", + .data_len = 60, + .ad = "\xfe\xed\xfa\xce\xde\xad\xbe\xef" + "\xfe\xed\xfa\xce\xde\xad\xbe\xef" + "\xab\xad\xda\xd2", + .ad_len = 20, + .tag = "\x25\x19\x49\x8e\x80\xf1\x47\x8f" + "\x37\xba\x55\xbd\x6d\x27\x61\x8c", + .tag_len = 16, + }, + + /* AES-256 Test Vectors */ + { + .name = "McGrew & Viega Test Case 13", + .key = "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00", + .key_len = 32, + .nonce = "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00", + .nonce_len = 12, + .ptext = "", + .ctext = "", + .data_len = 0, + .ad = "", + .ad_len = 0, + .tag = "\x53\x0f\x8a\xfb\xc7\x45\x36\xb9" + "\xa9\x63\xb4\xf1\xc4\xcb\x73\x8b", + .tag_len = 16, + }, + { + .name = "McGrew & Viega Test Case 14", + .key = "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00", + .key_len = 32, + .nonce = "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00", + .nonce_len = 12, + .ptext = "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00", + .ctext = "\xce\xa7\x40\x3d\x4d\x60\x6b\x6e" + "\x07\x4e\xc5\xd3\xba\xf3\x9d\x18", + .data_len = 16, + .ad = "", + .ad_len = 0, + .tag = "\xd0\xd1\xc8\xa7\x99\x99\x6b\xf0" + "\x26\x5b\x98\xb5\xd4\x8a\xb9\x19", + .tag_len = 16, + }, + { + .name = "McGrew & Viega Test Case 15", + .key = "\xfe\xff\xe9\x92\x86\x65\x73\x1c" + "\x6d\x6a\x8f\x94\x67\x30\x83\x08" + "\xfe\xff\xe9\x92\x86\x65\x73\x1c" + "\x6d\x6a\x8f\x94\x67\x30\x83\x08", + .key_len = 32, + .nonce = "\xca\xfe\xba\xbe\xfa\xce\xdb\xad" + "\xde\xca\xf8\x88", + .nonce_len = 12, + .ptext = "\xd9\x31\x32\x25\xf8\x84\x06\xe5" + "\xa5\x59\x09\xc5\xaf\xf5\x26\x9a" + "\x86\xa7\xa9\x53\x15\x34\xf7\xda" + "\x2e\x4c\x30\x3d\x8a\x31\x8a\x72" + "\x1c\x3c\x0c\x95\x95\x68\x09\x53" + "\x2f\xcf\x0e\x24\x49\xa6\xb5\x25" + "\xb1\x6a\xed\xf5\xaa\x0d\xe6\x57" + "\xba\x63\x7b\x39\x1a\xaf\xd2\x55", + .ctext = "\x52\x2d\xc1\xf0\x99\x56\x7d\x07" + "\xf4\x7f\x37\xa3\x2a\x84\x42\x7d" + "\x64\x3a\x8c\xdc\xbf\xe5\xc0\xc9" + "\x75\x98\xa2\xbd\x25\x55\xd1\xaa" + "\x8c\xb0\x8e\x48\x59\x0d\xbb\x3d" + "\xa7\xb0\x8b\x10\x56\x82\x88\x38" + "\xc5\xf6\x1e\x63\x93\xba\x7a\x0a" + "\xbc\xc9\xf6\x62\x89\x80\x15\xad", + .data_len = 64, + .ad = "", + .ad_len = 0, + .tag = "\xb0\x94\xda\xc5\xd9\x34\x71\xbd" + "\xec\x1a\x50\x22\x70\xe3\xcc\x6c", + .tag_len = 16, + }, + { + .name = "McGrew & Viega Test Case 16", + .key = "\xfe\xff\xe9\x92\x86\x65\x73\x1c" + "\x6d\x6a\x8f\x94\x67\x30\x83\x08" + "\xfe\xff\xe9\x92\x86\x65\x73\x1c" + "\x6d\x6a\x8f\x94\x67\x30\x83\x08", + .key_len = 32, + .nonce = "\xca\xfe\xba\xbe\xfa\xce\xdb\xad" + "\xde\xca\xf8\x88", + .nonce_len = 12, + .ptext = "\xd9\x31\x32\x25\xf8\x84\x06\xe5" + "\xa5\x59\x09\xc5\xaf\xf5\x26\x9a" + "\x86\xa7\xa9\x53\x15\x34\xf7\xda" + "\x2e\x4c\x30\x3d\x8a\x31\x8a\x72" + "\x1c\x3c\x0c\x95\x95\x68\x09\x53" + "\x2f\xcf\x0e\x24\x49\xa6\xb5\x25" + "\xb1\x6a\xed\xf5\xaa\x0d\xe6\x57" + "\xba\x63\x7b\x39", + .ctext = "\x52\x2d\xc1\xf0\x99\x56\x7d\x07" + "\xf4\x7f\x37\xa3\x2a\x84\x42\x7d" + "\x64\x3a\x8c\xdc\xbf\xe5\xc0\xc9" + "\x75\x98\xa2\xbd\x25\x55\xd1\xaa" + "\x8c\xb0\x8e\x48\x59\x0d\xbb\x3d" + "\xa7\xb0\x8b\x10\x56\x82\x88\x38" + "\xc5\xf6\x1e\x63\x93\xba\x7a\x0a" + "\xbc\xc9\xf6\x62", + .data_len = 60, + .ad = "\xfe\xed\xfa\xce\xde\xad\xbe\xef" + "\xfe\xed\xfa\xce\xde\xad\xbe\xef" + "\xab\xad\xda\xd2", + .ad_len = 20, + .tag = "\x76\xfc\x6e\xce\x0f\x4e\x17\x68" + "\xcd\xdf\x88\x53\xbb\x2d\x55\x1b", + .tag_len = 16, + }, +}; + +static void test_aes_gcm_one_test_vector(struct kunit *test, + const struct aes_gcm_testvec *tv) +{ + u8 *ctext = alloc_buf(test, tv->data_len); + u8 *decrypted = alloc_buf(test, tv->data_len); + u8 *tag = alloc_buf(test, tv->tag_len); + struct aes_gcm_key key; + int err; + + KUNIT_ASSERT_EQ(test, AES_GCM_NONCE_LEN, tv->nonce_len); + + err = aes_gcm_preparekey(&key, tv->key, tv->key_len, tv->tag_len); + KUNIT_ASSERT_EQ_MSG(test, 0, err, "Failed to prepare key for %s", + tv->name); + + aes_gcm_encrypt(ctext, tv->ptext, tv->data_len, tag, tv->ad, tv->ad_len, + tv->nonce, &key); + KUNIT_ASSERT_MEMEQ_MSG(test, tv->ctext, ctext, tv->data_len, + "Wrong ciphertext for %s", tv->name); + KUNIT_ASSERT_MEMEQ_MSG(test, tag, tv->tag, tv->tag_len, + "Wrong tag for %s", tv->name); + + err = aes_gcm_decrypt(decrypted, ctext, tv->data_len, tag, tv->ad, + tv->ad_len, tv->nonce, &key); + KUNIT_ASSERT_EQ_MSG(test, 0, err, "Decryption failed for %s", tv->name); + KUNIT_ASSERT_MEMEQ_MSG(test, tv->ptext, decrypted, tv->data_len, + "Wrong plaintext for %s", tv->name); +} + +static void test_aes_gcm_test_vectors(struct kunit *test) +{ + for (size_t i = 0; i < ARRAY_SIZE(aes_gcm_testvecs); i++) + test_aes_gcm_one_test_vector(test, &aes_gcm_testvecs[i]); +} + +static int aes_gcm_init_test(struct aes_gcm_ctx *ctx, u64 data_len, u64 ad_len, + const u8 *nonce, size_t nonce_len, + const struct aes_gcm_key *key) +{ + if (nonce_len != AES_GCM_NONCE_LEN) + return -EINVAL; + /* + * Ignore data_len and ad_len. Incremental AES-GCM doesn't need them at + * initialization time. + */ + aes_gcm_init(ctx, nonce, key); + return 0; +} + +static int aes_gcm_encrypt_test(u8 *dst, const u8 *src, size_t data_len, + u8 *authtag, const u8 *ad, size_t ad_len, + const u8 *nonce, size_t nonce_len, + const struct aes_gcm_key *key) +{ + if (nonce_len != AES_GCM_NONCE_LEN) + return -EINVAL; + /* aes_gcm_encrypt() returns void. */ + aes_gcm_encrypt(dst, src, data_len, authtag, ad, ad_len, nonce, key); + return 0; +} + +static int aes_gcm_decrypt_test(u8 *dst, const u8 *src, size_t data_len, + const u8 *authtag, const u8 *ad, size_t ad_len, + const u8 *nonce, size_t nonce_len, + const struct aes_gcm_key *key) +{ + if (nonce_len != AES_GCM_NONCE_LEN) + return -EINVAL; + return aes_gcm_decrypt(dst, src, data_len, authtag, ad, ad_len, nonce, + key); +} + +static const size_t aes_gcm_valid_key_lens[] = { 16, 24, 32 }; +#define AEAD_MAX_KEY_LEN 32 +#define AEAD_VALID_KEY_LENS aes_gcm_valid_key_lens + +static const size_t aes_gcm_valid_nonce_lens[] = { AES_GCM_NONCE_LEN }; +#define AEAD_MAX_NONCE_LEN AES_GCM_NONCE_LEN +#define AEAD_VALID_NONCE_LENS aes_gcm_valid_nonce_lens + +static const size_t aes_gcm_valid_tag_lens[] = { 4, 8, 12, 13, 14, 15, 16 }; +#define AEAD_MAX_TAG_LEN 16 +#define AEAD_VALID_TAG_LENS aes_gcm_valid_tag_lens + +#define AEAD_KEY aes_gcm_key +#define AEAD_CTX aes_gcm_ctx +#define AEAD_PREPAREKEY aes_gcm_preparekey +#define AEAD_ENCRYPT aes_gcm_encrypt_test +#define AEAD_DECRYPT aes_gcm_decrypt_test + +#define AEAD_INIT aes_gcm_init_test +#define AEAD_AUTH_UPDATE aes_gcm_auth_update +#define AEAD_ENCRYPT_UPDATE aes_gcm_encrypt_update +#define AEAD_DECRYPT_UPDATE aes_gcm_decrypt_update +#define AEAD_ENCRYPT_FINAL aes_gcm_encrypt_final +#define AEAD_DECRYPT_FINAL aes_gcm_decrypt_final + +/* This value was generated by gen-aead-testvecs.py. */ +static const u8 aes_gcm_monte_carlo_checksum[BLAKE2S_HASH_SIZE] = { + 0x6d, 0xd0, 0x6e, 0x6b, 0xde, 0x3e, 0x92, 0x9f, 0xae, 0x1f, 0xf1, + 0x84, 0x99, 0x5a, 0x9e, 0x7b, 0xfe, 0x20, 0x9e, 0x22, 0x7c, 0x5f, + 0x15, 0xb3, 0x59, 0x89, 0xd0, 0xb7, 0x74, 0x5d, 0xd2, 0xa5, +}; +#define AEAD_MONTE_CARLO_CHECKSUM aes_gcm_monte_carlo_checksum + +#include "aead-test-template.h" + +static struct kunit_case aes_gcm_test_cases[] = { + KUNIT_CASE(test_aes_gcm_test_vectors), + AEAD_KUNIT_CASES, + {}, +}; + +static struct kunit_suite aes_gcm_test_suite = { + .name = "aes_gcm", + .test_cases = aes_gcm_test_cases, +}; +kunit_test_suite(aes_gcm_test_suite); + +MODULE_DESCRIPTION("KUnit tests and benchmark for AES-GCM"); +MODULE_LICENSE("GPL"); diff --git a/lib/crypto/tests/blake2b_kunit.c b/lib/crypto/tests/blake2b_kunit.c index bc0be7da1e76..e2ce6cf3a99d 100644 --- a/lib/crypto/tests/blake2b_kunit.c +++ b/lib/crypto/tests/blake2b_kunit.c @@ -41,9 +41,9 @@ static void blake2b_init_default(struct blake2b_ctx *ctx) static void test_blake2b_all_key_and_hash_lens(struct kunit *test) { const size_t data_len = 100; - u8 *data = &test_buf[0]; - u8 *key = data + data_len; - u8 *hash = key + BLAKE2B_KEY_SIZE; + u8 *data = alloc_buf(test, data_len); + u8 *key = alloc_buf(test, BLAKE2B_KEY_SIZE); + u8 *hash = alloc_buf(test, BLAKE2B_HASH_SIZE); struct blake2b_ctx main_ctx; u8 main_hash[BLAKE2B_HASH_SIZE]; @@ -68,11 +68,13 @@ static void test_blake2b_all_key_and_hash_lens(struct kunit *test) static void test_blake2b_with_guarded_key_buf(struct kunit *test) { const size_t data_len = 100; + u8 *data = alloc_buf(test, data_len); + u8 *guarded_key_buf = alloc_guarded_buf(test, BLAKE2B_KEY_SIZE); - rand_bytes(test_buf, data_len); + rand_bytes(data, data_len); for (int key_len = 0; key_len <= BLAKE2B_KEY_SIZE; key_len++) { u8 key[BLAKE2B_KEY_SIZE]; - u8 *guarded_key = &test_buf[TEST_BUF_LEN - key_len]; + u8 *guarded_key = &guarded_key_buf[BLAKE2B_KEY_SIZE - key_len]; u8 hash1[BLAKE2B_HASH_SIZE]; u8 hash2[BLAKE2B_HASH_SIZE]; struct blake2b_ctx ctx; @@ -80,14 +82,13 @@ static void test_blake2b_with_guarded_key_buf(struct kunit *test) rand_bytes(key, key_len); memcpy(guarded_key, key, key_len); - blake2b(key, key_len, test_buf, data_len, - hash1, BLAKE2B_HASH_SIZE); - blake2b(guarded_key, key_len, test_buf, data_len, - hash2, BLAKE2B_HASH_SIZE); + blake2b(key, key_len, data, data_len, hash1, BLAKE2B_HASH_SIZE); + blake2b(guarded_key, key_len, data, data_len, hash2, + BLAKE2B_HASH_SIZE); KUNIT_ASSERT_MEMEQ(test, hash1, hash2, BLAKE2B_HASH_SIZE); blake2b_init_key(&ctx, BLAKE2B_HASH_SIZE, guarded_key, key_len); - blake2b_update(&ctx, test_buf, data_len); + blake2b_update(&ctx, data, data_len); blake2b_final(&ctx, hash2); KUNIT_ASSERT_MEMEQ(test, hash1, hash2, BLAKE2B_HASH_SIZE); } @@ -100,14 +101,16 @@ static void test_blake2b_with_guarded_key_buf(struct kunit *test) static void test_blake2b_with_guarded_out_buf(struct kunit *test) { const size_t data_len = 100; + u8 *data = alloc_buf(test, data_len); + u8 *out_buf = alloc_guarded_buf(test, BLAKE2B_HASH_SIZE); - rand_bytes(test_buf, data_len); + rand_bytes(data, data_len); for (int out_len = 1; out_len <= BLAKE2B_HASH_SIZE; out_len++) { u8 hash[BLAKE2B_HASH_SIZE]; - u8 *guarded_hash = &test_buf[TEST_BUF_LEN - out_len]; + u8 *guarded_hash = &out_buf[BLAKE2B_HASH_SIZE - out_len]; - blake2b(NULL, 0, test_buf, data_len, hash, out_len); - blake2b(NULL, 0, test_buf, data_len, guarded_hash, out_len); + blake2b(NULL, 0, data, data_len, hash, out_len); + blake2b(NULL, 0, data, data_len, guarded_hash, out_len); KUNIT_ASSERT_MEMEQ(test, hash, guarded_hash, out_len); } } @@ -124,8 +127,6 @@ static struct kunit_case blake2b_test_cases[] = { static struct kunit_suite blake2b_test_suite = { .name = "blake2b", .test_cases = blake2b_test_cases, - .suite_init = hash_suite_init, - .suite_exit = hash_suite_exit, }; kunit_test_suite(blake2b_test_suite); diff --git a/lib/crypto/tests/blake2s_kunit.c b/lib/crypto/tests/blake2s_kunit.c index 6832d9aa7b82..682f695f8a09 100644 --- a/lib/crypto/tests/blake2s_kunit.c +++ b/lib/crypto/tests/blake2s_kunit.c @@ -41,9 +41,9 @@ static void blake2s_init_default(struct blake2s_ctx *ctx) static void test_blake2s_all_key_and_hash_lens(struct kunit *test) { const size_t data_len = 100; - u8 *data = &test_buf[0]; - u8 *key = data + data_len; - u8 *hash = key + BLAKE2S_KEY_SIZE; + u8 *data = alloc_buf(test, data_len); + u8 *key = alloc_buf(test, BLAKE2S_KEY_SIZE); + u8 *hash = alloc_buf(test, BLAKE2S_HASH_SIZE); struct blake2s_ctx main_ctx; u8 main_hash[BLAKE2S_HASH_SIZE]; @@ -68,11 +68,13 @@ static void test_blake2s_all_key_and_hash_lens(struct kunit *test) static void test_blake2s_with_guarded_key_buf(struct kunit *test) { const size_t data_len = 100; + u8 *data = alloc_buf(test, data_len); + u8 *guarded_key_buf = alloc_guarded_buf(test, BLAKE2S_KEY_SIZE); - rand_bytes(test_buf, data_len); + rand_bytes(data, data_len); for (int key_len = 0; key_len <= BLAKE2S_KEY_SIZE; key_len++) { u8 key[BLAKE2S_KEY_SIZE]; - u8 *guarded_key = &test_buf[TEST_BUF_LEN - key_len]; + u8 *guarded_key = &guarded_key_buf[BLAKE2S_KEY_SIZE - key_len]; u8 hash1[BLAKE2S_HASH_SIZE]; u8 hash2[BLAKE2S_HASH_SIZE]; struct blake2s_ctx ctx; @@ -80,14 +82,13 @@ static void test_blake2s_with_guarded_key_buf(struct kunit *test) rand_bytes(key, key_len); memcpy(guarded_key, key, key_len); - blake2s(key, key_len, test_buf, data_len, - hash1, BLAKE2S_HASH_SIZE); - blake2s(guarded_key, key_len, test_buf, data_len, - hash2, BLAKE2S_HASH_SIZE); + blake2s(key, key_len, data, data_len, hash1, BLAKE2S_HASH_SIZE); + blake2s(guarded_key, key_len, data, data_len, hash2, + BLAKE2S_HASH_SIZE); KUNIT_ASSERT_MEMEQ(test, hash1, hash2, BLAKE2S_HASH_SIZE); blake2s_init_key(&ctx, BLAKE2S_HASH_SIZE, guarded_key, key_len); - blake2s_update(&ctx, test_buf, data_len); + blake2s_update(&ctx, data, data_len); blake2s_final(&ctx, hash2); KUNIT_ASSERT_MEMEQ(test, hash1, hash2, BLAKE2S_HASH_SIZE); } @@ -100,14 +101,16 @@ static void test_blake2s_with_guarded_key_buf(struct kunit *test) static void test_blake2s_with_guarded_out_buf(struct kunit *test) { const size_t data_len = 100; + u8 *data = alloc_buf(test, data_len); + u8 *out_buf = alloc_guarded_buf(test, BLAKE2S_HASH_SIZE); - rand_bytes(test_buf, data_len); + rand_bytes(data, data_len); for (int out_len = 1; out_len <= BLAKE2S_HASH_SIZE; out_len++) { u8 hash[BLAKE2S_HASH_SIZE]; - u8 *guarded_hash = &test_buf[TEST_BUF_LEN - out_len]; + u8 *guarded_hash = &out_buf[BLAKE2S_HASH_SIZE - out_len]; - blake2s(NULL, 0, test_buf, data_len, hash, out_len); - blake2s(NULL, 0, test_buf, data_len, guarded_hash, out_len); + blake2s(NULL, 0, data, data_len, hash, out_len); + blake2s(NULL, 0, data, data_len, guarded_hash, out_len); KUNIT_ASSERT_MEMEQ(test, hash, guarded_hash, out_len); } } @@ -124,8 +127,6 @@ static struct kunit_case blake2s_test_cases[] = { static struct kunit_suite blake2s_test_suite = { .name = "blake2s", .test_cases = blake2s_test_cases, - .suite_init = hash_suite_init, - .suite_exit = hash_suite_exit, }; kunit_test_suite(blake2s_test_suite); diff --git a/lib/crypto/tests/chacha20poly1305_kunit.c b/lib/crypto/tests/chacha20poly1305_kunit.c index 97a68fab88a7..d5504d0f4ad7 100644 --- a/lib/crypto/tests/chacha20poly1305_kunit.c +++ b/lib/crypto/tests/chacha20poly1305_kunit.c @@ -11,7 +11,7 @@ #include <linux/init.h> #include <linux/mm.h> #include <linux/kernel.h> -#include <linux/slab.h> +#include "test-utils.h" struct chacha20poly1305_testvec { const u8 *input, *output, *assoc, *nonce, *key; @@ -8890,11 +8890,8 @@ static void test_chacha20poly1305(struct kunit *test) bool ret; struct scatterlist sg_src[3]; - computed_output = kunit_kmalloc(test, MAXIMUM_TEST_BUFFER_LEN, - GFP_KERNEL); - input = kunit_kmalloc(test, MAXIMUM_TEST_BUFFER_LEN, GFP_KERNEL); - KUNIT_ASSERT_NOT_NULL(test, computed_output); - KUNIT_ASSERT_NOT_NULL(test, input); + computed_output = alloc_buf(test, MAXIMUM_TEST_BUFFER_LEN); + input = alloc_buf(test, MAXIMUM_TEST_BUFFER_LEN); for (i = 0; i < ARRAY_SIZE(chacha20poly1305_enc_vectors); ++i) { memset(computed_output, 0, MAXIMUM_TEST_BUFFER_LEN); diff --git a/lib/crypto/tests/ghash_kunit.c b/lib/crypto/tests/ghash_kunit.c index 68b3837a3607..4d7aa79b3cb2 100644 --- a/lib/crypto/tests/ghash_kunit.c +++ b/lib/crypto/tests/ghash_kunit.c @@ -39,17 +39,18 @@ static void ghash_withtestkey(const u8 *data, size_t len, */ static void test_ghash_allones_key_and_message(struct kunit *test) { + const size_t max_len = 4096; + u8 *data = alloc_buf(test, max_len); struct ghash_key key; struct ghash_ctx hashofhashes_ctx; u8 hash[GHASH_BLOCK_SIZE]; - static_assert(TEST_BUF_LEN >= 4096); - memset(test_buf, 0xff, 4096); + memset(data, 0xff, max_len); - ghash_preparekey(&key, test_buf); + ghash_preparekey(&key, data); ghash_init(&hashofhashes_ctx, &key); - for (size_t len = 0; len <= 4096; len += 16) { - ghash(&key, test_buf, len, hash); + for (size_t len = 0; len <= max_len; len += 16) { + ghash(&key, data, len, hash); ghash_update(&hashofhashes_ctx, hash, sizeof(hash)); } ghash_final(&hashofhashes_ctx, hash); @@ -68,7 +69,7 @@ static void check_key_consistency(struct kunit *test, const struct ghash_key *key1, const struct ghash_key *key2) { - u8 *data = test_buf; + u8 *data = alloc_buf(test, MAX_LEN_FOR_KEY_CHECK); u8 hash1[GHASH_BLOCK_SIZE]; u8 hash2[GHASH_BLOCK_SIZE]; @@ -88,10 +89,10 @@ static void check_key_consistency(struct kunit *test, static void test_ghash_with_guarded_key(struct kunit *test) { u8 raw_key[GHASH_BLOCK_SIZE]; - u8 *guarded_raw_key = &test_buf[TEST_BUF_LEN - sizeof(raw_key)]; + u8 *guarded_raw_key = alloc_guarded_buf(test, sizeof(raw_key)); struct ghash_key key1, key2; struct ghash_key *guarded_key = - (struct ghash_key *)&test_buf[TEST_BUF_LEN - sizeof(key1)]; + alloc_guarded_buf(test, sizeof(*guarded_key)); /* Prepare with regular buffers. */ rand_bytes(raw_key, sizeof(raw_key)); @@ -116,14 +117,14 @@ static void test_ghash_with_minimally_aligned_key(struct kunit *test) { u8 raw_key[GHASH_BLOCK_SIZE]; struct ghash_key key; + const size_t align = __alignof__(struct ghash_key); + u8 *key_buf = alloc_buf(test, sizeof(struct ghash_key) + 3 * align); struct ghash_key *minaligned_key = - (struct ghash_key *)&test_buf[MAX_LEN_FOR_KEY_CHECK + - __alignof__(struct ghash_key)]; + (struct ghash_key *)(PTR_ALIGN(key_buf, 2 * align) + align); - KUNIT_ASSERT_TRUE(test, IS_ALIGNED((uintptr_t)minaligned_key, - __alignof__(struct ghash_key))); - KUNIT_ASSERT_TRUE(test, !IS_ALIGNED((uintptr_t)minaligned_key, - 2 * __alignof__(struct ghash_key))); + KUNIT_ASSERT_TRUE(test, IS_ALIGNED((uintptr_t)minaligned_key, align)); + KUNIT_ASSERT_TRUE(test, + !IS_ALIGNED((uintptr_t)minaligned_key, 2 * align)); rand_bytes(raw_key, sizeof(raw_key)); ghash_preparekey(&key, raw_key); @@ -164,12 +165,7 @@ static int ghash_suite_init(struct kunit_suite *suite) rand_bytes_seeded_from_len(raw_key, sizeof(raw_key)); ghash_preparekey(&test_key, raw_key); - return hash_suite_init(suite); -} - -static void ghash_suite_exit(struct kunit_suite *suite) -{ - hash_suite_exit(suite); + return 0; } static struct kunit_case ghash_test_cases[] = { @@ -186,7 +182,6 @@ static struct kunit_suite ghash_test_suite = { .name = "ghash", .test_cases = ghash_test_cases, .suite_init = ghash_suite_init, - .suite_exit = ghash_suite_exit, }; kunit_test_suite(ghash_test_suite); diff --git a/lib/crypto/tests/hash-test-template.h b/lib/crypto/tests/hash-test-template.h index 61b43e62779f..bb6eaa509d0f 100644 --- a/lib/crypto/tests/hash-test-template.h +++ b/lib/crypto/tests/hash-test-template.h @@ -7,93 +7,7 @@ */ #include <kunit/run-in-irq-context.h> #include <kunit/test.h> -#include <linux/vmalloc.h> - -/* test_buf is a guarded buffer, i.e. &test_buf[TEST_BUF_LEN] is not mapped. */ -#define TEST_BUF_LEN 16384 -static u8 *test_buf; - -static u8 *orig_test_buf; - -static u64 random_seed; - -/* - * This is a simple linear congruential generator. It is used only for testing, - * which does not require cryptographically secure random numbers. A hard-coded - * algorithm is used instead of <linux/prandom.h> so that it matches the - * algorithm used by the test vector generation script. This allows the input - * data in random test vectors to be concisely stored as just the seed. - */ -static u32 rand32(void) -{ - random_seed = (random_seed * 25214903917 + 11) & ((1ULL << 48) - 1); - return random_seed >> 16; -} - -static void rand_bytes(u8 *out, size_t len) -{ - for (size_t i = 0; i < len; i++) - out[i] = rand32(); -} - -static void rand_bytes_seeded_from_len(u8 *out, size_t len) -{ - random_seed = len; - rand_bytes(out, len); -} - -static bool rand_bool(void) -{ - return rand32() % 2; -} - -/* Generate a random length, preferring small lengths. */ -static size_t rand_length(size_t max_len) -{ - size_t len; - - switch (rand32() % 3) { - case 0: - len = rand32() % 128; - break; - case 1: - len = rand32() % 3072; - break; - default: - len = rand32(); - break; - } - return len % (max_len + 1); -} - -static size_t rand_offset(size_t max_offset) -{ - return min(rand32() % 128, max_offset); -} - -static int hash_suite_init(struct kunit_suite *suite) -{ - /* - * Allocate the test buffer using vmalloc() with a page-aligned length - * so that it is immediately followed by a guard page. This allows - * buffer overreads to be detected, even in assembly code. - */ - size_t alloc_len = round_up(TEST_BUF_LEN, PAGE_SIZE); - - orig_test_buf = vmalloc(alloc_len); - if (!orig_test_buf) - return -ENOMEM; - - test_buf = orig_test_buf + alloc_len - TEST_BUF_LEN; - return 0; -} - -static void hash_suite_exit(struct kunit_suite *suite) -{ - vfree(orig_test_buf); - orig_test_buf = NULL; - test_buf = NULL; -} +#include "test-utils.h" /* * Test the hash function against a list of test vectors. @@ -104,14 +18,16 @@ static void hash_suite_exit(struct kunit_suite *suite) */ static void test_hash_test_vectors(struct kunit *test) { + const size_t max_len = 16384; + u8 *data = alloc_buf(test, max_len); + for (size_t i = 0; i < ARRAY_SIZE(hash_testvecs); i++) { size_t data_len = hash_testvecs[i].data_len; u8 actual_hash[HASH_SIZE]; - KUNIT_ASSERT_LE(test, data_len, TEST_BUF_LEN); - rand_bytes_seeded_from_len(test_buf, data_len); - - HASH(test_buf, data_len, actual_hash); + KUNIT_ASSERT_LE(test, data_len, max_len); + rand_bytes_seeded_from_len(data, data_len); + HASH(data, data_len, actual_hash); KUNIT_ASSERT_MEMEQ_MSG( test, actual_hash, hash_testvecs[i].digest, HASH_SIZE, "Wrong result with test vector %zu; data_len=%zu", i, @@ -127,14 +43,15 @@ static void test_hash_test_vectors(struct kunit *test) */ static void test_hash_all_lens_up_to_4096(struct kunit *test) { + const size_t max_len = 4096; + u8 *data = alloc_buf(test, max_len); struct HASH_CTX ctx; u8 hash[HASH_SIZE]; - static_assert(TEST_BUF_LEN >= 4096); - rand_bytes_seeded_from_len(test_buf, 4096); + rand_bytes_seeded_from_len(data, max_len); HASH_INIT(&ctx); - for (size_t len = 0; len <= 4096; len++) { - HASH(test_buf, len, hash); + for (size_t len = 0; len <= max_len; len++) { + HASH(data, len, hash); HASH_UPDATE(&ctx, hash, HASH_SIZE); } HASH_FINAL(&ctx, hash); @@ -147,6 +64,9 @@ static void test_hash_all_lens_up_to_4096(struct kunit *test) */ static void test_hash_incremental_updates(struct kunit *test) { + const size_t max_len = 16384; + u8 *data = alloc_guarded_buf(test, max_len); + for (int i = 0; i < 1000; i++) { size_t total_len, offset; struct HASH_CTX ctx; @@ -155,12 +75,12 @@ static void test_hash_incremental_updates(struct kunit *test) size_t num_parts = 0; size_t remaining_len, cur_offset; - total_len = rand_length(TEST_BUF_LEN); - offset = rand_offset(TEST_BUF_LEN - total_len); - rand_bytes(&test_buf[offset], total_len); + total_len = rand_length(max_len); + offset = rand_offset(max_len - total_len); + rand_bytes(&data[offset], total_len); /* Compute the hash value in one shot. */ - HASH(&test_buf[offset], total_len, hash1); + HASH(&data[offset], total_len, hash1); /* * Compute the hash value incrementally, using a randomly @@ -172,13 +92,13 @@ static void test_hash_incremental_updates(struct kunit *test) while (rand_bool()) { size_t part_len = rand_length(remaining_len); - HASH_UPDATE(&ctx, &test_buf[cur_offset], part_len); + HASH_UPDATE(&ctx, &data[cur_offset], part_len); num_parts++; cur_offset += part_len; remaining_len -= part_len; } if (remaining_len != 0 || rand_bool()) { - HASH_UPDATE(&ctx, &test_buf[cur_offset], remaining_len); + HASH_UPDATE(&ctx, &data[cur_offset], remaining_len); num_parts++; } HASH_FINAL(&ctx, hash2); @@ -197,11 +117,13 @@ static void test_hash_incremental_updates(struct kunit *test) */ static void test_hash_buffer_overruns(struct kunit *test) { - const size_t max_tested_len = TEST_BUF_LEN - sizeof(struct HASH_CTX); - void *const buf_end = &test_buf[TEST_BUF_LEN]; + const size_t buf_len = 16384; + u8 *buf = alloc_guarded_buf(test, buf_len); + void *const buf_end = &buf[buf_len]; + const size_t max_tested_len = buf_len - sizeof(struct HASH_CTX); struct HASH_CTX *guarded_ctx = buf_end - sizeof(*guarded_ctx); - rand_bytes(test_buf, TEST_BUF_LEN); + rand_bytes(buf, buf_len); for (int i = 0; i < 100; i++) { size_t len = rand_length(max_tested_len); @@ -215,14 +137,14 @@ static void test_hash_buffer_overruns(struct kunit *test) HASH_FINAL(&ctx, hash); /* Check for overruns of the hash value buffer. */ - HASH(test_buf, len, buf_end - HASH_SIZE); + HASH(buf, len, buf_end - HASH_SIZE); HASH_INIT(&ctx); - HASH_UPDATE(&ctx, test_buf, len); + HASH_UPDATE(&ctx, buf, len); HASH_FINAL(&ctx, buf_end - HASH_SIZE); - /* Check for overuns of the hash context. */ + /* Check for overruns of the hash context. */ HASH_INIT(guarded_ctx); - HASH_UPDATE(guarded_ctx, test_buf, len); + HASH_UPDATE(guarded_ctx, buf, len); HASH_FINAL(guarded_ctx, hash); } } @@ -233,30 +155,32 @@ static void test_hash_buffer_overruns(struct kunit *test) */ static void test_hash_overlaps(struct kunit *test) { - const size_t max_tested_len = TEST_BUF_LEN - HASH_SIZE; + const size_t buf_len = 16384; + u8 *buf = alloc_guarded_buf(test, buf_len); + const size_t max_tested_len = buf_len - HASH_SIZE; struct HASH_CTX ctx; u8 hash[HASH_SIZE]; - rand_bytes(test_buf, TEST_BUF_LEN); + rand_bytes(buf, buf_len); for (int i = 0; i < 100; i++) { size_t len = rand_length(max_tested_len); size_t offset = HASH_SIZE + rand_offset(max_tested_len - len); bool left_end = rand_bool(); - u8 *ovl_hash = left_end ? &test_buf[offset] : - &test_buf[offset + len - HASH_SIZE]; + u8 *ovl_hash = left_end ? &buf[offset] : + &buf[offset + len - HASH_SIZE]; - HASH(&test_buf[offset], len, hash); - HASH(&test_buf[offset], len, ovl_hash); + HASH(&buf[offset], len, hash); + HASH(&buf[offset], len, ovl_hash); KUNIT_ASSERT_MEMEQ_MSG( test, hash, ovl_hash, HASH_SIZE, "Overlap test 1 failed with len=%zu offset=%zu left_end=%d", len, offset, left_end); /* Repeat the above test, but this time use init+update+final */ - HASH(&test_buf[offset], len, hash); + HASH(&buf[offset], len, hash); HASH_INIT(&ctx); - HASH_UPDATE(&ctx, &test_buf[offset], len); + HASH_UPDATE(&ctx, &buf[offset], len); HASH_FINAL(&ctx, ovl_hash); KUNIT_ASSERT_MEMEQ_MSG( test, hash, ovl_hash, HASH_SIZE, @@ -264,10 +188,10 @@ static void test_hash_overlaps(struct kunit *test) len, offset, left_end); /* Test modifying the source data after it was used. */ - HASH(&test_buf[offset], len, hash); + HASH(&buf[offset], len, hash); HASH_INIT(&ctx); - HASH_UPDATE(&ctx, &test_buf[offset], len); - rand_bytes(&test_buf[offset], len); + HASH_UPDATE(&ctx, &buf[offset], len); + rand_bytes(&buf[offset], len); HASH_FINAL(&ctx, ovl_hash); KUNIT_ASSERT_MEMEQ_MSG( test, hash, ovl_hash, HASH_SIZE, @@ -282,20 +206,22 @@ static void test_hash_overlaps(struct kunit *test) */ static void test_hash_alignment_consistency(struct kunit *test) { + const size_t max_len = 16384; + u8 *data = alloc_guarded_buf(test, max_len); u8 hash1[128 + HASH_SIZE]; u8 hash2[128 + HASH_SIZE]; for (int i = 0; i < 100; i++) { - size_t len = rand_length(TEST_BUF_LEN); - size_t data_offs1 = rand_offset(TEST_BUF_LEN - len); - size_t data_offs2 = rand_offset(TEST_BUF_LEN - len); + size_t len = rand_length(max_len); + size_t data_offs1 = rand_offset(max_len - len); + size_t data_offs2 = rand_offset(max_len - len); size_t hash_offs1 = rand_offset(128); size_t hash_offs2 = rand_offset(128); - rand_bytes(&test_buf[data_offs1], len); - HASH(&test_buf[data_offs1], len, &hash1[hash_offs1]); - memmove(&test_buf[data_offs2], &test_buf[data_offs1], len); - HASH(&test_buf[data_offs2], len, &hash2[hash_offs2]); + rand_bytes(&data[data_offs1], len); + HASH(&data[data_offs1], len, &hash1[hash_offs1]); + memmove(&data[data_offs2], &data[data_offs1], len); + HASH(&data[data_offs2], len, &hash2[hash_offs2]); KUNIT_ASSERT_MEMEQ_MSG( test, &hash1[hash_offs1], &hash2[hash_offs2], HASH_SIZE, "Alignment consistency test failed with len=%zu data_offs=(%zu,%zu) hash_offs=(%zu,%zu)", @@ -308,11 +234,14 @@ static void test_hash_ctx_zeroization(struct kunit *test) { static const u8 zeroes[sizeof(struct HASH_CTX)]; struct HASH_CTX ctx; + const size_t data_len = 128; + u8 *data = alloc_buf(test, data_len); + u8 hash[HASH_SIZE]; - rand_bytes(test_buf, 128); + rand_bytes(data, data_len); HASH_INIT(&ctx); - HASH_UPDATE(&ctx, test_buf, 128); - HASH_FINAL(&ctx, test_buf); + HASH_UPDATE(&ctx, data, data_len); + HASH_FINAL(&ctx, hash); KUNIT_ASSERT_MEMEQ_MSG(test, &ctx, zeroes, sizeof(ctx), "Hash context was not zeroized by finalization"); } @@ -321,6 +250,7 @@ static void test_hash_ctx_zeroization(struct kunit *test) #define IRQ_TEST_NUM_BUFFERS 3 /* matches max concurrency level */ struct hash_irq_test1_state { + u8 *data; u8 expected_hashes[IRQ_TEST_NUM_BUFFERS][HASH_SIZE]; atomic_t seqno; }; @@ -336,7 +266,8 @@ static bool hash_irq_test1_func(void *state_) u32 i = (u32)atomic_inc_return(&state->seqno) % IRQ_TEST_NUM_BUFFERS; u8 actual_hash[HASH_SIZE]; - HASH(&test_buf[i * IRQ_TEST_DATA_LEN], IRQ_TEST_DATA_LEN, actual_hash); + HASH(&state->data[i * IRQ_TEST_DATA_LEN], IRQ_TEST_DATA_LEN, + actual_hash); return memcmp(actual_hash, state->expected_hashes[i], HASH_SIZE) == 0; } @@ -346,12 +277,14 @@ static bool hash_irq_test1_func(void *state_) */ static void test_hash_interrupt_context_1(struct kunit *test) { + const size_t total_data_len = IRQ_TEST_NUM_BUFFERS * IRQ_TEST_DATA_LEN; struct hash_irq_test1_state state = {}; /* Prepare some test messages and compute the expected hash of each. */ - rand_bytes(test_buf, IRQ_TEST_NUM_BUFFERS * IRQ_TEST_DATA_LEN); + state.data = alloc_buf(test, total_data_len); + rand_bytes(state.data, total_data_len); for (int i = 0; i < IRQ_TEST_NUM_BUFFERS; i++) - HASH(&test_buf[i * IRQ_TEST_DATA_LEN], IRQ_TEST_DATA_LEN, + HASH(&state.data[i * IRQ_TEST_DATA_LEN], IRQ_TEST_DATA_LEN, state.expected_hashes[i]); kunit_run_irq_test(test, hash_irq_test1_func, 100000, &state); @@ -365,6 +298,8 @@ struct hash_irq_test2_hash_ctx { }; struct hash_irq_test2_state { + u8 *data; + size_t data_len; struct hash_irq_test2_hash_ctx ctxs[IRQ_TEST_NUM_BUFFERS]; u8 expected_hash[HASH_SIZE]; u16 update_lens[32]; @@ -397,7 +332,7 @@ static bool hash_irq_test2_func(void *state_) ctx->step++; } else if (ctx->step < state->num_steps - 1) { /* Update step */ - HASH_UPDATE(&ctx->hash_ctx, &test_buf[ctx->offset], + HASH_UPDATE(&ctx->hash_ctx, &state->data[ctx->offset], state->update_lens[ctx->step - 1]); ctx->offset += state->update_lens[ctx->step - 1]; ctx->step++; @@ -405,7 +340,7 @@ static bool hash_irq_test2_func(void *state_) /* Final step */ u8 actual_hash[HASH_SIZE]; - if (WARN_ON_ONCE(ctx->offset != TEST_BUF_LEN)) + if (WARN_ON_ONCE(ctx->offset != state->data_len)) ret = false; HASH_FINAL(&ctx->hash_ctx, actual_hash); if (memcmp(actual_hash, state->expected_hash, HASH_SIZE) != 0) @@ -426,20 +361,23 @@ static bool hash_irq_test2_func(void *state_) */ static void test_hash_interrupt_context_2(struct kunit *test) { + const size_t data_len = 16384; struct hash_irq_test2_state *state; - int remaining = TEST_BUF_LEN; + size_t remaining = data_len; state = kunit_kzalloc(test, sizeof(*state), GFP_KERNEL); KUNIT_ASSERT_NOT_NULL(test, state); + state->data_len = data_len; + state->data = alloc_buf(test, data_len); - rand_bytes(test_buf, TEST_BUF_LEN); - HASH(test_buf, TEST_BUF_LEN, state->expected_hash); + rand_bytes(state->data, data_len); + HASH(state->data, data_len, state->expected_hash); /* * Generate a list of update lengths to use. Ensure that it contains * multiple entries but is limited to a maximum length. */ - static_assert(TEST_BUF_LEN / 4096 > 1); + KUNIT_ASSERT_GT(test, data_len / 4096, 1); for (state->num_steps = 0; state->num_steps < ARRAY_SIZE(state->update_lens) - 1 && remaining; state->num_steps++) { @@ -485,21 +423,23 @@ static void test_hash_interrupt_context_2(struct kunit *test) */ static void test_hmac(struct kunit *test) { + const size_t max_data_len = 4096; + const size_t max_key_len = 293; + const size_t outer_key_len = 32; + u8 *data = alloc_guarded_buf(test, max_data_len); + u8 *raw_key = alloc_guarded_buf(test, max_key_len); static const u8 zeroes[sizeof(struct HMAC_CTX)]; - u8 *raw_key; struct HMAC_KEY key; struct HMAC_CTX ctx; u8 mac[HASH_SIZE]; u8 mac2[HASH_SIZE]; - static_assert(TEST_BUF_LEN >= 4096 + 293); - rand_bytes_seeded_from_len(test_buf, 4096); - raw_key = &test_buf[4096]; + rand_bytes_seeded_from_len(data, max_data_len); + rand_bytes_seeded_from_len(raw_key, outer_key_len); - rand_bytes_seeded_from_len(raw_key, 32); - HMAC_PREPAREKEY(&key, raw_key, 32); + HMAC_PREPAREKEY(&key, raw_key, outer_key_len); HMAC_INIT(&ctx, &key); - for (size_t data_len = 0; data_len <= 4096; data_len++) { + for (size_t data_len = 0; data_len <= max_data_len; data_len++) { /* * Cycle through key lengths as well. Somewhat arbitrarily go * up to 293, which is somewhat larger than the largest hash @@ -507,17 +447,17 @@ static void test_hmac(struct kunit *test) * hashed down to one block); going higher would not be useful. * To reduce correlation with data_len, use a prime number here. */ - size_t key_len = data_len % 293; + size_t key_len = data_len % max_key_len; - HMAC_UPDATE(&ctx, test_buf, data_len); + HMAC_UPDATE(&ctx, data, data_len); rand_bytes_seeded_from_len(raw_key, key_len); - HMAC_USINGRAWKEY(raw_key, key_len, test_buf, data_len, mac); + HMAC_USINGRAWKEY(raw_key, key_len, data, data_len, mac); HMAC_UPDATE(&ctx, mac, HASH_SIZE); /* Verify that HMAC() is consistent with HMAC_USINGRAWKEY(). */ HMAC_PREPAREKEY(&key, raw_key, key_len); - HMAC(&key, test_buf, data_len, mac2); + HMAC(&key, data, data_len, mac2); KUNIT_ASSERT_MEMEQ_MSG( test, mac, mac2, HASH_SIZE, "HMAC gave different results with raw and prepared keys"); @@ -540,14 +480,17 @@ static void benchmark_hash(struct kunit *test) 1, 16, 64, 127, 128, 200, 256, 511, 512, 1024, 3173, 4096, 16384, }; + const size_t max_len = 16384; + u8 *data = alloc_buf(test, max_len); u8 hash[HASH_SIZE]; if (!IS_ENABLED(CONFIG_CRYPTO_LIB_BENCHMARK)) kunit_skip(test, "not enabled"); /* Warm-up */ - for (size_t i = 0; i < 10000000; i += TEST_BUF_LEN) - HASH(test_buf, TEST_BUF_LEN, hash); + memset(data, 0, max_len); + for (size_t i = 0; i < 10000000; i += max_len) + HASH(data, max_len, hash); for (size_t i = 0; i < ARRAY_SIZE(lens_to_test); i++) { size_t len = lens_to_test[i]; @@ -555,11 +498,11 @@ static void benchmark_hash(struct kunit *test) size_t num_iters = 10000000 / (len + 128); u64 t; - KUNIT_ASSERT_LE(test, len, TEST_BUF_LEN); + KUNIT_ASSERT_LE(test, len, max_len); preempt_disable(); t = ktime_get_ns(); for (size_t j = 0; j < num_iters; j++) - HASH(test_buf, len, hash); + HASH(data, len, hash); t = ktime_get_ns() - t; preempt_enable(); kunit_info(test, "len=%zu: %llu MB/s", len, diff --git a/lib/crypto/tests/md5_kunit.c b/lib/crypto/tests/md5_kunit.c index 38bd52c25ae3..1598f8585b45 100644 --- a/lib/crypto/tests/md5_kunit.c +++ b/lib/crypto/tests/md5_kunit.c @@ -30,8 +30,6 @@ static struct kunit_case hash_test_cases[] = { static struct kunit_suite hash_test_suite = { .name = "md5", .test_cases = hash_test_cases, - .suite_init = hash_suite_init, - .suite_exit = hash_suite_exit, }; kunit_test_suite(hash_test_suite); diff --git a/lib/crypto/tests/mldsa_kunit.c b/lib/crypto/tests/mldsa_kunit.c index 67f8f93e3dc6..ec64e10c97f2 100644 --- a/lib/crypto/tests/mldsa_kunit.c +++ b/lib/crypto/tests/mldsa_kunit.c @@ -8,6 +8,7 @@ #include <kunit/test.h> #include <linux/random.h> #include <linux/unaligned.h> +#include "test-utils.h" #define Q 8380417 /* The prime q = 2^23 - 2^13 + 1 */ @@ -60,14 +61,6 @@ static void do_mldsa_and_assert_success(struct kunit *test, KUNIT_ASSERT_EQ(test, err, 0); } -static u8 *kunit_kmemdup_or_fail(struct kunit *test, const u8 *src, size_t len) -{ - u8 *dst = kunit_kmalloc(test, len, GFP_KERNEL); - - KUNIT_ASSERT_NOT_NULL(test, dst); - return memcpy(dst, src, len); -} - /* * Test that changing coefficients in a valid signature's z vector results in * the following behavior from mldsa_verify(): @@ -83,7 +76,7 @@ static u8 *kunit_kmemdup_or_fail(struct kunit *test, const u8 *src, size_t len) static void test_mldsa_z_range(struct kunit *test, const struct mldsa_testvector *tv) { - u8 *sig = kunit_kmemdup_or_fail(test, tv->sig, tv->sig_len); + u8 *sig = memdup_buf(test, tv->sig, tv->sig_len); const int lambda = params[tv->alg].lambda; const s32 gamma1 = params[tv->alg].gamma1; const int beta = params[tv->alg].beta; @@ -146,7 +139,7 @@ static void test_mldsa_bad_hints(struct kunit *test, { const int omega = params[tv->alg].omega; const int k = params[tv->alg].k; - u8 *sig = kunit_kmemdup_or_fail(test, tv->sig, tv->sig_len); + u8 *sig = memdup_buf(test, tv->sig, tv->sig_len); /* Pointer to the encoded hint vector in the signature */ u8 *hintvec = &sig[tv->sig_len - omega - k]; u8 h; @@ -202,9 +195,9 @@ static void test_mldsa_mutation(struct kunit *test, const int msg_len = tv->msg_len; const int pk_len = tv->pk_len; const int num_iter = 200; - u8 *sig = kunit_kmemdup_or_fail(test, tv->sig, sig_len); - u8 *msg = kunit_kmemdup_or_fail(test, tv->msg, msg_len); - u8 *pk = kunit_kmemdup_or_fail(test, tv->pk, pk_len); + u8 *sig = memdup_buf(test, tv->sig, sig_len); + u8 *msg = memdup_buf(test, tv->msg, msg_len); + u8 *pk = memdup_buf(test, tv->pk, pk_len); /* Initially the signature is valid. */ do_mldsa_and_assert_success(test, tv); diff --git a/lib/crypto/tests/nh_kunit.c b/lib/crypto/tests/nh_kunit.c index a8a3c3f345cb..49e0fb3dd294 100644 --- a/lib/crypto/tests/nh_kunit.c +++ b/lib/crypto/tests/nh_kunit.c @@ -5,14 +5,13 @@ #include <crypto/nh.h> #include <kunit/test.h> #include "nh-testvecs.h" +#include "test-utils.h" static void test_nh(struct kunit *test) { - u32 *key = kunit_kmalloc(test, NH_KEY_BYTES, GFP_KERNEL); + u32 *key = memdup_buf(test, nh_test_key, NH_KEY_BYTES); __le64 hash[NH_NUM_PASSES]; - KUNIT_ASSERT_NOT_NULL(test, key); - memcpy(key, nh_test_key, NH_KEY_BYTES); le32_to_cpu_array(key, NH_KEY_WORDS); nh(key, nh_test_msg, 16, hash); diff --git a/lib/crypto/tests/poly1305_kunit.c b/lib/crypto/tests/poly1305_kunit.c index 7ac191bd96b6..f3cb6245bc29 100644 --- a/lib/crypto/tests/poly1305_kunit.c +++ b/lib/crypto/tests/poly1305_kunit.c @@ -46,12 +46,7 @@ static void poly1305_withtestkey(const u8 *data, size_t len, static int poly1305_suite_init(struct kunit_suite *suite) { rand_bytes_seeded_from_len(test_key, POLY1305_KEY_SIZE); - return hash_suite_init(suite); -} - -static void poly1305_suite_exit(struct kunit_suite *suite) -{ - hash_suite_exit(suite); + return 0; } /* @@ -81,19 +76,20 @@ static void poly1305_suite_exit(struct kunit_suite *suite) */ static void test_poly1305_allones_keys_and_message(struct kunit *test) { + const size_t max_len = 4096; + u8 *data = alloc_buf(test, max_len); struct poly1305_desc_ctx mac_ctx, macofmacs_ctx; u8 mac[POLY1305_DIGEST_SIZE]; - static_assert(TEST_BUF_LEN >= 4096); - memset(test_buf, 0xff, 4096); + memset(data, 0xff, max_len); - poly1305_init(&mac_ctx, test_buf); - poly1305_init(&macofmacs_ctx, test_buf); + poly1305_init(&mac_ctx, data); + poly1305_init(&macofmacs_ctx, data); for (int i = 0; i < 32; i++) { - for (size_t len = 0; len <= 4096; len += 16) { + for (size_t len = 0; len <= max_len; len += 16) { struct poly1305_desc_ctx tmp_ctx; - poly1305_update(&mac_ctx, test_buf, len); + poly1305_update(&mac_ctx, data, len); tmp_ctx = mac_ctx; poly1305_final(&tmp_ctx, mac); poly1305_update(&macofmacs_ctx, mac, @@ -157,7 +153,6 @@ static struct kunit_suite poly1305_test_suite = { .name = "poly1305", .test_cases = poly1305_test_cases, .suite_init = poly1305_suite_init, - .suite_exit = poly1305_suite_exit, }; kunit_test_suite(poly1305_test_suite); diff --git a/lib/crypto/tests/polyval_kunit.c b/lib/crypto/tests/polyval_kunit.c index d1f53a690ab8..2835929e890c 100644 --- a/lib/crypto/tests/polyval_kunit.c +++ b/lib/crypto/tests/polyval_kunit.c @@ -66,17 +66,18 @@ static void test_polyval_rfc8452_testvec(struct kunit *test) */ static void test_polyval_allones_key_and_message(struct kunit *test) { + const size_t max_len = 4096; + u8 *data = alloc_buf(test, max_len); struct polyval_key key; struct polyval_ctx hashofhashes_ctx; u8 hash[POLYVAL_BLOCK_SIZE]; - static_assert(TEST_BUF_LEN >= 4096); - memset(test_buf, 0xff, 4096); + memset(data, 0xff, max_len); - polyval_preparekey(&key, test_buf); + polyval_preparekey(&key, data); polyval_init(&hashofhashes_ctx, &key); - for (size_t len = 0; len <= 4096; len += 16) { - polyval(&key, test_buf, len, hash); + for (size_t len = 0; len <= max_len; len += 16) { + polyval(&key, data, len, hash); polyval_update(&hashofhashes_ctx, hash, sizeof(hash)); } polyval_final(&hashofhashes_ctx, hash); @@ -95,7 +96,7 @@ static void check_key_consistency(struct kunit *test, const struct polyval_key *key1, const struct polyval_key *key2) { - u8 *data = test_buf; + u8 *data = alloc_buf(test, MAX_LEN_FOR_KEY_CHECK); u8 hash1[POLYVAL_BLOCK_SIZE]; u8 hash2[POLYVAL_BLOCK_SIZE]; @@ -115,10 +116,10 @@ static void check_key_consistency(struct kunit *test, static void test_polyval_with_guarded_key(struct kunit *test) { u8 raw_key[POLYVAL_BLOCK_SIZE]; - u8 *guarded_raw_key = &test_buf[TEST_BUF_LEN - sizeof(raw_key)]; + u8 *guarded_raw_key = alloc_guarded_buf(test, sizeof(raw_key)); struct polyval_key key1, key2; struct polyval_key *guarded_key = - (struct polyval_key *)&test_buf[TEST_BUF_LEN - sizeof(key1)]; + alloc_guarded_buf(test, sizeof(*guarded_key)); /* Prepare with regular buffers. */ rand_bytes(raw_key, sizeof(raw_key)); @@ -137,21 +138,20 @@ static void test_polyval_with_guarded_key(struct kunit *test) /* * Test that polyval_key only needs to be aligned to * __alignof__(struct polyval_key), i.e. 8 bytes. The assembly code may prefer - * 16-byte or higher alignment, but it musn't require it. + * 16-byte or higher alignment, but it mustn't require it. */ static void test_polyval_with_minimally_aligned_key(struct kunit *test) { u8 raw_key[POLYVAL_BLOCK_SIZE]; struct polyval_key key; + const size_t align = __alignof__(struct polyval_key); + u8 *key_buf = alloc_buf(test, sizeof(struct polyval_key) + 3 * align); struct polyval_key *minaligned_key = - (struct polyval_key *)&test_buf[MAX_LEN_FOR_KEY_CHECK + - __alignof__(struct polyval_key)]; + (struct polyval_key *)(PTR_ALIGN(key_buf, 2 * align) + align); - KUNIT_ASSERT_TRUE(test, IS_ALIGNED((uintptr_t)minaligned_key, - __alignof__(struct polyval_key))); + KUNIT_ASSERT_TRUE(test, IS_ALIGNED((uintptr_t)minaligned_key, align)); KUNIT_ASSERT_TRUE(test, - !IS_ALIGNED((uintptr_t)minaligned_key, - 2 * __alignof__(struct polyval_key))); + !IS_ALIGNED((uintptr_t)minaligned_key, 2 * align)); rand_bytes(raw_key, sizeof(raw_key)); polyval_preparekey(&key, raw_key); @@ -192,12 +192,7 @@ static int polyval_suite_init(struct kunit_suite *suite) rand_bytes_seeded_from_len(raw_key, sizeof(raw_key)); polyval_preparekey(&test_key, raw_key); - return hash_suite_init(suite); -} - -static void polyval_suite_exit(struct kunit_suite *suite) -{ - hash_suite_exit(suite); + return 0; } static struct kunit_case polyval_test_cases[] = { @@ -215,7 +210,6 @@ static struct kunit_suite polyval_test_suite = { .name = "polyval", .test_cases = polyval_test_cases, .suite_init = polyval_suite_init, - .suite_exit = polyval_suite_exit, }; kunit_test_suite(polyval_test_suite); diff --git a/lib/crypto/tests/sha1_kunit.c b/lib/crypto/tests/sha1_kunit.c index 24ba8d5669c8..27286afaa407 100644 --- a/lib/crypto/tests/sha1_kunit.c +++ b/lib/crypto/tests/sha1_kunit.c @@ -30,8 +30,6 @@ static struct kunit_case hash_test_cases[] = { static struct kunit_suite hash_test_suite = { .name = "sha1", .test_cases = hash_test_cases, - .suite_init = hash_suite_init, - .suite_exit = hash_suite_exit, }; kunit_test_suite(hash_test_suite); diff --git a/lib/crypto/tests/sha224_kunit.c b/lib/crypto/tests/sha224_kunit.c index 962ad46b9c99..bcf8b90f9ae2 100644 --- a/lib/crypto/tests/sha224_kunit.c +++ b/lib/crypto/tests/sha224_kunit.c @@ -30,8 +30,6 @@ static struct kunit_case hash_test_cases[] = { static struct kunit_suite hash_test_suite = { .name = "sha224", .test_cases = hash_test_cases, - .suite_init = hash_suite_init, - .suite_exit = hash_suite_exit, }; kunit_test_suite(hash_test_suite); diff --git a/lib/crypto/tests/sha256_kunit.c b/lib/crypto/tests/sha256_kunit.c index 5dccdee79693..17daa09adfe7 100644 --- a/lib/crypto/tests/sha256_kunit.c +++ b/lib/crypto/tests/sha256_kunit.c @@ -4,6 +4,7 @@ */ #include <crypto/sha2.h> #include "sha256-testvecs.h" +#include "test-utils.h" /* Generate the HASH_KUNIT_CASES using hash-test-template.h. */ #define HASH sha256 @@ -22,26 +23,6 @@ #define HMAC_USINGRAWKEY hmac_sha256_usingrawkey #include "hash-test-template.h" -static void free_guarded_buf(void *buf) -{ - vfree(buf); -} - -/* - * Allocate a KUnit-managed buffer that has length @len bytes immediately - * followed by an unmapped page, and assert that the allocation succeeds. - */ -static void *alloc_guarded_buf(struct kunit *test, size_t len) -{ - size_t full_len = round_up(len, PAGE_SIZE); - void *buf = vmalloc(full_len); - - KUNIT_ASSERT_NOT_NULL(test, buf); - KUNIT_ASSERT_EQ(test, 0, - kunit_add_action_or_reset(test, free_guarded_buf, buf)); - return buf + full_len - len; -} - /* * Test for sha256_finup_2x(). Specifically, choose various data lengths and * salt lengths, and for each one, verify that sha256_finup_2x() produces the @@ -105,19 +86,20 @@ static void test_sha256_finup_2x(struct kunit *test) static void test_sha256_finup_2x_defaultctx(struct kunit *test) { const size_t data_len = 128; + u8 *data = alloc_buf(test, 2 * data_len); struct sha256_ctx ctx; u8 hash1_a[SHA256_DIGEST_SIZE]; u8 hash2_a[SHA256_DIGEST_SIZE]; u8 hash1_b[SHA256_DIGEST_SIZE]; u8 hash2_b[SHA256_DIGEST_SIZE]; - rand_bytes(test_buf, 2 * data_len); + rand_bytes(data, 2 * data_len); sha256_init(&ctx); - sha256_finup_2x(&ctx, test_buf, &test_buf[data_len], data_len, hash1_a, + sha256_finup_2x(&ctx, data, &data[data_len], data_len, hash1_a, hash2_a); - sha256_finup_2x(NULL, test_buf, &test_buf[data_len], data_len, hash1_b, + sha256_finup_2x(NULL, data, &data[data_len], data_len, hash1_b, hash2_b); KUNIT_ASSERT_MEMEQ(test, hash1_a, hash1_b, SHA256_DIGEST_SIZE); @@ -131,18 +113,19 @@ static void test_sha256_finup_2x_defaultctx(struct kunit *test) static void test_sha256_finup_2x_hugelen(struct kunit *test) { const size_t data_len = 4 * SHA256_BLOCK_SIZE; + u8 *data = alloc_buf(test, data_len); struct sha256_ctx ctx = {}; u8 expected_hash[SHA256_DIGEST_SIZE]; u8 hash[SHA256_DIGEST_SIZE]; - rand_bytes(test_buf, data_len); + rand_bytes(data, data_len); for (size_t align = 0; align < SHA256_BLOCK_SIZE; align++) { sha256_init(&ctx); ctx.ctx.bytecount = 0x123456789abcd00 + align; - sha256_finup_2x(&ctx, test_buf, test_buf, data_len, hash, hash); + sha256_finup_2x(&ctx, data, data, data_len, hash, hash); - sha256_update(&ctx, test_buf, data_len); + sha256_update(&ctx, data, data_len); sha256_final(&ctx, expected_hash); KUNIT_ASSERT_MEMEQ(test, hash, expected_hash, @@ -161,6 +144,7 @@ static void benchmark_sha256_finup_2x(struct kunit *test) static const size_t salt_lens_to_test[] = { 0, 32, 64 }; const size_t data_len = 4096; const size_t num_iters = 4096; + u8 *data = alloc_buf(test, data_len * 2); struct sha256_ctx ctx; u8 hash1[SHA256_DIGEST_SIZE]; u8 hash2[SHA256_DIGEST_SIZE]; @@ -170,12 +154,12 @@ static void benchmark_sha256_finup_2x(struct kunit *test) if (!sha256_finup_2x_is_optimized()) kunit_skip(test, "not relevant"); - rand_bytes(test_buf, data_len * 2); + rand_bytes(data, data_len * 2); /* Warm-up */ for (size_t i = 0; i < num_iters; i++) - sha256_finup_2x(NULL, &test_buf[0], &test_buf[data_len], - data_len, hash1, hash2); + sha256_finup_2x(NULL, &data[0], &data[data_len], data_len, + hash1, hash2); for (size_t i = 0; i < ARRAY_SIZE(salt_lens_to_test); i++) { size_t salt_len = salt_lens_to_test[i]; @@ -186,12 +170,12 @@ static void benchmark_sha256_finup_2x(struct kunit *test) * not measured; we're just interested in sha256_finup_2x(). */ sha256_init(&ctx); - sha256_update(&ctx, test_buf, salt_len); + sha256_update(&ctx, data, salt_len); preempt_disable(); t0 = ktime_get_ns(); for (size_t j = 0; j < num_iters; j++) - sha256_finup_2x(&ctx, &test_buf[0], &test_buf[data_len], + sha256_finup_2x(&ctx, &data[0], &data[data_len], data_len, hash1, hash2); t1 = ktime_get_ns(); preempt_enable(); @@ -215,8 +199,6 @@ static struct kunit_case hash_test_cases[] = { static struct kunit_suite hash_test_suite = { .name = "sha256", .test_cases = hash_test_cases, - .suite_init = hash_suite_init, - .suite_exit = hash_suite_exit, }; kunit_test_suite(hash_test_suite); diff --git a/lib/crypto/tests/sha384_kunit.c b/lib/crypto/tests/sha384_kunit.c index e1ef5c995bb6..76409822d965 100644 --- a/lib/crypto/tests/sha384_kunit.c +++ b/lib/crypto/tests/sha384_kunit.c @@ -30,8 +30,6 @@ static struct kunit_case hash_test_cases[] = { static struct kunit_suite hash_test_suite = { .name = "sha384", .test_cases = hash_test_cases, - .suite_init = hash_suite_init, - .suite_exit = hash_suite_exit, }; kunit_test_suite(hash_test_suite); diff --git a/lib/crypto/tests/sha3_kunit.c b/lib/crypto/tests/sha3_kunit.c index ed5fbe80337f..81b113079755 100644 --- a/lib/crypto/tests/sha3_kunit.c +++ b/lib/crypto/tests/sha3_kunit.c @@ -273,12 +273,10 @@ static void test_shake_all_lens_up_to_4096(struct kunit *test) { struct sha3_ctx main_ctx; const size_t max_len = 4096; - u8 *const in = test_buf; - u8 *const out = &test_buf[TEST_BUF_LEN - max_len]; + u8 *const in = alloc_buf(test, max_len); + u8 *const out = alloc_buf(test, max_len); u8 main_hash[SHA3_256_DIGEST_SIZE]; - KUNIT_ASSERT_LE(test, 2 * max_len, TEST_BUF_LEN); - rand_bytes_seeded_from_len(in, max_len); for (int alg = 0; alg < 2; alg++) { sha3_256_init(&main_ctx); @@ -309,12 +307,8 @@ static void test_shake_all_lens_up_to_4096(struct kunit *test) static void test_shake_multiple_squeezes(struct kunit *test) { const size_t max_len = 512; - u8 *ref_out; - - KUNIT_ASSERT_GE(test, TEST_BUF_LEN, 2 * max_len); - - ref_out = kunit_kzalloc(test, max_len, GFP_KERNEL); - KUNIT_ASSERT_NOT_NULL(test, ref_out); + u8 *buf = alloc_buf(test, max_len); + u8 *ref_out = alloc_buf(test, max_len); for (int i = 0; i < 2000; i++) { const int alg = rand32() % 2; @@ -322,8 +316,8 @@ static void test_shake_multiple_squeezes(struct kunit *test) const size_t out_len = rand_length(max_len); const size_t in_offs = rand_offset(max_len - in_len); const size_t out_offs = rand_offset(max_len - out_len); - u8 *const in = &test_buf[in_offs]; - u8 *const out = &test_buf[out_offs]; + u8 *const in = &buf[in_offs]; + u8 *const out = &buf[out_offs]; struct shake_ctx ctx; size_t remaining_len, j, num_parts; @@ -368,16 +362,12 @@ static void test_shake_multiple_squeezes(struct kunit *test) static void test_shake_with_guarded_bufs(struct kunit *test) { const size_t max_len = 512; - u8 *reg_buf; - - KUNIT_ASSERT_GE(test, TEST_BUF_LEN, max_len); - - reg_buf = kunit_kzalloc(test, max_len, GFP_KERNEL); - KUNIT_ASSERT_NOT_NULL(test, reg_buf); + u8 *buf = alloc_guarded_buf(test, max_len); + u8 *reg_buf = alloc_buf(test, max_len); for (int alg = 0; alg < 2; alg++) { for (size_t len = 0; len <= max_len; len++) { - u8 *guarded_buf = &test_buf[TEST_BUF_LEN - len]; + u8 *guarded_buf = &buf[max_len - len]; rand_bytes(reg_buf, len); memcpy(guarded_buf, reg_buf, len); @@ -413,8 +403,6 @@ static struct kunit_case sha3_test_cases[] = { static struct kunit_suite sha3_test_suite = { .name = "sha3", .test_cases = sha3_test_cases, - .suite_init = hash_suite_init, - .suite_exit = hash_suite_exit, }; kunit_test_suite(sha3_test_suite); diff --git a/lib/crypto/tests/sha512_kunit.c b/lib/crypto/tests/sha512_kunit.c index 8923e2d7d3d4..e03926c24403 100644 --- a/lib/crypto/tests/sha512_kunit.c +++ b/lib/crypto/tests/sha512_kunit.c @@ -30,8 +30,6 @@ static struct kunit_case hash_test_cases[] = { static struct kunit_suite hash_test_suite = { .name = "sha512", .test_cases = hash_test_cases, - .suite_init = hash_suite_init, - .suite_exit = hash_suite_exit, }; kunit_test_suite(hash_test_suite); diff --git a/lib/crypto/tests/sm3_kunit.c b/lib/crypto/tests/sm3_kunit.c index dc8136acdff6..1cba384946e9 100644 --- a/lib/crypto/tests/sm3_kunit.c +++ b/lib/crypto/tests/sm3_kunit.c @@ -22,8 +22,6 @@ static struct kunit_case sm3_test_cases[] = { static struct kunit_suite sm3_test_suite = { .name = "sm3", .test_cases = sm3_test_cases, - .suite_init = hash_suite_init, - .suite_exit = hash_suite_exit, }; kunit_test_suite(sm3_test_suite); diff --git a/lib/crypto/tests/test-utils.h b/lib/crypto/tests/test-utils.h new file mode 100644 index 000000000000..73ca21f9176e --- /dev/null +++ b/lib/crypto/tests/test-utils.h @@ -0,0 +1,111 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Test utility functions shared by the crypto library tests. + * + * For now this is simply a header that's included into the KUnit test suites + * that need it. If this gets too large it could be made its own translation + * unit and libcrypto_test_utils module, but that seems overkill for now. + */ +#ifndef LIB_CRYPTO_TEST_UTILS_H +#define LIB_CRYPTO_TEST_UTILS_H + +#include <kunit/test.h> +#include <linux/math.h> +#include <linux/minmax.h> +#include <linux/string.h> +#include <linux/vmalloc.h> + +static u64 random_seed; + +static __maybe_unused void action_free_guarded_buf(void *buf) +{ + vfree(buf); +} + +/* + * Allocate a KUnit-managed buffer that has length @size bytes (> 0) immediately + * followed by an unmapped page, and assert that the allocation succeeds. + */ +static __maybe_unused void *alloc_guarded_buf(struct kunit *test, size_t size) +{ + size_t full_size = round_up(size, PAGE_SIZE); + void *buf = vmalloc(full_size); + + KUNIT_ASSERT_NOT_NULL(test, buf); + KUNIT_ASSERT_EQ(test, 0, + kunit_add_action_or_reset(test, action_free_guarded_buf, + buf)); + return buf + full_size - size; +} + +static __maybe_unused void *alloc_buf(struct kunit *test, size_t size) +{ + void *buf = kunit_kmalloc(test, size, GFP_KERNEL); + + KUNIT_ASSERT_NOT_NULL(test, buf); + return buf; +} + +static __maybe_unused void *memdup_buf(struct kunit *test, const void *src, + size_t size) +{ + void *dst = alloc_buf(test, size); + + return memcpy(dst, src, size); +} + +/* + * This is a simple linear congruential generator. It is used only for testing, + * which does not require cryptographically secure random numbers. A hard-coded + * algorithm is used instead of <linux/prandom.h> so that it matches the + * algorithm used by the test vector generation script. This allows the input + * data in random test vectors to be concisely stored as just the seed. + */ +static __maybe_unused u32 rand32(void) +{ + random_seed = (random_seed * 25214903917 + 11) & ((1ULL << 48) - 1); + return random_seed >> 16; +} + +static __maybe_unused void rand_bytes(u8 *out, size_t len) +{ + for (size_t i = 0; i < len; i++) + out[i] = rand32(); +} + +static __maybe_unused void rand_bytes_seeded_from_len(u8 *out, size_t len) +{ + random_seed = len; + rand_bytes(out, len); +} + +static __maybe_unused bool rand_bool(void) +{ + return rand32() % 2; +} + +/* Generate a random length, preferring small lengths. */ +static __maybe_unused size_t rand_length(size_t max_len) +{ + size_t len; + + switch (rand32() % 3) { + case 0: + len = rand32() % 128; + break; + case 1: + len = rand32() % 3072; + break; + default: + len = rand32(); + break; + } + return len % (max_len + 1); +} + +static __maybe_unused size_t rand_offset(size_t max_offset) +{ + return min(rand32() % 128, max_offset); +} + +#endif /* LIB_CRYPTO_TEST_UTILS_H */ |
