ieee80211_crypto_wep.c revision 147045
1/*-
2 * Copyright (c) 2002-2005 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 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 *    derived from this software without specific prior written permission.
15 *
16 * Alternatively, this software may be distributed under the terms of the
17 * GNU General Public License ("GPL") version 2 as published by the Free
18 * Software Foundation.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32#include <sys/cdefs.h>
33__FBSDID("$FreeBSD: head/sys/net80211/ieee80211_crypto_wep.c 147045 2005-06-06 04:04:38Z sam $");
34
35/*
36 * IEEE 802.11 WEP crypto support.
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/module.h>
44#include <sys/endian.h>
45
46#include <sys/socket.h>
47
48#include <net/if.h>
49#include <net/if_media.h>
50#include <net/ethernet.h>
51
52#include <net80211/ieee80211_var.h>
53
54static	void *wep_attach(struct ieee80211com *, struct ieee80211_key *);
55static	void wep_detach(struct ieee80211_key *);
56static	int wep_setkey(struct ieee80211_key *);
57static	int wep_encap(struct ieee80211_key *, struct mbuf *, u_int8_t keyid);
58static	int wep_decap(struct ieee80211_key *, struct mbuf *);
59static	int wep_enmic(struct ieee80211_key *, struct mbuf *, int);
60static	int wep_demic(struct ieee80211_key *, struct mbuf *, int);
61
62static const struct ieee80211_cipher wep = {
63	.ic_name	= "WEP",
64	.ic_cipher	= IEEE80211_CIPHER_WEP,
65	.ic_header	= IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN,
66	.ic_trailer	= IEEE80211_WEP_CRCLEN,
67	.ic_miclen	= 0,
68	.ic_attach	= wep_attach,
69	.ic_detach	= wep_detach,
70	.ic_setkey	= wep_setkey,
71	.ic_encap	= wep_encap,
72	.ic_decap	= wep_decap,
73	.ic_enmic	= wep_enmic,
74	.ic_demic	= wep_demic,
75};
76
77static	int wep_encrypt(struct ieee80211_key *, struct mbuf *, int hdrlen);
78static	int wep_decrypt(struct ieee80211_key *, struct mbuf *, int hdrlen);
79
80struct wep_ctx {
81	struct ieee80211com *wc_ic;	/* for diagnostics */
82	u_int32_t	wc_iv;		/* initial vector for crypto */
83};
84
85static void *
86wep_attach(struct ieee80211com *ic, struct ieee80211_key *k)
87{
88	struct wep_ctx *ctx;
89
90	MALLOC(ctx, struct wep_ctx *, sizeof(struct wep_ctx),
91		M_DEVBUF, M_NOWAIT | M_ZERO);
92	if (ctx == NULL) {
93		ic->ic_stats.is_crypto_nomem++;
94		return NULL;
95	}
96
97	ctx->wc_ic = ic;
98	get_random_bytes(&ctx->wc_iv, sizeof(ctx->wc_iv));
99	return ctx;
100}
101
102static void
103wep_detach(struct ieee80211_key *k)
104{
105	struct wep_ctx *ctx = k->wk_private;
106
107	FREE(ctx, M_DEVBUF);
108}
109
110static int
111wep_setkey(struct ieee80211_key *k)
112{
113	return k->wk_keylen >= 40/NBBY;
114}
115
116/*
117 * Add privacy headers appropriate for the specified key.
118 */
119static int
120wep_encap(struct ieee80211_key *k, struct mbuf *m, u_int8_t keyid)
121{
122	struct wep_ctx *ctx = k->wk_private;
123	struct ieee80211com *ic = ctx->wc_ic;
124	u_int32_t iv;
125	u_int8_t *ivp;
126	int hdrlen;
127
128	hdrlen = ieee80211_hdrspace(ic, mtod(m, void *));
129
130	/*
131	 * Copy down 802.11 header and add the IV + KeyID.
132	 */
133	M_PREPEND(m, wep.ic_header, M_NOWAIT);
134	if (m == NULL)
135		return 0;
136	ivp = mtod(m, u_int8_t *);
137	ovbcopy(ivp + wep.ic_header, ivp, hdrlen);
138	ivp += hdrlen;
139
140	/*
141	 * XXX
142	 * IV must not duplicate during the lifetime of the key.
143	 * But no mechanism to renew keys is defined in IEEE 802.11
144	 * for WEP.  And the IV may be duplicated at other stations
145	 * because the session key itself is shared.  So we use a
146	 * pseudo random IV for now, though it is not the right way.
147	 *
148	 * NB: Rather than use a strictly random IV we select a
149	 * random one to start and then increment the value for
150	 * each frame.  This is an explicit tradeoff between
151	 * overhead and security.  Given the basic insecurity of
152	 * WEP this seems worthwhile.
153	 */
154
155	/*
156	 * Skip 'bad' IVs from Fluhrer/Mantin/Shamir:
157	 * (B, 255, N) with 3 <= B < 16 and 0 <= N <= 255
158	 */
159	iv = ctx->wc_iv;
160	if ((iv & 0xff00) == 0xff00) {
161		int B = (iv & 0xff0000) >> 16;
162		if (3 <= B && B < 16)
163			iv += 0x0100;
164	}
165	ctx->wc_iv = iv + 1;
166
167	/*
168	 * NB: Preserve byte order of IV for packet
169	 *     sniffers; it doesn't matter otherwise.
170	 */
171#if _BYTE_ORDER == _BIG_ENDIAN
172	ivp[0] = iv >> 0;
173	ivp[1] = iv >> 8;
174	ivp[2] = iv >> 16;
175#else
176	ivp[2] = iv >> 0;
177	ivp[1] = iv >> 8;
178	ivp[0] = iv >> 16;
179#endif
180	ivp[3] = keyid;
181
182	/*
183	 * Finally, do software encrypt if neeed.
184	 */
185	if ((k->wk_flags & IEEE80211_KEY_SWCRYPT) &&
186	    !wep_encrypt(k, m, hdrlen))
187		return 0;
188
189	return 1;
190}
191
192/*
193 * Add MIC to the frame as needed.
194 */
195static int
196wep_enmic(struct ieee80211_key *k, struct mbuf *m, int force)
197{
198
199	return 1;
200}
201
202/*
203 * Validate and strip privacy headers (and trailer) for a
204 * received frame.  If necessary, decrypt the frame using
205 * the specified key.
206 */
207static int
208wep_decap(struct ieee80211_key *k, struct mbuf *m)
209{
210	struct wep_ctx *ctx = k->wk_private;
211	struct ieee80211_frame *wh;
212	int hdrlen;
213
214	wh = mtod(m, struct ieee80211_frame *);
215	hdrlen = ieee80211_hdrsize(wh);
216
217	/*
218	 * Check if the device handled the decrypt in hardware.
219	 * If so we just strip the header; otherwise we need to
220	 * handle the decrypt in software.
221	 */
222	if ((k->wk_flags & IEEE80211_KEY_SWCRYPT) &&
223	    !wep_decrypt(k, m, hdrlen)) {
224		IEEE80211_DPRINTF(ctx->wc_ic, IEEE80211_MSG_CRYPTO,
225		    "[%s] WEP ICV mismatch on decrypt\n",
226		    ether_sprintf(wh->i_addr2));
227		ctx->wc_ic->ic_stats.is_rx_wepfail++;
228		return 0;
229	}
230
231	/*
232	 * Copy up 802.11 header and strip crypto bits.
233	 */
234	ovbcopy(mtod(m, void *), mtod(m, u_int8_t *) + wep.ic_header, hdrlen);
235	m_adj(m, wep.ic_header);
236	m_adj(m, -wep.ic_trailer);
237
238	return 1;
239}
240
241/*
242 * Verify and strip MIC from the frame.
243 */
244static int
245wep_demic(struct ieee80211_key *k, struct mbuf *skb, int force)
246{
247	return 1;
248}
249
250static const uint32_t crc32_table[256] = {
251	0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
252	0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
253	0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
254	0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
255	0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
256	0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
257	0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
258	0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
259	0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
260	0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
261	0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
262	0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
263	0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
264	0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
265	0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
266	0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
267	0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
268	0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
269	0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
270	0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
271	0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
272	0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
273	0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
274	0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
275	0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
276	0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
277	0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
278	0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
279	0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
280	0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
281	0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
282	0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
283	0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
284	0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
285	0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
286	0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
287	0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
288	0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
289	0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
290	0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
291	0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
292	0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
293	0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
294	0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
295	0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
296	0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
297	0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
298	0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
299	0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
300	0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
301	0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
302	0x2d02ef8dL
303};
304
305static int
306wep_encrypt(struct ieee80211_key *key, struct mbuf *m0, int hdrlen)
307{
308#define S_SWAP(a,b) do { uint8_t t = S[a]; S[a] = S[b]; S[b] = t; } while(0)
309	struct wep_ctx *ctx = key->wk_private;
310	struct mbuf *m = m0;
311	u_int8_t rc4key[IEEE80211_WEP_IVLEN + IEEE80211_KEYBUF_SIZE];
312	uint8_t icv[IEEE80211_WEP_CRCLEN];
313	uint32_t i, j, k, crc;
314	size_t buflen, data_len;
315	uint8_t S[256];
316	uint8_t *pos;
317	u_int off, keylen;
318
319	ctx->wc_ic->ic_stats.is_crypto_wep++;
320
321	/* NB: this assumes the header was pulled up */
322	memcpy(rc4key, mtod(m, u_int8_t *) + hdrlen, IEEE80211_WEP_IVLEN);
323	memcpy(rc4key + IEEE80211_WEP_IVLEN, key->wk_key, key->wk_keylen);
324
325	/* Setup RC4 state */
326	for (i = 0; i < 256; i++)
327		S[i] = i;
328	j = 0;
329	keylen = key->wk_keylen + IEEE80211_WEP_IVLEN;
330	for (i = 0; i < 256; i++) {
331		j = (j + S[i] + rc4key[i % keylen]) & 0xff;
332		S_SWAP(i, j);
333	}
334
335	off = hdrlen + wep.ic_header;
336	data_len = m->m_pkthdr.len - off;
337
338	/* Compute CRC32 over unencrypted data and apply RC4 to data */
339	crc = ~0;
340	i = j = 0;
341	pos = mtod(m, uint8_t *) + off;
342	buflen = m->m_len - off;
343	for (;;) {
344		if (buflen > data_len)
345			buflen = data_len;
346		data_len -= buflen;
347		for (k = 0; k < buflen; k++) {
348			crc = crc32_table[(crc ^ *pos) & 0xff] ^ (crc >> 8);
349			i = (i + 1) & 0xff;
350			j = (j + S[i]) & 0xff;
351			S_SWAP(i, j);
352			*pos++ ^= S[(S[i] + S[j]) & 0xff];
353		}
354		if (m->m_next == NULL) {
355			if (data_len != 0) {		/* out of data */
356				IEEE80211_DPRINTF(ctx->wc_ic,
357				    IEEE80211_MSG_CRYPTO,
358				    "[%s] out of data for WEP (data_len %zu)\n",
359				    ether_sprintf(mtod(m0,
360					struct ieee80211_frame *)->i_addr2),
361				    data_len);
362				return 0;
363			}
364			break;
365		}
366		m = m->m_next;
367		pos = mtod(m, uint8_t *);
368		buflen = m->m_len;
369	}
370	crc = ~crc;
371
372	/* Append little-endian CRC32 and encrypt it to produce ICV */
373	icv[0] = crc;
374	icv[1] = crc >> 8;
375	icv[2] = crc >> 16;
376	icv[3] = crc >> 24;
377	for (k = 0; k < IEEE80211_WEP_CRCLEN; k++) {
378		i = (i + 1) & 0xff;
379		j = (j + S[i]) & 0xff;
380		S_SWAP(i, j);
381		icv[k] ^= S[(S[i] + S[j]) & 0xff];
382	}
383	return m_append(m0, IEEE80211_WEP_CRCLEN, icv);
384#undef S_SWAP
385}
386
387static int
388wep_decrypt(struct ieee80211_key *key, struct mbuf *m0, int hdrlen)
389{
390#define S_SWAP(a,b) do { uint8_t t = S[a]; S[a] = S[b]; S[b] = t; } while(0)
391	struct wep_ctx *ctx = key->wk_private;
392	struct mbuf *m = m0;
393	u_int8_t rc4key[IEEE80211_WEP_IVLEN + IEEE80211_KEYBUF_SIZE];
394	uint8_t icv[IEEE80211_WEP_CRCLEN];
395	uint32_t i, j, k, crc;
396	size_t buflen, data_len;
397	uint8_t S[256];
398	uint8_t *pos;
399	u_int off, keylen;
400
401	ctx->wc_ic->ic_stats.is_crypto_wep++;
402
403	/* NB: this assumes the header was pulled up */
404	memcpy(rc4key, mtod(m, u_int8_t *) + hdrlen, IEEE80211_WEP_IVLEN);
405	memcpy(rc4key + IEEE80211_WEP_IVLEN, key->wk_key, key->wk_keylen);
406
407	/* Setup RC4 state */
408	for (i = 0; i < 256; i++)
409		S[i] = i;
410	j = 0;
411	keylen = key->wk_keylen + IEEE80211_WEP_IVLEN;
412	for (i = 0; i < 256; i++) {
413		j = (j + S[i] + rc4key[i % keylen]) & 0xff;
414		S_SWAP(i, j);
415	}
416
417	off = hdrlen + wep.ic_header;
418	data_len = m->m_pkthdr.len - (off + wep.ic_trailer),
419
420	/* Compute CRC32 over unencrypted data and apply RC4 to data */
421	crc = ~0;
422	i = j = 0;
423	pos = mtod(m, uint8_t *) + off;
424	buflen = m->m_len - off;
425	for (;;) {
426		if (buflen > data_len)
427			buflen = data_len;
428		data_len -= buflen;
429		for (k = 0; k < buflen; k++) {
430			i = (i + 1) & 0xff;
431			j = (j + S[i]) & 0xff;
432			S_SWAP(i, j);
433			*pos ^= S[(S[i] + S[j]) & 0xff];
434			crc = crc32_table[(crc ^ *pos) & 0xff] ^ (crc >> 8);
435			pos++;
436		}
437		m = m->m_next;
438		if (m == NULL) {
439			if (data_len != 0) {		/* out of data */
440				IEEE80211_DPRINTF(ctx->wc_ic,
441				    IEEE80211_MSG_CRYPTO,
442				    "[%s] out of data for WEP (data_len %zu)\n",
443				    ether_sprintf(mtod(m0,
444					struct ieee80211_frame *)->i_addr2),
445				    data_len);
446				return 0;
447			}
448			break;
449		}
450		pos = mtod(m, uint8_t *);
451		buflen = m->m_len;
452	}
453	crc = ~crc;
454
455	/* Encrypt little-endian CRC32 and verify that it matches with
456	 * received ICV */
457	icv[0] = crc;
458	icv[1] = crc >> 8;
459	icv[2] = crc >> 16;
460	icv[3] = crc >> 24;
461	for (k = 0; k < IEEE80211_WEP_CRCLEN; k++) {
462		i = (i + 1) & 0xff;
463		j = (j + S[i]) & 0xff;
464		S_SWAP(i, j);
465		/* XXX assumes ICV is contiguous in mbuf */
466		if ((icv[k] ^ S[(S[i] + S[j]) & 0xff]) != *pos++) {
467			/* ICV mismatch - drop frame */
468			return 0;
469		}
470	}
471	return 1;
472#undef S_SWAP
473}
474
475/*
476 * Module glue.
477 */
478static int
479wep_modevent(module_t mod, int type, void *unused)
480{
481	switch (type) {
482	case MOD_LOAD:
483		ieee80211_crypto_register(&wep);
484		return 0;
485	case MOD_UNLOAD:
486		ieee80211_crypto_unregister(&wep);
487		return 0;
488	}
489	return EINVAL;
490}
491
492static moduledata_t wep_mod = {
493	"wlan_wep",
494	wep_modevent,
495	0
496};
497DECLARE_MODULE(wlan_wep, wep_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST);
498MODULE_VERSION(wlan_wep, 1);
499MODULE_DEPEND(wlan_wep, wlan, 1, 1, 1);
500