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