lib/crypto: FIPS self-tests for AES encryption modes
Subsystems (2)
Eric Biggers
maintainercover lib/crypto: FIPS self-tests for AES encryption modes
Add FIPS self-tests for all the FIPS-approved AES modes implemented in aes.c. These are needed to exercise the inverse direction of the block cipher, and to prepare for the planned integration of architecture-optimized implementations of individual modes.
Eric Biggers (3):
lib/crypto: fips: Split fips.h into fips-aes.h and fips-sha.h lib/crypto: aes: Add FIPS self-tests for unauthenticated modes lib/crypto: aes: Add FIPS self-tests for GCM and CCM
lib/crypto/aes.c | 259 ++++++++++++++++++++++++++--
lib/crypto/fips-aes.h | 78 +++++++++
lib/crypto/{fips.h => fips-sha.h} | 6 +-
lib/crypto/sha1.c | 2 +-
lib/crypto/sha256.c | 2 +-
lib/crypto/sha3.c | 2 +-
lib/crypto/sha512.c | 2 +-
scripts/crypto/gen-fips-testvecs.py | 164 ++++++++++++++----
8 files changed, 459 insertions(+), 56 deletions(-)
create mode 100644 lib/crypto/fips-aes.h
rename lib/crypto/{fips.h => fips-sha.h} (90%)base-commit: 6d22ec26295c1412d765e3d687e46224fc332928
Signature · 1 line
2.55.0
Eric Biggers
maintainerPATCH 1/3 lib/crypto: fips: Split fips.h into fips-aes.h and fips-sha.h
In preparation for adding FIPS self-tests for AES encryption modes, split fips.h into separate files for the AES and SHA test vectors.
They are still generated by the same script, but this keeps things a bit more organized.
---
lib/crypto/aes.c | 2 +-
lib/crypto/fips-aes.h | 20 +++++++
lib/crypto/{fips.h => fips-sha.h} | 6 +-
lib/crypto/sha1.c | 2 +-
lib/crypto/sha256.c | 2 +-
lib/crypto/sha3.c | 2 +-
lib/crypto/sha512.c | 2 +-
scripts/crypto/gen-fips-testvecs.py | 93 +++++++++++++++++++----------
8 files changed, 88 insertions(+), 41 deletions(-)
create mode 100644 lib/crypto/fips-aes.h
rename lib/crypto/{fips.h => fips-sha.h} (90%)lib/crypto/aes.c +1 -1
@@ -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 ,
lib/crypto/fips-aes.h new file +20 -0
@@ -0,0 +1,20 @@ +/* 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_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_aes_cmac_value[]__initconst __maybe_unused = { +0xc5 ,0x88 ,0x28 ,0x55 ,0xd7 ,0x2c ,0x00 ,0xb6 , +0x6a ,0xa7 ,0xfc ,0x82 ,0x90 ,0x81 ,0xcf ,0x18 , +};
lib/crypto/fips-sha.h renamed from lib/crypto/fips.h +1 -5
@@ -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 , -};
lib/crypto/sha1.c +1 -1
@@ -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 },
lib/crypto/sha256.c +1 -1
@@ -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 = {
lib/crypto/sha3.c +1 -1
@@ -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
lib/crypto/sha512.c +1 -1
@@ -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 = {
scripts/crypto/gen-fips-testvecs.py +62 -31
104 lines not on this page · raw message
Signature · 1 line
2.55.0
Eric Biggers
maintainerPATCH 2/3 lib/crypto: aes: Add FIPS self-tests for unauthenticated modes
In reply to Eric BiggersUpcoming changes will wire up architecture-optimized implementations of ECB, CBC, CBC-CTS, CTR, and XTS. FIPS labs can consider such designs to meet the threshold for separate self-tests to be needed.
The inverse direction of the block cipher also needs to be exercised, which the existing CMAC self-test doesn't do.
Therefore, add FIPS self-tests for encryption and decryption in these modes as well as the "bare" AES.
--- lib/crypto/aes.c | 176 +++++++++++++++++++++++++++- lib/crypto/fips-aes.h | 39 ++++++ scripts/crypto/gen-fips-testvecs.py | 48 ++++++++ 3 files changed, 258 insertions(+), 5 deletions(-)
lib/crypto/aes.c +171 -5
@@ -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
@@ -797,7 +817,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 +1027,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 +1181,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 +1437,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 )/*
@@ -1905,8 +2064,15 @@ static int __init aes_mod_init(void)#ifdef aes_mod_init_archaes_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 (); + }return 0 ; }subsys_initcall (aes_mod_init);
lib/crypto/fips-aes.h +39 -0
@@ -9,12 +9,51 @@ static const u8 fips_test_data[] __initconst __maybe_unused = { 0x74, 0x20, 0x64, 0x61, 0x74, 0x61, 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 , +};
scripts/crypto/gen-fips-testvecs.py +48 -0
67 lines not on this page · raw message
Signature · 1 line
2.55.0
Eric Biggers
maintainerPATCH 3/3 lib/crypto: aes: Add FIPS self-tests for GCM and CCM
In reply to Eric BiggersUpcoming 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.
--- lib/crypto/aes.c | 81 +++++++++++++++++++++++++---- lib/crypto/fips-aes.h | 19 +++++++ scripts/crypto/gen-fips-testvecs.py | 23 ++++++++ 3 files changed, 113 insertions(+), 10 deletions(-)
lib/crypto/aes.c +71 -10
@@ -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 ; }
lib/crypto/fips-aes.h +19 -0
@@ -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 , +};
scripts/crypto/gen-fips-testvecs.py +23 -0
@@ -8,6 +8,7 @@ # Copyright 2025 Google LLC import cryptography.hazmat.primitives.ciphers +import cryptography.hazmat.primitives.ciphers.aead import cryptography.hazmat.primitives.cmac import hashlib import hmac
@@ -32,12 +33,14 @@ def print_header(file): def gen_aes_test_data(file): fips_test_data = b"fips test data\0\0" + fips_test_ad = b"fips test ad\0\0\0\0" fips_test_iv = b"fips test iv\0\0\0\0" fips_test_key = b"fips test key\0\0\0" fips_test_xts_key = b"key1" + (b"\0" * 12) + b"key2" + (b"\0" * 12) print_header(file) print_static_u8_array_definition(file, "fips_test_data", fips_test_data) + print_static_u8_array_definition(file, "fips_test_ad", fips_test_ad) print_static_u8_array_definition(file, "fips_test_iv", fips_test_iv) print_static_u8_array_definition(file, "fips_test_key", fips_test_key) print_static_u8_array_definition(file, "fips_test_xts_key", fips_test_xts_key)
@@ -93,6 +96,26 @@ def gen_aes_test_data(file): ctext = encryptor.update(fips_test_data) + encryptor.finalize() print_static_u8_array_definition(file, "fips_test_aes_xts_ctext", ctext) + # AES-GCM + cipher = cryptography.hazmat.primitives.ciphers.aead.AESGCM(fips_test_key) + ct_and_tag = cipher.encrypt( + nonce=fips_test_iv[:12], data=fips_test_data, associated_data=fips_test_ad + ) + print_static_u8_array_definition( + file, "fips_test_aes_gcm_ctext_and_tag", ct_and_tag + ) + + # AES-CCM + cipher = cryptography.hazmat.primitives.ciphers.aead.AESCCM( + fips_test_key, tag_length=16 + ) + ct_and_tag = cipher.encrypt( + nonce=fips_test_iv[:13], data=fips_test_data, associated_data=fips_test_ad + ) + print_static_u8_array_definition( + file, "fips_test_aes_ccm_ctext_and_tag", ct_and_tag + ) + def gen_sha_test_data(file): fips_test_data = b"fips test data\0\0"
Signature · 1 line
2.55.0
Quoted 10 lines · Eric Biggers
Add FIPS self-tests for all the FIPS-approved AES modes implemented in
aes.c. These are needed to exercise the inverse direction of the block cipher, and to prepare for the planned integration of architecture-optimized implementations of individual modes.Eric Biggers (3):
lib/crypto: fips: Splitfips.hintofips-aes.handfips-sha.hlib/crypto: aes: Add FIPS self-tests for unauthenticated modes lib/crypto: aes: Add FIPS self-tests for GCM and CCM
Quoted 10 lines · Eric Biggers
Add FIPS self-tests for all the FIPS-approved AES modes implemented in
aes.c. These are needed to exercise the inverse direction of the block cipher, and to prepare for the planned integration of architecture-optimized implementations of individual modes.Eric Biggers (3):
lib/crypto: fips: Splitfips.hintofips-aes.handfips-sha.hlib/crypto: aes: Add FIPS self-tests for unauthenticated modes lib/crypto: aes: Add FIPS self-tests for GCM and CCM
Quoted 11 lines
lib/crypto/aes.c | 259 ++++++++++++++++++++++++++--
lib/crypto/fips-aes.h | 78 +++++++++
lib/crypto/{fips.h => fips-sha.h} | 6 +-
lib/crypto/sha1.c | 2 +-
lib/crypto/sha256.c | 2 +-
lib/crypto/sha3.c | 2 +-
lib/crypto/sha512.c | 2 +-
scripts/crypto/gen-fips-testvecs.py | 164 ++++++++++++++----
8 files changed, 459 insertions(+), 56 deletions(-)
create mode 100644 lib/crypto/fips-aes.h
rename lib/crypto/{fips.h => fips-sha.h} (90%)Applied to https://git.kernel.org/pub/scm/linux/kernel/git/ebiggers/linux.git/log/?h=libcrypto-next
- Eric