ieee80211_crypto.c revision 116742
1/*-
2 * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer,
10 *    without modification.
11 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
12 *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
13 *    redistribution must be conditioned upon including a substantially
14 *    similar Disclaimer requirement for further binary redistribution.
15 * 3. Neither the names of the above-listed copyright holders nor the names
16 *    of any contributors may be used to endorse or promote products derived
17 *    from this software without specific prior written permission.
18 *
19 * Alternatively, this software may be distributed under the terms of the
20 * GNU General Public License ("GPL") version 2 as published by the Free
21 * Software Foundation.
22 *
23 * NO WARRANTY
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26 * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
27 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
28 * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
29 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
32 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
34 * THE POSSIBILITY OF SUCH DAMAGES.
35 *
36 * $Id: ieee80211_crypto.c,v 1.2 2003/06/22 06:16:32 sam Exp $
37 */
38
39#include <sys/cdefs.h>
40__FBSDID("$FreeBSD: head/sys/net80211/ieee80211_crypto.c 116742 2003-06-23 16:55:01Z sam $");
41
42#include "opt_inet.h"
43
44#include <sys/param.h>
45#include <sys/systm.h>
46#include <sys/mbuf.h>
47#include <sys/malloc.h>
48#include <sys/kernel.h>
49#include <sys/socket.h>
50#include <sys/sockio.h>
51#include <sys/endian.h>
52#include <sys/errno.h>
53#include <sys/bus.h>
54#include <sys/proc.h>
55#include <sys/sysctl.h>
56
57#include <machine/atomic.h>
58
59#include <net/if.h>
60#include <net/if_dl.h>
61#include <net/if_media.h>
62#include <net/if_arp.h>
63#include <net/ethernet.h>
64#include <net/if_llc.h>
65
66#include <net80211/ieee80211_var.h>
67
68#include <net/bpf.h>
69
70#ifdef INET
71#include <netinet/in.h>
72#include <netinet/if_ether.h>
73#endif
74
75#include <crypto/rc4/rc4.h>
76#define	arc4_ctxlen()			sizeof (struct rc4_state)
77#define	arc4_setkey(_c,_k,_l)		rc4_init(_c,_k,_l)
78#define	arc4_encrypt(_c,_d,_s,_l)	rc4_crypt(_c,_s,_d,_l)
79
80static	void ieee80211_crc_init(void);
81static	u_int32_t ieee80211_crc_update(u_int32_t crc, u_int8_t *buf, int len);
82
83void
84ieee80211_crypto_attach(struct ifnet *ifp)
85{
86	struct ieee80211com *ic = (void *)ifp;
87
88	/*
89	 * Setup crypto support.
90	 */
91	ieee80211_crc_init();
92	ic->ic_iv = arc4random();
93}
94
95void
96ieee80211_crypto_detach(struct ifnet *ifp)
97{
98	struct ieee80211com *ic = (void *)ifp;
99
100	if (ic->ic_wep_ctx != NULL) {
101		free(ic->ic_wep_ctx, M_DEVBUF);
102		ic->ic_wep_ctx = NULL;
103	}
104}
105
106struct mbuf *
107ieee80211_wep_crypt(struct ifnet *ifp, struct mbuf *m0, int txflag)
108{
109	struct ieee80211com *ic = (void *)ifp;
110	struct mbuf *m, *n, *n0;
111	struct ieee80211_frame *wh;
112	int i, left, len, moff, noff, kid;
113	u_int32_t iv, crc;
114	u_int8_t *ivp;
115	void *ctx;
116	u_int8_t keybuf[IEEE80211_WEP_IVLEN + IEEE80211_KEYBUF_SIZE];
117	u_int8_t crcbuf[IEEE80211_WEP_CRCLEN];
118
119	n0 = NULL;
120	if ((ctx = ic->ic_wep_ctx) == NULL) {
121		ctx = malloc(arc4_ctxlen(), M_DEVBUF, M_NOWAIT);
122		if (ctx == NULL)
123			goto fail;
124		ic->ic_wep_ctx = ctx;
125	}
126	m = m0;
127	left = m->m_pkthdr.len;
128	MGET(n, M_DONTWAIT, m->m_type);
129	n0 = n;
130	if (n == NULL)
131		goto fail;
132	M_MOVE_PKTHDR(n, m);
133	len = IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN + IEEE80211_WEP_CRCLEN;
134	if (txflag) {
135		n->m_pkthdr.len += len;
136	} else {
137		n->m_pkthdr.len -= len;
138		left -= len;
139	}
140	n->m_len = MHLEN;
141	if (n->m_pkthdr.len >= MINCLSIZE) {
142		MCLGET(n, M_DONTWAIT);
143		if (n->m_flags & M_EXT)
144			n->m_len = n->m_ext.ext_size;
145	}
146	len = sizeof(struct ieee80211_frame);
147	memcpy(mtod(n, caddr_t), mtod(m, caddr_t), len);
148	wh = mtod(n, struct ieee80211_frame *);
149	left -= len;
150	moff = len;
151	noff = len;
152	if (txflag) {
153		kid = ic->ic_wep_txkey;
154		wh->i_fc[1] |= IEEE80211_FC1_WEP;
155                iv = ic->ic_iv;
156		/*
157		 * Skip 'bad' IVs from Fluhrer/Mantin/Shamir:
158		 * (B, 255, N) with 3 <= B < 8
159		 */
160		if (iv >= 0x03ff00 &&
161		    (iv & 0xf8ff00) == 0x00ff00)
162			iv += 0x000100;
163		ic->ic_iv = iv + 1;
164		/* put iv in little endian to prepare 802.11i */
165		ivp = mtod(n, u_int8_t *) + noff;
166		for (i = 0; i < IEEE80211_WEP_IVLEN; i++) {
167			ivp[i] = iv & 0xff;
168			iv >>= 8;
169		}
170		ivp[IEEE80211_WEP_IVLEN] = kid << 6;	/* pad and keyid */
171		noff += IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN;
172	} else {
173		wh->i_fc[1] &= ~IEEE80211_FC1_WEP;
174		ivp = mtod(m, u_int8_t *) + moff;
175		kid = ivp[IEEE80211_WEP_IVLEN] >> 6;
176		moff += IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN;
177	}
178	memcpy(keybuf, ivp, IEEE80211_WEP_IVLEN);
179	memcpy(keybuf + IEEE80211_WEP_IVLEN, ic->ic_nw_keys[kid].wk_key,
180	    ic->ic_nw_keys[kid].wk_len);
181	arc4_setkey(ctx, keybuf,
182	    IEEE80211_WEP_IVLEN + ic->ic_nw_keys[kid].wk_len);
183
184	/* encrypt with calculating CRC */
185	crc = ~0;
186	while (left > 0) {
187		len = m->m_len - moff;
188		if (len == 0) {
189			m = m->m_next;
190			moff = 0;
191			continue;
192		}
193		if (len > n->m_len - noff) {
194			len = n->m_len - noff;
195			if (len == 0) {
196				MGET(n->m_next, M_DONTWAIT, n->m_type);
197				if (n->m_next == NULL)
198					goto fail;
199				n = n->m_next;
200				n->m_len = MLEN;
201				if (left >= MINCLSIZE) {
202					MCLGET(n, M_DONTWAIT);
203					if (n->m_flags & M_EXT)
204						n->m_len = n->m_ext.ext_size;
205				}
206				noff = 0;
207				continue;
208			}
209		}
210		if (len > left)
211			len = left;
212		arc4_encrypt(ctx, mtod(n, caddr_t) + noff,
213		    mtod(m, caddr_t) + moff, len);
214		if (txflag)
215			crc = ieee80211_crc_update(crc,
216			    mtod(m, u_int8_t *) + moff, len);
217		else
218			crc = ieee80211_crc_update(crc,
219			    mtod(n, u_int8_t *) + noff, len);
220		left -= len;
221		moff += len;
222		noff += len;
223	}
224	crc = ~crc;
225	if (txflag) {
226		*(u_int32_t *)crcbuf = htole32(crc);
227		if (n->m_len >= noff + sizeof(crcbuf))
228			n->m_len = noff + sizeof(crcbuf);
229		else {
230			n->m_len = noff;
231			MGET(n->m_next, M_DONTWAIT, n->m_type);
232			if (n->m_next == NULL)
233				goto fail;
234			n = n->m_next;
235			n->m_len = sizeof(crcbuf);
236			noff = 0;
237		}
238		arc4_encrypt(ctx, mtod(n, caddr_t) + noff, crcbuf,
239		    sizeof(crcbuf));
240	} else {
241		n->m_len = noff;
242		for (noff = 0; noff < sizeof(crcbuf); noff += len) {
243			len = sizeof(crcbuf) - noff;
244			if (len > m->m_len - moff)
245				len = m->m_len - moff;
246			if (len > 0)
247				arc4_encrypt(ctx, crcbuf + noff,
248				    mtod(m, caddr_t) + moff, len);
249			m = m->m_next;
250			moff = 0;
251		}
252		if (crc != le32toh(*(u_int32_t *)crcbuf)) {
253#ifdef IEEE80211_DEBUG
254			if (ieee80211_debug) {
255				if_printf(ifp, "decrypt CRC error\n");
256				if (ieee80211_debug > 1)
257					ieee80211_dump_pkt(n0->m_data,
258					    n0->m_len, -1, -1);
259			}
260#endif
261			goto fail;
262		}
263	}
264	m_freem(m0);
265	return n0;
266
267  fail:
268	m_freem(m0);
269	m_freem(n0);
270	return NULL;
271}
272
273/*
274 * CRC 32 -- routine from RFC 2083
275 */
276
277/* Table of CRCs of all 8-bit messages */
278static u_int32_t ieee80211_crc_table[256];
279
280/* Make the table for a fast CRC. */
281static void
282ieee80211_crc_init(void)
283{
284	u_int32_t c;
285	int n, k;
286
287	for (n = 0; n < 256; n++) {
288		c = (u_int32_t)n;
289		for (k = 0; k < 8; k++) {
290			if (c & 1)
291				c = 0xedb88320UL ^ (c >> 1);
292			else
293				c = c >> 1;
294		}
295		ieee80211_crc_table[n] = c;
296	}
297}
298
299/*
300 * Update a running CRC with the bytes buf[0..len-1]--the CRC
301 * should be initialized to all 1's, and the transmitted value
302 * is the 1's complement of the final running CRC
303 */
304
305static u_int32_t
306ieee80211_crc_update(u_int32_t crc, u_int8_t *buf, int len)
307{
308	u_int8_t *endbuf;
309
310	for (endbuf = buf + len; buf < endbuf; buf++)
311		crc = ieee80211_crc_table[(crc ^ *buf) & 0xff] ^ (crc >> 8);
312	return crc;
313}
314