Merge branch 'linus' into release
[linux-2.6] / drivers / staging / wlan-ng / p80211wep.c
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
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  */
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. */
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 }