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