History

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.

Eric Biggers committed 3 months ago

Commit fbdb43c1 parent e967fa93 files · +113 −10Browse files

Unified · Split

3 files
  1. lib/crypto/aes.c +71 −10
  2. lib/crypto/fips-aes.h +19 −0
  3. scripts/crypto/gen-fips-testvecs.py +23 −0
lib/crypto/aes.c+71−10
@@ -737,14 +737,7 @@ void aes_cbcmac_final(struct aes_cbcmac_ctx *ctx, u8 out[AES_BLOCK_SIZE]) · 736 unmodified lines
737}737}
738EXPORT_SYMBOL_NS_GPL(aes_cbcmac_final, "CRYPTO_INTERNAL");738EXPORT_SYMBOL_NS_GPL(aes_cbcmac_final, "CRYPTO_INTERNAL");
739 739
740/*740/* FIPS cryptographic algorithm self-test for AES-CMAC */
741 * FIPS cryptographic algorithm self-test for AES-CMAC. As per the FIPS 140-3
742 * Implementation Guidance, a cryptographic algorithm self-test for at least one
743 * of AES-GCM, AES-CCM, AES-CMAC, or AES-GMAC is required if any of those modes
744 * is implemented. This fulfills that requirement via AES-CMAC.
745 *
746 * This is just for FIPS. The full tests are in the KUnit test suite.
747 */
748static void __init aes_cmac_fips_test(void)741static void __init aes_cmac_fips_test(void)
749{742{
750 struct aes_cmac_key key;743 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, · 994 unmodified lines
1745}1738}
1746EXPORT_SYMBOL_GPL(aes_gcm_decrypt);1739EXPORT_SYMBOL_GPL(aes_gcm_decrypt);
1747 1740
1748#endif /* CONFIG_CRYPTO_LIB_AES_GCM */1741/* FIPS cryptographic algorithm self-test for AES-GCM */
1742static void __init aes_gcm_fips_test(void)
1743{
1744 const size_t data_len = sizeof(fips_test_data);
1745 u8 buf[sizeof(fips_test_data) + AES_BLOCK_SIZE];
1746 struct aes_gcm_key key;
1747 int err;
1748
1749 if (aes_gcm_preparekey(&key, fips_test_key, sizeof(fips_test_key),
1750 AES_BLOCK_SIZE) != 0)
1751 panic("aes: GCM FIPS self-test failed (preparekey)\n");
1752
1753 aes_gcm_encrypt(buf, fips_test_data, data_len, &buf[data_len],
1754 fips_test_ad, sizeof(fips_test_ad), fips_test_iv, &key);
1755 if (memcmp(fips_test_aes_gcm_ctext_and_tag, buf, sizeof(buf)) != 0)
1756 panic("aes: GCM FIPS self-test failed (wrong ciphertext and/or tag)\n");
1757
1758 err = aes_gcm_decrypt(buf, buf, data_len, &buf[data_len], fips_test_ad,
1759 sizeof(fips_test_ad), fips_test_iv, &key);
1760 if (err != 0)
1761 panic("aes: GCM FIPS self-test failed (decryption failed)\n");
1762 if (memcmp(fips_test_data, buf, data_len) != 0)
1763 panic("aes: GCM FIPS self-test failed (wrong plaintext)\n");
1764
1765 memzero_explicit(&key, sizeof(key));
1766}
1767#else /* CONFIG_CRYPTO_LIB_AES_GCM */
1768static inline void aes_gcm_fips_test(void)
1769{
1770}
1771#endif /* !CONFIG_CRYPTO_LIB_AES_GCM */
1749 1772
1750#if IS_ENABLED(CONFIG_CRYPTO_LIB_AES_CCM)1773#if IS_ENABLED(CONFIG_CRYPTO_LIB_AES_CCM)
1751int aes_ccm_preparekey(struct aes_ccm_key *key, const u8 *in_key,1774int 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, · 305 unmodified lines
2057 return err;2080 return err;
2058}2081}
2059EXPORT_SYMBOL_GPL(aes_ccm_decrypt);2082EXPORT_SYMBOL_GPL(aes_ccm_decrypt);
2060#endif /* CONFIG_CRYPTO_LIB_AES_CCM */2083
2084/* FIPS cryptographic algorithm self-test for AES-CCM */
2085static void __init aes_ccm_fips_test(void)
2086{
2087 const size_t data_len = sizeof(fips_test_data);
2088 const size_t nonce_len = 13;
2089 u8 buf[sizeof(fips_test_data) + AES_BLOCK_SIZE];
2090 struct aes_ccm_key key;
2091 int err;
2092
2093 if (aes_ccm_preparekey(&key, fips_test_key, sizeof(fips_test_key),
2094 AES_BLOCK_SIZE) != 0)
2095 panic("aes: CCM FIPS self-test failed (preparekey)\n");
2096
2097 err = aes_ccm_encrypt(buf, fips_test_data, data_len, &buf[data_len],
2098 fips_test_ad, sizeof(fips_test_ad), fips_test_iv,
2099 nonce_len, &key);
2100 if (err != 0)
2101 panic("aes: CCM FIPS self-test failed (encryption failed)\n");
2102 if (memcmp(fips_test_aes_ccm_ctext_and_tag, buf, sizeof(buf)) != 0)
2103 panic("aes: CCM FIPS self-test failed (wrong ciphertext and/or tag)\n");
2104
2105 err = aes_ccm_decrypt(buf, buf, data_len, &buf[data_len], fips_test_ad,
2106 sizeof(fips_test_ad), fips_test_iv, nonce_len,
2107 &key);
2108 if (err != 0)
2109 panic("aes: CCM FIPS self-test failed (decryption failed)\n");
2110 if (memcmp(fips_test_data, buf, data_len) != 0)
2111 panic("aes: CCM FIPS self-test failed (wrong plaintext)\n");
2112
2113 memzero_explicit(&key, sizeof(key));
2114}
2115#else /* CONFIG_CRYPTO_LIB_AES_CCM */
2116static inline void aes_ccm_fips_test(void)
2117{
2118}
2119#endif /* !CONFIG_CRYPTO_LIB_AES_CCM */
2061 2120
2062static int __init aes_mod_init(void)2121static int __init aes_mod_init(void)
2063{2122{
@@ -2072,6 +2131,8 @@ static int __init aes_mod_init(void) · 8 unmodified lines
2072 aes_cbc_cts_fips_test();2131 aes_cbc_cts_fips_test();
2073 aes_ctr_fips_test();2132 aes_ctr_fips_test();
2074 aes_xts_fips_test();2133 aes_xts_fips_test();
2134 aes_gcm_fips_test();
2135 aes_ccm_fips_test();
2075 }2136 }
2076 return 0;2137 return 0;
2077}2138}
lib/crypto/fips-aes.h+19−0
@@ -9,6 +9,11 @@ static const u8 fips_test_data[] __initconst __maybe_unused = { · 8 unmodified lines
9 0x74, 0x20, 0x64, 0x61, 0x74, 0x61, 0x00, 0x00,9 0x74, 0x20, 0x64, 0x61, 0x74, 0x61, 0x00, 0x00,
10};10};
11 11
12static const u8 fips_test_ad[] __initconst __maybe_unused = {
13 0x66, 0x69, 0x70, 0x73, 0x20, 0x74, 0x65, 0x73,
14 0x74, 0x20, 0x61, 0x64, 0x00, 0x00, 0x00, 0x00,
15};
16
12static const u8 fips_test_iv[] __initconst __maybe_unused = {17static const u8 fips_test_iv[] __initconst __maybe_unused = {
13 0x66, 0x69, 0x70, 0x73, 0x20, 0x74, 0x65, 0x73,18 0x66, 0x69, 0x70, 0x73, 0x20, 0x74, 0x65, 0x73,
14 0x74, 0x20, 0x69, 0x76, 0x00, 0x00, 0x00, 0x00,19 0x74, 0x20, 0x69, 0x76, 0x00, 0x00, 0x00, 0x00,
@@ -57,3 +62,17 @@ static const u8 fips_test_aes_xts_ctext[] __initconst __maybe_unused = { · 42 unmodified lines
57 0xd4, 0x51, 0x7f, 0x01, 0x14, 0x91, 0x16, 0x29,62 0xd4, 0x51, 0x7f, 0x01, 0x14, 0x91, 0x16, 0x29,
58 0x26, 0xbe, 0xec, 0x9b, 0x90, 0xed, 0x59, 0x30,63 0x26, 0xbe, 0xec, 0x9b, 0x90, 0xed, 0x59, 0x30,
59};64};
65
66static const u8 fips_test_aes_gcm_ctext_and_tag[] __initconst __maybe_unused = {
67 0x12, 0x0c, 0x5d, 0x03, 0x32, 0x93, 0x13, 0x44,
68 0x06, 0x35, 0x26, 0x9d, 0xe0, 0xea, 0xbc, 0xe2,
69 0x30, 0xa9, 0xa4, 0x15, 0xc5, 0x3d, 0xb3, 0xf9,
70 0x30, 0x82, 0xdf, 0x9c, 0xd8, 0xc4, 0x3f, 0x2f,
71};
72
73static const u8 fips_test_aes_ccm_ctext_and_tag[] __initconst __maybe_unused = {
74 0x11, 0x8e, 0x01, 0xcb, 0xb5, 0x22, 0x6d, 0xb4,
75 0x66, 0x98, 0x97, 0x1d, 0x35, 0x53, 0x78, 0xdd,
76 0xd1, 0xc5, 0xff, 0xb6, 0x90, 0xcf, 0xb1, 0xf2,
77 0x87, 0x99, 0xd6, 0x1e, 0xd5, 0xd1, 0xed, 0x63,
78};
scripts/crypto/gen-fips-testvecs.py+23−0
@@ -8,6 +8,7 @@ · 7 unmodified lines
8# Copyright 2025 Google LLC8# Copyright 2025 Google LLC
9 9
10import cryptography.hazmat.primitives.ciphers10import cryptography.hazmat.primitives.ciphers
11import cryptography.hazmat.primitives.ciphers.aead
11import cryptography.hazmat.primitives.cmac12import cryptography.hazmat.primitives.cmac
12import hashlib13import hashlib
13import hmac14import hmac
@@ -32,12 +33,14 @@ def print_header(file): · 18 unmodified lines
32 33
33def gen_aes_test_data(file):34def gen_aes_test_data(file):
34 fips_test_data = b"fips test data\0\0"35 fips_test_data = b"fips test data\0\0"
36 fips_test_ad = b"fips test ad\0\0\0\0"
35 fips_test_iv = b"fips test iv\0\0\0\0"37 fips_test_iv = b"fips test iv\0\0\0\0"
36 fips_test_key = b"fips test key\0\0\0"38 fips_test_key = b"fips test key\0\0\0"
37 fips_test_xts_key = b"key1" + (b"\0" * 12) + b"key2" + (b"\0" * 12)39 fips_test_xts_key = b"key1" + (b"\0" * 12) + b"key2" + (b"\0" * 12)
38 40
39 print_header(file)41 print_header(file)
40 print_static_u8_array_definition(file, "fips_test_data", fips_test_data)42 print_static_u8_array_definition(file, "fips_test_data", fips_test_data)
43 print_static_u8_array_definition(file, "fips_test_ad", fips_test_ad)
41 print_static_u8_array_definition(file, "fips_test_iv", fips_test_iv)44 print_static_u8_array_definition(file, "fips_test_iv", fips_test_iv)
42 print_static_u8_array_definition(file, "fips_test_key", fips_test_key)45 print_static_u8_array_definition(file, "fips_test_key", fips_test_key)
43 print_static_u8_array_definition(file, "fips_test_xts_key", fips_test_xts_key)46 print_static_u8_array_definition(file, "fips_test_xts_key", fips_test_xts_key)
@@ -93,6 +96,26 @@ def gen_aes_test_data(file): · 49 unmodified lines
93 ctext = encryptor.update(fips_test_data) + encryptor.finalize()96 ctext = encryptor.update(fips_test_data) + encryptor.finalize()
94 print_static_u8_array_definition(file, "fips_test_aes_xts_ctext", ctext)97 print_static_u8_array_definition(file, "fips_test_aes_xts_ctext", ctext)
95 98
99 # AES-GCM
100 cipher = cryptography.hazmat.primitives.ciphers.aead.AESGCM(fips_test_key)
101 ct_and_tag = cipher.encrypt(
102 nonce=fips_test_iv[:12], data=fips_test_data, associated_data=fips_test_ad
103 )
104 print_static_u8_array_definition(
105 file, "fips_test_aes_gcm_ctext_and_tag", ct_and_tag
106 )
107
108 # AES-CCM
109 cipher = cryptography.hazmat.primitives.ciphers.aead.AESCCM(
110 fips_test_key, tag_length=16
111 )
112 ct_and_tag = cipher.encrypt(
113 nonce=fips_test_iv[:13], data=fips_test_data, associated_data=fips_test_ad
114 )
115 print_static_u8_array_definition(
116 file, "fips_test_aes_ccm_ctext_and_tag", ct_and_tag
117 )
118
96 119
97def gen_sha_test_data(file):120def gen_sha_test_data(file):
98 fips_test_data = b"fips test data\0\0"121 fips_test_data = b"fips test data\0\0"