]>
git.ipfire.org Git - thirdparty/hostap.git/blob - wlantest/ccmp.c
2a1ad83c9ee244612cf0254464cc5693ee927377
2 * CTR with CBC-MAC Protocol (CCMP)
3 * Copyright (c) 2010-2012, Jouni Malinen <j@w1.fi>
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
9 #include "utils/includes.h"
11 #include "utils/common.h"
12 #include "common/ieee802_11_defs.h"
13 #include "crypto/aes.h"
14 #include "crypto/aes_wrap.h"
18 static void ccmp_aad_nonce(const struct ieee80211_hdr
*hdr
, const u8
*data
,
19 u8
*aad
, size_t *aad_len
, u8
*nonce
)
22 int qos
= 0, addr4
= 0;
27 fc
= le_to_host16(hdr
->frame_control
);
28 stype
= WLAN_FC_GET_STYPE(fc
);
29 if ((fc
& (WLAN_FC_TODS
| WLAN_FC_FROMDS
)) ==
30 (WLAN_FC_TODS
| WLAN_FC_FROMDS
))
33 if (WLAN_FC_GET_TYPE(fc
) == WLAN_FC_TYPE_DATA
) {
34 fc
&= ~0x0070; /* Mask subtype bits */
39 qc
= (const u8
*) (hdr
+ 1);
42 nonce
[0] = qc
[0] & 0x0f;
44 } else if (WLAN_FC_GET_TYPE(fc
) == WLAN_FC_TYPE_MGMT
)
45 nonce
[0] |= 0x10; /* Management */
47 fc
&= ~(WLAN_FC_RETRY
| WLAN_FC_PWRMGT
| WLAN_FC_MOREDATA
);
49 WPA_PUT_LE16(aad
, fc
);
51 os_memcpy(pos
, hdr
->addr1
, 3 * ETH_ALEN
);
53 seq
= le_to_host16(hdr
->seq_ctrl
);
54 seq
&= ~0xfff0; /* Mask Seq#; do not modify Frag# */
55 WPA_PUT_LE16(pos
, seq
);
58 os_memcpy(pos
, hdr
+ 1, addr4
* ETH_ALEN
+ qos
* 2);
59 pos
+= addr4
* ETH_ALEN
;
62 if (1 /* FIX: either device has SPP A-MSDU Capab = 0 */)
70 os_memcpy(nonce
+ 1, hdr
->addr2
, ETH_ALEN
);
71 nonce
[7] = data
[7]; /* PN5 */
72 nonce
[8] = data
[6]; /* PN4 */
73 nonce
[9] = data
[5]; /* PN3 */
74 nonce
[10] = data
[4]; /* PN2 */
75 nonce
[11] = data
[1]; /* PN1 */
76 nonce
[12] = data
[0]; /* PN0 */
80 static void ccmp_aad_nonce_pv1(const u8
*hdr
, const u8
*a1
, const u8
*a2
,
81 const u8
*a3
, const u8
*pn
,
82 u8
*aad
, size_t *aad_len
, u8
*nonce
)
87 nonce
[0] = BIT(5); /* PV1 */
88 /* TODO: Priority for QMF; 0 is used for Data frames */
90 fc
= WPA_GET_LE16(hdr
);
91 type
= (fc
& (BIT(2) | BIT(3) | BIT(4))) >> 2;
94 nonce
[0] |= 0x10; /* Management */
96 fc
&= ~(BIT(10) | BIT(11) | BIT(13) | BIT(14) | BIT(15));
98 WPA_PUT_LE16(aad
, fc
);
100 if (type
== 0 || type
== 3) {
103 os_memcpy(pos
, a1
, ETH_ALEN
);
105 os_memcpy(pos
, a2
, ETH_ALEN
);
109 /* Either A1 or A2 contains SID */
110 sc
= hdr
+ 2 + 2 + ETH_ALEN
;
112 /* Both A1 and A2 contain full addresses */
113 sc
= hdr
+ 2 + 2 * ETH_ALEN
;
115 /* SC with Sequence Number subfield (bits 4-15 of the Sequence
116 * Control field) masked to 0. */
121 os_memcpy(pos
, a3
, ETH_ALEN
);
126 *aad_len
= pos
- aad
;
128 os_memcpy(nonce
+ 1, a2
, ETH_ALEN
);
129 nonce
[7] = pn
[5]; /* PN5 */
130 nonce
[8] = pn
[4]; /* PN4 */
131 nonce
[9] = pn
[3]; /* PN3 */
132 nonce
[10] = pn
[2]; /* PN2 */
133 nonce
[11] = pn
[1]; /* PN1 */
134 nonce
[12] = pn
[0]; /* PN0 */
138 u8
* ccmp_decrypt(const u8
*tk
, const struct ieee80211_hdr
*hdr
,
139 const u8
*data
, size_t data_len
, size_t *decrypted_len
)
141 u8 aad
[30], nonce
[13];
146 if (data_len
< 8 + 8)
149 plain
= os_malloc(data_len
+ AES_BLOCK_SIZE
);
153 mlen
= data_len
- 8 - 8;
155 os_memset(aad
, 0, sizeof(aad
));
156 ccmp_aad_nonce(hdr
, data
, aad
, &aad_len
, nonce
);
157 wpa_hexdump(MSG_EXCESSIVE
, "CCMP AAD", aad
, aad_len
);
158 wpa_hexdump(MSG_EXCESSIVE
, "CCMP nonce", nonce
, 13);
160 if (aes_ccm_ad(tk
, 16, nonce
, 8, data
+ 8, mlen
, aad
, aad_len
,
161 data
+ 8 + mlen
, plain
) < 0) {
162 u16 seq_ctrl
= le_to_host16(hdr
->seq_ctrl
);
163 wpa_printf(MSG_INFO
, "Invalid CCMP MIC in frame: A1=" MACSTR
164 " A2=" MACSTR
" A3=" MACSTR
" seq=%u frag=%u",
165 MAC2STR(hdr
->addr1
), MAC2STR(hdr
->addr2
),
167 WLAN_GET_SEQ_SEQ(seq_ctrl
),
168 WLAN_GET_SEQ_FRAG(seq_ctrl
));
172 wpa_hexdump(MSG_EXCESSIVE
, "CCMP decrypted", plain
, mlen
);
174 *decrypted_len
= mlen
;
179 void ccmp_get_pn(u8
*pn
, const u8
*data
)
181 pn
[0] = data
[7]; /* PN5 */
182 pn
[1] = data
[6]; /* PN4 */
183 pn
[2] = data
[5]; /* PN3 */
184 pn
[3] = data
[4]; /* PN2 */
185 pn
[4] = data
[1]; /* PN1 */
186 pn
[5] = data
[0]; /* PN0 */
190 u8
* ccmp_encrypt(const u8
*tk
, u8
*frame
, size_t len
, size_t hdrlen
, u8
*qos
,
191 u8
*pn
, int keyid
, size_t *encrypted_len
)
193 u8 aad
[30], nonce
[13];
194 size_t aad_len
, plen
;
196 struct ieee80211_hdr
*hdr
;
198 if (len
< hdrlen
|| hdrlen
< 24)
202 crypt
= os_malloc(hdrlen
+ 8 + plen
+ 8 + AES_BLOCK_SIZE
);
206 os_memcpy(crypt
, frame
, hdrlen
);
207 hdr
= (struct ieee80211_hdr
*) crypt
;
208 hdr
->frame_control
|= host_to_le16(WLAN_FC_ISWEP
);
209 pos
= crypt
+ hdrlen
;
210 *pos
++ = pn
[5]; /* PN0 */
211 *pos
++ = pn
[4]; /* PN1 */
212 *pos
++ = 0x00; /* Rsvd */
213 *pos
++ = 0x20 | (keyid
<< 6);
214 *pos
++ = pn
[3]; /* PN2 */
215 *pos
++ = pn
[2]; /* PN3 */
216 *pos
++ = pn
[1]; /* PN4 */
217 *pos
++ = pn
[0]; /* PN5 */
219 os_memset(aad
, 0, sizeof(aad
));
220 ccmp_aad_nonce(hdr
, crypt
+ hdrlen
, aad
, &aad_len
, nonce
);
221 wpa_hexdump(MSG_EXCESSIVE
, "CCMP AAD", aad
, aad_len
);
222 wpa_hexdump(MSG_EXCESSIVE
, "CCMP nonce", nonce
, 13);
224 if (aes_ccm_ae(tk
, 16, nonce
, 8, frame
+ hdrlen
, plen
, aad
, aad_len
,
225 pos
, pos
+ plen
) < 0) {
230 wpa_hexdump(MSG_EXCESSIVE
, "CCMP encrypted", crypt
+ hdrlen
+ 8, plen
);
232 *encrypted_len
= hdrlen
+ 8 + plen
+ 8;
238 u8
* ccmp_encrypt_pv1(const u8
*tk
, const u8
*a1
, const u8
*a2
, const u8
*a3
,
239 const u8
*frame
, size_t len
,
240 size_t hdrlen
, const u8
*pn
, int keyid
,
241 size_t *encrypted_len
)
243 u8 aad
[24], nonce
[13];
244 size_t aad_len
, plen
;
246 struct ieee80211_hdr
*hdr
;
248 if (len
< hdrlen
|| hdrlen
< 12)
252 crypt
= os_malloc(hdrlen
+ plen
+ 8 + AES_BLOCK_SIZE
);
256 os_memcpy(crypt
, frame
, hdrlen
);
257 hdr
= (struct ieee80211_hdr
*) crypt
;
258 hdr
->frame_control
|= host_to_le16(BIT(12)); /* Protected Frame */
259 pos
= crypt
+ hdrlen
;
261 os_memset(aad
, 0, sizeof(aad
));
262 ccmp_aad_nonce_pv1(crypt
, a1
, a2
, a3
, pn
, aad
, &aad_len
, nonce
);
263 wpa_hexdump(MSG_EXCESSIVE
, "CCMP AAD", aad
, aad_len
);
264 wpa_hexdump(MSG_EXCESSIVE
, "CCMP nonce", nonce
, sizeof(nonce
));
266 if (aes_ccm_ae(tk
, 16, nonce
, 8, frame
+ hdrlen
, plen
, aad
, aad_len
,
267 pos
, pos
+ plen
) < 0) {
272 wpa_hexdump(MSG_EXCESSIVE
, "CCMP encrypted", crypt
+ hdrlen
, plen
);
274 *encrypted_len
= hdrlen
+ plen
+ 8;
280 u8
* ccmp_256_decrypt(const u8
*tk
, const struct ieee80211_hdr
*hdr
,
281 const u8
*data
, size_t data_len
, size_t *decrypted_len
)
283 u8 aad
[30], nonce
[13];
288 if (data_len
< 8 + 16)
291 plain
= os_malloc(data_len
+ AES_BLOCK_SIZE
);
295 mlen
= data_len
- 8 - 16;
297 os_memset(aad
, 0, sizeof(aad
));
298 ccmp_aad_nonce(hdr
, data
, aad
, &aad_len
, nonce
);
299 wpa_hexdump(MSG_EXCESSIVE
, "CCMP-256 AAD", aad
, aad_len
);
300 wpa_hexdump(MSG_EXCESSIVE
, "CCMP-256 nonce", nonce
, 13);
302 if (aes_ccm_ad(tk
, 32, nonce
, 16, data
+ 8, mlen
, aad
, aad_len
,
303 data
+ 8 + mlen
, plain
) < 0) {
304 u16 seq_ctrl
= le_to_host16(hdr
->seq_ctrl
);
305 wpa_printf(MSG_INFO
, "Invalid CCMP-256 MIC in frame: A1=" MACSTR
306 " A2=" MACSTR
" A3=" MACSTR
" seq=%u frag=%u",
307 MAC2STR(hdr
->addr1
), MAC2STR(hdr
->addr2
),
309 WLAN_GET_SEQ_SEQ(seq_ctrl
),
310 WLAN_GET_SEQ_FRAG(seq_ctrl
));
314 wpa_hexdump(MSG_EXCESSIVE
, "CCMP-256 decrypted", plain
, mlen
);
316 *decrypted_len
= mlen
;
321 u8
* ccmp_256_encrypt(const u8
*tk
, u8
*frame
, size_t len
, size_t hdrlen
,
322 u8
*qos
, u8
*pn
, int keyid
, size_t *encrypted_len
)
324 u8 aad
[30], nonce
[13];
325 size_t aad_len
, plen
;
327 struct ieee80211_hdr
*hdr
;
329 if (len
< hdrlen
|| hdrlen
< 24)
333 crypt
= os_malloc(hdrlen
+ 8 + plen
+ 16 + AES_BLOCK_SIZE
);
337 os_memcpy(crypt
, frame
, hdrlen
);
338 hdr
= (struct ieee80211_hdr
*) crypt
;
339 hdr
->frame_control
|= host_to_le16(WLAN_FC_ISWEP
);
340 pos
= crypt
+ hdrlen
;
341 *pos
++ = pn
[5]; /* PN0 */
342 *pos
++ = pn
[4]; /* PN1 */
343 *pos
++ = 0x00; /* Rsvd */
344 *pos
++ = 0x20 | (keyid
<< 6);
345 *pos
++ = pn
[3]; /* PN2 */
346 *pos
++ = pn
[2]; /* PN3 */
347 *pos
++ = pn
[1]; /* PN4 */
348 *pos
++ = pn
[0]; /* PN5 */
350 os_memset(aad
, 0, sizeof(aad
));
351 ccmp_aad_nonce(hdr
, crypt
+ hdrlen
, aad
, &aad_len
, nonce
);
352 wpa_hexdump(MSG_EXCESSIVE
, "CCMP-256 AAD", aad
, aad_len
);
353 wpa_hexdump(MSG_EXCESSIVE
, "CCMP-256 nonce", nonce
, 13);
355 if (aes_ccm_ae(tk
, 32, nonce
, 16, frame
+ hdrlen
, plen
, aad
, aad_len
,
356 pos
, pos
+ plen
) < 0) {
361 wpa_hexdump(MSG_EXCESSIVE
, "CCMP-256 encrypted", crypt
+ hdrlen
+ 8,
364 *encrypted_len
= hdrlen
+ 8 + plen
+ 16;