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.
Unified · Split
| @@ -737,14 +737,7 @@ void aes_cbcmac_final(struct aes_cbcmac_ctx *ctx, u8 out[AES_BLOCK_SIZE]) · 736 unmodified lines | |||
| 737 | } | 737 | } |
| 738 | EXPORT_SYMBOL_NS_GPL(aes_cbcmac_final, "CRYPTO_INTERNAL"); | 738 | EXPORT_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 | */ | ||
| 748 | static void __init aes_cmac_fips_test(void) | 741 | static 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 | } |
| 1746 | EXPORT_SYMBOL_GPL(aes_gcm_decrypt); | 1739 | EXPORT_SYMBOL_GPL(aes_gcm_decrypt); |
| 1747 | 1740 | ||
| 1748 | #endif /* CONFIG_CRYPTO_LIB_AES_GCM */ | 1741 | /* FIPS cryptographic algorithm self-test for AES-GCM */ |
| 1742 | static 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 */ | ||
| 1768 | static 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) |
| 1751 | int aes_ccm_preparekey(struct aes_ccm_key *key, const u8 *in_key, | 1774 | 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, · 305 unmodified lines | |||
| 2057 | return err; | 2080 | return err; |
| 2058 | } | 2081 | } |
| 2059 | EXPORT_SYMBOL_GPL(aes_ccm_decrypt); | 2082 | EXPORT_SYMBOL_GPL(aes_ccm_decrypt); |
| 2060 | #endif /* CONFIG_CRYPTO_LIB_AES_CCM */ | 2083 | |
| 2084 | /* FIPS cryptographic algorithm self-test for AES-CCM */ | ||
| 2085 | static 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 */ | ||
| 2116 | static inline void aes_ccm_fips_test(void) | ||
| 2117 | { | ||
| 2118 | } | ||
| 2119 | #endif /* !CONFIG_CRYPTO_LIB_AES_CCM */ | ||
| 2061 | 2120 | ||
| 2062 | static int __init aes_mod_init(void) | 2121 | static 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 | } |
| @@ -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 | ||
| 12 | static 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 | |||
| 12 | static const u8 fips_test_iv[] __initconst __maybe_unused = { | 17 | static 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 | |||
| 66 | static 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 | |||
| 73 | static 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 | }; | ||
| @@ -8,6 +8,7 @@ · 7 unmodified lines | |||
| 8 | # Copyright 2025 Google LLC | 8 | # Copyright 2025 Google LLC |
| 9 | 9 | ||
| 10 | import cryptography.hazmat.primitives.ciphers | 10 | import cryptography.hazmat.primitives.ciphers |
| 11 | import cryptography.hazmat.primitives.ciphers.aead | ||
| 11 | import cryptography.hazmat.primitives.cmac | 12 | import cryptography.hazmat.primitives.cmac |
| 12 | import hashlib | 13 | import hashlib |
| 13 | import hmac | 14 | import hmac |
| @@ -32,12 +33,14 @@ def print_header(file): · 18 unmodified lines | |||
| 32 | 33 | ||
| 33 | def gen_aes_test_data(file): | 34 | def 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 | ||
| 97 | def gen_sha_test_data(file): | 120 | def 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" |