xref: /linux/lib/crypto/tests/aes_ccm_kunit.c (revision 2aeef50ecadca2fea0c96abed49452ff9b582b48)
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