1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * KUnit test suite for AES-CCM 4 * 5 * Copyright 2026 Google LLC 6 */ 7 #include <crypto/aes-ccm.h> 8 #include <crypto/blake2s.h> 9 #include "test-utils.h" 10 11 /* AES-CCM test vectors from external sources */ 12 static const struct aes_ccm_testvec { 13 const char *name; 14 const char *key; 15 size_t key_len; 16 const char *nonce; 17 size_t nonce_len; 18 const char *ad; 19 size_t ad_len; 20 const char *ptext; 21 const char *ctext; 22 size_t data_len; 23 const char *tag; 24 size_t tag_len; 25 } aes_ccm_testvecs[] = { 26 { 27 .name = "RFC 3610 Packet Vector #1", 28 .key = "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7" 29 "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf", 30 .key_len = 16, 31 .nonce = "\x00\x00\x00\x03\x02\x01\x00\xa0" 32 "\xa1\xa2\xa3\xa4\xa5", 33 .nonce_len = 13, 34 .ad = "\x00\x01\x02\x03\x04\x05\x06\x07", 35 .ad_len = 8, 36 .ptext = "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" 37 "\x10\x11\x12\x13\x14\x15\x16\x17" 38 "\x18\x19\x1a\x1b\x1c\x1d\x1e", 39 .ctext = "\x58\x8c\x97\x9a\x61\xc6\x63\xd2" 40 "\xf0\x66\xd0\xc2\xc0\xf9\x89\x80" 41 "\x6d\x5f\x6b\x61\xda\xc3\x84", 42 .data_len = 23, 43 .tag = "\x17\xe8\xd1\x2c\xfd\xf9\x26\xe0", 44 .tag_len = 8, 45 }, 46 { 47 .name = "RFC 3610 Packet Vector #5", 48 .key = "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7" 49 "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf", 50 .key_len = 16, 51 .nonce = "\x00\x00\x00\x07\x06\x05\x04\xa0" 52 "\xa1\xa2\xa3\xa4\xa5", 53 .nonce_len = 13, 54 .ad = "\x00\x01\x02\x03\x04\x05\x06\x07" 55 "\x08\x09\x0a\x0b", 56 .ad_len = 12, 57 .ptext = "\x0c\x0d\x0e\x0f\x10\x11\x12\x13" 58 "\x14\x15\x16\x17\x18\x19\x1a\x1b" 59 "\x1c\x1d\x1e\x1f", 60 .ctext = "\xdc\xf1\xfb\x7b\x5d\x9e\x23\xfb" 61 "\x9d\x4e\x13\x12\x53\x65\x8a\xd8" 62 "\x6e\xbd\xca\x3e", 63 .data_len = 20, 64 .tag = "\x51\xe8\x3f\x07\x7d\x9c\x2d\x93", 65 .tag_len = 8, 66 }, 67 { 68 .name = "RFC 3610 Packet Vector #9", 69 .key = "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7" 70 "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf", 71 .key_len = 16, 72 .nonce = "\x00\x00\x00\x0b\x0a\x09\x08\xa0" 73 "\xa1\xa2\xa3\xa4\xa5", 74 .nonce_len = 13, 75 .ad = "\x00\x01\x02\x03\x04\x05\x06\x07", 76 .ad_len = 8, 77 .ptext = "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" 78 "\x10\x11\x12\x13\x14\x15\x16\x17" 79 "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" 80 "\x20", 81 .ctext = "\x82\x53\x1a\x60\xcc\x24\x94\x5a" 82 "\x4b\x82\x79\x18\x1a\xb5\xc8\x4d" 83 "\xf2\x1c\xe7\xf9\xb7\x3f\x42\xe1" 84 "\x97", 85 .data_len = 25, 86 .tag = "\xea\x9c\x07\xe5\x6b\x5e\xb1\x7e" 87 "\x5f\x4e", 88 .tag_len = 10, 89 }, 90 { 91 .name = "NIST SP 800-38C Example 1", 92 .key = "\x40\x41\x42\x43\x44\x45\x46\x47" 93 "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f", 94 .key_len = 16, 95 .nonce = "\x10\x11\x12\x13\x14\x15\x16", 96 .nonce_len = 7, 97 .ad = "\x00\x01\x02\x03\x04\x05\x06\x07", 98 .ad_len = 8, 99 .ptext = "\x20\x21\x22\x23", 100 .ctext = "\x71\x62\x01\x5b", 101 .data_len = 4, 102 .tag = "\x4d\xac\x25\x5d", 103 .tag_len = 4, 104 }, 105 { 106 .name = "NIST SP 800-38C Example 2", 107 .key = "\x40\x41\x42\x43\x44\x45\x46\x47" 108 "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f", 109 .key_len = 16, 110 .nonce = "\x10\x11\x12\x13\x14\x15\x16\x17", 111 .nonce_len = 8, 112 .ad = "\x00\x01\x02\x03\x04\x05\x06\x07" 113 "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", 114 .ad_len = 16, 115 .ptext = "\x20\x21\x22\x23\x24\x25\x26\x27" 116 "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f", 117 .ctext = "\xd2\xa1\xf0\xe0\x51\xea\x5f\x62" 118 "\x08\x1a\x77\x92\x07\x3d\x59\x3d", 119 .data_len = 16, 120 .tag = "\x1f\xc6\x4f\xbf\xac\xcd", 121 .tag_len = 6, 122 }, 123 { 124 .name = "NIST SP 800-38C Example 3", 125 .key = "\x40\x41\x42\x43\x44\x45\x46\x47" 126 "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f", 127 .key_len = 16, 128 .nonce = "\x10\x11\x12\x13\x14\x15\x16\x17" 129 "\x18\x19\x1a\x1b", 130 .nonce_len = 12, 131 .ad = "\x00\x01\x02\x03\x04\x05\x06\x07" 132 "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" 133 "\x10\x11\x12\x13", 134 .ad_len = 20, 135 .ptext = "\x20\x21\x22\x23\x24\x25\x26\x27" 136 "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f" 137 "\x30\x31\x32\x33\x34\x35\x36\x37", 138 .ctext = "\xe3\xb2\x01\xa9\xf5\xb7\x1a\x7a" 139 "\x9b\x1c\xea\xec\xcd\x97\xe7\x0b" 140 "\x61\x76\xaa\xd9\xa4\x42\x8a\xa5", 141 .data_len = 24, 142 .tag = "\x48\x43\x92\xfb\xc1\xb0\x99\x51", 143 .tag_len = 8, 144 }, 145 }; 146 147 static void test_aes_ccm_one_test_vector(struct kunit *test, 148 const struct aes_ccm_testvec *tv) 149 { 150 u8 *ctext = alloc_buf(test, tv->data_len); 151 u8 *decrypted = alloc_buf(test, tv->data_len); 152 u8 *tag = alloc_buf(test, tv->tag_len); 153 struct aes_ccm_key key; 154 int err; 155 156 err = aes_ccm_preparekey(&key, tv->key, tv->key_len, tv->tag_len); 157 KUNIT_ASSERT_EQ_MSG(test, 0, err, "Failed to prepare key for %s", 158 tv->name); 159 160 err = aes_ccm_encrypt(ctext, tv->ptext, tv->data_len, tag, tv->ad, 161 tv->ad_len, tv->nonce, tv->nonce_len, &key); 162 KUNIT_ASSERT_EQ_MSG(test, 0, err, "Encryption failed for %s", tv->name); 163 KUNIT_ASSERT_MEMEQ_MSG(test, tv->ctext, ctext, tv->data_len, 164 "Wrong ciphertext for %s", tv->name); 165 KUNIT_ASSERT_MEMEQ_MSG(test, tag, tv->tag, tv->tag_len, 166 "Wrong tag for %s", tv->name); 167 168 err = aes_ccm_decrypt(decrypted, ctext, tv->data_len, tag, tv->ad, 169 tv->ad_len, tv->nonce, tv->nonce_len, &key); 170 KUNIT_ASSERT_EQ_MSG(test, 0, err, "Decryption failed for %s", tv->name); 171 KUNIT_ASSERT_MEMEQ_MSG(test, tv->ptext, decrypted, tv->data_len, 172 "Wrong plaintext for %s", tv->name); 173 } 174 175 static void test_aes_ccm_test_vectors(struct kunit *test) 176 { 177 for (size_t i = 0; i < ARRAY_SIZE(aes_ccm_testvecs); i++) 178 test_aes_ccm_one_test_vector(test, &aes_ccm_testvecs[i]); 179 } 180 181 /* 182 * Test NIST SP 800-38C Example 4, which uses a deterministically-generated 183 * 65536-byte associated data string. 184 */ 185 static void test_aes_ccm_nist_sp800_38c_example4(struct kunit *test) 186 { 187 struct aes_ccm_testvec tv = { 188 .name = "NIST SP 800-38C Example 4", 189 .key_len = 16, 190 .nonce_len = 13, 191 .ad_len = 65536, 192 .ctext = "\x69\x91\x5d\xad\x1e\x84\xc6\x37" 193 "\x6a\x68\xc2\x96\x7e\x4d\xab\x61" 194 "\x5a\xe0\xfd\x1f\xae\xc4\x4c\xc4" 195 "\x84\x82\x85\x29\x46\x3c\xcf\x72", 196 .data_len = 32, 197 .tag = "\xb4\xac\x6b\xec\x93\xe8\x59\x8e" 198 "\x7f\x0d\xad\xbc\xea\x5b", 199 .tag_len = 14, 200 }; 201 u8 *key, *nonce, *ad, *ptext; 202 203 key = alloc_buf(test, tv.key_len); 204 for (size_t i = 0; i < tv.key_len; i++) 205 key[i] = 0x40 + i; 206 207 nonce = alloc_guarded_buf(test, tv.nonce_len); 208 for (size_t i = 0; i < tv.nonce_len; i++) 209 nonce[i] = 0x10 + i; 210 211 ad = alloc_guarded_buf(test, tv.ad_len); 212 for (size_t i = 0; i < tv.ad_len; i++) 213 ad[i] = (u8)i; 214 215 ptext = alloc_guarded_buf(test, tv.data_len); 216 for (size_t i = 0; i < tv.data_len; i++) 217 ptext[i] = 0x20 + i; 218 219 tv.key = key; 220 tv.nonce = nonce; 221 tv.ad = ad; 222 tv.ptext = ptext; 223 224 test_aes_ccm_one_test_vector(test, &tv); 225 } 226 227 static const size_t aes_ccm_valid_key_lens[] = { 16, 24, 32 }; 228 #define AEAD_MAX_KEY_LEN 32 229 #define AEAD_VALID_KEY_LENS aes_ccm_valid_key_lens 230 231 static const size_t aes_ccm_valid_nonce_lens[] = { 7, 8, 9, 10, 11, 12, 13 }; 232 #define AEAD_MAX_NONCE_LEN 13 233 #define AEAD_VALID_NONCE_LENS aes_ccm_valid_nonce_lens 234 235 static const size_t aes_ccm_valid_tag_lens[] = { 4, 6, 8, 10, 12, 14, 16 }; 236 #define AEAD_MAX_TAG_LEN 16 237 #define AEAD_VALID_TAG_LENS aes_ccm_valid_tag_lens 238 239 #define AEAD_KEY aes_ccm_key 240 #define AEAD_CTX aes_ccm_ctx 241 #define AEAD_PREPAREKEY aes_ccm_preparekey 242 #define AEAD_ENCRYPT aes_ccm_encrypt 243 #define AEAD_DECRYPT aes_ccm_decrypt 244 245 #define AEAD_INIT aes_ccm_init 246 #define AEAD_AUTH_UPDATE aes_ccm_auth_update 247 #define AEAD_ENCRYPT_UPDATE aes_ccm_encrypt_update 248 #define AEAD_DECRYPT_UPDATE aes_ccm_decrypt_update 249 #define AEAD_ENCRYPT_FINAL aes_ccm_encrypt_final 250 #define AEAD_DECRYPT_FINAL aes_ccm_decrypt_final 251 252 /* This value was generated by gen-aead-testvecs.py. */ 253 static const u8 aes_ccm_monte_carlo_checksum[BLAKE2S_HASH_SIZE] = { 254 0x70, 0x1c, 0xde, 0xa4, 0xe2, 0x03, 0x50, 0xb2, 0xf5, 0x9e, 0x61, 255 0x66, 0xe4, 0xe5, 0x13, 0x1a, 0x00, 0x95, 0x34, 0x03, 0xb7, 0x61, 256 0x2c, 0xdb, 0xc3, 0x15, 0x36, 0x84, 0x93, 0x7f, 0xb4, 0x5b, 257 }; 258 #define AEAD_MONTE_CARLO_CHECKSUM aes_ccm_monte_carlo_checksum 259 260 #include "aead-test-template.h" 261 262 /* 263 * Test that for each AES-CCM nonce length, the message length is validated 264 * against the correct corresponding maximum message length. 265 */ 266 static void test_aes_ccm_data_len_too_large(struct kunit *test) 267 { 268 static const struct { 269 size_t nonce_len; 270 u64 max_data_len; 271 } lens[] = { 272 /* clang-format off */ 273 { 7, 0xffffffffffffffff }, /* U64_MAX */ 274 { 8, 0xffffffffffffff }, 275 { 9, 0xffffffffffff }, 276 { 10, 0xffffffffff }, 277 { 11, 0xffffffff }, 278 { 12, 0xffffff }, 279 { 13, 0xffff }, 280 /* clang-format on */ 281 }; 282 u8 nonce[13] = {}; 283 u8 raw_key[AES_KEYSIZE_256] = {}; 284 int err; 285 struct aes_ccm_key *key = alloc_buf(test, sizeof(*key)); 286 struct aes_ccm_ctx ctx; 287 288 err = aes_ccm_preparekey(key, raw_key, sizeof(raw_key), 16); 289 KUNIT_ASSERT_EQ(test, 0, err); 290 291 for (size_t i = 0; i < ARRAY_SIZE(lens); i++) { 292 size_t nonce_len = lens[i].nonce_len; 293 u64 max_data_len = lens[i].max_data_len; 294 295 /* data_len <= max_data_len should be accepted. */ 296 err = aes_ccm_init(&ctx, 0, 0, nonce, nonce_len, key); 297 KUNIT_ASSERT_EQ_MSG( 298 test, 0, err, 299 "data_len=0 wasn't accepted with nonce_len=%zu", 300 nonce_len); 301 err = aes_ccm_init(&ctx, max_data_len, 0, nonce, nonce_len, 302 key); 303 KUNIT_ASSERT_EQ_MSG( 304 test, 0, err, 305 "data_len=%llu wasn't accepted with nonce_len=%zu", 306 max_data_len, nonce_len); 307 308 /* data_len > max_data_len should be rejected. */ 309 if (max_data_len == U64_MAX) 310 continue; 311 err = aes_ccm_init(&ctx, max_data_len + 1, 0, nonce, nonce_len, 312 key); 313 KUNIT_ASSERT_EQ_MSG( 314 test, -EOVERFLOW, err, 315 "data_len=%llu wasn't rejected with -EOVERFLOW with nonce_len=%zu (aes_ccm_init)", 316 max_data_len + 1, nonce_len); 317 if (max_data_len + 1 <= SIZE_MAX) { 318 err = aes_ccm_encrypt(NULL, NULL, max_data_len + 1, 319 NULL, NULL, 0, nonce, nonce_len, 320 key); 321 KUNIT_ASSERT_EQ_MSG( 322 test, -EOVERFLOW, err, 323 "data_len=%llu wasn't rejected with -EOVERFLOW with nonce_len=%zu (aes_ccm_encrypt)", 324 max_data_len + 1, nonce_len); 325 err = aes_ccm_decrypt(NULL, NULL, max_data_len + 1, 326 NULL, NULL, 0, nonce, nonce_len, 327 key); 328 KUNIT_ASSERT_EQ_MSG( 329 test, -EOVERFLOW, err, 330 "data_len=%llu wasn't rejected with -EOVERFLOW with nonce_len=%zu (aes_ccm_decrypt)", 331 max_data_len + 1, nonce_len); 332 } 333 err = aes_ccm_init(&ctx, U64_MAX, 0, nonce, nonce_len, key); 334 KUNIT_ASSERT_EQ_MSG( 335 test, -EOVERFLOW, err, 336 "data_len=U64_MAX wasn't rejected with -EOVERFLOW with nonce_len=%zu (aes_ccm_init)", 337 nonce_len); 338 } 339 } 340 341 static struct kunit_case aes_ccm_test_cases[] = { 342 KUNIT_CASE(test_aes_ccm_test_vectors), 343 KUNIT_CASE(test_aes_ccm_nist_sp800_38c_example4), 344 KUNIT_CASE(test_aes_ccm_data_len_too_large), 345 AEAD_KUNIT_CASES, 346 {}, 347 }; 348 349 static struct kunit_suite aes_ccm_test_suite = { 350 .name = "aes_ccm", 351 .test_cases = aes_ccm_test_cases, 352 }; 353 kunit_test_suite(aes_ccm_test_suite); 354 355 MODULE_DESCRIPTION("KUnit tests and benchmark for AES-CCM"); 356 MODULE_LICENSE("GPL"); 357