xref: /linux/lib/crypto/tests/aes_cbc_macs_kunit.c (revision 2aeef50ecadca2fea0c96abed49452ff9b582b48)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright 2026 Google LLC
4  */
5 #include <crypto/aes-cbc-macs.h>
6 #include "aes-cmac-testvecs.h"
7 
8 /*
9  * A fixed key used when presenting AES-CMAC as an unkeyed hash function in
10  * order to reuse hash-test-template.h.  At the beginning of the test suite,
11  * this is initialized to a key prepared from bytes generated from a fixed seed.
12  */
13 static struct aes_cmac_key test_key;
14 
15 static void aes_cmac_init_withtestkey(struct aes_cmac_ctx *ctx)
16 {
17 	aes_cmac_init(ctx, &test_key);
18 }
19 
20 static void aes_cmac_withtestkey(const u8 *data, size_t data_len,
21 				 u8 out[AES_BLOCK_SIZE])
22 {
23 	aes_cmac(&test_key, data, data_len, out);
24 }
25 
26 #define HASH aes_cmac_withtestkey
27 #define HASH_CTX aes_cmac_ctx
28 #define HASH_SIZE AES_BLOCK_SIZE
29 #define HASH_INIT aes_cmac_init_withtestkey
30 #define HASH_UPDATE aes_cmac_update
31 #define HASH_FINAL aes_cmac_final
32 #include "hash-test-template.h"
33 
34 static int aes_cbc_macs_suite_init(struct kunit_suite *suite)
35 {
36 	u8 raw_key[AES_KEYSIZE_256];
37 
38 	rand_bytes_seeded_from_len(raw_key, sizeof(raw_key));
39 	return aes_cmac_preparekey(&test_key, raw_key, sizeof(raw_key));
40 }
41 
42 /* Verify compatibility of the AES-CMAC implementation with RFC 4493. */
43 static void test_aes_cmac_rfc4493(struct kunit *test)
44 {
45 	static const u8 raw_key[AES_KEYSIZE_128] = {
46 		0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
47 		0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c,
48 	};
49 	static const struct {
50 		size_t data_len;
51 		const u8 data[40];
52 		const u8 mac[AES_BLOCK_SIZE];
53 	} testvecs[] = {
54 		{
55 			/* Example 1 from RFC 4493 */
56 			.data_len = 0,
57 			.mac = {
58 				0xbb, 0x1d, 0x69, 0x29, 0xe9, 0x59, 0x37, 0x28,
59 				0x7f, 0xa3, 0x7d, 0x12, 0x9b, 0x75, 0x67, 0x46,
60 			},
61 
62 		},
63 		{
64 			/* Example 2 from RFC 4493 */
65 			.data = {
66 				0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
67 				0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
68 			},
69 			.data_len = 16,
70 			.mac = {
71 				0x07, 0x0a, 0x16, 0xb4, 0x6b, 0x4d, 0x41, 0x44,
72 				0xf7, 0x9b, 0xdd, 0x9d, 0xd0, 0x4a, 0x28, 0x7c,
73 			},
74 		},
75 		{
76 			/* Example 3 from RFC 4493 */
77 			.data = {
78 				0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
79 				0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
80 				0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c,
81 				0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
82 				0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11,
83 			},
84 			.data_len = 40,
85 			.mac = {
86 				0xdf, 0xa6, 0x67, 0x47, 0xde, 0x9a, 0xe6, 0x30,
87 				0x30, 0xca, 0x32, 0x61, 0x14, 0x97, 0xc8, 0x27,
88 			},
89 		},
90 	};
91 	struct aes_cmac_key key;
92 	int err;
93 
94 	err = aes_cmac_preparekey(&key, raw_key, sizeof(raw_key));
95 	KUNIT_ASSERT_EQ(test, err, 0);
96 
97 	for (size_t i = 0; i < ARRAY_SIZE(testvecs); i++) {
98 		u8 mac[AES_BLOCK_SIZE];
99 
100 		aes_cmac(&key, testvecs[i].data, testvecs[i].data_len, mac);
101 		KUNIT_ASSERT_MEMEQ(test, mac, testvecs[i].mac, AES_BLOCK_SIZE);
102 	}
103 }
104 
105 /*
106  * Verify compatibility of the AES-XCBC-MAC implementation with RFC 3566.
107  *
108  * Additional AES-XCBC-MAC tests are not necessary, since the AES-XCBC-MAC
109  * implementation is well covered by the AES-CMAC tests already.  Only the key
110  * preparation function differs; the rest of the code is shared.
111  */
112 static void test_aes_xcbcmac_rfc3566(struct kunit *test)
113 {
114 	struct aes_cmac_key key;
115 	/* AES-XCBC-MAC Test Case #4 from RFC 3566 */
116 	static const u8 raw_key[AES_KEYSIZE_128] = {
117 		0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
118 		0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
119 	};
120 	static const u8 message[20] = {
121 		0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
122 		0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13,
123 	};
124 	static const u8 expected_mac[AES_BLOCK_SIZE] = {
125 		0x47, 0xf5, 0x1b, 0x45, 0x64, 0x96, 0x62, 0x15,
126 		0xb8, 0x98, 0x5c, 0x63, 0x05, 0x5e, 0xd3, 0x08,
127 	};
128 	u8 actual_mac[AES_BLOCK_SIZE];
129 
130 	aes_xcbcmac_preparekey(&key, raw_key);
131 	aes_cmac(&key, message, sizeof(message), actual_mac);
132 	KUNIT_ASSERT_MEMEQ(test, actual_mac, expected_mac, AES_BLOCK_SIZE);
133 }
134 
135 static void test_aes_cbcmac_rfc3610(struct kunit *test)
136 {
137 	/*
138 	 * The following AES-CBC-MAC test vector is extracted from RFC 3610
139 	 * Packet Vector #11.  It required some rearrangement to get the actual
140 	 * input to AES-CBC-MAC from the values given.
141 	 */
142 	static const u8 raw_key[AES_KEYSIZE_128] = {
143 		0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
144 		0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
145 	};
146 	const size_t unpadded_data_len = 52;
147 	static const u8 data[64] = {
148 		/* clang-format off */
149 		/* CCM header */
150 		0x61, 0x00, 0x00, 0x00, 0x0d, 0x0c, 0x0b, 0x0a,
151 		0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0x00, 0x14,
152 		/* CCM additional authentication blocks */
153 		0x00, 0x0c, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
154 		0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x00, 0x00,
155 		/* CCM message blocks */
156 		0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13,
157 		0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
158 		0x1c, 0x1d, 0x1e, 0x1f, 0x00, 0x00, 0x00, 0x00,
159 		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
160 		/* clang-format on */
161 	};
162 	static const u8 expected_mac[AES_BLOCK_SIZE] = {
163 		0x6b, 0x5e, 0x24, 0x34, 0x12, 0xcc, 0xc2, 0xad,
164 		0x6f, 0x1b, 0x11, 0xc3, 0xa1, 0xa9, 0xd8, 0xbc,
165 	};
166 	struct aes_enckey key;
167 	struct aes_cbcmac_ctx ctx;
168 	u8 actual_mac[AES_BLOCK_SIZE];
169 	int err;
170 
171 	err = aes_prepareenckey(&key, raw_key, sizeof(raw_key));
172 	KUNIT_ASSERT_EQ(test, err, 0);
173 
174 	/*
175 	 * Trailing zeroes should not affect the CBC-MAC value, up to the next
176 	 * AES block boundary.
177 	 */
178 	for (size_t data_len = unpadded_data_len; data_len <= sizeof(data);
179 	     data_len++) {
180 		aes_cbcmac_init(&ctx, &key);
181 		aes_cbcmac_update(&ctx, data, data_len);
182 		aes_cbcmac_final(&ctx, actual_mac);
183 		KUNIT_ASSERT_MEMEQ(test, actual_mac, expected_mac,
184 				   AES_BLOCK_SIZE);
185 
186 		/* Incremental computations should produce the same result. */
187 		for (size_t part1_len = 0; part1_len <= data_len; part1_len++) {
188 			aes_cbcmac_init(&ctx, &key);
189 			aes_cbcmac_update(&ctx, data, part1_len);
190 			aes_cbcmac_update(&ctx, &data[part1_len],
191 					  data_len - part1_len);
192 			aes_cbcmac_final(&ctx, actual_mac);
193 			KUNIT_ASSERT_MEMEQ(test, actual_mac, expected_mac,
194 					   AES_BLOCK_SIZE);
195 		}
196 	}
197 }
198 
199 static struct kunit_case aes_cbc_macs_test_cases[] = {
200 	HASH_KUNIT_CASES,
201 	KUNIT_CASE(test_aes_cmac_rfc4493),
202 	KUNIT_CASE(test_aes_xcbcmac_rfc3566),
203 	KUNIT_CASE(test_aes_cbcmac_rfc3610),
204 	KUNIT_CASE(benchmark_hash),
205 	{},
206 };
207 
208 static struct kunit_suite aes_cbc_macs_test_suite = {
209 	.name = "aes_cbc_macs",
210 	.test_cases = aes_cbc_macs_test_cases,
211 	.suite_init = aes_cbc_macs_suite_init,
212 };
213 kunit_test_suite(aes_cbc_macs_test_suite);
214 
215 MODULE_DESCRIPTION(
216 	"KUnit tests and benchmark for AES-CMAC, AES-XCBC-MAC, and AES-CBC-MAC");
217 MODULE_IMPORT_NS("CRYPTO_INTERNAL");
218 MODULE_LICENSE("GPL");
219