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