xref: /openbsd-src/sys/net80211/ieee80211_crypto_tkip.c (revision 678831be5eff0bcb5217b54d0dcfb6698acf8411)
1*678831beSjsg /*	$OpenBSD: ieee80211_crypto_tkip.c,v 1.33 2021/03/10 10:21:48 jsg Exp $	*/
2e03e709cSdamien 
3e03e709cSdamien /*-
4e03e709cSdamien  * Copyright (c) 2008 Damien Bergamini <damien.bergamini@free.fr>
5e03e709cSdamien  *
6e03e709cSdamien  * Permission to use, copy, modify, and distribute this software for any
7e03e709cSdamien  * purpose with or without fee is hereby granted, provided that the above
8e03e709cSdamien  * copyright notice and this permission notice appear in all copies.
9e03e709cSdamien  *
10e03e709cSdamien  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11e03e709cSdamien  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12e03e709cSdamien  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13e03e709cSdamien  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14e03e709cSdamien  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15e03e709cSdamien  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16e03e709cSdamien  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17e03e709cSdamien  */
18e03e709cSdamien 
192e8aae21Sdamien /*
202e8aae21Sdamien  * This code implements the Temporal Key Integrity Protocol (TKIP) defined
212e8aae21Sdamien  * in IEEE Std 802.11-2007 section 8.3.2.
222e8aae21Sdamien  */
232e8aae21Sdamien 
24e03e709cSdamien #include <sys/param.h>
25e03e709cSdamien #include <sys/systm.h>
26e03e709cSdamien #include <sys/mbuf.h>
27e03e709cSdamien #include <sys/malloc.h>
28e03e709cSdamien #include <sys/kernel.h>
29e03e709cSdamien #include <sys/socket.h>
30e03e709cSdamien #include <sys/endian.h>
31e03e709cSdamien #include <sys/syslog.h>
32e03e709cSdamien 
33e03e709cSdamien #include <net/if.h>
34e03e709cSdamien #include <net/if_dl.h>
35e03e709cSdamien #include <net/if_media.h>
36e03e709cSdamien 
37e03e709cSdamien #include <netinet/in.h>
38e03e709cSdamien #include <netinet/if_ether.h>
39e03e709cSdamien 
40e03e709cSdamien #include <net80211/ieee80211_var.h>
41e03e709cSdamien #include <net80211/ieee80211_crypto.h>
42e03e709cSdamien 
43e03e709cSdamien #include <crypto/arc4.h>
44e03e709cSdamien #include <crypto/michael.h>
45e03e709cSdamien 
46e03e709cSdamien typedef u_int8_t  byte;	/* 8-bit byte (octet) */
47e03e709cSdamien typedef u_int16_t u16b;	/* 16-bit unsigned word */
48e03e709cSdamien typedef u_int32_t u32b;	/* 32-bit unsigned word */
49e03e709cSdamien 
50e03e709cSdamien static void	Phase1(u16b *, const byte *, const byte *, u32b);
51e03e709cSdamien static void	Phase2(byte *, const byte *, const u16b *, u16b);
52e03e709cSdamien 
53e03e709cSdamien /* TKIP software crypto context */
54e03e709cSdamien struct ieee80211_tkip_ctx {
55e03e709cSdamien 	struct rc4_ctx	rc4;
56e03e709cSdamien 	const u_int8_t	*txmic;
57e03e709cSdamien 	const u_int8_t	*rxmic;
5874e35d90Sdamien 	u_int16_t	txttak[5];
5974e35d90Sdamien 	u_int16_t	rxttak[5];
60385d9c2aSdamien 	u_int8_t	txttak_ok;
6174e35d90Sdamien 	u_int8_t	rxttak_ok;
62e03e709cSdamien };
63e03e709cSdamien 
64e03e709cSdamien /*
65e03e709cSdamien  * Initialize software crypto context.  This function can be overridden
66e03e709cSdamien  * by drivers doing hardware crypto.
67e03e709cSdamien  */
68e03e709cSdamien int
ieee80211_tkip_set_key(struct ieee80211com * ic,struct ieee80211_key * k)69e03e709cSdamien ieee80211_tkip_set_key(struct ieee80211com *ic, struct ieee80211_key *k)
70e03e709cSdamien {
71e03e709cSdamien 	struct ieee80211_tkip_ctx *ctx;
72e03e709cSdamien 
73e03e709cSdamien 	ctx = malloc(sizeof(*ctx), M_DEVBUF, M_NOWAIT | M_ZERO);
74e03e709cSdamien 	if (ctx == NULL)
75e03e709cSdamien 		return ENOMEM;
76e03e709cSdamien 	/*
77e03e709cSdamien 	 * Use bits 128-191 as the Michael key for AA->SPA and bits
78e03e709cSdamien 	 * 192-255 as the Michael key for SPA->AA.
79e03e709cSdamien 	 */
80171ac09aSdamien #ifndef IEEE80211_STA_ONLY
81e03e709cSdamien 	if (ic->ic_opmode == IEEE80211_M_HOSTAP) {
82e03e709cSdamien 		ctx->txmic = &k->k_key[16];
83e03e709cSdamien 		ctx->rxmic = &k->k_key[24];
84171ac09aSdamien 	} else
85171ac09aSdamien #endif
86171ac09aSdamien 	{
87e03e709cSdamien 		ctx->rxmic = &k->k_key[16];
88e03e709cSdamien 		ctx->txmic = &k->k_key[24];
89e03e709cSdamien 	}
90e03e709cSdamien 	k->k_priv = ctx;
91e03e709cSdamien 	return 0;
92e03e709cSdamien }
93e03e709cSdamien 
94e03e709cSdamien void
ieee80211_tkip_delete_key(struct ieee80211com * ic,struct ieee80211_key * k)95e03e709cSdamien ieee80211_tkip_delete_key(struct ieee80211com *ic, struct ieee80211_key *k)
96e03e709cSdamien {
97ad281cb6Stb 	if (k->k_priv != NULL) {
98ad281cb6Stb 		explicit_bzero(k->k_priv, sizeof(struct ieee80211_tkip_ctx));
99ad281cb6Stb 		free(k->k_priv, M_DEVBUF, sizeof(struct ieee80211_tkip_ctx));
100ad281cb6Stb 	}
101e03e709cSdamien 	k->k_priv = NULL;
102e03e709cSdamien }
103e03e709cSdamien 
104e03e709cSdamien /* pseudo-header used for TKIP MIC computation */
105e03e709cSdamien struct ieee80211_tkip_frame {
106e03e709cSdamien 	u_int8_t	i_da[IEEE80211_ADDR_LEN];
107e03e709cSdamien 	u_int8_t	i_sa[IEEE80211_ADDR_LEN];
108e03e709cSdamien 	u_int8_t	i_pri;
109e03e709cSdamien 	u_int8_t	i_pad[3];
110e03e709cSdamien } __packed;
111e03e709cSdamien 
112e03e709cSdamien /*
113e03e709cSdamien  * Compute TKIP MIC over an mbuf chain starting "off" bytes from the
114*678831beSjsg  * beginning.  This function should be kept independent from the software
115e03e709cSdamien  * TKIP crypto code so that drivers doing hardware crypto but not MIC can
116e03e709cSdamien  * call it without a software crypto context.
117e03e709cSdamien  */
118e03e709cSdamien void
ieee80211_tkip_mic(struct mbuf * m0,int off,const u_int8_t * key,u_int8_t mic[IEEE80211_TKIP_MICLEN])119e03e709cSdamien ieee80211_tkip_mic(struct mbuf *m0, int off, const u_int8_t *key,
120e03e709cSdamien     u_int8_t mic[IEEE80211_TKIP_MICLEN])
121e03e709cSdamien {
122e03e709cSdamien 	const struct ieee80211_frame *wh;
123e03e709cSdamien 	struct ieee80211_tkip_frame wht;
124e03e709cSdamien 	MICHAEL_CTX ctx;	/* small enough */
125e03e709cSdamien 	struct mbuf *m;
126e03e709cSdamien 	caddr_t pos;
127e03e709cSdamien 	int len;
128e03e709cSdamien 
129e03e709cSdamien 	/* assumes 802.11 header is contiguous */
130e03e709cSdamien 	wh = mtod(m0, struct ieee80211_frame *);
131e03e709cSdamien 
132e03e709cSdamien 	/* construct pseudo-header for TKIP MIC computation */
133e03e709cSdamien 	switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) {
134e03e709cSdamien 	case IEEE80211_FC1_DIR_NODS:
135e03e709cSdamien 		IEEE80211_ADDR_COPY(wht.i_da, wh->i_addr1);
136e03e709cSdamien 		IEEE80211_ADDR_COPY(wht.i_sa, wh->i_addr2);
137e03e709cSdamien 		break;
138e03e709cSdamien 	case IEEE80211_FC1_DIR_TODS:
139e03e709cSdamien 		IEEE80211_ADDR_COPY(wht.i_da, wh->i_addr3);
140e03e709cSdamien 		IEEE80211_ADDR_COPY(wht.i_sa, wh->i_addr2);
141e03e709cSdamien 		break;
142e03e709cSdamien 	case IEEE80211_FC1_DIR_FROMDS:
143e03e709cSdamien 		IEEE80211_ADDR_COPY(wht.i_da, wh->i_addr1);
144e03e709cSdamien 		IEEE80211_ADDR_COPY(wht.i_sa, wh->i_addr3);
145e03e709cSdamien 		break;
146e03e709cSdamien 	case IEEE80211_FC1_DIR_DSTODS:
147290fe1efSdamien 		IEEE80211_ADDR_COPY(wht.i_da, wh->i_addr3);
148290fe1efSdamien 		IEEE80211_ADDR_COPY(wht.i_sa,
149290fe1efSdamien 		    ((const struct ieee80211_frame_addr4 *)wh)->i_addr4);
150e03e709cSdamien 		break;
151e03e709cSdamien 	}
152b4e72b72Sdamien 	if (ieee80211_has_qos(wh))
153b4e72b72Sdamien 		wht.i_pri = ieee80211_get_qos(wh) & IEEE80211_QOS_TID;
154b4e72b72Sdamien 	else
155e03e709cSdamien 		wht.i_pri = 0;
156e03e709cSdamien 	wht.i_pad[0] = wht.i_pad[1] = wht.i_pad[2] = 0;
157e03e709cSdamien 
158e03e709cSdamien 	michael_init(&ctx);
159e03e709cSdamien 	michael_key(key, &ctx);
160e03e709cSdamien 
161e03e709cSdamien 	michael_update(&ctx, (caddr_t)&wht, sizeof(wht));
162e03e709cSdamien 
163e03e709cSdamien 	m = m0;
164e03e709cSdamien 	/* assumes the first "off" bytes are contiguous */
165e03e709cSdamien 	pos = mtod(m, caddr_t) + off;
166e03e709cSdamien 	len = m->m_len - off;
167e03e709cSdamien 	for (;;) {
168e03e709cSdamien 		michael_update(&ctx, pos, len);
169e03e709cSdamien 		if ((m = m->m_next) == NULL)
170e03e709cSdamien 			break;
171e03e709cSdamien 		pos = mtod(m, caddr_t);
172e03e709cSdamien 		len = m->m_len;
173e03e709cSdamien 	}
174e03e709cSdamien 
175e03e709cSdamien 	michael_final(mic, &ctx);
176e03e709cSdamien }
177e03e709cSdamien 
178e03e709cSdamien /* shortcuts */
179e03e709cSdamien #define IEEE80211_TKIP_TAILLEN	\
180e03e709cSdamien 	(IEEE80211_TKIP_MICLEN + IEEE80211_WEP_CRCLEN)
181e03e709cSdamien #define IEEE80211_TKIP_OVHD	\
182e03e709cSdamien 	(IEEE80211_TKIP_HDRLEN + IEEE80211_TKIP_TAILLEN)
183e03e709cSdamien 
184e03e709cSdamien struct mbuf *
ieee80211_tkip_encrypt(struct ieee80211com * ic,struct mbuf * m0,struct ieee80211_key * k)185e03e709cSdamien ieee80211_tkip_encrypt(struct ieee80211com *ic, struct mbuf *m0,
186e03e709cSdamien     struct ieee80211_key *k)
187e03e709cSdamien {
188e03e709cSdamien 	struct ieee80211_tkip_ctx *ctx = k->k_priv;
189df495f6aSdamien 	u_int16_t wepseed[8];	/* needs to be 16-bit aligned for Phase2 */
190e03e709cSdamien 	const struct ieee80211_frame *wh;
191e03e709cSdamien 	u_int8_t *ivp, *mic, *icvp;
192e03e709cSdamien 	struct mbuf *n0, *m, *n;
193e03e709cSdamien 	u_int32_t crc;
194e03e709cSdamien 	int left, moff, noff, len, hdrlen;
195e03e709cSdamien 
196e03e709cSdamien 	MGET(n0, M_DONTWAIT, m0->m_type);
197e03e709cSdamien 	if (n0 == NULL)
198e03e709cSdamien 		goto nospace;
1997fbb3004Sblambert 	if (m_dup_pkthdr(n0, m0, M_DONTWAIT))
200da3be2eeSkrw 		goto nospace;
201e03e709cSdamien 	n0->m_pkthdr.len += IEEE80211_TKIP_HDRLEN;
202e03e709cSdamien 	n0->m_len = MHLEN;
203e03e709cSdamien 	if (n0->m_pkthdr.len >= MINCLSIZE - IEEE80211_TKIP_TAILLEN) {
204e03e709cSdamien 		MCLGET(n0, M_DONTWAIT);
205e03e709cSdamien 		if (n0->m_flags & M_EXT)
206e03e709cSdamien 			n0->m_len = n0->m_ext.ext_size;
207e03e709cSdamien 	}
208e03e709cSdamien 	if (n0->m_len > n0->m_pkthdr.len)
209e03e709cSdamien 		n0->m_len = n0->m_pkthdr.len;
210e03e709cSdamien 
211e03e709cSdamien 	/* copy 802.11 header */
212e03e709cSdamien 	wh = mtod(m0, struct ieee80211_frame *);
213e03e709cSdamien 	hdrlen = ieee80211_get_hdrlen(wh);
214e03e709cSdamien 	memcpy(mtod(n0, caddr_t), wh, hdrlen);
215e03e709cSdamien 
216385d9c2aSdamien 	k->k_tsc++;	/* increment the 48-bit TSC */
217385d9c2aSdamien 
218e03e709cSdamien 	/* construct TKIP header */
219e03e709cSdamien 	ivp = mtod(n0, u_int8_t *) + hdrlen;
220e03e709cSdamien 	ivp[0] = k->k_tsc >> 8;		/* TSC1 */
221e03e709cSdamien 	/* WEP Seed = (TSC1 | 0x20) & 0x7f (see 8.3.2.2) */
222e03e709cSdamien 	ivp[1] = (ivp[0] | 0x20) & 0x7f;
223e03e709cSdamien 	ivp[2] = k->k_tsc;		/* TSC0 */
224e03e709cSdamien 	ivp[3] = k->k_id << 6 | IEEE80211_WEP_EXTIV;	/* KeyID | ExtIV */
225e03e709cSdamien 	ivp[4] = k->k_tsc >> 16;	/* TSC2 */
226e03e709cSdamien 	ivp[5] = k->k_tsc >> 24;	/* TSC3 */
227e03e709cSdamien 	ivp[6] = k->k_tsc >> 32;	/* TSC4 */
228e03e709cSdamien 	ivp[7] = k->k_tsc >> 40;	/* TSC5 */
229e03e709cSdamien 
230e03e709cSdamien 	/* compute WEP seed */
231385d9c2aSdamien 	if (!ctx->txttak_ok || (k->k_tsc & 0xffff) == 0) {
23274e35d90Sdamien 		Phase1(ctx->txttak, k->k_key, wh->i_addr2, k->k_tsc >> 16);
233385d9c2aSdamien 		ctx->txttak_ok = 1;
234385d9c2aSdamien 	}
23574e35d90Sdamien 	Phase2((u_int8_t *)wepseed, k->k_key, ctx->txttak, k->k_tsc & 0xffff);
236df495f6aSdamien 	rc4_keysetup(&ctx->rc4, (u_int8_t *)wepseed, 16);
23748e63f16Stb 	explicit_bzero(wepseed, sizeof(wepseed));
238e03e709cSdamien 
239e03e709cSdamien 	/* encrypt frame body and compute WEP ICV */
240e03e709cSdamien 	m = m0;
241e03e709cSdamien 	n = n0;
242e03e709cSdamien 	moff = hdrlen;
243e03e709cSdamien 	noff = hdrlen + IEEE80211_TKIP_HDRLEN;
244e03e709cSdamien 	left = m0->m_pkthdr.len - moff;
245e03e709cSdamien 	crc = ~0;
246e03e709cSdamien 	while (left > 0) {
247e03e709cSdamien 		if (moff == m->m_len) {
248e03e709cSdamien 			/* nothing left to copy from m */
249e03e709cSdamien 			m = m->m_next;
250e03e709cSdamien 			moff = 0;
251e03e709cSdamien 		}
252e03e709cSdamien 		if (noff == n->m_len) {
253e03e709cSdamien 			/* n is full and there's more data to copy */
254e03e709cSdamien 			MGET(n->m_next, M_DONTWAIT, n->m_type);
255e03e709cSdamien 			if (n->m_next == NULL)
256e03e709cSdamien 				goto nospace;
257e03e709cSdamien 			n = n->m_next;
258e03e709cSdamien 			n->m_len = MLEN;
25909fd81a2Shenning 			if (left >= MINCLSIZE - IEEE80211_TKIP_TAILLEN) {
260e03e709cSdamien 				MCLGET(n, M_DONTWAIT);
261e03e709cSdamien 				if (n->m_flags & M_EXT)
262e03e709cSdamien 					n->m_len = n->m_ext.ext_size;
263e03e709cSdamien 			}
264e03e709cSdamien 			if (n->m_len > left)
265e03e709cSdamien 				n->m_len = left;
266e03e709cSdamien 			noff = 0;
267e03e709cSdamien 		}
268e03e709cSdamien 		len = min(m->m_len - moff, n->m_len - noff);
269e03e709cSdamien 
2700849d918Sdjm 		crc = ether_crc32_le_update(crc, mtod(m, caddr_t) + moff, len);
271e03e709cSdamien 		rc4_crypt(&ctx->rc4, mtod(m, caddr_t) + moff,
272e03e709cSdamien 		    mtod(n, caddr_t) + noff, len);
273e03e709cSdamien 
274e03e709cSdamien 		moff += len;
275e03e709cSdamien 		noff += len;
276e03e709cSdamien 		left -= len;
277e03e709cSdamien 	}
278e03e709cSdamien 
279e03e709cSdamien 	/* reserve trailing space for TKIP MIC and WEP ICV */
280b5b7f62eSclaudio 	if (m_trailingspace(n) < IEEE80211_TKIP_TAILLEN) {
281e03e709cSdamien 		MGET(n->m_next, M_DONTWAIT, n->m_type);
282e03e709cSdamien 		if (n->m_next == NULL)
283e03e709cSdamien 			goto nospace;
284e03e709cSdamien 		n = n->m_next;
285e03e709cSdamien 		n->m_len = 0;
286e03e709cSdamien 	}
287e03e709cSdamien 
288e03e709cSdamien 	/* compute TKIP MIC over clear text */
289e03e709cSdamien 	mic = mtod(n, caddr_t) + n->m_len;
290e03e709cSdamien 	ieee80211_tkip_mic(m0, hdrlen, ctx->txmic, mic);
2910849d918Sdjm 	crc = ether_crc32_le_update(crc, mic, IEEE80211_TKIP_MICLEN);
292e03e709cSdamien 	rc4_crypt(&ctx->rc4, mic, mic, IEEE80211_TKIP_MICLEN);
293e03e709cSdamien 	n->m_len += IEEE80211_TKIP_MICLEN;
294e03e709cSdamien 
295e03e709cSdamien 	/* finalize WEP ICV */
296e03e709cSdamien 	icvp = mtod(n, caddr_t) + n->m_len;
297e03e709cSdamien 	crc = ~crc;
298e03e709cSdamien 	icvp[0] = crc;
299e03e709cSdamien 	icvp[1] = crc >> 8;
300e03e709cSdamien 	icvp[2] = crc >> 16;
301e03e709cSdamien 	icvp[3] = crc >> 24;
302e03e709cSdamien 	rc4_crypt(&ctx->rc4, icvp, icvp, IEEE80211_WEP_CRCLEN);
303e03e709cSdamien 	n->m_len += IEEE80211_WEP_CRCLEN;
304e03e709cSdamien 
305e03e709cSdamien 	n0->m_pkthdr.len += IEEE80211_TKIP_TAILLEN;
306e03e709cSdamien 
307e03e709cSdamien 	m_freem(m0);
308e03e709cSdamien 	return n0;
309e03e709cSdamien  nospace:
310e03e709cSdamien 	ic->ic_stats.is_tx_nombuf++;
311e03e709cSdamien 	m_freem(m0);
312e03e709cSdamien 	m_freem(n0);
313e03e709cSdamien 	return NULL;
314e03e709cSdamien }
315e03e709cSdamien 
316e995d523Sstsp int
ieee80211_tkip_get_tsc(uint64_t * tsc,uint64_t ** prsc,struct mbuf * m,struct ieee80211_key * k)317e995d523Sstsp ieee80211_tkip_get_tsc(uint64_t *tsc, uint64_t **prsc, struct mbuf *m,
318e995d523Sstsp     struct ieee80211_key *k)
319e995d523Sstsp {
320e995d523Sstsp 	struct ieee80211_frame *wh;
321e995d523Sstsp 	int hdrlen;
322e995d523Sstsp 	u_int8_t tid;
323e995d523Sstsp 	const u_int8_t *ivp;
324e995d523Sstsp 
325e995d523Sstsp 	wh = mtod(m, struct ieee80211_frame *);
326e995d523Sstsp 	hdrlen = ieee80211_get_hdrlen(wh);
327e995d523Sstsp 
328e995d523Sstsp 	if (m->m_pkthdr.len < hdrlen + IEEE80211_TKIP_HDRLEN)
329e995d523Sstsp 		return EINVAL;
330e995d523Sstsp 
331e995d523Sstsp 	ivp = (u_int8_t *)wh + hdrlen;
332e995d523Sstsp 	/* check that ExtIV bit is set */
333e995d523Sstsp 	if (!(ivp[3] & IEEE80211_WEP_EXTIV))
334e995d523Sstsp 		return EINVAL;
335e995d523Sstsp 
336e995d523Sstsp 	/* Retrieve last seen packet number for this frame priority. */
337e995d523Sstsp 	tid = ieee80211_has_qos(wh) ?
338e995d523Sstsp 	    ieee80211_get_qos(wh) & IEEE80211_QOS_TID : 0;
339e995d523Sstsp 	*prsc = &k->k_rsc[tid];
340e995d523Sstsp 
341e995d523Sstsp 	/* extract the 48-bit TSC from the TKIP header */
342e995d523Sstsp 	*tsc = (u_int64_t)ivp[2]      |
343e995d523Sstsp 	      (u_int64_t)ivp[0] <<  8 |
344e995d523Sstsp 	      (u_int64_t)ivp[4] << 16 |
345e995d523Sstsp 	      (u_int64_t)ivp[5] << 24 |
346e995d523Sstsp 	      (u_int64_t)ivp[6] << 32 |
347e995d523Sstsp 	      (u_int64_t)ivp[7] << 40;
348e995d523Sstsp 
349e995d523Sstsp 	return 0;
350e995d523Sstsp }
351e995d523Sstsp 
352e03e709cSdamien struct mbuf *
ieee80211_tkip_decrypt(struct ieee80211com * ic,struct mbuf * m0,struct ieee80211_key * k)353e03e709cSdamien ieee80211_tkip_decrypt(struct ieee80211com *ic, struct mbuf *m0,
354e03e709cSdamien     struct ieee80211_key *k)
355e03e709cSdamien {
356e03e709cSdamien 	struct ieee80211_tkip_ctx *ctx = k->k_priv;
357e03e709cSdamien 	struct ieee80211_frame *wh;
358df495f6aSdamien 	u_int16_t wepseed[8];	/* needs to be 16-bit aligned for Phase2 */
359e03e709cSdamien 	u_int8_t buf[IEEE80211_TKIP_MICLEN + IEEE80211_WEP_CRCLEN];
360e03e709cSdamien 	u_int8_t mic[IEEE80211_TKIP_MICLEN];
361cd64323fSdamien 	u_int64_t tsc, *prsc;
362e03e709cSdamien 	u_int32_t crc, crc0;
363e995d523Sstsp 	u_int8_t *mic0;
364e03e709cSdamien 	struct mbuf *n0, *m, *n;
365e03e709cSdamien 	int hdrlen, left, moff, noff, len;
366e03e709cSdamien 
367e03e709cSdamien 	wh = mtod(m0, struct ieee80211_frame *);
368e03e709cSdamien 	hdrlen = ieee80211_get_hdrlen(wh);
369e03e709cSdamien 
370e03e709cSdamien 	if (m0->m_pkthdr.len < hdrlen + IEEE80211_TKIP_OVHD) {
371e03e709cSdamien 		m_freem(m0);
372e03e709cSdamien 		return NULL;
373e03e709cSdamien 	}
374e03e709cSdamien 
375e995d523Sstsp 	/*
376*678831beSjsg 	 * Get the frame's Transmit Sequence Counter (TSC), and a pointer to
377e995d523Sstsp 	 * our last-seen Receive Sequence Counter (RSC) with which we can
378e995d523Sstsp 	 * detect replays.
379e995d523Sstsp 	 */
380e995d523Sstsp 	if (ieee80211_tkip_get_tsc(&tsc, &prsc, m0, k) != 0) {
381e03e709cSdamien 		m_freem(m0);
382e03e709cSdamien 		return NULL;
383e03e709cSdamien 	}
384cd64323fSdamien 	if (tsc <= *prsc) {
385e03e709cSdamien 		/* replayed frame, discard */
3862e8aae21Sdamien 		ic->ic_stats.is_tkip_replays++;
387e03e709cSdamien 		m_freem(m0);
388e03e709cSdamien 		return NULL;
389e03e709cSdamien 	}
390e03e709cSdamien 
391e03e709cSdamien 	MGET(n0, M_DONTWAIT, m0->m_type);
392e03e709cSdamien 	if (n0 == NULL)
393e03e709cSdamien 		goto nospace;
3947fbb3004Sblambert 	if (m_dup_pkthdr(n0, m0, M_DONTWAIT))
395da3be2eeSkrw 		goto nospace;
396e03e709cSdamien 	n0->m_pkthdr.len -= IEEE80211_TKIP_OVHD;
397e03e709cSdamien 	n0->m_len = MHLEN;
398e03e709cSdamien 	if (n0->m_pkthdr.len >= MINCLSIZE) {
399e03e709cSdamien 		MCLGET(n0, M_DONTWAIT);
400e03e709cSdamien 		if (n0->m_flags & M_EXT)
401e03e709cSdamien 			n0->m_len = n0->m_ext.ext_size;
402e03e709cSdamien 	}
403e03e709cSdamien 	if (n0->m_len > n0->m_pkthdr.len)
404e03e709cSdamien 		n0->m_len = n0->m_pkthdr.len;
405e03e709cSdamien 
406e03e709cSdamien 	/* copy 802.11 header and clear protected bit */
407e03e709cSdamien 	memcpy(mtod(n0, caddr_t), wh, hdrlen);
408e03e709cSdamien 	wh = mtod(n0, struct ieee80211_frame *);
409e03e709cSdamien 	wh->i_fc[1] &= ~IEEE80211_FC1_PROTECTED;
410e03e709cSdamien 
411e03e709cSdamien 	/* compute WEP seed */
41274e35d90Sdamien 	if (!ctx->rxttak_ok || (tsc >> 16) != (*prsc >> 16)) {
41374e35d90Sdamien 		ctx->rxttak_ok = 0;	/* invalidate cached TTAK (if any) */
41474e35d90Sdamien 		Phase1(ctx->rxttak, k->k_key, wh->i_addr2, tsc >> 16);
415290fe1efSdamien 	}
41674e35d90Sdamien 	Phase2((u_int8_t *)wepseed, k->k_key, ctx->rxttak, tsc & 0xffff);
417df495f6aSdamien 	rc4_keysetup(&ctx->rc4, (u_int8_t *)wepseed, 16);
41848e63f16Stb 	explicit_bzero(wepseed, sizeof(wepseed));
419e03e709cSdamien 
420e03e709cSdamien 	/* decrypt frame body and compute WEP ICV */
421e03e709cSdamien 	m = m0;
422e03e709cSdamien 	n = n0;
423e03e709cSdamien 	moff = hdrlen + IEEE80211_TKIP_HDRLEN;
424e03e709cSdamien 	noff = hdrlen;
425e03e709cSdamien 	left = n0->m_pkthdr.len - noff;
426e03e709cSdamien 	crc = ~0;
427e03e709cSdamien 	while (left > 0) {
428e03e709cSdamien 		if (moff == m->m_len) {
429e03e709cSdamien 			/* nothing left to copy from m */
430e03e709cSdamien 			m = m->m_next;
431e03e709cSdamien 			moff = 0;
432e03e709cSdamien 		}
433e03e709cSdamien 		if (noff == n->m_len) {
434e03e709cSdamien 			/* n is full and there's more data to copy */
435e03e709cSdamien 			MGET(n->m_next, M_DONTWAIT, n->m_type);
436e03e709cSdamien 			if (n->m_next == NULL)
437e03e709cSdamien 				goto nospace;
438e03e709cSdamien 			n = n->m_next;
439e03e709cSdamien 			n->m_len = MLEN;
44009fd81a2Shenning 			if (left >= MINCLSIZE) {
441e03e709cSdamien 				MCLGET(n, M_DONTWAIT);
442e03e709cSdamien 				if (n->m_flags & M_EXT)
443e03e709cSdamien 					n->m_len = n->m_ext.ext_size;
444e03e709cSdamien 			}
445e03e709cSdamien 			if (n->m_len > left)
446e03e709cSdamien 				n->m_len = left;
447e03e709cSdamien 			noff = 0;
448e03e709cSdamien 		}
449e03e709cSdamien 		len = min(m->m_len - moff, n->m_len - noff);
450e03e709cSdamien 
451e03e709cSdamien 		rc4_crypt(&ctx->rc4, mtod(m, caddr_t) + moff,
452e03e709cSdamien 		    mtod(n, caddr_t) + noff, len);
4530849d918Sdjm 		crc = ether_crc32_le_update(crc, mtod(n, caddr_t) + noff, len);
454e03e709cSdamien 
455e03e709cSdamien 		moff += len;
456e03e709cSdamien 		noff += len;
457e03e709cSdamien 		left -= len;
458e03e709cSdamien 	}
459e03e709cSdamien 
460e03e709cSdamien 	/* extract and decrypt TKIP MIC and WEP ICV from m0's tail */
461e03e709cSdamien 	m_copydata(m, moff, IEEE80211_TKIP_TAILLEN, buf);
462e03e709cSdamien 	rc4_crypt(&ctx->rc4, buf, buf, IEEE80211_TKIP_TAILLEN);
463e03e709cSdamien 
464e03e709cSdamien 	/* include TKIP MIC in WEP ICV */
465e03e709cSdamien 	mic0 = buf;
4660849d918Sdjm 	crc = ether_crc32_le_update(crc, mic0, IEEE80211_TKIP_MICLEN);
467e03e709cSdamien 	crc = ~crc;
468e03e709cSdamien 
469e03e709cSdamien 	/* decrypt ICV and compare it with calculated ICV */
470e03e709cSdamien 	crc0 = *(u_int32_t *)(buf + IEEE80211_TKIP_MICLEN);
471e03e709cSdamien 	if (crc != letoh32(crc0)) {
4722e8aae21Sdamien 		ic->ic_stats.is_tkip_icv_errs++;
473e03e709cSdamien 		m_freem(m0);
474e03e709cSdamien 		m_freem(n0);
475e03e709cSdamien 		return NULL;
476e03e709cSdamien 	}
477e03e709cSdamien 
478e03e709cSdamien 	/* compute TKIP MIC over decrypted message */
479e03e709cSdamien 	ieee80211_tkip_mic(n0, hdrlen, ctx->rxmic, mic);
480e03e709cSdamien 	/* check that it matches the MIC in received frame */
481e1212bedSmatthew 	if (timingsafe_bcmp(mic0, mic, IEEE80211_TKIP_MICLEN) != 0) {
482e03e709cSdamien 		m_freem(m0);
483e03e709cSdamien 		m_freem(n0);
484e03e709cSdamien 		ic->ic_stats.is_rx_locmicfail++;
485e03e709cSdamien 		ieee80211_michael_mic_failure(ic, tsc);
486e03e709cSdamien 		return NULL;
487e03e709cSdamien 	}
488e03e709cSdamien 
4892e8aae21Sdamien 	/* update last seen packet number (MIC is validated) */
490cd64323fSdamien 	*prsc = tsc;
49174e35d90Sdamien 	/* mark cached TTAK as valid */
49274e35d90Sdamien 	ctx->rxttak_ok = 1;
493e03e709cSdamien 
494e03e709cSdamien 	m_freem(m0);
495e03e709cSdamien 	return n0;
496e03e709cSdamien  nospace:
497e03e709cSdamien 	ic->ic_stats.is_rx_nombuf++;
498e03e709cSdamien 	m_freem(m0);
499e03e709cSdamien 	m_freem(n0);
500e03e709cSdamien 	return NULL;
501e03e709cSdamien }
502e03e709cSdamien 
503171ac09aSdamien #ifndef IEEE80211_STA_ONLY
504e03e709cSdamien /*
505e03e709cSdamien  * This function is called in HostAP mode to deauthenticate all STAs using
506e03e709cSdamien  * TKIP as their pairwise or group cipher (as part of TKIP countermeasures).
507e03e709cSdamien  */
508e03e709cSdamien static void
ieee80211_tkip_deauth(void * arg,struct ieee80211_node * ni)509e03e709cSdamien ieee80211_tkip_deauth(void *arg, struct ieee80211_node *ni)
510e03e709cSdamien {
511e03e709cSdamien 	struct ieee80211com *ic = arg;
512e03e709cSdamien 
513e03e709cSdamien 	if (ni->ni_state == IEEE80211_STA_ASSOC &&
514e03e709cSdamien 	    (ic->ic_bss->ni_rsngroupcipher == IEEE80211_CIPHER_TKIP ||
515e03e709cSdamien 	     ni->ni_rsncipher == IEEE80211_CIPHER_TKIP)) {
516e03e709cSdamien 		/* deauthenticate STA */
517e03e709cSdamien 		IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_DEAUTH,
518e03e709cSdamien 		    IEEE80211_REASON_MIC_FAILURE);
519e03e709cSdamien 		ieee80211_node_leave(ic, ni);
520e03e709cSdamien 	}
521e03e709cSdamien }
522dd6ea6d2Sstsp 
523dd6ea6d2Sstsp void
ieee80211_michael_mic_failure_timeout(void * arg)524dd6ea6d2Sstsp ieee80211_michael_mic_failure_timeout(void *arg)
525dd6ea6d2Sstsp {
526dd6ea6d2Sstsp 	struct ieee80211com *ic = arg;
527dd6ea6d2Sstsp 
528dd6ea6d2Sstsp 	/* Disable TKIP countermeasures. */
529dd6ea6d2Sstsp 	ic->ic_flags &= ~IEEE80211_F_COUNTERM;
530dd6ea6d2Sstsp }
531171ac09aSdamien #endif	/* IEEE80211_STA_ONLY */
532e03e709cSdamien 
533e03e709cSdamien /*
534e03e709cSdamien  * This function can be called by the software TKIP crypto code or by the
535e03e709cSdamien  * drivers when their hardware crypto engines detect a Michael MIC failure.
536e03e709cSdamien  */
537e03e709cSdamien void
ieee80211_michael_mic_failure(struct ieee80211com * ic,u_int64_t tsc)538e03e709cSdamien ieee80211_michael_mic_failure(struct ieee80211com *ic, u_int64_t tsc)
539e03e709cSdamien {
540a03326bbScheloha 	time_t now;
541dd6ea6d2Sstsp #ifndef IEEE80211_STA_ONLY
542dd6ea6d2Sstsp 	int sec;
543dd6ea6d2Sstsp #endif
544e03e709cSdamien 
545e03e709cSdamien 	if (ic->ic_flags & IEEE80211_F_COUNTERM)
546e03e709cSdamien 		return;	/* countermeasures already active */
547e03e709cSdamien 
548a79f8698Sdamien 	log(LOG_WARNING, "%s: Michael MIC failure\n", ic->ic_if.if_xname);
549e03e709cSdamien 
550851a9019Sdjm 	/*
551851a9019Sdjm 	 * NB. do not send Michael MIC Failure reports as recommended since
552851a9019Sdjm 	 * these may be used as an oracle to verify CRC guesses as described
553851a9019Sdjm 	 * in Beck, M. and Tews S. "Practical attacks against WEP and WPA"
554851a9019Sdjm 	 * http://dl.aircrack-ng.org/breakingwepandwpa.pdf
555851a9019Sdjm 	 */
556851a9019Sdjm 
557e03e709cSdamien 	/*
558dd6ea6d2Sstsp 	 * Activate TKIP countermeasures (see 802.11-2012 11.4.2.4) if less than
559dd6ea6d2Sstsp 	 * 60 seconds have passed since the most recent previous MIC failure.
560e03e709cSdamien 	 */
561a03326bbScheloha 	now = getuptime();
562a03326bbScheloha 	if (ic->ic_tkip_micfail == 0 || ic->ic_tkip_micfail + 60 >= now) {
563a03326bbScheloha 		ic->ic_tkip_micfail = now;
5643b819ab4Sdjm 		ic->ic_tkip_micfail_last_tsc = tsc;
565e03e709cSdamien 		return;
566e03e709cSdamien 	}
567e03e709cSdamien 
568171ac09aSdamien 	switch (ic->ic_opmode) {
569171ac09aSdamien #ifndef IEEE80211_STA_ONLY
570171ac09aSdamien 	case IEEE80211_M_HOSTAP:
571dd6ea6d2Sstsp 		/* refuse new TKIP associations for at least 60 seconds */
572e03e709cSdamien 		ic->ic_flags |= IEEE80211_F_COUNTERM;
57394678f65Sstsp 		sec = 60 + arc4random_uniform(30);
574dd6ea6d2Sstsp 		log(LOG_WARNING, "%s: HostAP will be disabled for %d seconds "
575dd6ea6d2Sstsp 		    "as a countermeasure against TKIP key cracking attempts\n",
576dd6ea6d2Sstsp 		    ic->ic_if.if_xname, sec);
577dd6ea6d2Sstsp 		timeout_add_sec(&ic->ic_tkip_micfail_timeout, sec);
578e03e709cSdamien 
579e03e709cSdamien 		/* deauthenticate all currently associated STAs using TKIP */
580e03e709cSdamien 		ieee80211_iterate_nodes(ic, ieee80211_tkip_deauth, ic);
581dd6ea6d2Sstsp 
582dd6ea6d2Sstsp 		/* schedule a GTK change */
583dd6ea6d2Sstsp 		timeout_add_sec(&ic->ic_rsn_timeout, 1);
584171ac09aSdamien 		break;
585171ac09aSdamien #endif
586171ac09aSdamien 	case IEEE80211_M_STA:
587851a9019Sdjm 		/*
588851a9019Sdjm 		 * Notify the AP of MIC failures: send two Michael
589851a9019Sdjm 		 * MIC Failure Report frames back-to-back to trigger
590851a9019Sdjm 		 * countermeasures at the AP end.
591851a9019Sdjm 		 */
592851a9019Sdjm 		(void)ieee80211_send_eapol_key_req(ic, ic->ic_bss,
593851a9019Sdjm 		    EAPOL_KEY_KEYMIC | EAPOL_KEY_ERROR | EAPOL_KEY_SECURE,
5943b819ab4Sdjm 		    ic->ic_tkip_micfail_last_tsc);
595851a9019Sdjm 		(void)ieee80211_send_eapol_key_req(ic, ic->ic_bss,
596851a9019Sdjm 		    EAPOL_KEY_KEYMIC | EAPOL_KEY_ERROR | EAPOL_KEY_SECURE,
597851a9019Sdjm 		    tsc);
598851a9019Sdjm 
599e03e709cSdamien 		/* deauthenticate from the AP.. */
600e03e709cSdamien 		IEEE80211_SEND_MGMT(ic, ic->ic_bss,
601e03e709cSdamien 		    IEEE80211_FC0_SUBTYPE_DEAUTH,
602e03e709cSdamien 		    IEEE80211_REASON_MIC_FAILURE);
603e03e709cSdamien 		/* ..and find another one */
604e03e709cSdamien 		(void)ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
605171ac09aSdamien 		break;
606171ac09aSdamien 	default:
607171ac09aSdamien 		break;
608e03e709cSdamien 	}
6093b819ab4Sdjm 
610a03326bbScheloha 	ic->ic_tkip_micfail = now;
6113b819ab4Sdjm 	ic->ic_tkip_micfail_last_tsc = tsc;
612e03e709cSdamien }
613e03e709cSdamien 
614e03e709cSdamien /***********************************************************************
615e03e709cSdamien    Contents:    Generate IEEE 802.11 per-frame RC4 key hash test vectors
616e03e709cSdamien    Date:        April 19, 2002
617e03e709cSdamien    Notes:
618e03e709cSdamien    This code is written for pedagogical purposes, NOT for performance.
619e03e709cSdamien ************************************************************************/
620e03e709cSdamien 
621e03e709cSdamien /* macros for extraction/creation of byte/u16b values */
622e03e709cSdamien #define RotR1(v16)	((((v16) >> 1) & 0x7FFF) ^ (((v16) & 1) << 15))
623e03e709cSdamien #define   Lo8(v16)	((byte)( (v16)       & 0x00FF))
624e03e709cSdamien #define   Hi8(v16)	((byte)(((v16) >> 8) & 0x00FF))
625e03e709cSdamien #define Lo16(v32)	((u16b)( (v32)       & 0xFFFF))
626e03e709cSdamien #define Hi16(v32)	((u16b)(((v32) >>16) & 0xFFFF))
627e03e709cSdamien #define Mk16(hi,lo)	((lo) ^ (((u16b)(hi)) << 8))
628e03e709cSdamien 
629e03e709cSdamien /* select the Nth 16-bit word of the Temporal Key byte array TK[] */
630e03e709cSdamien #define TK16(N)		Mk16(TK[2 * (N) + 1], TK[2 * (N)])
631e03e709cSdamien 
632e03e709cSdamien /* S-box lookup: 16 bits --> 16 bits */
633e03e709cSdamien #define _S_(v16)	(Sbox[Lo8(v16)] ^ swap16(Sbox[Hi8(v16)]))
634e03e709cSdamien 
635e03e709cSdamien /* fixed algorithm "parameters" */
636e03e709cSdamien #define PHASE1_LOOP_CNT	 8	/* this needs to be "big enough"     */
637e03e709cSdamien #define TA_SIZE		 6	/* 48-bit transmitter address        */
638e03e709cSdamien #define TK_SIZE		16	/* 128-bit Temporal Key              */
639e03e709cSdamien #define P1K_SIZE	10	/* 80-bit Phase1 key                 */
640e03e709cSdamien #define RC4_KEY_SIZE	16	/* 128-bit RC4KEY (104 bits unknown) */
641e03e709cSdamien 
642e03e709cSdamien /* 2-byte by 2-byte subset of the full AES S-box table */
643e03e709cSdamien static const u16b Sbox[256]=	/* Sbox for hash */
644e03e709cSdamien {
645e03e709cSdamien 	0xC6A5, 0xF884, 0xEE99, 0xF68D, 0xFF0D, 0xD6BD, 0xDEB1, 0x9154,
646e03e709cSdamien 	0x6050, 0x0203, 0xCEA9, 0x567D, 0xE719, 0xB562, 0x4DE6, 0xEC9A,
647e03e709cSdamien 	0x8F45, 0x1F9D, 0x8940, 0xFA87, 0xEF15, 0xB2EB, 0x8EC9, 0xFB0B,
648e03e709cSdamien 	0x41EC, 0xB367, 0x5FFD, 0x45EA, 0x23BF, 0x53F7, 0xE496, 0x9B5B,
649e03e709cSdamien 	0x75C2, 0xE11C, 0x3DAE, 0x4C6A, 0x6C5A, 0x7E41, 0xF502, 0x834F,
650e03e709cSdamien 	0x685C, 0x51F4, 0xD134, 0xF908, 0xE293, 0xAB73, 0x6253, 0x2A3F,
651e03e709cSdamien 	0x080C, 0x9552, 0x4665, 0x9D5E, 0x3028, 0x37A1, 0x0A0F, 0x2FB5,
652e03e709cSdamien 	0x0E09, 0x2436, 0x1B9B, 0xDF3D, 0xCD26, 0x4E69, 0x7FCD, 0xEA9F,
653e03e709cSdamien 	0x121B, 0x1D9E, 0x5874, 0x342E, 0x362D, 0xDCB2, 0xB4EE, 0x5BFB,
654e03e709cSdamien 	0xA4F6, 0x764D, 0xB761, 0x7DCE, 0x527B, 0xDD3E, 0x5E71, 0x1397,
655e03e709cSdamien 	0xA6F5, 0xB968, 0x0000, 0xC12C, 0x4060, 0xE31F, 0x79C8, 0xB6ED,
656e03e709cSdamien 	0xD4BE, 0x8D46, 0x67D9, 0x724B, 0x94DE, 0x98D4, 0xB0E8, 0x854A,
657e03e709cSdamien 	0xBB6B, 0xC52A, 0x4FE5, 0xED16, 0x86C5, 0x9AD7, 0x6655, 0x1194,
658e03e709cSdamien 	0x8ACF, 0xE910, 0x0406, 0xFE81, 0xA0F0, 0x7844, 0x25BA, 0x4BE3,
659e03e709cSdamien 	0xA2F3, 0x5DFE, 0x80C0, 0x058A, 0x3FAD, 0x21BC, 0x7048, 0xF104,
660e03e709cSdamien 	0x63DF, 0x77C1, 0xAF75, 0x4263, 0x2030, 0xE51A, 0xFD0E, 0xBF6D,
661e03e709cSdamien 	0x814C, 0x1814, 0x2635, 0xC32F, 0xBEE1, 0x35A2, 0x88CC, 0x2E39,
662e03e709cSdamien 	0x9357, 0x55F2, 0xFC82, 0x7A47, 0xC8AC, 0xBAE7, 0x322B, 0xE695,
663e03e709cSdamien 	0xC0A0, 0x1998, 0x9ED1, 0xA37F, 0x4466, 0x547E, 0x3BAB, 0x0B83,
664e03e709cSdamien 	0x8CCA, 0xC729, 0x6BD3, 0x283C, 0xA779, 0xBCE2, 0x161D, 0xAD76,
665e03e709cSdamien 	0xDB3B, 0x6456, 0x744E, 0x141E, 0x92DB, 0x0C0A, 0x486C, 0xB8E4,
666e03e709cSdamien 	0x9F5D, 0xBD6E, 0x43EF, 0xC4A6, 0x39A8, 0x31A4, 0xD337, 0xF28B,
667e03e709cSdamien 	0xD532, 0x8B43, 0x6E59, 0xDAB7, 0x018C, 0xB164, 0x9CD2, 0x49E0,
668e03e709cSdamien 	0xD8B4, 0xACFA, 0xF307, 0xCF25, 0xCAAF, 0xF48E, 0x47E9, 0x1018,
669e03e709cSdamien 	0x6FD5, 0xF088, 0x4A6F, 0x5C72, 0x3824, 0x57F1, 0x73C7, 0x9751,
670e03e709cSdamien 	0xCB23, 0xA17C, 0xE89C, 0x3E21, 0x96DD, 0x61DC, 0x0D86, 0x0F85,
671e03e709cSdamien 	0xE090, 0x7C42, 0x71C4, 0xCCAA, 0x90D8, 0x0605, 0xF701, 0x1C12,
672e03e709cSdamien 	0xC2A3, 0x6A5F, 0xAEF9, 0x69D0, 0x1791, 0x9958, 0x3A27, 0x27B9,
673e03e709cSdamien 	0xD938, 0xEB13, 0x2BB3, 0x2233, 0xD2BB, 0xA970, 0x0789, 0x33A7,
674e03e709cSdamien 	0x2DB6, 0x3C22, 0x1592, 0xC920, 0x8749, 0xAAFF, 0x5078, 0xA57A,
675e03e709cSdamien 	0x038F, 0x59F8, 0x0980, 0x1A17, 0x65DA, 0xD731, 0x84C6, 0xD0B8,
676e03e709cSdamien 	0x82C3, 0x29B0, 0x5A77, 0x1E11, 0x7BCB, 0xA8FC, 0x6DD6, 0x2C3A
677e03e709cSdamien };
678e03e709cSdamien 
679e03e709cSdamien /*
680e03e709cSdamien  **********************************************************************
681e03e709cSdamien  * Routine: Phase 1 -- generate P1K, given TA, TK, IV32
682e03e709cSdamien  *
683e03e709cSdamien  * Inputs:
684e03e709cSdamien  *     TK[]      = Temporal Key                         [128 bits]
685e03e709cSdamien  *     TA[]      = transmitter's MAC address            [ 48 bits]
686e03e709cSdamien  *     IV32      = upper 32 bits of IV                  [ 32 bits]
687e03e709cSdamien  * Output:
688e03e709cSdamien  *     P1K[]     = Phase 1 key                          [ 80 bits]
689e03e709cSdamien  *
690e03e709cSdamien  * Note:
691e03e709cSdamien  *     This function only needs to be called every 2**16 frames,
692e03e709cSdamien  *     although in theory it could be called every frame.
693e03e709cSdamien  *
694e03e709cSdamien  **********************************************************************
695e03e709cSdamien  */
696e03e709cSdamien static void
Phase1(u16b * P1K,const byte * TK,const byte * TA,u32b IV32)697e03e709cSdamien Phase1(u16b *P1K, const byte *TK, const byte *TA, u32b IV32)
698e03e709cSdamien {
699e03e709cSdamien 	int i;
700e03e709cSdamien 
701e03e709cSdamien 	/* Initialize the 80 bits of P1K[] from IV32 and TA[0..5] */
702e03e709cSdamien 	P1K[0] = Lo16(IV32);
703e03e709cSdamien 	P1K[1] = Hi16(IV32);
704e03e709cSdamien 	P1K[2] = Mk16(TA[1], TA[0]);	/* use TA[] as little-endian */
705e03e709cSdamien 	P1K[3] = Mk16(TA[3], TA[2]);
706e03e709cSdamien 	P1K[4] = Mk16(TA[5], TA[4]);
707e03e709cSdamien 
708e03e709cSdamien 	/* Now compute an unbalanced Feistel cipher with 80-bit block */
709e03e709cSdamien 	/* size on the 80-bit block P1K[], using the 128-bit key TK[] */
710e03e709cSdamien 	for (i = 0; i < PHASE1_LOOP_CNT; i++) {
711e03e709cSdamien 		/* Each add operation here is mod 2**16 */
712e03e709cSdamien 		P1K[0] += _S_(P1K[4] ^ TK16((i & 1) + 0));
713e03e709cSdamien 		P1K[1] += _S_(P1K[0] ^ TK16((i & 1) + 2));
714e03e709cSdamien 		P1K[2] += _S_(P1K[1] ^ TK16((i & 1) + 4));
715e03e709cSdamien 		P1K[3] += _S_(P1K[2] ^ TK16((i & 1) + 6));
716e03e709cSdamien 		P1K[4] += _S_(P1K[3] ^ TK16((i & 1) + 0));
717e03e709cSdamien 		P1K[4] += i;	/* avoid "slide attacks" */
718e03e709cSdamien 	}
719e03e709cSdamien }
720e03e709cSdamien 
721e03e709cSdamien /*
722e03e709cSdamien  **********************************************************************
723e03e709cSdamien  * Routine: Phase 2 -- generate RC4KEY, given TK, P1K, IV16
724e03e709cSdamien  *
725e03e709cSdamien  * Inputs:
726e03e709cSdamien  *     TK[]      = Temporal Key                         [128 bits]
727e03e709cSdamien  *     P1K[]     = Phase 1 output key                   [ 80 bits]
728e03e709cSdamien  *     IV16      = low 16 bits of IV counter            [ 16 bits]
729e03e709cSdamien  * Output:
730e03e709cSdamien  *     RC4KEY[] = the key used to encrypt the frame     [128 bits]
731e03e709cSdamien  *
732e03e709cSdamien  * Note:
733e03e709cSdamien  *     The value {TA,IV32,IV16} for Phase1/Phase2 must be unique
734e03e709cSdamien  *     across all frames using the same key TK value. Then, for a
735e03e709cSdamien  *     given value of TK[], this TKIP48 construction guarantees that
736e03e709cSdamien  *     the final RC4KEY value is unique across all frames.
737e03e709cSdamien  *
738e03e709cSdamien  **********************************************************************
739e03e709cSdamien  */
740e03e709cSdamien static void
Phase2(byte * RC4KEY,const byte * TK,const u16b * P1K,u16b IV16)741e03e709cSdamien Phase2(byte *RC4KEY, const byte *TK, const u16b *P1K, u16b IV16)
742e03e709cSdamien {
743df495f6aSdamien 	u16b *PPK;	/* temporary key for mixing */
744e03e709cSdamien 	int i;
745e03e709cSdamien 
746df495f6aSdamien 	/*
747df495f6aSdamien 	 * Suggested implementation optimization: if PPK[] is "overlaid"
748df495f6aSdamien 	 * appropriately on RC4KEY[], there is no need for the final for
749df495f6aSdamien 	 * loop that copies the PPK[] result into RC4KEY[].
750df495f6aSdamien 	 */
751df495f6aSdamien 	PPK = (u16b *)&RC4KEY[4];
752df495f6aSdamien 
753e03e709cSdamien 	/* all adds in the PPK[] equations below are mod 2**16 */
754e03e709cSdamien 	for (i = 0; i < 5; i++)
755e03e709cSdamien 		PPK[i] = P1K[i];	/* first, copy P1K to PPK */
756e03e709cSdamien 	PPK[5] = P1K[4] + IV16;		/* next, add in IV16 */
757e03e709cSdamien 
758e03e709cSdamien 	/* Bijective non-linear mixing of the 96 bits of PPK[0..5] */
759e03e709cSdamien 	PPK[0] += _S_(PPK[5] ^ TK16(0)); /* Mix key in each "round" */
760e03e709cSdamien 	PPK[1] += _S_(PPK[0] ^ TK16(1));
761e03e709cSdamien 	PPK[2] += _S_(PPK[1] ^ TK16(2));
762e03e709cSdamien 	PPK[3] += _S_(PPK[2] ^ TK16(3));
763e03e709cSdamien 	PPK[4] += _S_(PPK[3] ^ TK16(4));
764e03e709cSdamien 	PPK[5] += _S_(PPK[4] ^ TK16(5)); /* Total # S-box lookups == 6 */
765e03e709cSdamien 
766e03e709cSdamien 	/* Final sweep: bijective, linear. Rotates kill LSB correlations */
767e03e709cSdamien 	PPK[0] += RotR1(PPK[5] ^ TK16(6));
768e03e709cSdamien 	PPK[1] += RotR1(PPK[0] ^ TK16(7)); /* Use all of TK[] in Phase2 */
769e03e709cSdamien 	PPK[2] += RotR1(PPK[1]);
770e03e709cSdamien 	PPK[3] += RotR1(PPK[2]);
771e03e709cSdamien 	PPK[4] += RotR1(PPK[3]);
772e03e709cSdamien 	PPK[5] += RotR1(PPK[4]);
773e03e709cSdamien 
774e03e709cSdamien 	/* At this point, for a given key TK[0..15], the 96-bit output */
775e03e709cSdamien 	/* value PPK[0..5] is guaranteed to be unique, as a function */
776e03e709cSdamien 	/* of the 96-bit "input" value   {TA,IV32,IV16}. That is, P1K */
777e03e709cSdamien 	/* is now a keyed permutation of {TA,IV32,IV16}. */
778e03e709cSdamien 	/* Set RC4KEY[0..3], which includes cleartext portion of RC4 key  */
779e03e709cSdamien 	RC4KEY[0] = Hi8(IV16);	/* RC4KEY[0..2] is the WEP IV */
780e03e709cSdamien 	RC4KEY[1] =(Hi8(IV16) | 0x20) & 0x7F; /* Help avoid FMS weak keys */
781e03e709cSdamien 	RC4KEY[2] = Lo8(IV16);
782e03e709cSdamien 	RC4KEY[3] = Lo8((PPK[5] ^ TK16(0)) >> 1);
783e03e709cSdamien 
784df495f6aSdamien #if BYTE_ORDER == BIG_ENDIAN
785e03e709cSdamien 	/* Copy 96 bits of PPK[0..5] to RC4KEY[4..15] (little-endian) */
786df495f6aSdamien 	for (i = 0; i < 6; i++)
787df495f6aSdamien 		PPK[i] = swap16(PPK[i]);
788df495f6aSdamien #endif
789e03e709cSdamien }
790