blob: 894aa743b2386b0fef6bcdcbba6358ade134a0a2 [file] [log] [blame]
b.liue9582032025-04-17 19:18:16 +08001/*
2 * CTR with CBC-MAC Protocol (CCMP)
3 * Copyright (c) 2010-2012, Jouni Malinen <j@w1.fi>
4 *
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
7 */
8
9#include "utils/includes.h"
10
11#include "utils/common.h"
12#include "common/ieee802_11_defs.h"
13#include "crypto/aes.h"
14#include "crypto/aes_wrap.h"
15#include "wlantest.h"
16
17
18static void ccmp_aad_nonce(const struct ieee80211_hdr *hdr, const u8 *data,
19 const u8 *a1, const u8 *a2, const u8 *a3,
20 u8 *aad, size_t *aad_len, u8 *nonce)
21{
22 u16 fc, stype, seq;
23 int qos = 0, addr4 = 0;
24 u8 *pos;
25
26 nonce[0] = 0;
27
28 fc = le_to_host16(hdr->frame_control);
29 stype = WLAN_FC_GET_STYPE(fc);
30 if ((fc & (WLAN_FC_TODS | WLAN_FC_FROMDS)) ==
31 (WLAN_FC_TODS | WLAN_FC_FROMDS))
32 addr4 = 1;
33
34 if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_DATA) {
35 fc &= ~0x0070; /* Mask subtype bits */
36 if (stype & 0x08) {
37 const u8 *qc;
38 qos = 1;
39 fc &= ~WLAN_FC_HTC;
40 qc = (const u8 *) (hdr + 1);
41 if (addr4)
42 qc += ETH_ALEN;
43 nonce[0] = qc[0] & 0x0f;
44 }
45 } else if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT)
46 nonce[0] |= 0x10; /* Management */
47
48 fc &= ~(WLAN_FC_RETRY | WLAN_FC_PWRMGT | WLAN_FC_MOREDATA);
49 fc |= WLAN_FC_ISWEP;
50 WPA_PUT_LE16(aad, fc);
51 pos = aad + 2;
52 os_memcpy(pos, hdr->addr1, 3 * ETH_ALEN);
53 if (a1)
54 os_memcpy(pos, a1, ETH_ALEN);
55 if (a2)
56 os_memcpy(pos + ETH_ALEN, a2, ETH_ALEN);
57 if (a3)
58 os_memcpy(pos + 2 * ETH_ALEN, a3, ETH_ALEN);
59 pos += 3 * ETH_ALEN;
60 seq = le_to_host16(hdr->seq_ctrl);
61 seq &= ~0xfff0; /* Mask Seq#; do not modify Frag# */
62 WPA_PUT_LE16(pos, seq);
63 pos += 2;
64
65 os_memcpy(pos, hdr + 1, addr4 * ETH_ALEN + qos * 2);
66 pos += addr4 * ETH_ALEN;
67 if (qos) {
68 pos[0] &= ~0x70;
69 if (1 /* FIX: either device has SPP A-MSDU Capab = 0 */)
70 pos[0] &= ~0x80;
71 pos++;
72 *pos++ = 0x00;
73 }
74
75 *aad_len = pos - aad;
76
77 if (a2)
78 os_memcpy(nonce + 1, a2, ETH_ALEN);
79 else
80 os_memcpy(nonce + 1, hdr->addr2, ETH_ALEN);
81 nonce[7] = data[7]; /* PN5 */
82 nonce[8] = data[6]; /* PN4 */
83 nonce[9] = data[5]; /* PN3 */
84 nonce[10] = data[4]; /* PN2 */
85 nonce[11] = data[1]; /* PN1 */
86 nonce[12] = data[0]; /* PN0 */
87}
88
89
90static void ccmp_aad_nonce_pv1(const u8 *hdr, const u8 *a1, const u8 *a2,
91 const u8 *a3, const u8 *pn,
92 u8 *aad, size_t *aad_len, u8 *nonce)
93{
94 u16 fc, type;
95 u8 *pos;
96
97 nonce[0] = BIT(5); /* PV1 */
98 /* TODO: Priority for QMF; 0 is used for Data frames */
99
100 fc = WPA_GET_LE16(hdr);
101 type = (fc & (BIT(2) | BIT(3) | BIT(4))) >> 2;
102
103 if (type == 1)
104 nonce[0] |= 0x10; /* Management */
105
106 fc &= ~(BIT(10) | BIT(11) | BIT(13) | BIT(14) | BIT(15));
107 fc |= BIT(12);
108 WPA_PUT_LE16(aad, fc);
109 pos = aad + 2;
110 if (type == 0 || type == 3) {
111 const u8 *sc;
112
113 os_memcpy(pos, a1, ETH_ALEN);
114 pos += ETH_ALEN;
115 os_memcpy(pos, a2, ETH_ALEN);
116 pos += ETH_ALEN;
117
118 if (type == 0) {
119 /* Either A1 or A2 contains SID */
120 sc = hdr + 2 + 2 + ETH_ALEN;
121 } else {
122 /* Both A1 and A2 contain full addresses */
123 sc = hdr + 2 + 2 * ETH_ALEN;
124 }
125 /* SC with Sequence Number subfield (bits 4-15 of the Sequence
126 * Control field) masked to 0. */
127 *pos++ = *sc & 0x0f;
128 *pos++ = 0;
129
130 if (a3) {
131 os_memcpy(pos, a3, ETH_ALEN);
132 pos += ETH_ALEN;
133 }
134 }
135
136 *aad_len = pos - aad;
137
138 os_memcpy(nonce + 1, a2, ETH_ALEN);
139 nonce[7] = pn[5]; /* PN5 */
140 nonce[8] = pn[4]; /* PN4 */
141 nonce[9] = pn[3]; /* PN3 */
142 nonce[10] = pn[2]; /* PN2 */
143 nonce[11] = pn[1]; /* PN1 */
144 nonce[12] = pn[0]; /* PN0 */
145}
146
147
148u8 * ccmp_decrypt(const u8 *tk, const struct ieee80211_hdr *hdr,
149 const u8 *a1, const u8 *a2, const u8 *a3,
150 const u8 *data, size_t data_len,
151 size_t *decrypted_len)
152{
153 u8 aad[30], nonce[13];
154 size_t aad_len;
155 size_t mlen;
156 u8 *plain;
157
158 if (data_len < 8 + 8)
159 return NULL;
160
161 plain = os_malloc(data_len + AES_BLOCK_SIZE);
162 if (plain == NULL)
163 return NULL;
164
165 mlen = data_len - 8 - 8;
166
167 os_memset(aad, 0, sizeof(aad));
168 ccmp_aad_nonce(hdr, data, a1, a2, a3, aad, &aad_len, nonce);
169 wpa_hexdump(MSG_EXCESSIVE, "CCMP AAD", aad, aad_len);
170 wpa_hexdump(MSG_EXCESSIVE, "CCMP nonce", nonce, 13);
171
172 if (aes_ccm_ad(tk, 16, nonce, 8, data + 8, mlen, aad, aad_len,
173 data + 8 + mlen, plain) < 0) {
174 u16 seq_ctrl = le_to_host16(hdr->seq_ctrl);
175 wpa_printf(MSG_INFO, "Invalid CCMP MIC in frame: A1=" MACSTR
176 " A2=" MACSTR " A3=" MACSTR " seq=%u frag=%u",
177 MAC2STR(hdr->addr1), MAC2STR(hdr->addr2),
178 MAC2STR(hdr->addr3),
179 WLAN_GET_SEQ_SEQ(seq_ctrl),
180 WLAN_GET_SEQ_FRAG(seq_ctrl));
181 os_free(plain);
182 return NULL;
183 }
184 wpa_hexdump(MSG_EXCESSIVE, "CCMP decrypted", plain, mlen);
185
186 *decrypted_len = mlen;
187 return plain;
188}
189
190
191void ccmp_get_pn(u8 *pn, const u8 *data)
192{
193 pn[0] = data[7]; /* PN5 */
194 pn[1] = data[6]; /* PN4 */
195 pn[2] = data[5]; /* PN3 */
196 pn[3] = data[4]; /* PN2 */
197 pn[4] = data[1]; /* PN1 */
198 pn[5] = data[0]; /* PN0 */
199}
200
201
202u8 * ccmp_encrypt(const u8 *tk, u8 *frame, size_t len, size_t hdrlen,
203 const u8 *qos, const u8 *a1, const u8 *a2, const u8 *a3,
204 const u8 *pn, int keyid, size_t *encrypted_len)
205{
206 u8 aad[30], nonce[13];
207 size_t aad_len, plen;
208 u8 *crypt, *pos;
209 struct ieee80211_hdr *hdr;
210
211 if (len < hdrlen || hdrlen < 24)
212 return NULL;
213 plen = len - hdrlen;
214
215 crypt = os_malloc(hdrlen + 8 + plen + 8 + AES_BLOCK_SIZE);
216 if (crypt == NULL)
217 return NULL;
218
219 os_memcpy(crypt, frame, hdrlen);
220 hdr = (struct ieee80211_hdr *) crypt;
221 hdr->frame_control |= host_to_le16(WLAN_FC_ISWEP);
222 pos = crypt + hdrlen;
223 *pos++ = pn[5]; /* PN0 */
224 *pos++ = pn[4]; /* PN1 */
225 *pos++ = 0x00; /* Rsvd */
226 *pos++ = 0x20 | (keyid << 6);
227 *pos++ = pn[3]; /* PN2 */
228 *pos++ = pn[2]; /* PN3 */
229 *pos++ = pn[1]; /* PN4 */
230 *pos++ = pn[0]; /* PN5 */
231
232 os_memset(aad, 0, sizeof(aad));
233 ccmp_aad_nonce(hdr, crypt + hdrlen, a1, a2, a3, aad, &aad_len, nonce);
234 wpa_hexdump(MSG_EXCESSIVE, "CCMP AAD", aad, aad_len);
235 wpa_hexdump(MSG_EXCESSIVE, "CCMP nonce", nonce, 13);
236
237 if (aes_ccm_ae(tk, 16, nonce, 8, frame + hdrlen, plen, aad, aad_len,
238 pos, pos + plen) < 0) {
239 os_free(crypt);
240 return NULL;
241 }
242
243 wpa_hexdump(MSG_EXCESSIVE, "CCMP encrypted", crypt + hdrlen + 8, plen);
244
245 *encrypted_len = hdrlen + 8 + plen + 8;
246
247 return crypt;
248}
249
250
251u8 * ccmp_encrypt_pv1(const u8 *tk, const u8 *a1, const u8 *a2, const u8 *a3,
252 const u8 *frame, size_t len,
253 size_t hdrlen, const u8 *pn, int keyid,
254 size_t *encrypted_len)
255{
256 u8 aad[24], nonce[13];
257 size_t aad_len, plen;
258 u8 *crypt, *pos;
259 struct ieee80211_hdr *hdr;
260
261 if (len < hdrlen || hdrlen < 12)
262 return NULL;
263 plen = len - hdrlen;
264
265 crypt = os_malloc(hdrlen + plen + 8 + AES_BLOCK_SIZE);
266 if (crypt == NULL)
267 return NULL;
268
269 os_memcpy(crypt, frame, hdrlen);
270 hdr = (struct ieee80211_hdr *) crypt;
271 hdr->frame_control |= host_to_le16(BIT(12)); /* Protected Frame */
272 pos = crypt + hdrlen;
273
274 os_memset(aad, 0, sizeof(aad));
275 ccmp_aad_nonce_pv1(crypt, a1, a2, a3, pn, aad, &aad_len, nonce);
276 wpa_hexdump(MSG_EXCESSIVE, "CCMP AAD", aad, aad_len);
277 wpa_hexdump(MSG_EXCESSIVE, "CCMP nonce", nonce, sizeof(nonce));
278
279 if (aes_ccm_ae(tk, 16, nonce, 8, frame + hdrlen, plen, aad, aad_len,
280 pos, pos + plen) < 0) {
281 os_free(crypt);
282 return NULL;
283 }
284
285 wpa_hexdump(MSG_EXCESSIVE, "CCMP encrypted", crypt + hdrlen, plen);
286
287 *encrypted_len = hdrlen + plen + 8;
288
289 return crypt;
290}
291
292
293u8 * ccmp_256_decrypt(const u8 *tk, const struct ieee80211_hdr *hdr,
294 const u8 *a1, const u8 *a2, const u8 *a3,
295 const u8 *data, size_t data_len, size_t *decrypted_len)
296{
297 u8 aad[30], nonce[13];
298 size_t aad_len;
299 size_t mlen;
300 u8 *plain;
301
302 if (data_len < 8 + 16)
303 return NULL;
304
305 plain = os_malloc(data_len + AES_BLOCK_SIZE);
306 if (plain == NULL)
307 return NULL;
308
309 mlen = data_len - 8 - 16;
310
311 os_memset(aad, 0, sizeof(aad));
312 ccmp_aad_nonce(hdr, data, a1, a2, a3, aad, &aad_len, nonce);
313 wpa_hexdump(MSG_EXCESSIVE, "CCMP-256 AAD", aad, aad_len);
314 wpa_hexdump(MSG_EXCESSIVE, "CCMP-256 nonce", nonce, 13);
315
316 if (aes_ccm_ad(tk, 32, nonce, 16, data + 8, mlen, aad, aad_len,
317 data + 8 + mlen, plain) < 0) {
318 u16 seq_ctrl = le_to_host16(hdr->seq_ctrl);
319 wpa_printf(MSG_INFO, "Invalid CCMP-256 MIC in frame: A1=" MACSTR
320 " A2=" MACSTR " A3=" MACSTR " seq=%u frag=%u",
321 MAC2STR(hdr->addr1), MAC2STR(hdr->addr2),
322 MAC2STR(hdr->addr3),
323 WLAN_GET_SEQ_SEQ(seq_ctrl),
324 WLAN_GET_SEQ_FRAG(seq_ctrl));
325 os_free(plain);
326 return NULL;
327 }
328 wpa_hexdump(MSG_EXCESSIVE, "CCMP-256 decrypted", plain, mlen);
329
330 *decrypted_len = mlen;
331 return plain;
332}
333
334
335u8 * ccmp_256_encrypt(const u8 *tk, u8 *frame, size_t len, size_t hdrlen,
336 const u8 *qos, const u8 *a1, const u8 *a2, const u8 *a3,
337 const u8 *pn, int keyid, size_t *encrypted_len)
338{
339 u8 aad[30], nonce[13];
340 size_t aad_len, plen;
341 u8 *crypt, *pos;
342 struct ieee80211_hdr *hdr;
343
344 if (len < hdrlen || hdrlen < 24)
345 return NULL;
346 plen = len - hdrlen;
347
348 crypt = os_malloc(hdrlen + 8 + plen + 16 + AES_BLOCK_SIZE);
349 if (crypt == NULL)
350 return NULL;
351
352 os_memcpy(crypt, frame, hdrlen);
353 hdr = (struct ieee80211_hdr *) crypt;
354 hdr->frame_control |= host_to_le16(WLAN_FC_ISWEP);
355 pos = crypt + hdrlen;
356 *pos++ = pn[5]; /* PN0 */
357 *pos++ = pn[4]; /* PN1 */
358 *pos++ = 0x00; /* Rsvd */
359 *pos++ = 0x20 | (keyid << 6);
360 *pos++ = pn[3]; /* PN2 */
361 *pos++ = pn[2]; /* PN3 */
362 *pos++ = pn[1]; /* PN4 */
363 *pos++ = pn[0]; /* PN5 */
364
365 os_memset(aad, 0, sizeof(aad));
366 ccmp_aad_nonce(hdr, crypt + hdrlen, a1, a2, a3, aad, &aad_len, nonce);
367 wpa_hexdump(MSG_EXCESSIVE, "CCMP-256 AAD", aad, aad_len);
368 wpa_hexdump(MSG_EXCESSIVE, "CCMP-256 nonce", nonce, 13);
369
370 if (aes_ccm_ae(tk, 32, nonce, 16, frame + hdrlen, plen, aad, aad_len,
371 pos, pos + plen) < 0) {
372 os_free(crypt);
373 return NULL;
374 }
375
376 wpa_hexdump(MSG_EXCESSIVE, "CCMP-256 encrypted", crypt + hdrlen + 8,
377 plen);
378
379 *encrypted_len = hdrlen + 8 + plen + 16;
380
381 return crypt;
382}