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