• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* src/p80211/p80211wep.c
2 *
3 * WEP encode/decode for P80211.
4 *
5 * Copyright (C) 2002 AbsoluteValue Systems, Inc.  All Rights Reserved.
6 * --------------------------------------------------------------------
7 *
8 * linux-wlan
9 *
10 *   The contents of this file are subject to the Mozilla Public
11 *   License Version 1.1 (the "License"); you may not use this file
12 *   except in compliance with the License. You may obtain a copy of
13 *   the License at http://www.mozilla.org/MPL/
14 *
15 *   Software distributed under the License is distributed on an "AS
16 *   IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
17 *   implied. See the License for the specific language governing
18 *   rights and limitations under the License.
19 *
20 *   Alternatively, the contents of this file may be used under the
21 *   terms of the GNU Public License version 2 (the "GPL"), in which
22 *   case the provisions of the GPL are applicable instead of the
23 *   above.  If you wish to allow the use of your version of this file
24 *   only under the terms of the GPL and not to allow others to use
25 *   your version of this file under the MPL, indicate your decision
26 *   by deleting the provisions above and replace them with the notice
27 *   and other provisions required by the GPL.  If you do not delete
28 *   the provisions above, a recipient may use your version of this
29 *   file under either the MPL or the GPL.
30 *
31 * --------------------------------------------------------------------
32 *
33 * Inquiries regarding the linux-wlan Open Source project can be
34 * made directly to:
35 *
36 * AbsoluteValue Systems Inc.
37 * info@linux-wlan.com
38 * http://www.linux-wlan.com
39 *
40 * --------------------------------------------------------------------
41 *
42 * Portions of the development of this software were funded by
43 * Intersil Corporation as part of PRISM(R) chipset product development.
44 *
45 * --------------------------------------------------------------------
46 */
47 
48 /*================================================================*/
49 /* System Includes */
50 
51 
52 #include <linux/version.h>
53 
54 #include <linux/netdevice.h>
55 #include <linux/wireless.h>
56 #include <linux/slab.h>
57 #include <linux/random.h>
58 
59 #include "wlan_compat.h"
60 
61 // #define WEP_DEBUG
62 
63 /*================================================================*/
64 /* Project Includes */
65 
66 #include "p80211hdr.h"
67 #include "p80211types.h"
68 #include "p80211msg.h"
69 #include "p80211conv.h"
70 #include "p80211netdev.h"
71 
72 /*================================================================*/
73 /* Local Constants */
74 
75 #define SSWAP(a,b) {u8 tmp = s[a]; s[a] = s[b]; s[b] = tmp;}
76 #define WEP_KEY(x)       (((x) & 0xC0) >> 6)
77 
78 /*================================================================*/
79 /* Local Macros */
80 
81 
82 /*================================================================*/
83 /* Local Types */
84 
85 
86 /*================================================================*/
87 /* Local Static Definitions */
88 
89 static const u32 wep_crc32_table[256] = {
90         0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
91         0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
92         0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
93         0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
94         0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
95         0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
96         0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
97         0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
98         0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
99         0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
100         0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
101         0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
102         0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
103         0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
104         0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
105         0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
106         0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
107         0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
108         0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
109         0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
110         0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
111         0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
112         0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
113         0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
114         0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
115         0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
116         0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
117         0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
118         0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
119         0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
120         0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
121         0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
122         0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
123         0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
124         0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
125         0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
126         0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
127         0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
128         0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
129         0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
130         0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
131         0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
132         0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
133         0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
134         0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
135         0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
136         0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
137         0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
138         0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
139         0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
140         0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
141         0x2d02ef8dL
142 };
143 
144 /*================================================================*/
145 /* Local Function Declarations */
146 
147 /*================================================================*/
148 /* Function Definitions */
149 
150 /* keylen in bytes! */
151 
wep_change_key(wlandevice_t * wlandev,int keynum,u8 * key,int keylen)152 int wep_change_key(wlandevice_t *wlandev, int keynum, u8* key, int keylen)
153 {
154 	if (keylen < 0)  return -1;
155 	if (keylen >= MAX_KEYLEN) return -1;
156 	if (key == NULL) return -1;
157 	if (keynum < 0)  return -1;
158 	if (keynum >= NUM_WEPKEYS) return -1;
159 
160 
161 #ifdef WEP_DEBUG
162 	printk(KERN_DEBUG "WEP key %d len %d = %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", keynum, keylen, key[0], key[1], key[2], key[3], key[4], key[5], key[6], key[7]);
163 #endif
164 
165 	wlandev->wep_keylens[keynum] = keylen;
166 	memcpy(wlandev->wep_keys[keynum], key, keylen);
167 
168 	return 0;
169 }
170 
171 /*
172   4-byte IV at start of buffer, 4-byte ICV at end of buffer.
173   if successful, buf start is payload begin, length -= 8;
174  */
wep_decrypt(wlandevice_t * wlandev,u8 * buf,u32 len,int key_override,u8 * iv,u8 * icv)175 int wep_decrypt(wlandevice_t *wlandev, u8 *buf, u32 len, int key_override, u8 *iv, u8 *icv)
176 {
177 	u32 i, j, k, crc, keylen;
178 	u8 s[256], key[64], c_crc[4];
179 	u8 keyidx;
180 
181 	/* Needs to be at least 8 bytes of payload */
182 	if (len <= 0) return -1;
183 
184 	/* initialize the first bytes of the key from the IV */
185 	key[0] = iv[0];
186 	key[1] = iv[1];
187 	key[2] = iv[2];
188 	keyidx = WEP_KEY(iv[3]);
189 
190 	if (key_override >= 0)
191 		keyidx = key_override;
192 
193 	if (keyidx >= NUM_WEPKEYS) return -2;
194 
195 	keylen = wlandev->wep_keylens[keyidx];
196 
197 	if (keylen == 0) return -3;
198 
199 	/* copy the rest of the key over from the designated key */
200 	memcpy(key+3, wlandev->wep_keys[keyidx], keylen);
201 
202 	keylen+=3;  /* add in IV bytes */
203 
204 #ifdef WEP_DEBUG
205 	printk(KERN_DEBUG "D %d: %02x %02x %02x (%d %d) %02x:%02x:%02x:%02x:%02x\n", len, key[0], key[1], key[2], keyidx, keylen, key[3], key[4], key[5], key[6], key[7]);
206 #endif
207 
208 	/* set up the RC4 state */
209 	for (i = 0; i < 256; i++)
210 		s[i] = i;
211 	j = 0;
212 	for (i = 0; i < 256; i++) {
213 		j = (j + s[i] + key[i % keylen]) & 0xff;
214 		SSWAP(i,j);
215 	}
216 
217 	/* Apply the RC4 to the data, update the CRC32 */
218 	crc = ~0;
219 	i = j = 0;
220 	for (k = 0; k < len; k++) {
221 		i = (i+1) & 0xff;
222 		j = (j+s[i]) & 0xff;
223 		SSWAP(i,j);
224 		buf[k] ^= s[(s[i] + s[j]) & 0xff];
225 		crc = wep_crc32_table[(crc ^ buf[k]) & 0xff] ^ (crc >> 8);
226 	}
227 	crc = ~crc;
228 
229 	/* now let's check the crc */
230 	c_crc[0] = crc;
231 	c_crc[1] = crc >> 8;
232 	c_crc[2] = crc >> 16;
233 	c_crc[3] = crc >> 24;
234 
235 	for (k = 0; k < 4; k++) {
236 		i = (i + 1) & 0xff;
237 		j = (j+s[i]) & 0xff;
238 		SSWAP(i,j);
239 		if ((c_crc[k] ^ s[(s[i] + s[j]) & 0xff]) != icv[k])
240 			return -(4 | (k << 4)) ; /* ICV mismatch */
241 	}
242 
243 	return 0;
244 }
245 
246 /* encrypts in-place. */
wep_encrypt(wlandevice_t * wlandev,u8 * buf,u8 * dst,u32 len,int keynum,u8 * iv,u8 * icv)247 int wep_encrypt(wlandevice_t *wlandev, u8 *buf, u8 *dst, u32 len, int keynum, u8 *iv, u8 *icv)
248 {
249 	u32 i, j, k, crc, keylen;
250 	u8 s[256], key[64];
251 
252 	/* no point in WEPping an empty frame */
253 	if (len <= 0) return -1;
254 
255 	/* we need to have a real key.. */
256 	if (keynum >= NUM_WEPKEYS) return -2;
257 	keylen = wlandev->wep_keylens[keynum];
258 	if (keylen <= 0) return -3;
259 
260 	/* use a random IV.  And skip known weak ones. */
261 	get_random_bytes(iv, 3);
262 	while ((iv[1] == 0xff) && (iv[0] >= 3) && (iv[0] < keylen))
263 		get_random_bytes(iv, 3);
264 
265 	iv[3] = (keynum & 0x03) << 6;
266 
267 	key[0] = iv[0];
268 	key[1] = iv[1];
269 	key[2] = iv[2];
270 
271 	/* copy the rest of the key over from the designated key */
272 	memcpy(key+3, wlandev->wep_keys[keynum], keylen);
273 
274 	keylen+=3;  /* add in IV bytes */
275 
276 #ifdef WEP_DEBUG
277 	printk(KERN_DEBUG "E %d (%d/%d %d) %02x %02x %02x %02x:%02x:%02x:%02x:%02x\n", len,  iv[3], keynum, keylen, key[0], key[1], key[2], key[3], key[4], key[5], key[6], key[7]);
278 #endif
279 
280 	/* set up the RC4 state */
281 	for (i = 0; i < 256; i++)
282 		s[i] = i;
283 	j = 0;
284 	for (i = 0; i < 256; i++) {
285 		j = (j + s[i] + key[i % keylen]) & 0xff;
286 		SSWAP(i,j);
287 	}
288 
289 	/* Update CRC32 then apply RC4 to the data */
290 	crc = ~0;
291 	i = j = 0;
292 	for (k = 0; k < len; k++) {
293 		crc = wep_crc32_table[(crc ^ buf[k]) & 0xff] ^ (crc >> 8);
294 		i = (i+1) & 0xff;
295 		j = (j+s[i]) & 0xff;
296 		SSWAP(i,j);
297 		dst[k] = buf[k] ^ s[(s[i] + s[j]) & 0xff];
298 	}
299 	crc = ~crc;
300 
301 	/* now let's encrypt the crc */
302 	icv[0] = crc;
303 	icv[1] = crc >> 8;
304 	icv[2] = crc >> 16;
305 	icv[3] = crc >> 24;
306 
307 	for (k = 0; k < 4; k++) {
308 		i = (i + 1) & 0xff;
309 		j = (j+s[i]) & 0xff;
310 		SSWAP(i,j);
311 		icv[k] ^= s[(s[i] + s[j]) & 0xff];
312 	}
313 
314 	return 0;
315 }
316