diff options
| author | Eric Biggers <ebiggers@kernel.org> | 2026-08-02 15:24:08 -0700 |
|---|---|---|
| committer | Eric Biggers <ebiggers@kernel.org> | 2026-08-10 20:17:56 -0700 |
| commit | fbdb43c0007b37e574fa0ca76afd13bed96db8f6 (patch) | |
| tree | fafe26a7c50c3bbabc245b28f7c3d7375a1ee9aa /lib | |
| parent | e967fa98f7618e98b50b3d49a1768deba8981a98 (diff) | |
lib/crypto: aes: Add FIPS self-tests for GCM and CCM
Upcoming changes will wire up architecture-optimized implementations of
GCM and CCM. FIPS labs can consider such designs to meet the threshold
for separate self-tests to be needed.
Therefore, add FIPS self-tests for encryption and decryption in these
modes.
Reviewed-by: Ard Biesheuvel <ardb@kernel.org>
Link: https://patch.msgid.link/20260802222408.91757-4-ebiggers@kernel.org
Signed-off-by: Eric Biggers <ebiggers@kernel.org>
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/crypto/aes.c | 81 | ||||
| -rw-r--r-- | lib/crypto/fips-aes.h | 19 |
2 files changed, 90 insertions, 10 deletions
diff --git a/lib/crypto/aes.c b/lib/crypto/aes.c index e9119f82b0cc..41aaa82cb1a1 100644 --- a/lib/crypto/aes.c +++ b/lib/crypto/aes.c @@ -737,14 +737,7 @@ 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; @@ -1745,7 +1738,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, @@ -2057,7 +2080,43 @@ 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) { @@ -2072,6 +2131,8 @@ static int __init aes_mod_init(void) aes_cbc_cts_fips_test(); aes_ctr_fips_test(); aes_xts_fips_test(); + aes_gcm_fips_test(); + aes_ccm_fips_test(); } return 0; } diff --git a/lib/crypto/fips-aes.h b/lib/crypto/fips-aes.h index cfacf5d98e07..2a1746606533 100644 --- a/lib/crypto/fips-aes.h +++ b/lib/crypto/fips-aes.h @@ -9,6 +9,11 @@ static const u8 fips_test_data[] __initconst __maybe_unused = { 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, @@ -57,3 +62,17 @@ 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, +}; |
