]>
git.ipfire.org Git - thirdparty/hostap.git/blob - wlantest/gcmp.c
2 * GCM with GMAC Protocol (GCMP)
3 * Copyright (c) 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 gcmp_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;
25 fc
= le_to_host16(hdr
->frame_control
);
26 stype
= WLAN_FC_GET_STYPE(fc
);
27 if ((fc
& (WLAN_FC_TODS
| WLAN_FC_FROMDS
)) ==
28 (WLAN_FC_TODS
| WLAN_FC_FROMDS
))
31 if (WLAN_FC_GET_TYPE(fc
) == WLAN_FC_TYPE_DATA
) {
32 fc
&= ~0x0070; /* Mask subtype bits */
37 qc
= (const u8
*) (hdr
+ 1);
43 fc
&= ~(WLAN_FC_RETRY
| WLAN_FC_PWRMGT
| WLAN_FC_MOREDATA
);
45 WPA_PUT_LE16(aad
, fc
);
47 os_memcpy(pos
, hdr
->addr1
, 3 * ETH_ALEN
);
49 seq
= le_to_host16(hdr
->seq_ctrl
);
50 seq
&= ~0xfff0; /* Mask Seq#; do not modify Frag# */
51 WPA_PUT_LE16(pos
, seq
);
54 os_memcpy(pos
, hdr
+ 1, addr4
* ETH_ALEN
+ qos
* 2);
55 pos
+= addr4
* ETH_ALEN
;
58 if (1 /* FIX: either device has SPP A-MSDU Capab = 0 */)
66 os_memcpy(nonce
, hdr
->addr2
, ETH_ALEN
);
67 nonce
[6] = data
[7]; /* PN5 */
68 nonce
[7] = data
[6]; /* PN4 */
69 nonce
[8] = data
[5]; /* PN3 */
70 nonce
[9] = data
[4]; /* PN2 */
71 nonce
[10] = data
[1]; /* PN1 */
72 nonce
[11] = data
[0]; /* PN0 */
76 u8
* gcmp_decrypt(const u8
*tk
, size_t tk_len
, const struct ieee80211_hdr
*hdr
,
77 const u8
*data
, size_t data_len
, size_t *decrypted_len
)
79 u8 aad
[30], nonce
[12], *plain
;
83 if (data_len
< 8 + 16)
86 plain
= os_malloc(data_len
+ AES_BLOCK_SIZE
);
91 mlen
= data_len
- 8 - 16;
93 os_memset(aad
, 0, sizeof(aad
));
94 gcmp_aad_nonce(hdr
, data
, aad
, &aad_len
, nonce
);
95 wpa_hexdump(MSG_EXCESSIVE
, "GCMP AAD", aad
, aad_len
);
96 wpa_hexdump(MSG_EXCESSIVE
, "GCMP nonce", nonce
, sizeof(nonce
));
98 if (aes_gcm_ad(tk
, tk_len
, nonce
, sizeof(nonce
), m
, mlen
, aad
, aad_len
,
99 m
+ mlen
, plain
) < 0) {
100 u16 seq_ctrl
= le_to_host16(hdr
->seq_ctrl
);
101 wpa_printf(MSG_INFO
, "Invalid GCMP frame: A1=" MACSTR
102 " A2=" MACSTR
" A3=" MACSTR
" seq=%u frag=%u",
103 MAC2STR(hdr
->addr1
), MAC2STR(hdr
->addr2
),
105 WLAN_GET_SEQ_SEQ(seq_ctrl
),
106 WLAN_GET_SEQ_FRAG(seq_ctrl
));
111 *decrypted_len
= mlen
;
116 u8
* gcmp_encrypt(const u8
*tk
, size_t tk_len
, u8
*frame
, size_t len
,
117 size_t hdrlen
, u8
*qos
,
118 u8
*pn
, int keyid
, size_t *encrypted_len
)
120 u8 aad
[30], nonce
[12], *crypt
, *pos
;
121 size_t aad_len
, plen
;
122 struct ieee80211_hdr
*hdr
;
124 if (len
< hdrlen
|| hdrlen
< 24)
128 crypt
= os_malloc(hdrlen
+ 8 + plen
+ 16 + AES_BLOCK_SIZE
);
132 os_memcpy(crypt
, frame
, hdrlen
);
133 hdr
= (struct ieee80211_hdr
*) crypt
;
134 hdr
->frame_control
|= host_to_le16(WLAN_FC_ISWEP
);
135 pos
= crypt
+ hdrlen
;
136 *pos
++ = pn
[5]; /* PN0 */
137 *pos
++ = pn
[4]; /* PN1 */
138 *pos
++ = 0x00; /* Rsvd */
139 *pos
++ = 0x20 | (keyid
<< 6);
140 *pos
++ = pn
[3]; /* PN2 */
141 *pos
++ = pn
[2]; /* PN3 */
142 *pos
++ = pn
[1]; /* PN4 */
143 *pos
++ = pn
[0]; /* PN5 */
145 os_memset(aad
, 0, sizeof(aad
));
146 gcmp_aad_nonce(hdr
, crypt
+ hdrlen
, aad
, &aad_len
, nonce
);
147 wpa_hexdump(MSG_EXCESSIVE
, "GCMP AAD", aad
, aad_len
);
148 wpa_hexdump(MSG_EXCESSIVE
, "GCMP nonce", nonce
, sizeof(nonce
));
150 if (aes_gcm_ae(tk
, tk_len
, nonce
, sizeof(nonce
), frame
+ hdrlen
, plen
,
151 aad
, aad_len
, pos
, pos
+ plen
) < 0) {
156 wpa_hexdump(MSG_EXCESSIVE
, "GCMP MIC", pos
+ plen
, 16);
157 wpa_hexdump(MSG_EXCESSIVE
, "GCMP encrypted", pos
, plen
);
159 *encrypted_len
= hdrlen
+ 8 + plen
+ 16;