132176cfdSRui Paulo /*-
232176cfdSRui Paulo * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
3841ab66cSSepherosa Ziehau * All rights reserved.
4841ab66cSSepherosa Ziehau *
5841ab66cSSepherosa Ziehau * Redistribution and use in source and binary forms, with or without
6841ab66cSSepherosa Ziehau * modification, are permitted provided that the following conditions
7841ab66cSSepherosa Ziehau * are met:
8841ab66cSSepherosa Ziehau * 1. Redistributions of source code must retain the above copyright
9841ab66cSSepherosa Ziehau * notice, this list of conditions and the following disclaimer.
10841ab66cSSepherosa Ziehau * 2. Redistributions in binary form must reproduce the above copyright
11841ab66cSSepherosa Ziehau * notice, this list of conditions and the following disclaimer in the
12841ab66cSSepherosa Ziehau * documentation and/or other materials provided with the distribution.
13841ab66cSSepherosa Ziehau *
14841ab66cSSepherosa Ziehau * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15841ab66cSSepherosa Ziehau * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16841ab66cSSepherosa Ziehau * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17841ab66cSSepherosa Ziehau * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18841ab66cSSepherosa Ziehau * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19841ab66cSSepherosa Ziehau * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20841ab66cSSepherosa Ziehau * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21841ab66cSSepherosa Ziehau * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22841ab66cSSepherosa Ziehau * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23841ab66cSSepherosa Ziehau * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24841ab66cSSepherosa Ziehau */
25841ab66cSSepherosa Ziehau
26085ff963SMatthew Dillon #include <sys/cdefs.h>
27085ff963SMatthew Dillon __FBSDID("$FreeBSD$");
28085ff963SMatthew Dillon
29841ab66cSSepherosa Ziehau /*
30841ab66cSSepherosa Ziehau * IEEE 802.11i TKIP crypto support.
31841ab66cSSepherosa Ziehau *
32841ab66cSSepherosa Ziehau * Part of this module is derived from similar code in the Host
33841ab66cSSepherosa Ziehau * AP driver. The code is used with the consent of the author and
34841ab66cSSepherosa Ziehau * it's license is included below.
35841ab66cSSepherosa Ziehau */
3632176cfdSRui Paulo #include "opt_wlan.h"
3732176cfdSRui Paulo
38841ab66cSSepherosa Ziehau #include <sys/param.h>
39841ab66cSSepherosa Ziehau #include <sys/systm.h>
40841ab66cSSepherosa Ziehau #include <sys/mbuf.h>
41841ab66cSSepherosa Ziehau #include <sys/malloc.h>
42841ab66cSSepherosa Ziehau #include <sys/kernel.h>
43841ab66cSSepherosa Ziehau #include <sys/module.h>
44841ab66cSSepherosa Ziehau #include <sys/endian.h>
45841ab66cSSepherosa Ziehau
46841ab66cSSepherosa Ziehau #include <sys/socket.h>
47841ab66cSSepherosa Ziehau
48841ab66cSSepherosa Ziehau #include <net/if.h>
49*bff82488SAaron LI #include <net/if_var.h>
50841ab66cSSepherosa Ziehau #include <net/if_media.h>
51841ab66cSSepherosa Ziehau #include <net/ethernet.h>
52841ab66cSSepherosa Ziehau
53841ab66cSSepherosa Ziehau #include <netproto/802_11/ieee80211_var.h>
54841ab66cSSepherosa Ziehau
5532176cfdSRui Paulo static void *tkip_attach(struct ieee80211vap *, struct ieee80211_key *);
56841ab66cSSepherosa Ziehau static void tkip_detach(struct ieee80211_key *);
57841ab66cSSepherosa Ziehau static int tkip_setkey(struct ieee80211_key *);
584f655ef5SMatthew Dillon static void tkip_setiv(struct ieee80211_key *, uint8_t *);
594f655ef5SMatthew Dillon static int tkip_encap(struct ieee80211_key *, struct mbuf *);
60841ab66cSSepherosa Ziehau static int tkip_enmic(struct ieee80211_key *, struct mbuf *, int);
61841ab66cSSepherosa Ziehau static int tkip_decap(struct ieee80211_key *, struct mbuf *, int);
62841ab66cSSepherosa Ziehau static int tkip_demic(struct ieee80211_key *, struct mbuf *, int);
63841ab66cSSepherosa Ziehau
64841ab66cSSepherosa Ziehau static const struct ieee80211_cipher tkip = {
65841ab66cSSepherosa Ziehau .ic_name = "TKIP",
66841ab66cSSepherosa Ziehau .ic_cipher = IEEE80211_CIPHER_TKIP,
67841ab66cSSepherosa Ziehau .ic_header = IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN +
68841ab66cSSepherosa Ziehau IEEE80211_WEP_EXTIVLEN,
69841ab66cSSepherosa Ziehau .ic_trailer = IEEE80211_WEP_CRCLEN,
70841ab66cSSepherosa Ziehau .ic_miclen = IEEE80211_WEP_MICLEN,
71841ab66cSSepherosa Ziehau .ic_attach = tkip_attach,
72841ab66cSSepherosa Ziehau .ic_detach = tkip_detach,
73841ab66cSSepherosa Ziehau .ic_setkey = tkip_setkey,
744f655ef5SMatthew Dillon .ic_setiv = tkip_setiv,
75841ab66cSSepherosa Ziehau .ic_encap = tkip_encap,
76841ab66cSSepherosa Ziehau .ic_decap = tkip_decap,
77841ab66cSSepherosa Ziehau .ic_enmic = tkip_enmic,
78841ab66cSSepherosa Ziehau .ic_demic = tkip_demic,
79841ab66cSSepherosa Ziehau };
80841ab66cSSepherosa Ziehau
8132176cfdSRui Paulo typedef uint8_t u8;
8232176cfdSRui Paulo typedef uint16_t u16;
8332176cfdSRui Paulo typedef uint32_t __u32;
8432176cfdSRui Paulo typedef uint32_t u32;
85841ab66cSSepherosa Ziehau
86841ab66cSSepherosa Ziehau struct tkip_ctx {
8732176cfdSRui Paulo struct ieee80211vap *tc_vap; /* for diagnostics+statistics */
88841ab66cSSepherosa Ziehau
8932176cfdSRui Paulo u16 tx_ttak[5];
9032176cfdSRui Paulo u8 tx_rc4key[16]; /* XXX for test module; make locals? */
91841ab66cSSepherosa Ziehau
9232176cfdSRui Paulo u16 rx_ttak[5];
93841ab66cSSepherosa Ziehau int rx_phase1_done;
9432176cfdSRui Paulo u8 rx_rc4key[16]; /* XXX for test module; make locals? */
95841ab66cSSepherosa Ziehau uint64_t rx_rsc; /* held until MIC verified */
96841ab66cSSepherosa Ziehau };
97841ab66cSSepherosa Ziehau
9832176cfdSRui Paulo static void michael_mic(struct tkip_ctx *, const u8 *key,
99841ab66cSSepherosa Ziehau struct mbuf *m, u_int off, size_t data_len,
10032176cfdSRui Paulo u8 mic[IEEE80211_WEP_MICLEN]);
101841ab66cSSepherosa Ziehau static int tkip_encrypt(struct tkip_ctx *, struct ieee80211_key *,
102841ab66cSSepherosa Ziehau struct mbuf *, int hdr_len);
103841ab66cSSepherosa Ziehau static int tkip_decrypt(struct tkip_ctx *, struct ieee80211_key *,
104841ab66cSSepherosa Ziehau struct mbuf *, int hdr_len);
105841ab66cSSepherosa Ziehau
106841ab66cSSepherosa Ziehau /* number of references from net80211 layer */
107841ab66cSSepherosa Ziehau static int nrefs = 0;
108841ab66cSSepherosa Ziehau
109841ab66cSSepherosa Ziehau static void *
tkip_attach(struct ieee80211vap * vap,struct ieee80211_key * k)11032176cfdSRui Paulo tkip_attach(struct ieee80211vap *vap, struct ieee80211_key *k)
111841ab66cSSepherosa Ziehau {
112841ab66cSSepherosa Ziehau struct tkip_ctx *ctx;
113841ab66cSSepherosa Ziehau
1144f655ef5SMatthew Dillon #if defined(__DragonFly__)
11532176cfdSRui Paulo ctx = (struct tkip_ctx *) kmalloc(sizeof(struct tkip_ctx),
116c567b546SJoe Talbott M_80211_CRYPTO, M_INTWAIT | M_ZERO);
1174f655ef5SMatthew Dillon #else
1184f655ef5SMatthew Dillon ctx = (struct tkip_ctx *) IEEE80211_MALLOC(sizeof(struct tkip_ctx),
1194f655ef5SMatthew Dillon M_80211_CRYPTO, IEEE80211_M_NOWAIT | IEEE80211_M_ZERO);
1204f655ef5SMatthew Dillon #endif
121841ab66cSSepherosa Ziehau if (ctx == NULL) {
12232176cfdSRui Paulo vap->iv_stats.is_crypto_nomem++;
123841ab66cSSepherosa Ziehau return NULL;
124841ab66cSSepherosa Ziehau }
125841ab66cSSepherosa Ziehau
12632176cfdSRui Paulo ctx->tc_vap = vap;
127841ab66cSSepherosa Ziehau nrefs++; /* NB: we assume caller locking */
128841ab66cSSepherosa Ziehau return ctx;
129841ab66cSSepherosa Ziehau }
130841ab66cSSepherosa Ziehau
131841ab66cSSepherosa Ziehau static void
tkip_detach(struct ieee80211_key * k)132841ab66cSSepherosa Ziehau tkip_detach(struct ieee80211_key *k)
133841ab66cSSepherosa Ziehau {
134841ab66cSSepherosa Ziehau struct tkip_ctx *ctx = k->wk_private;
135841ab66cSSepherosa Ziehau
1364f655ef5SMatthew Dillon IEEE80211_FREE(ctx, M_80211_CRYPTO);
137841ab66cSSepherosa Ziehau KASSERT(nrefs > 0, ("imbalanced attach/detach"));
138841ab66cSSepherosa Ziehau nrefs--; /* NB: we assume caller locking */
139841ab66cSSepherosa Ziehau }
140841ab66cSSepherosa Ziehau
141841ab66cSSepherosa Ziehau static int
tkip_setkey(struct ieee80211_key * k)142841ab66cSSepherosa Ziehau tkip_setkey(struct ieee80211_key *k)
143841ab66cSSepherosa Ziehau {
144841ab66cSSepherosa Ziehau struct tkip_ctx *ctx = k->wk_private;
145841ab66cSSepherosa Ziehau
146841ab66cSSepherosa Ziehau if (k->wk_keylen != (128/NBBY)) {
147841ab66cSSepherosa Ziehau (void) ctx; /* XXX */
14832176cfdSRui Paulo IEEE80211_DPRINTF(ctx->tc_vap, IEEE80211_MSG_CRYPTO,
149841ab66cSSepherosa Ziehau "%s: Invalid key length %u, expecting %u\n",
150841ab66cSSepherosa Ziehau __func__, k->wk_keylen, 128/NBBY);
151841ab66cSSepherosa Ziehau return 0;
152841ab66cSSepherosa Ziehau }
15332176cfdSRui Paulo ctx->rx_phase1_done = 0;
154841ab66cSSepherosa Ziehau return 1;
155841ab66cSSepherosa Ziehau }
156841ab66cSSepherosa Ziehau
1574f655ef5SMatthew Dillon static void
tkip_setiv(struct ieee80211_key * k,uint8_t * ivp)1584f655ef5SMatthew Dillon tkip_setiv(struct ieee80211_key *k, uint8_t *ivp)
1594f655ef5SMatthew Dillon {
1604f655ef5SMatthew Dillon struct tkip_ctx *ctx = k->wk_private;
1614f655ef5SMatthew Dillon struct ieee80211vap *vap = ctx->tc_vap;
1624f655ef5SMatthew Dillon uint8_t keyid;
1634f655ef5SMatthew Dillon
1644f655ef5SMatthew Dillon keyid = ieee80211_crypto_get_keyid(vap, k) << 6;
1654f655ef5SMatthew Dillon
1664f655ef5SMatthew Dillon k->wk_keytsc++;
1674f655ef5SMatthew Dillon ivp[0] = k->wk_keytsc >> 8; /* TSC1 */
1684f655ef5SMatthew Dillon ivp[1] = (ivp[0] | 0x20) & 0x7f; /* WEP seed */
1694f655ef5SMatthew Dillon ivp[2] = k->wk_keytsc >> 0; /* TSC0 */
1704f655ef5SMatthew Dillon ivp[3] = keyid | IEEE80211_WEP_EXTIV; /* KeyID | ExtID */
1714f655ef5SMatthew Dillon ivp[4] = k->wk_keytsc >> 16; /* TSC2 */
1724f655ef5SMatthew Dillon ivp[5] = k->wk_keytsc >> 24; /* TSC3 */
1734f655ef5SMatthew Dillon ivp[6] = k->wk_keytsc >> 32; /* TSC4 */
1744f655ef5SMatthew Dillon ivp[7] = k->wk_keytsc >> 40; /* TSC5 */
1754f655ef5SMatthew Dillon }
1764f655ef5SMatthew Dillon
177841ab66cSSepherosa Ziehau /*
178841ab66cSSepherosa Ziehau * Add privacy headers and do any s/w encryption required.
179841ab66cSSepherosa Ziehau */
180841ab66cSSepherosa Ziehau static int
tkip_encap(struct ieee80211_key * k,struct mbuf * m)1814f655ef5SMatthew Dillon tkip_encap(struct ieee80211_key *k, struct mbuf *m)
182841ab66cSSepherosa Ziehau {
183841ab66cSSepherosa Ziehau struct tkip_ctx *ctx = k->wk_private;
18432176cfdSRui Paulo struct ieee80211vap *vap = ctx->tc_vap;
18532176cfdSRui Paulo struct ieee80211com *ic = vap->iv_ic;
186841ab66cSSepherosa Ziehau uint8_t *ivp;
187841ab66cSSepherosa Ziehau int hdrlen;
188841ab66cSSepherosa Ziehau
189841ab66cSSepherosa Ziehau /*
190841ab66cSSepherosa Ziehau * Handle TKIP counter measures requirement.
191841ab66cSSepherosa Ziehau */
19232176cfdSRui Paulo if (vap->iv_flags & IEEE80211_F_COUNTERM) {
193841ab66cSSepherosa Ziehau #ifdef IEEE80211_DEBUG
194841ab66cSSepherosa Ziehau struct ieee80211_frame *wh = mtod(m, struct ieee80211_frame *);
195841ab66cSSepherosa Ziehau #endif
196841ab66cSSepherosa Ziehau
19732176cfdSRui Paulo IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO, wh->i_addr2,
19832176cfdSRui Paulo "discard frame due to countermeasures (%s)", __func__);
19932176cfdSRui Paulo vap->iv_stats.is_crypto_tkipcm++;
200841ab66cSSepherosa Ziehau return 0;
201841ab66cSSepherosa Ziehau }
202841ab66cSSepherosa Ziehau hdrlen = ieee80211_hdrspace(ic, mtod(m, void *));
203841ab66cSSepherosa Ziehau
204841ab66cSSepherosa Ziehau /*
205841ab66cSSepherosa Ziehau * Copy down 802.11 header and add the IV, KeyID, and ExtIV.
206841ab66cSSepherosa Ziehau */
207b5523eacSSascha Wildner M_PREPEND(m, tkip.ic_header, M_NOWAIT);
208841ab66cSSepherosa Ziehau if (m == NULL)
209841ab66cSSepherosa Ziehau return 0;
210841ab66cSSepherosa Ziehau ivp = mtod(m, uint8_t *);
211841ab66cSSepherosa Ziehau memmove(ivp, ivp + tkip.ic_header, hdrlen);
212841ab66cSSepherosa Ziehau ivp += hdrlen;
213841ab66cSSepherosa Ziehau
2144f655ef5SMatthew Dillon tkip_setiv(k, ivp);
215841ab66cSSepherosa Ziehau
216841ab66cSSepherosa Ziehau /*
2174f655ef5SMatthew Dillon * Finally, do software encrypt if needed.
218841ab66cSSepherosa Ziehau */
2194f655ef5SMatthew Dillon if ((k->wk_flags & IEEE80211_KEY_SWENCRYPT) &&
2204f655ef5SMatthew Dillon !tkip_encrypt(ctx, k, m, hdrlen))
221841ab66cSSepherosa Ziehau return 0;
222841ab66cSSepherosa Ziehau
223841ab66cSSepherosa Ziehau return 1;
224841ab66cSSepherosa Ziehau }
225841ab66cSSepherosa Ziehau
226841ab66cSSepherosa Ziehau /*
227841ab66cSSepherosa Ziehau * Add MIC to the frame as needed.
228841ab66cSSepherosa Ziehau */
229841ab66cSSepherosa Ziehau static int
tkip_enmic(struct ieee80211_key * k,struct mbuf * m,int force)230841ab66cSSepherosa Ziehau tkip_enmic(struct ieee80211_key *k, struct mbuf *m, int force)
231841ab66cSSepherosa Ziehau {
232841ab66cSSepherosa Ziehau struct tkip_ctx *ctx = k->wk_private;
233841ab66cSSepherosa Ziehau
23432176cfdSRui Paulo if (force || (k->wk_flags & IEEE80211_KEY_SWENMIC)) {
235841ab66cSSepherosa Ziehau struct ieee80211_frame *wh = mtod(m, struct ieee80211_frame *);
23632176cfdSRui Paulo struct ieee80211vap *vap = ctx->tc_vap;
23732176cfdSRui Paulo struct ieee80211com *ic = vap->iv_ic;
238841ab66cSSepherosa Ziehau int hdrlen;
239841ab66cSSepherosa Ziehau uint8_t mic[IEEE80211_WEP_MICLEN];
240841ab66cSSepherosa Ziehau
24132176cfdSRui Paulo vap->iv_stats.is_crypto_tkipenmic++;
242841ab66cSSepherosa Ziehau
243841ab66cSSepherosa Ziehau hdrlen = ieee80211_hdrspace(ic, wh);
244841ab66cSSepherosa Ziehau
245841ab66cSSepherosa Ziehau michael_mic(ctx, k->wk_txmic,
246841ab66cSSepherosa Ziehau m, hdrlen, m->m_pkthdr.len - hdrlen, mic);
24732176cfdSRui Paulo return m_append(m, tkip.ic_miclen, mic);
248841ab66cSSepherosa Ziehau }
249841ab66cSSepherosa Ziehau return 1;
250841ab66cSSepherosa Ziehau }
251841ab66cSSepherosa Ziehau
252841ab66cSSepherosa Ziehau static __inline uint64_t
READ_6(uint8_t b0,uint8_t b1,uint8_t b2,uint8_t b3,uint8_t b4,uint8_t b5)253841ab66cSSepherosa Ziehau READ_6(uint8_t b0, uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4, uint8_t b5)
254841ab66cSSepherosa Ziehau {
255841ab66cSSepherosa Ziehau uint32_t iv32 = (b0 << 0) | (b1 << 8) | (b2 << 16) | (b3 << 24);
256841ab66cSSepherosa Ziehau uint16_t iv16 = (b4 << 0) | (b5 << 8);
257841ab66cSSepherosa Ziehau return (((uint64_t)iv16) << 32) | iv32;
258841ab66cSSepherosa Ziehau }
259841ab66cSSepherosa Ziehau
260841ab66cSSepherosa Ziehau /*
261841ab66cSSepherosa Ziehau * Validate and strip privacy headers (and trailer) for a
262841ab66cSSepherosa Ziehau * received frame. If necessary, decrypt the frame using
263841ab66cSSepherosa Ziehau * the specified key.
264841ab66cSSepherosa Ziehau */
265841ab66cSSepherosa Ziehau static int
tkip_decap(struct ieee80211_key * k,struct mbuf * m,int hdrlen)266841ab66cSSepherosa Ziehau tkip_decap(struct ieee80211_key *k, struct mbuf *m, int hdrlen)
267841ab66cSSepherosa Ziehau {
268841ab66cSSepherosa Ziehau struct tkip_ctx *ctx = k->wk_private;
26932176cfdSRui Paulo struct ieee80211vap *vap = ctx->tc_vap;
270841ab66cSSepherosa Ziehau struct ieee80211_frame *wh;
27132176cfdSRui Paulo uint8_t *ivp, tid;
272841ab66cSSepherosa Ziehau
273841ab66cSSepherosa Ziehau /*
274841ab66cSSepherosa Ziehau * Header should have extended IV and sequence number;
275841ab66cSSepherosa Ziehau * verify the former and validate the latter.
276841ab66cSSepherosa Ziehau */
277841ab66cSSepherosa Ziehau wh = mtod(m, struct ieee80211_frame *);
278841ab66cSSepherosa Ziehau ivp = mtod(m, uint8_t *) + hdrlen;
279841ab66cSSepherosa Ziehau if ((ivp[IEEE80211_WEP_IVLEN] & IEEE80211_WEP_EXTIV) == 0) {
280841ab66cSSepherosa Ziehau /*
281841ab66cSSepherosa Ziehau * No extended IV; discard frame.
282841ab66cSSepherosa Ziehau */
28332176cfdSRui Paulo IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO, wh->i_addr2,
28432176cfdSRui Paulo "%s", "missing ExtIV for TKIP cipher");
28532176cfdSRui Paulo vap->iv_stats.is_rx_tkipformat++;
286841ab66cSSepherosa Ziehau return 0;
287841ab66cSSepherosa Ziehau }
288841ab66cSSepherosa Ziehau /*
289841ab66cSSepherosa Ziehau * Handle TKIP counter measures requirement.
290841ab66cSSepherosa Ziehau */
29132176cfdSRui Paulo if (vap->iv_flags & IEEE80211_F_COUNTERM) {
29232176cfdSRui Paulo IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO, wh->i_addr2,
29332176cfdSRui Paulo "discard frame due to countermeasures (%s)", __func__);
29432176cfdSRui Paulo vap->iv_stats.is_crypto_tkipcm++;
295841ab66cSSepherosa Ziehau return 0;
296841ab66cSSepherosa Ziehau }
297841ab66cSSepherosa Ziehau
29832176cfdSRui Paulo tid = ieee80211_gettid(wh);
299841ab66cSSepherosa Ziehau ctx->rx_rsc = READ_6(ivp[2], ivp[0], ivp[4], ivp[5], ivp[6], ivp[7]);
300085ff963SMatthew Dillon if (ctx->rx_rsc <= k->wk_keyrsc[tid] &&
301085ff963SMatthew Dillon (k->wk_flags & IEEE80211_KEY_NOREPLAY) == 0) {
302841ab66cSSepherosa Ziehau /*
303841ab66cSSepherosa Ziehau * Replay violation; notify upper layer.
304841ab66cSSepherosa Ziehau */
30532176cfdSRui Paulo ieee80211_notify_replay_failure(vap, wh, k, ctx->rx_rsc, tid);
30632176cfdSRui Paulo vap->iv_stats.is_rx_tkipreplay++;
307841ab66cSSepherosa Ziehau return 0;
308841ab66cSSepherosa Ziehau }
309841ab66cSSepherosa Ziehau /*
310841ab66cSSepherosa Ziehau * NB: We can't update the rsc in the key until MIC is verified.
311841ab66cSSepherosa Ziehau *
312841ab66cSSepherosa Ziehau * We assume we are not preempted between doing the check above
313841ab66cSSepherosa Ziehau * and updating wk_keyrsc when stripping the MIC in tkip_demic.
314841ab66cSSepherosa Ziehau * Otherwise we might process another packet and discard it as
315841ab66cSSepherosa Ziehau * a replay.
316841ab66cSSepherosa Ziehau */
317841ab66cSSepherosa Ziehau
318841ab66cSSepherosa Ziehau /*
319841ab66cSSepherosa Ziehau * Check if the device handled the decrypt in hardware.
320841ab66cSSepherosa Ziehau * If so we just strip the header; otherwise we need to
321841ab66cSSepherosa Ziehau * handle the decrypt in software.
322841ab66cSSepherosa Ziehau */
32332176cfdSRui Paulo if ((k->wk_flags & IEEE80211_KEY_SWDECRYPT) &&
324841ab66cSSepherosa Ziehau !tkip_decrypt(ctx, k, m, hdrlen))
325841ab66cSSepherosa Ziehau return 0;
326841ab66cSSepherosa Ziehau
327841ab66cSSepherosa Ziehau /*
328841ab66cSSepherosa Ziehau * Copy up 802.11 header and strip crypto bits.
329841ab66cSSepherosa Ziehau */
330841ab66cSSepherosa Ziehau memmove(mtod(m, uint8_t *) + tkip.ic_header, mtod(m, void *), hdrlen);
331841ab66cSSepherosa Ziehau m_adj(m, tkip.ic_header);
332841ab66cSSepherosa Ziehau m_adj(m, -tkip.ic_trailer);
333841ab66cSSepherosa Ziehau
334841ab66cSSepherosa Ziehau return 1;
335841ab66cSSepherosa Ziehau }
336841ab66cSSepherosa Ziehau
337841ab66cSSepherosa Ziehau /*
338841ab66cSSepherosa Ziehau * Verify and strip MIC from the frame.
339841ab66cSSepherosa Ziehau */
340841ab66cSSepherosa Ziehau static int
tkip_demic(struct ieee80211_key * k,struct mbuf * m,int force)341841ab66cSSepherosa Ziehau tkip_demic(struct ieee80211_key *k, struct mbuf *m, int force)
342841ab66cSSepherosa Ziehau {
343841ab66cSSepherosa Ziehau struct tkip_ctx *ctx = k->wk_private;
34432176cfdSRui Paulo struct ieee80211_frame *wh;
34532176cfdSRui Paulo uint8_t tid;
346841ab66cSSepherosa Ziehau
34732176cfdSRui Paulo wh = mtod(m, struct ieee80211_frame *);
34832176cfdSRui Paulo if ((k->wk_flags & IEEE80211_KEY_SWDEMIC) || force) {
34932176cfdSRui Paulo struct ieee80211vap *vap = ctx->tc_vap;
35032176cfdSRui Paulo int hdrlen = ieee80211_hdrspace(vap->iv_ic, wh);
35132176cfdSRui Paulo u8 mic[IEEE80211_WEP_MICLEN];
35232176cfdSRui Paulo u8 mic0[IEEE80211_WEP_MICLEN];
353841ab66cSSepherosa Ziehau
35432176cfdSRui Paulo vap->iv_stats.is_crypto_tkipdemic++;
355841ab66cSSepherosa Ziehau
356841ab66cSSepherosa Ziehau michael_mic(ctx, k->wk_rxmic,
357841ab66cSSepherosa Ziehau m, hdrlen, m->m_pkthdr.len - (hdrlen + tkip.ic_miclen),
358841ab66cSSepherosa Ziehau mic);
359841ab66cSSepherosa Ziehau m_copydata(m, m->m_pkthdr.len - tkip.ic_miclen,
36032176cfdSRui Paulo tkip.ic_miclen, mic0);
361841ab66cSSepherosa Ziehau if (memcmp(mic, mic0, tkip.ic_miclen)) {
362841ab66cSSepherosa Ziehau /* NB: 802.11 layer handles statistic and debug msg */
36332176cfdSRui Paulo ieee80211_notify_michael_failure(vap, wh,
364841ab66cSSepherosa Ziehau k->wk_rxkeyix != IEEE80211_KEYIX_NONE ?
365841ab66cSSepherosa Ziehau k->wk_rxkeyix : k->wk_keyix);
366841ab66cSSepherosa Ziehau return 0;
367841ab66cSSepherosa Ziehau }
368841ab66cSSepherosa Ziehau }
369841ab66cSSepherosa Ziehau /*
370841ab66cSSepherosa Ziehau * Strip MIC from the tail.
371841ab66cSSepherosa Ziehau */
372841ab66cSSepherosa Ziehau m_adj(m, -tkip.ic_miclen);
373841ab66cSSepherosa Ziehau
374841ab66cSSepherosa Ziehau /*
375841ab66cSSepherosa Ziehau * Ok to update rsc now that MIC has been verified.
376841ab66cSSepherosa Ziehau */
37732176cfdSRui Paulo tid = ieee80211_gettid(wh);
37832176cfdSRui Paulo k->wk_keyrsc[tid] = ctx->rx_rsc;
379841ab66cSSepherosa Ziehau
380841ab66cSSepherosa Ziehau return 1;
381841ab66cSSepherosa Ziehau }
382841ab66cSSepherosa Ziehau
383841ab66cSSepherosa Ziehau /*
384841ab66cSSepherosa Ziehau * Host AP crypt: host-based TKIP encryption implementation for Host AP driver
385841ab66cSSepherosa Ziehau *
386841ab66cSSepherosa Ziehau * Copyright (c) 2003-2004, Jouni Malinen <jkmaline@cc.hut.fi>
387841ab66cSSepherosa Ziehau *
388841ab66cSSepherosa Ziehau * This program is free software; you can redistribute it and/or modify
389841ab66cSSepherosa Ziehau * it under the terms of the GNU General Public License version 2 as
390841ab66cSSepherosa Ziehau * published by the Free Software Foundation. See README and COPYING for
391841ab66cSSepherosa Ziehau * more details.
392841ab66cSSepherosa Ziehau *
393841ab66cSSepherosa Ziehau * Alternatively, this software may be distributed under the terms of BSD
394841ab66cSSepherosa Ziehau * license.
395841ab66cSSepherosa Ziehau */
396841ab66cSSepherosa Ziehau
39732176cfdSRui Paulo static const __u32 crc32_table[256] = {
398841ab66cSSepherosa Ziehau 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
399841ab66cSSepherosa Ziehau 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
400841ab66cSSepherosa Ziehau 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
401841ab66cSSepherosa Ziehau 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
402841ab66cSSepherosa Ziehau 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
403841ab66cSSepherosa Ziehau 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
404841ab66cSSepherosa Ziehau 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
405841ab66cSSepherosa Ziehau 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
406841ab66cSSepherosa Ziehau 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
407841ab66cSSepherosa Ziehau 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
408841ab66cSSepherosa Ziehau 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
409841ab66cSSepherosa Ziehau 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
410841ab66cSSepherosa Ziehau 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
411841ab66cSSepherosa Ziehau 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
412841ab66cSSepherosa Ziehau 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
413841ab66cSSepherosa Ziehau 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
414841ab66cSSepherosa Ziehau 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
415841ab66cSSepherosa Ziehau 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
416841ab66cSSepherosa Ziehau 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
417841ab66cSSepherosa Ziehau 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
418841ab66cSSepherosa Ziehau 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
419841ab66cSSepherosa Ziehau 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
420841ab66cSSepherosa Ziehau 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
421841ab66cSSepherosa Ziehau 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
422841ab66cSSepherosa Ziehau 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
423841ab66cSSepherosa Ziehau 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
424841ab66cSSepherosa Ziehau 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
425841ab66cSSepherosa Ziehau 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
426841ab66cSSepherosa Ziehau 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
427841ab66cSSepherosa Ziehau 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
428841ab66cSSepherosa Ziehau 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
429841ab66cSSepherosa Ziehau 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
430841ab66cSSepherosa Ziehau 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
431841ab66cSSepherosa Ziehau 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
432841ab66cSSepherosa Ziehau 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
433841ab66cSSepherosa Ziehau 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
434841ab66cSSepherosa Ziehau 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
435841ab66cSSepherosa Ziehau 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
436841ab66cSSepherosa Ziehau 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
437841ab66cSSepherosa Ziehau 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
438841ab66cSSepherosa Ziehau 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
439841ab66cSSepherosa Ziehau 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
440841ab66cSSepherosa Ziehau 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
441841ab66cSSepherosa Ziehau 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
442841ab66cSSepherosa Ziehau 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
443841ab66cSSepherosa Ziehau 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
444841ab66cSSepherosa Ziehau 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
445841ab66cSSepherosa Ziehau 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
446841ab66cSSepherosa Ziehau 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
447841ab66cSSepherosa Ziehau 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
448841ab66cSSepherosa Ziehau 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
449841ab66cSSepherosa Ziehau 0x2d02ef8dL
450841ab66cSSepherosa Ziehau };
451841ab66cSSepherosa Ziehau
RotR1(u16 val)45232176cfdSRui Paulo static __inline u16 RotR1(u16 val)
453841ab66cSSepherosa Ziehau {
454841ab66cSSepherosa Ziehau return (val >> 1) | (val << 15);
455841ab66cSSepherosa Ziehau }
456841ab66cSSepherosa Ziehau
Lo8(u16 val)45732176cfdSRui Paulo static __inline u8 Lo8(u16 val)
458841ab66cSSepherosa Ziehau {
459841ab66cSSepherosa Ziehau return val & 0xff;
460841ab66cSSepherosa Ziehau }
461841ab66cSSepherosa Ziehau
Hi8(u16 val)46232176cfdSRui Paulo static __inline u8 Hi8(u16 val)
463841ab66cSSepherosa Ziehau {
464841ab66cSSepherosa Ziehau return val >> 8;
465841ab66cSSepherosa Ziehau }
466841ab66cSSepherosa Ziehau
Lo16(u32 val)46732176cfdSRui Paulo static __inline u16 Lo16(u32 val)
468841ab66cSSepherosa Ziehau {
469841ab66cSSepherosa Ziehau return val & 0xffff;
470841ab66cSSepherosa Ziehau }
471841ab66cSSepherosa Ziehau
Hi16(u32 val)47232176cfdSRui Paulo static __inline u16 Hi16(u32 val)
473841ab66cSSepherosa Ziehau {
474841ab66cSSepherosa Ziehau return val >> 16;
475841ab66cSSepherosa Ziehau }
476841ab66cSSepherosa Ziehau
Mk16(u8 hi,u8 lo)47732176cfdSRui Paulo static __inline u16 Mk16(u8 hi, u8 lo)
478841ab66cSSepherosa Ziehau {
47932176cfdSRui Paulo return lo | (((u16) hi) << 8);
480841ab66cSSepherosa Ziehau }
481841ab66cSSepherosa Ziehau
Mk16_le(const u16 * v)48232176cfdSRui Paulo static __inline u16 Mk16_le(const u16 *v)
483841ab66cSSepherosa Ziehau {
484841ab66cSSepherosa Ziehau return le16toh(*v);
485841ab66cSSepherosa Ziehau }
486841ab66cSSepherosa Ziehau
48732176cfdSRui Paulo static const u16 Sbox[256] = {
488841ab66cSSepherosa Ziehau 0xC6A5, 0xF884, 0xEE99, 0xF68D, 0xFF0D, 0xD6BD, 0xDEB1, 0x9154,
489841ab66cSSepherosa Ziehau 0x6050, 0x0203, 0xCEA9, 0x567D, 0xE719, 0xB562, 0x4DE6, 0xEC9A,
490841ab66cSSepherosa Ziehau 0x8F45, 0x1F9D, 0x8940, 0xFA87, 0xEF15, 0xB2EB, 0x8EC9, 0xFB0B,
491841ab66cSSepherosa Ziehau 0x41EC, 0xB367, 0x5FFD, 0x45EA, 0x23BF, 0x53F7, 0xE496, 0x9B5B,
492841ab66cSSepherosa Ziehau 0x75C2, 0xE11C, 0x3DAE, 0x4C6A, 0x6C5A, 0x7E41, 0xF502, 0x834F,
493841ab66cSSepherosa Ziehau 0x685C, 0x51F4, 0xD134, 0xF908, 0xE293, 0xAB73, 0x6253, 0x2A3F,
494841ab66cSSepherosa Ziehau 0x080C, 0x9552, 0x4665, 0x9D5E, 0x3028, 0x37A1, 0x0A0F, 0x2FB5,
495841ab66cSSepherosa Ziehau 0x0E09, 0x2436, 0x1B9B, 0xDF3D, 0xCD26, 0x4E69, 0x7FCD, 0xEA9F,
496841ab66cSSepherosa Ziehau 0x121B, 0x1D9E, 0x5874, 0x342E, 0x362D, 0xDCB2, 0xB4EE, 0x5BFB,
497841ab66cSSepherosa Ziehau 0xA4F6, 0x764D, 0xB761, 0x7DCE, 0x527B, 0xDD3E, 0x5E71, 0x1397,
498841ab66cSSepherosa Ziehau 0xA6F5, 0xB968, 0x0000, 0xC12C, 0x4060, 0xE31F, 0x79C8, 0xB6ED,
499841ab66cSSepherosa Ziehau 0xD4BE, 0x8D46, 0x67D9, 0x724B, 0x94DE, 0x98D4, 0xB0E8, 0x854A,
500841ab66cSSepherosa Ziehau 0xBB6B, 0xC52A, 0x4FE5, 0xED16, 0x86C5, 0x9AD7, 0x6655, 0x1194,
501841ab66cSSepherosa Ziehau 0x8ACF, 0xE910, 0x0406, 0xFE81, 0xA0F0, 0x7844, 0x25BA, 0x4BE3,
502841ab66cSSepherosa Ziehau 0xA2F3, 0x5DFE, 0x80C0, 0x058A, 0x3FAD, 0x21BC, 0x7048, 0xF104,
503841ab66cSSepherosa Ziehau 0x63DF, 0x77C1, 0xAF75, 0x4263, 0x2030, 0xE51A, 0xFD0E, 0xBF6D,
504841ab66cSSepherosa Ziehau 0x814C, 0x1814, 0x2635, 0xC32F, 0xBEE1, 0x35A2, 0x88CC, 0x2E39,
505841ab66cSSepherosa Ziehau 0x9357, 0x55F2, 0xFC82, 0x7A47, 0xC8AC, 0xBAE7, 0x322B, 0xE695,
506841ab66cSSepherosa Ziehau 0xC0A0, 0x1998, 0x9ED1, 0xA37F, 0x4466, 0x547E, 0x3BAB, 0x0B83,
507841ab66cSSepherosa Ziehau 0x8CCA, 0xC729, 0x6BD3, 0x283C, 0xA779, 0xBCE2, 0x161D, 0xAD76,
508841ab66cSSepherosa Ziehau 0xDB3B, 0x6456, 0x744E, 0x141E, 0x92DB, 0x0C0A, 0x486C, 0xB8E4,
509841ab66cSSepherosa Ziehau 0x9F5D, 0xBD6E, 0x43EF, 0xC4A6, 0x39A8, 0x31A4, 0xD337, 0xF28B,
510841ab66cSSepherosa Ziehau 0xD532, 0x8B43, 0x6E59, 0xDAB7, 0x018C, 0xB164, 0x9CD2, 0x49E0,
511841ab66cSSepherosa Ziehau 0xD8B4, 0xACFA, 0xF307, 0xCF25, 0xCAAF, 0xF48E, 0x47E9, 0x1018,
512841ab66cSSepherosa Ziehau 0x6FD5, 0xF088, 0x4A6F, 0x5C72, 0x3824, 0x57F1, 0x73C7, 0x9751,
513841ab66cSSepherosa Ziehau 0xCB23, 0xA17C, 0xE89C, 0x3E21, 0x96DD, 0x61DC, 0x0D86, 0x0F85,
514841ab66cSSepherosa Ziehau 0xE090, 0x7C42, 0x71C4, 0xCCAA, 0x90D8, 0x0605, 0xF701, 0x1C12,
515841ab66cSSepherosa Ziehau 0xC2A3, 0x6A5F, 0xAEF9, 0x69D0, 0x1791, 0x9958, 0x3A27, 0x27B9,
516841ab66cSSepherosa Ziehau 0xD938, 0xEB13, 0x2BB3, 0x2233, 0xD2BB, 0xA970, 0x0789, 0x33A7,
517841ab66cSSepherosa Ziehau 0x2DB6, 0x3C22, 0x1592, 0xC920, 0x8749, 0xAAFF, 0x5078, 0xA57A,
518841ab66cSSepherosa Ziehau 0x038F, 0x59F8, 0x0980, 0x1A17, 0x65DA, 0xD731, 0x84C6, 0xD0B8,
519841ab66cSSepherosa Ziehau 0x82C3, 0x29B0, 0x5A77, 0x1E11, 0x7BCB, 0xA8FC, 0x6DD6, 0x2C3A,
520841ab66cSSepherosa Ziehau };
521841ab66cSSepherosa Ziehau
_S_(u16 v)52232176cfdSRui Paulo static __inline u16 _S_(u16 v)
523841ab66cSSepherosa Ziehau {
52432176cfdSRui Paulo u16 t = Sbox[Hi8(v)];
525841ab66cSSepherosa Ziehau return Sbox[Lo8(v)] ^ ((t << 8) | (t >> 8));
526841ab66cSSepherosa Ziehau }
527841ab66cSSepherosa Ziehau
528841ab66cSSepherosa Ziehau #define PHASE1_LOOP_COUNT 8
529841ab66cSSepherosa Ziehau
tkip_mixing_phase1(u16 * TTAK,const u8 * TK,const u8 * TA,u32 IV32)53032176cfdSRui Paulo static void tkip_mixing_phase1(u16 *TTAK, const u8 *TK, const u8 *TA, u32 IV32)
531841ab66cSSepherosa Ziehau {
532841ab66cSSepherosa Ziehau int i, j;
533841ab66cSSepherosa Ziehau
534841ab66cSSepherosa Ziehau /* Initialize the 80-bit TTAK from TSC (IV32) and TA[0..5] */
535841ab66cSSepherosa Ziehau TTAK[0] = Lo16(IV32);
536841ab66cSSepherosa Ziehau TTAK[1] = Hi16(IV32);
537841ab66cSSepherosa Ziehau TTAK[2] = Mk16(TA[1], TA[0]);
538841ab66cSSepherosa Ziehau TTAK[3] = Mk16(TA[3], TA[2]);
539841ab66cSSepherosa Ziehau TTAK[4] = Mk16(TA[5], TA[4]);
540841ab66cSSepherosa Ziehau
541841ab66cSSepherosa Ziehau for (i = 0; i < PHASE1_LOOP_COUNT; i++) {
542841ab66cSSepherosa Ziehau j = 2 * (i & 1);
543841ab66cSSepherosa Ziehau TTAK[0] += _S_(TTAK[4] ^ Mk16(TK[1 + j], TK[0 + j]));
544841ab66cSSepherosa Ziehau TTAK[1] += _S_(TTAK[0] ^ Mk16(TK[5 + j], TK[4 + j]));
545841ab66cSSepherosa Ziehau TTAK[2] += _S_(TTAK[1] ^ Mk16(TK[9 + j], TK[8 + j]));
546841ab66cSSepherosa Ziehau TTAK[3] += _S_(TTAK[2] ^ Mk16(TK[13 + j], TK[12 + j]));
547841ab66cSSepherosa Ziehau TTAK[4] += _S_(TTAK[3] ^ Mk16(TK[1 + j], TK[0 + j])) + i;
548841ab66cSSepherosa Ziehau }
549841ab66cSSepherosa Ziehau }
550841ab66cSSepherosa Ziehau
551841ab66cSSepherosa Ziehau #ifndef _BYTE_ORDER
552841ab66cSSepherosa Ziehau #error "Don't know native byte order"
553841ab66cSSepherosa Ziehau #endif
554841ab66cSSepherosa Ziehau
tkip_mixing_phase2(u8 * WEPSeed,const u8 * TK,const u16 * TTAK,u16 IV16)55532176cfdSRui Paulo static void tkip_mixing_phase2(u8 *WEPSeed, const u8 *TK, const u16 *TTAK,
55632176cfdSRui Paulo u16 IV16)
557841ab66cSSepherosa Ziehau {
558841ab66cSSepherosa Ziehau /* Make temporary area overlap WEP seed so that the final copy can be
559841ab66cSSepherosa Ziehau * avoided on little endian hosts. */
56032176cfdSRui Paulo u16 *PPK = (u16 *) &WEPSeed[4];
561841ab66cSSepherosa Ziehau
562841ab66cSSepherosa Ziehau /* Step 1 - make copy of TTAK and bring in TSC */
563841ab66cSSepherosa Ziehau PPK[0] = TTAK[0];
564841ab66cSSepherosa Ziehau PPK[1] = TTAK[1];
565841ab66cSSepherosa Ziehau PPK[2] = TTAK[2];
566841ab66cSSepherosa Ziehau PPK[3] = TTAK[3];
567841ab66cSSepherosa Ziehau PPK[4] = TTAK[4];
568841ab66cSSepherosa Ziehau PPK[5] = TTAK[4] + IV16;
569841ab66cSSepherosa Ziehau
570841ab66cSSepherosa Ziehau /* Step 2 - 96-bit bijective mixing using S-box */
57132176cfdSRui Paulo PPK[0] += _S_(PPK[5] ^ Mk16_le((const u16 *) &TK[0]));
57232176cfdSRui Paulo PPK[1] += _S_(PPK[0] ^ Mk16_le((const u16 *) &TK[2]));
57332176cfdSRui Paulo PPK[2] += _S_(PPK[1] ^ Mk16_le((const u16 *) &TK[4]));
57432176cfdSRui Paulo PPK[3] += _S_(PPK[2] ^ Mk16_le((const u16 *) &TK[6]));
57532176cfdSRui Paulo PPK[4] += _S_(PPK[3] ^ Mk16_le((const u16 *) &TK[8]));
57632176cfdSRui Paulo PPK[5] += _S_(PPK[4] ^ Mk16_le((const u16 *) &TK[10]));
577841ab66cSSepherosa Ziehau
57832176cfdSRui Paulo PPK[0] += RotR1(PPK[5] ^ Mk16_le((const u16 *) &TK[12]));
57932176cfdSRui Paulo PPK[1] += RotR1(PPK[0] ^ Mk16_le((const u16 *) &TK[14]));
580841ab66cSSepherosa Ziehau PPK[2] += RotR1(PPK[1]);
581841ab66cSSepherosa Ziehau PPK[3] += RotR1(PPK[2]);
582841ab66cSSepherosa Ziehau PPK[4] += RotR1(PPK[3]);
583841ab66cSSepherosa Ziehau PPK[5] += RotR1(PPK[4]);
584841ab66cSSepherosa Ziehau
585841ab66cSSepherosa Ziehau /* Step 3 - bring in last of TK bits, assign 24-bit WEP IV value
586841ab66cSSepherosa Ziehau * WEPSeed[0..2] is transmitted as WEP IV */
587841ab66cSSepherosa Ziehau WEPSeed[0] = Hi8(IV16);
588841ab66cSSepherosa Ziehau WEPSeed[1] = (Hi8(IV16) | 0x20) & 0x7F;
589841ab66cSSepherosa Ziehau WEPSeed[2] = Lo8(IV16);
59032176cfdSRui Paulo WEPSeed[3] = Lo8((PPK[5] ^ Mk16_le((const u16 *) &TK[0])) >> 1);
591841ab66cSSepherosa Ziehau
592841ab66cSSepherosa Ziehau #if _BYTE_ORDER == _BIG_ENDIAN
593841ab66cSSepherosa Ziehau {
594841ab66cSSepherosa Ziehau int i;
595841ab66cSSepherosa Ziehau for (i = 0; i < 6; i++)
596841ab66cSSepherosa Ziehau PPK[i] = (PPK[i] << 8) | (PPK[i] >> 8);
597841ab66cSSepherosa Ziehau }
598841ab66cSSepherosa Ziehau #endif
599841ab66cSSepherosa Ziehau }
600841ab66cSSepherosa Ziehau
601841ab66cSSepherosa Ziehau static void
wep_encrypt(u8 * key,struct mbuf * m0,u_int off,size_t data_len,uint8_t icv[IEEE80211_WEP_CRCLEN])60232176cfdSRui Paulo wep_encrypt(u8 *key, struct mbuf *m0, u_int off, size_t data_len,
603841ab66cSSepherosa Ziehau uint8_t icv[IEEE80211_WEP_CRCLEN])
604841ab66cSSepherosa Ziehau {
60532176cfdSRui Paulo u32 i, j, k, crc;
606841ab66cSSepherosa Ziehau size_t buflen;
60732176cfdSRui Paulo u8 S[256];
60832176cfdSRui Paulo u8 *pos;
609841ab66cSSepherosa Ziehau struct mbuf *m;
61032176cfdSRui Paulo #define S_SWAP(a,b) do { u8 t = S[a]; S[a] = S[b]; S[b] = t; } while(0)
611841ab66cSSepherosa Ziehau
612841ab66cSSepherosa Ziehau /* Setup RC4 state */
613841ab66cSSepherosa Ziehau for (i = 0; i < 256; i++)
614841ab66cSSepherosa Ziehau S[i] = i;
615841ab66cSSepherosa Ziehau j = 0;
616841ab66cSSepherosa Ziehau for (i = 0; i < 256; i++) {
617841ab66cSSepherosa Ziehau j = (j + S[i] + key[i & 0x0f]) & 0xff;
618841ab66cSSepherosa Ziehau S_SWAP(i, j);
619841ab66cSSepherosa Ziehau }
620841ab66cSSepherosa Ziehau
621841ab66cSSepherosa Ziehau /* Compute CRC32 over unencrypted data and apply RC4 to data */
622841ab66cSSepherosa Ziehau crc = ~0;
623841ab66cSSepherosa Ziehau i = j = 0;
624841ab66cSSepherosa Ziehau m = m0;
625841ab66cSSepherosa Ziehau pos = mtod(m, uint8_t *) + off;
626841ab66cSSepherosa Ziehau buflen = m->m_len - off;
627841ab66cSSepherosa Ziehau for (;;) {
628841ab66cSSepherosa Ziehau if (buflen > data_len)
629841ab66cSSepherosa Ziehau buflen = data_len;
630841ab66cSSepherosa Ziehau data_len -= buflen;
631841ab66cSSepherosa Ziehau for (k = 0; k < buflen; k++) {
632841ab66cSSepherosa Ziehau crc = crc32_table[(crc ^ *pos) & 0xff] ^ (crc >> 8);
633841ab66cSSepherosa Ziehau i = (i + 1) & 0xff;
634841ab66cSSepherosa Ziehau j = (j + S[i]) & 0xff;
635841ab66cSSepherosa Ziehau S_SWAP(i, j);
636841ab66cSSepherosa Ziehau *pos++ ^= S[(S[i] + S[j]) & 0xff];
637841ab66cSSepherosa Ziehau }
638841ab66cSSepherosa Ziehau m = m->m_next;
639841ab66cSSepherosa Ziehau if (m == NULL) {
640841ab66cSSepherosa Ziehau KASSERT(data_len == 0,
641085ff963SMatthew Dillon ("out of buffers with data_len %zu\n", data_len));
642841ab66cSSepherosa Ziehau break;
643841ab66cSSepherosa Ziehau }
644841ab66cSSepherosa Ziehau pos = mtod(m, uint8_t *);
645841ab66cSSepherosa Ziehau buflen = m->m_len;
646841ab66cSSepherosa Ziehau }
647841ab66cSSepherosa Ziehau crc = ~crc;
648841ab66cSSepherosa Ziehau
649841ab66cSSepherosa Ziehau /* Append little-endian CRC32 and encrypt it to produce ICV */
650841ab66cSSepherosa Ziehau icv[0] = crc;
651841ab66cSSepherosa Ziehau icv[1] = crc >> 8;
652841ab66cSSepherosa Ziehau icv[2] = crc >> 16;
653841ab66cSSepherosa Ziehau icv[3] = crc >> 24;
654841ab66cSSepherosa Ziehau for (k = 0; k < IEEE80211_WEP_CRCLEN; k++) {
655841ab66cSSepherosa Ziehau i = (i + 1) & 0xff;
656841ab66cSSepherosa Ziehau j = (j + S[i]) & 0xff;
657841ab66cSSepherosa Ziehau S_SWAP(i, j);
658841ab66cSSepherosa Ziehau icv[k] ^= S[(S[i] + S[j]) & 0xff];
659841ab66cSSepherosa Ziehau }
660841ab66cSSepherosa Ziehau }
661841ab66cSSepherosa Ziehau
662841ab66cSSepherosa Ziehau static int
wep_decrypt(u8 * key,struct mbuf * m,u_int off,size_t data_len)66332176cfdSRui Paulo wep_decrypt(u8 *key, struct mbuf *m, u_int off, size_t data_len)
664841ab66cSSepherosa Ziehau {
66532176cfdSRui Paulo u32 i, j, k, crc;
66632176cfdSRui Paulo u8 S[256];
66732176cfdSRui Paulo u8 *pos, icv[4];
668841ab66cSSepherosa Ziehau size_t buflen;
669841ab66cSSepherosa Ziehau
670841ab66cSSepherosa Ziehau /* Setup RC4 state */
671841ab66cSSepherosa Ziehau for (i = 0; i < 256; i++)
672841ab66cSSepherosa Ziehau S[i] = i;
673841ab66cSSepherosa Ziehau j = 0;
674841ab66cSSepherosa Ziehau for (i = 0; i < 256; i++) {
675841ab66cSSepherosa Ziehau j = (j + S[i] + key[i & 0x0f]) & 0xff;
676841ab66cSSepherosa Ziehau S_SWAP(i, j);
677841ab66cSSepherosa Ziehau }
678841ab66cSSepherosa Ziehau
679841ab66cSSepherosa Ziehau /* Apply RC4 to data and compute CRC32 over decrypted data */
680841ab66cSSepherosa Ziehau crc = ~0;
681841ab66cSSepherosa Ziehau i = j = 0;
682841ab66cSSepherosa Ziehau pos = mtod(m, uint8_t *) + off;
683841ab66cSSepherosa Ziehau buflen = m->m_len - off;
684841ab66cSSepherosa Ziehau for (;;) {
685841ab66cSSepherosa Ziehau if (buflen > data_len)
686841ab66cSSepherosa Ziehau buflen = data_len;
687841ab66cSSepherosa Ziehau data_len -= buflen;
688841ab66cSSepherosa Ziehau for (k = 0; k < buflen; k++) {
689841ab66cSSepherosa Ziehau i = (i + 1) & 0xff;
690841ab66cSSepherosa Ziehau j = (j + S[i]) & 0xff;
691841ab66cSSepherosa Ziehau S_SWAP(i, j);
692841ab66cSSepherosa Ziehau *pos ^= S[(S[i] + S[j]) & 0xff];
693841ab66cSSepherosa Ziehau crc = crc32_table[(crc ^ *pos) & 0xff] ^ (crc >> 8);
694841ab66cSSepherosa Ziehau pos++;
695841ab66cSSepherosa Ziehau }
696841ab66cSSepherosa Ziehau m = m->m_next;
697841ab66cSSepherosa Ziehau if (m == NULL) {
698841ab66cSSepherosa Ziehau KASSERT(data_len == 0,
699085ff963SMatthew Dillon ("out of buffers with data_len %zu\n", data_len));
700841ab66cSSepherosa Ziehau break;
701841ab66cSSepherosa Ziehau }
702841ab66cSSepherosa Ziehau pos = mtod(m, uint8_t *);
703841ab66cSSepherosa Ziehau buflen = m->m_len;
704841ab66cSSepherosa Ziehau }
705841ab66cSSepherosa Ziehau crc = ~crc;
706841ab66cSSepherosa Ziehau
707841ab66cSSepherosa Ziehau /* Encrypt little-endian CRC32 and verify that it matches with the
708841ab66cSSepherosa Ziehau * received ICV */
709841ab66cSSepherosa Ziehau icv[0] = crc;
710841ab66cSSepherosa Ziehau icv[1] = crc >> 8;
711841ab66cSSepherosa Ziehau icv[2] = crc >> 16;
712841ab66cSSepherosa Ziehau icv[3] = crc >> 24;
713841ab66cSSepherosa Ziehau for (k = 0; k < 4; k++) {
714841ab66cSSepherosa Ziehau i = (i + 1) & 0xff;
715841ab66cSSepherosa Ziehau j = (j + S[i]) & 0xff;
716841ab66cSSepherosa Ziehau S_SWAP(i, j);
717841ab66cSSepherosa Ziehau if ((icv[k] ^ S[(S[i] + S[j]) & 0xff]) != *pos++) {
718841ab66cSSepherosa Ziehau /* ICV mismatch - drop frame */
719841ab66cSSepherosa Ziehau return -1;
720841ab66cSSepherosa Ziehau }
721841ab66cSSepherosa Ziehau }
722841ab66cSSepherosa Ziehau
723841ab66cSSepherosa Ziehau return 0;
724841ab66cSSepherosa Ziehau }
725841ab66cSSepherosa Ziehau
726841ab66cSSepherosa Ziehau
rotl(u32 val,int bits)72732176cfdSRui Paulo static __inline u32 rotl(u32 val, int bits)
728841ab66cSSepherosa Ziehau {
729841ab66cSSepherosa Ziehau return (val << bits) | (val >> (32 - bits));
730841ab66cSSepherosa Ziehau }
731841ab66cSSepherosa Ziehau
732841ab66cSSepherosa Ziehau
rotr(u32 val,int bits)73332176cfdSRui Paulo static __inline u32 rotr(u32 val, int bits)
734841ab66cSSepherosa Ziehau {
735841ab66cSSepherosa Ziehau return (val >> bits) | (val << (32 - bits));
736841ab66cSSepherosa Ziehau }
737841ab66cSSepherosa Ziehau
738841ab66cSSepherosa Ziehau
xswap(u32 val)73932176cfdSRui Paulo static __inline u32 xswap(u32 val)
740841ab66cSSepherosa Ziehau {
741841ab66cSSepherosa Ziehau return ((val & 0x00ff00ff) << 8) | ((val & 0xff00ff00) >> 8);
742841ab66cSSepherosa Ziehau }
743841ab66cSSepherosa Ziehau
744841ab66cSSepherosa Ziehau
745841ab66cSSepherosa Ziehau #define michael_block(l, r) \
746841ab66cSSepherosa Ziehau do { \
747841ab66cSSepherosa Ziehau r ^= rotl(l, 17); \
748841ab66cSSepherosa Ziehau l += r; \
749841ab66cSSepherosa Ziehau r ^= xswap(l); \
750841ab66cSSepherosa Ziehau l += r; \
751841ab66cSSepherosa Ziehau r ^= rotl(l, 3); \
752841ab66cSSepherosa Ziehau l += r; \
753841ab66cSSepherosa Ziehau r ^= rotr(l, 2); \
754841ab66cSSepherosa Ziehau l += r; \
755841ab66cSSepherosa Ziehau } while (0)
756841ab66cSSepherosa Ziehau
757841ab66cSSepherosa Ziehau
get_le32_split(u8 b0,u8 b1,u8 b2,u8 b3)75832176cfdSRui Paulo static __inline u32 get_le32_split(u8 b0, u8 b1, u8 b2, u8 b3)
759841ab66cSSepherosa Ziehau {
760841ab66cSSepherosa Ziehau return b0 | (b1 << 8) | (b2 << 16) | (b3 << 24);
761841ab66cSSepherosa Ziehau }
762841ab66cSSepherosa Ziehau
get_le32(const u8 * p)76332176cfdSRui Paulo static __inline u32 get_le32(const u8 *p)
764841ab66cSSepherosa Ziehau {
765841ab66cSSepherosa Ziehau return get_le32_split(p[0], p[1], p[2], p[3]);
766841ab66cSSepherosa Ziehau }
767841ab66cSSepherosa Ziehau
768841ab66cSSepherosa Ziehau
put_le32(u8 * p,u32 v)76932176cfdSRui Paulo static __inline void put_le32(u8 *p, u32 v)
770841ab66cSSepherosa Ziehau {
771841ab66cSSepherosa Ziehau p[0] = v;
772841ab66cSSepherosa Ziehau p[1] = v >> 8;
773841ab66cSSepherosa Ziehau p[2] = v >> 16;
774841ab66cSSepherosa Ziehau p[3] = v >> 24;
775841ab66cSSepherosa Ziehau }
776841ab66cSSepherosa Ziehau
777841ab66cSSepherosa Ziehau /*
778841ab66cSSepherosa Ziehau * Craft pseudo header used to calculate the MIC.
779841ab66cSSepherosa Ziehau */
780841ab66cSSepherosa Ziehau static void
michael_mic_hdr(const struct ieee80211_frame * wh0,uint8_t hdr[16])781841ab66cSSepherosa Ziehau michael_mic_hdr(const struct ieee80211_frame *wh0, uint8_t hdr[16])
782841ab66cSSepherosa Ziehau {
783841ab66cSSepherosa Ziehau const struct ieee80211_frame_addr4 *wh =
784841ab66cSSepherosa Ziehau (const struct ieee80211_frame_addr4 *) wh0;
785841ab66cSSepherosa Ziehau
786841ab66cSSepherosa Ziehau switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) {
787841ab66cSSepherosa Ziehau case IEEE80211_FC1_DIR_NODS:
788841ab66cSSepherosa Ziehau IEEE80211_ADDR_COPY(hdr, wh->i_addr1); /* DA */
789841ab66cSSepherosa Ziehau IEEE80211_ADDR_COPY(hdr + IEEE80211_ADDR_LEN, wh->i_addr2);
790841ab66cSSepherosa Ziehau break;
791841ab66cSSepherosa Ziehau case IEEE80211_FC1_DIR_TODS:
792841ab66cSSepherosa Ziehau IEEE80211_ADDR_COPY(hdr, wh->i_addr3); /* DA */
793841ab66cSSepherosa Ziehau IEEE80211_ADDR_COPY(hdr + IEEE80211_ADDR_LEN, wh->i_addr2);
794841ab66cSSepherosa Ziehau break;
795841ab66cSSepherosa Ziehau case IEEE80211_FC1_DIR_FROMDS:
796841ab66cSSepherosa Ziehau IEEE80211_ADDR_COPY(hdr, wh->i_addr1); /* DA */
797841ab66cSSepherosa Ziehau IEEE80211_ADDR_COPY(hdr + IEEE80211_ADDR_LEN, wh->i_addr3);
798841ab66cSSepherosa Ziehau break;
799841ab66cSSepherosa Ziehau case IEEE80211_FC1_DIR_DSTODS:
800841ab66cSSepherosa Ziehau IEEE80211_ADDR_COPY(hdr, wh->i_addr3); /* DA */
801841ab66cSSepherosa Ziehau IEEE80211_ADDR_COPY(hdr + IEEE80211_ADDR_LEN, wh->i_addr4);
802841ab66cSSepherosa Ziehau break;
803841ab66cSSepherosa Ziehau }
804841ab66cSSepherosa Ziehau
805841ab66cSSepherosa Ziehau if (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_QOS) {
806841ab66cSSepherosa Ziehau const struct ieee80211_qosframe *qwh =
807841ab66cSSepherosa Ziehau (const struct ieee80211_qosframe *) wh;
808841ab66cSSepherosa Ziehau hdr[12] = qwh->i_qos[0] & IEEE80211_QOS_TID;
809841ab66cSSepherosa Ziehau } else
810841ab66cSSepherosa Ziehau hdr[12] = 0;
811841ab66cSSepherosa Ziehau hdr[13] = hdr[14] = hdr[15] = 0; /* reserved */
812841ab66cSSepherosa Ziehau }
813841ab66cSSepherosa Ziehau
814841ab66cSSepherosa Ziehau static void
michael_mic(struct tkip_ctx * ctx,const u8 * key,struct mbuf * m,u_int off,size_t data_len,u8 mic[IEEE80211_WEP_MICLEN])81532176cfdSRui Paulo michael_mic(struct tkip_ctx *ctx, const u8 *key,
816841ab66cSSepherosa Ziehau struct mbuf *m, u_int off, size_t data_len,
81732176cfdSRui Paulo u8 mic[IEEE80211_WEP_MICLEN])
818841ab66cSSepherosa Ziehau {
819841ab66cSSepherosa Ziehau uint8_t hdr[16];
82032176cfdSRui Paulo u32 l, r;
821841ab66cSSepherosa Ziehau const uint8_t *data;
822841ab66cSSepherosa Ziehau u_int space;
823841ab66cSSepherosa Ziehau
824841ab66cSSepherosa Ziehau michael_mic_hdr(mtod(m, struct ieee80211_frame *), hdr);
825841ab66cSSepherosa Ziehau
826841ab66cSSepherosa Ziehau l = get_le32(key);
827841ab66cSSepherosa Ziehau r = get_le32(key + 4);
828841ab66cSSepherosa Ziehau
829841ab66cSSepherosa Ziehau /* Michael MIC pseudo header: DA, SA, 3 x 0, Priority */
830841ab66cSSepherosa Ziehau l ^= get_le32(hdr);
831841ab66cSSepherosa Ziehau michael_block(l, r);
832841ab66cSSepherosa Ziehau l ^= get_le32(&hdr[4]);
833841ab66cSSepherosa Ziehau michael_block(l, r);
834841ab66cSSepherosa Ziehau l ^= get_le32(&hdr[8]);
835841ab66cSSepherosa Ziehau michael_block(l, r);
836841ab66cSSepherosa Ziehau l ^= get_le32(&hdr[12]);
837841ab66cSSepherosa Ziehau michael_block(l, r);
838841ab66cSSepherosa Ziehau
839841ab66cSSepherosa Ziehau /* first buffer has special handling */
840841ab66cSSepherosa Ziehau data = mtod(m, const uint8_t *) + off;
841841ab66cSSepherosa Ziehau space = m->m_len - off;
842841ab66cSSepherosa Ziehau for (;;) {
843841ab66cSSepherosa Ziehau if (space > data_len)
844841ab66cSSepherosa Ziehau space = data_len;
845841ab66cSSepherosa Ziehau /* collect 32-bit blocks from current buffer */
846841ab66cSSepherosa Ziehau while (space >= sizeof(uint32_t)) {
847841ab66cSSepherosa Ziehau l ^= get_le32(data);
848841ab66cSSepherosa Ziehau michael_block(l, r);
849841ab66cSSepherosa Ziehau data += sizeof(uint32_t), space -= sizeof(uint32_t);
850841ab66cSSepherosa Ziehau data_len -= sizeof(uint32_t);
851841ab66cSSepherosa Ziehau }
85232176cfdSRui Paulo /*
85332176cfdSRui Paulo * NB: when space is zero we make one more trip around
85432176cfdSRui Paulo * the loop to advance to the next mbuf where there is
85532176cfdSRui Paulo * data. This handles the case where there are 4*n
85632176cfdSRui Paulo * bytes in an mbuf followed by <4 bytes in a later mbuf.
85732176cfdSRui Paulo * By making an extra trip we'll drop out of the loop
85832176cfdSRui Paulo * with m pointing at the mbuf with 3 bytes and space
85932176cfdSRui Paulo * set as required by the remainder handling below.
86032176cfdSRui Paulo */
86132176cfdSRui Paulo if (data_len == 0 ||
86232176cfdSRui Paulo (data_len < sizeof(uint32_t) && space != 0))
863841ab66cSSepherosa Ziehau break;
864841ab66cSSepherosa Ziehau m = m->m_next;
865841ab66cSSepherosa Ziehau if (m == NULL) {
866085ff963SMatthew Dillon KASSERT(0, ("out of data, data_len %zu\n", data_len));
867841ab66cSSepherosa Ziehau break;
868841ab66cSSepherosa Ziehau }
869841ab66cSSepherosa Ziehau if (space != 0) {
870841ab66cSSepherosa Ziehau const uint8_t *data_next;
871841ab66cSSepherosa Ziehau /*
872841ab66cSSepherosa Ziehau * Block straddles buffers, split references.
873841ab66cSSepherosa Ziehau */
874841ab66cSSepherosa Ziehau data_next = mtod(m, const uint8_t *);
875841ab66cSSepherosa Ziehau KASSERT(m->m_len >= sizeof(uint32_t) - space,
876841ab66cSSepherosa Ziehau ("not enough data in following buffer, "
877085ff963SMatthew Dillon "m_len %u need %zu\n", m->m_len,
878841ab66cSSepherosa Ziehau sizeof(uint32_t) - space));
879841ab66cSSepherosa Ziehau switch (space) {
880841ab66cSSepherosa Ziehau case 1:
881841ab66cSSepherosa Ziehau l ^= get_le32_split(data[0], data_next[0],
882841ab66cSSepherosa Ziehau data_next[1], data_next[2]);
883841ab66cSSepherosa Ziehau data = data_next + 3;
884841ab66cSSepherosa Ziehau space = m->m_len - 3;
885841ab66cSSepherosa Ziehau break;
886841ab66cSSepherosa Ziehau case 2:
887841ab66cSSepherosa Ziehau l ^= get_le32_split(data[0], data[1],
888841ab66cSSepherosa Ziehau data_next[0], data_next[1]);
889841ab66cSSepherosa Ziehau data = data_next + 2;
890841ab66cSSepherosa Ziehau space = m->m_len - 2;
891841ab66cSSepherosa Ziehau break;
892841ab66cSSepherosa Ziehau case 3:
893841ab66cSSepherosa Ziehau l ^= get_le32_split(data[0], data[1],
894841ab66cSSepherosa Ziehau data[2], data_next[0]);
895841ab66cSSepherosa Ziehau data = data_next + 1;
896841ab66cSSepherosa Ziehau space = m->m_len - 1;
897841ab66cSSepherosa Ziehau break;
898841ab66cSSepherosa Ziehau }
899841ab66cSSepherosa Ziehau michael_block(l, r);
900841ab66cSSepherosa Ziehau data_len -= sizeof(uint32_t);
901841ab66cSSepherosa Ziehau } else {
902841ab66cSSepherosa Ziehau /*
903841ab66cSSepherosa Ziehau * Setup for next buffer.
904841ab66cSSepherosa Ziehau */
905841ab66cSSepherosa Ziehau data = mtod(m, const uint8_t *);
906841ab66cSSepherosa Ziehau space = m->m_len;
907841ab66cSSepherosa Ziehau }
908841ab66cSSepherosa Ziehau }
90932176cfdSRui Paulo /*
91032176cfdSRui Paulo * Catch degenerate cases like mbuf[4*n+1 bytes] followed by
91132176cfdSRui Paulo * mbuf[2 bytes]. I don't believe these should happen; if they
91232176cfdSRui Paulo * do then we'll need more involved logic.
91332176cfdSRui Paulo */
91432176cfdSRui Paulo KASSERT(data_len <= space,
915085ff963SMatthew Dillon ("not enough data, data_len %zu space %u\n", data_len, space));
91632176cfdSRui Paulo
917841ab66cSSepherosa Ziehau /* Last block and padding (0x5a, 4..7 x 0) */
918841ab66cSSepherosa Ziehau switch (data_len) {
919841ab66cSSepherosa Ziehau case 0:
920841ab66cSSepherosa Ziehau l ^= get_le32_split(0x5a, 0, 0, 0);
921841ab66cSSepherosa Ziehau break;
922841ab66cSSepherosa Ziehau case 1:
923841ab66cSSepherosa Ziehau l ^= get_le32_split(data[0], 0x5a, 0, 0);
924841ab66cSSepherosa Ziehau break;
925841ab66cSSepherosa Ziehau case 2:
926841ab66cSSepherosa Ziehau l ^= get_le32_split(data[0], data[1], 0x5a, 0);
927841ab66cSSepherosa Ziehau break;
928841ab66cSSepherosa Ziehau case 3:
929841ab66cSSepherosa Ziehau l ^= get_le32_split(data[0], data[1], data[2], 0x5a);
930841ab66cSSepherosa Ziehau break;
931841ab66cSSepherosa Ziehau }
932841ab66cSSepherosa Ziehau michael_block(l, r);
933841ab66cSSepherosa Ziehau /* l ^= 0; */
934841ab66cSSepherosa Ziehau michael_block(l, r);
935841ab66cSSepherosa Ziehau
936841ab66cSSepherosa Ziehau put_le32(mic, l);
937841ab66cSSepherosa Ziehau put_le32(mic + 4, r);
938841ab66cSSepherosa Ziehau }
939841ab66cSSepherosa Ziehau
940841ab66cSSepherosa Ziehau static int
tkip_encrypt(struct tkip_ctx * ctx,struct ieee80211_key * key,struct mbuf * m,int hdrlen)941841ab66cSSepherosa Ziehau tkip_encrypt(struct tkip_ctx *ctx, struct ieee80211_key *key,
942841ab66cSSepherosa Ziehau struct mbuf *m, int hdrlen)
943841ab66cSSepherosa Ziehau {
944841ab66cSSepherosa Ziehau struct ieee80211_frame *wh;
945841ab66cSSepherosa Ziehau uint8_t icv[IEEE80211_WEP_CRCLEN];
946841ab66cSSepherosa Ziehau
94732176cfdSRui Paulo ctx->tc_vap->iv_stats.is_crypto_tkip++;
948841ab66cSSepherosa Ziehau
949841ab66cSSepherosa Ziehau wh = mtod(m, struct ieee80211_frame *);
9504f655ef5SMatthew Dillon if ((u16)(key->wk_keytsc) == 0 || key->wk_keytsc == 1) {
951841ab66cSSepherosa Ziehau tkip_mixing_phase1(ctx->tx_ttak, key->wk_key, wh->i_addr2,
95232176cfdSRui Paulo (u32)(key->wk_keytsc >> 16));
953841ab66cSSepherosa Ziehau }
954841ab66cSSepherosa Ziehau tkip_mixing_phase2(ctx->tx_rc4key, key->wk_key, ctx->tx_ttak,
95532176cfdSRui Paulo (u16) key->wk_keytsc);
956841ab66cSSepherosa Ziehau
957841ab66cSSepherosa Ziehau wep_encrypt(ctx->tx_rc4key,
958841ab66cSSepherosa Ziehau m, hdrlen + tkip.ic_header,
959841ab66cSSepherosa Ziehau m->m_pkthdr.len - (hdrlen + tkip.ic_header),
960841ab66cSSepherosa Ziehau icv);
96132176cfdSRui Paulo (void) m_append(m, IEEE80211_WEP_CRCLEN, icv); /* XXX check return */
962841ab66cSSepherosa Ziehau
963841ab66cSSepherosa Ziehau return 1;
964841ab66cSSepherosa Ziehau }
965841ab66cSSepherosa Ziehau
966841ab66cSSepherosa Ziehau static int
tkip_decrypt(struct tkip_ctx * ctx,struct ieee80211_key * key,struct mbuf * m,int hdrlen)967841ab66cSSepherosa Ziehau tkip_decrypt(struct tkip_ctx *ctx, struct ieee80211_key *key,
968841ab66cSSepherosa Ziehau struct mbuf *m, int hdrlen)
969841ab66cSSepherosa Ziehau {
970841ab66cSSepherosa Ziehau struct ieee80211_frame *wh;
97132176cfdSRui Paulo struct ieee80211vap *vap = ctx->tc_vap;
97232176cfdSRui Paulo u32 iv32;
97332176cfdSRui Paulo u16 iv16;
97432176cfdSRui Paulo u8 tid;
975841ab66cSSepherosa Ziehau
97632176cfdSRui Paulo vap->iv_stats.is_crypto_tkip++;
977841ab66cSSepherosa Ziehau
978841ab66cSSepherosa Ziehau wh = mtod(m, struct ieee80211_frame *);
979841ab66cSSepherosa Ziehau /* NB: tkip_decap already verified header and left seq in rx_rsc */
98032176cfdSRui Paulo iv16 = (u16) ctx->rx_rsc;
98132176cfdSRui Paulo iv32 = (u32) (ctx->rx_rsc >> 16);
982841ab66cSSepherosa Ziehau
98332176cfdSRui Paulo tid = ieee80211_gettid(wh);
98432176cfdSRui Paulo if (iv32 != (u32)(key->wk_keyrsc[tid] >> 16) || !ctx->rx_phase1_done) {
985841ab66cSSepherosa Ziehau tkip_mixing_phase1(ctx->rx_ttak, key->wk_key,
986841ab66cSSepherosa Ziehau wh->i_addr2, iv32);
987841ab66cSSepherosa Ziehau ctx->rx_phase1_done = 1;
988841ab66cSSepherosa Ziehau }
989841ab66cSSepherosa Ziehau tkip_mixing_phase2(ctx->rx_rc4key, key->wk_key, ctx->rx_ttak, iv16);
990841ab66cSSepherosa Ziehau
991841ab66cSSepherosa Ziehau /* NB: m is unstripped; deduct headers + ICV to get payload */
992841ab66cSSepherosa Ziehau if (wep_decrypt(ctx->rx_rc4key,
993841ab66cSSepherosa Ziehau m, hdrlen + tkip.ic_header,
994841ab66cSSepherosa Ziehau m->m_pkthdr.len - (hdrlen + tkip.ic_header + tkip.ic_trailer))) {
99532176cfdSRui Paulo if (iv32 != (u32)(key->wk_keyrsc[tid] >> 16)) {
996841ab66cSSepherosa Ziehau /* Previously cached Phase1 result was already lost, so
997841ab66cSSepherosa Ziehau * it needs to be recalculated for the next packet. */
998841ab66cSSepherosa Ziehau ctx->rx_phase1_done = 0;
999841ab66cSSepherosa Ziehau }
100032176cfdSRui Paulo IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO, wh->i_addr2,
100132176cfdSRui Paulo "%s", "TKIP ICV mismatch on decrypt");
100232176cfdSRui Paulo vap->iv_stats.is_rx_tkipicv++;
1003841ab66cSSepherosa Ziehau return 0;
1004841ab66cSSepherosa Ziehau }
1005841ab66cSSepherosa Ziehau return 1;
1006841ab66cSSepherosa Ziehau }
1007841ab66cSSepherosa Ziehau
1008841ab66cSSepherosa Ziehau /*
1009841ab66cSSepherosa Ziehau * Module glue.
1010841ab66cSSepherosa Ziehau */
101132176cfdSRui Paulo IEEE80211_CRYPTO_MODULE(tkip, 1);
1012