]>
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
);
44 WPA_PUT_LE16(aad
, fc
);
46 os_memcpy(pos
, hdr
->addr1
, 3 * ETH_ALEN
);
48 seq
= le_to_host16(hdr
->seq_ctrl
);
49 seq
&= ~0xfff0; /* Mask Seq#; do not modify Frag# */
50 WPA_PUT_LE16(pos
, seq
);
53 os_memcpy(pos
, hdr
+ 1, addr4
* ETH_ALEN
+ qos
* 2);
54 pos
+= addr4
* ETH_ALEN
;
57 if (1 /* FIX: either device has SPP A-MSDU Capab = 0 */)
65 os_memcpy(nonce
, hdr
->addr2
, ETH_ALEN
);
66 nonce
[6] = data
[7]; /* PN5 */
67 nonce
[7] = data
[6]; /* PN4 */
68 nonce
[8] = data
[5]; /* PN3 */
69 nonce
[9] = data
[4]; /* PN2 */
70 nonce
[10] = data
[1]; /* PN1 */
71 nonce
[11] = data
[0]; /* PN0 */
75 u8
* gcmp_decrypt(const u8
*tk
, size_t tk_len
, const struct ieee80211_hdr
*hdr
,
76 const u8
*data
, size_t data_len
, size_t *decrypted_len
)
78 u8 aad
[30], nonce
[12], *plain
;
82 if (data_len
< 8 + 16)
85 plain
= os_malloc(data_len
+ AES_BLOCK_SIZE
);
90 mlen
= data_len
- 8 - 16;
92 os_memset(aad
, 0, sizeof(aad
));
93 gcmp_aad_nonce(hdr
, data
, aad
, &aad_len
, nonce
);
94 wpa_hexdump(MSG_EXCESSIVE
, "GCMP AAD", aad
, aad_len
);
95 wpa_hexdump(MSG_EXCESSIVE
, "GCMP nonce", nonce
, sizeof(nonce
));
97 if (aes_gcm_ad(tk
, tk_len
, nonce
, sizeof(nonce
), m
, mlen
, aad
, aad_len
,
98 m
+ mlen
, plain
) < 0) {
99 u16 seq_ctrl
= le_to_host16(hdr
->seq_ctrl
);
100 wpa_printf(MSG_INFO
, "Invalid GCMP frame: A1=" MACSTR
101 " A2=" MACSTR
" A3=" MACSTR
" seq=%u frag=%u",
102 MAC2STR(hdr
->addr1
), MAC2STR(hdr
->addr2
),
104 WLAN_GET_SEQ_SEQ(seq_ctrl
),
105 WLAN_GET_SEQ_FRAG(seq_ctrl
));
110 *decrypted_len
= mlen
;
115 u8
* gcmp_encrypt(const u8
*tk
, size_t tk_len
, const u8
*frame
, size_t len
,
116 size_t hdrlen
, const u8
*qos
,
117 const u8
*pn
, int keyid
, size_t *encrypted_len
)
119 u8 aad
[30], nonce
[12], *crypt
, *pos
;
120 size_t aad_len
, plen
;
121 struct ieee80211_hdr
*hdr
;
123 if (len
< hdrlen
|| hdrlen
< 24)
127 crypt
= os_malloc(hdrlen
+ 8 + plen
+ 16 + AES_BLOCK_SIZE
);
131 os_memcpy(crypt
, frame
, hdrlen
);
132 hdr
= (struct ieee80211_hdr
*) crypt
;
133 pos
= crypt
+ hdrlen
;
134 *pos
++ = pn
[5]; /* PN0 */
135 *pos
++ = pn
[4]; /* PN1 */
136 *pos
++ = 0x00; /* Rsvd */
137 *pos
++ = 0x20 | (keyid
<< 6);
138 *pos
++ = pn
[3]; /* PN2 */
139 *pos
++ = pn
[2]; /* PN3 */
140 *pos
++ = pn
[1]; /* PN4 */
141 *pos
++ = pn
[0]; /* PN5 */
143 os_memset(aad
, 0, sizeof(aad
));
144 gcmp_aad_nonce(hdr
, crypt
+ hdrlen
, aad
, &aad_len
, nonce
);
145 wpa_hexdump(MSG_EXCESSIVE
, "GCMP AAD", aad
, aad_len
);
146 wpa_hexdump(MSG_EXCESSIVE
, "GCMP nonce", nonce
, sizeof(nonce
));
148 if (aes_gcm_ae(tk
, tk_len
, nonce
, sizeof(nonce
), frame
+ hdrlen
, plen
,
149 aad
, aad_len
, pos
, pos
+ plen
) < 0) {
154 wpa_hexdump(MSG_EXCESSIVE
, "GCMP MIC", pos
+ plen
, 16);
155 wpa_hexdump(MSG_EXCESSIVE
, "GCMP encrypted", pos
, plen
);
157 *encrypted_len
= hdrlen
+ 8 + plen
+ 16;