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