Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
[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 "version.h"
60 #include "wlan_compat.h"
61
62 // #define WEP_DEBUG
63
64 /*================================================================*/
65 /* Project Includes */
66
67 #include "version.h"
68 #include "p80211hdr.h"
69 #include "p80211types.h"
70 #include "p80211msg.h"
71 #include "p80211conv.h"
72 #include "p80211netdev.h"
73
74 /*================================================================*/
75 /* Local Constants */
76
77 #define SSWAP(a,b) {UINT8 tmp = s[a]; s[a] = s[b]; s[b] = tmp;}
78 #define WEP_KEY(x)       (((x) & 0xC0) >> 6)
79
80 /*================================================================*/
81 /* Local Macros */
82
83
84 /*================================================================*/
85 /* Local Types */
86
87
88 /*================================================================*/
89 /* Local Static Definitions */
90
91 static const UINT32 wep_crc32_table[256] = {
92         0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
93         0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
94         0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
95         0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
96         0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
97         0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
98         0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
99         0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
100         0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
101         0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
102         0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
103         0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
104         0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
105         0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
106         0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
107         0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
108         0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
109         0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
110         0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
111         0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
112         0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
113         0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
114         0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
115         0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
116         0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
117         0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
118         0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
119         0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
120         0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
121         0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
122         0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
123         0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
124         0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
125         0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
126         0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
127         0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
128         0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
129         0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
130         0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
131         0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
132         0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
133         0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
134         0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
135         0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
136         0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
137         0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
138         0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
139         0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
140         0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
141         0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
142         0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
143         0x2d02ef8dL
144 };
145
146 /*================================================================*/
147 /* Local Function Declarations */
148
149 /*================================================================*/
150 /* Function Definitions */
151
152 /* keylen in bytes! */
153
154 int wep_change_key(wlandevice_t *wlandev, int keynum, UINT8* key, int keylen)
155 {
156         if (keylen < 0)  return -1;
157         if (keylen >= MAX_KEYLEN) return -1;
158         if (key == NULL) return -1;
159         if (keynum < 0)  return -1;
160         if (keynum >= NUM_WEPKEYS) return -1;
161
162
163 #ifdef WEP_DEBUG
164         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]);
165 #endif
166
167         wlandev->wep_keylens[keynum] = keylen;
168         memcpy(wlandev->wep_keys[keynum], key, keylen);
169
170         return 0;
171 }
172
173 /*
174   4-byte IV at start of buffer, 4-byte ICV at end of buffer.
175   if successful, buf start is payload begin, length -= 8;
176  */
177 int wep_decrypt(wlandevice_t *wlandev, UINT8 *buf, UINT32 len, int key_override, UINT8 *iv, UINT8 *icv)
178 {
179         UINT32 i, j, k, crc, keylen;
180         UINT8 s[256], key[64], c_crc[4];
181         UINT8 keyidx;
182
183         /* Needs to be at least 8 bytes of payload */
184         if (len <= 0) return -1;
185
186         /* initialize the first bytes of the key from the IV */
187         key[0] = iv[0];
188         key[1] = iv[1];
189         key[2] = iv[2];
190         keyidx = WEP_KEY(iv[3]);
191
192         if (key_override >= 0)
193                 keyidx = key_override;
194
195         if (keyidx >= NUM_WEPKEYS) return -2;
196
197         keylen = wlandev->wep_keylens[keyidx];
198
199         if (keylen == 0) return -3;
200
201         /* copy the rest of the key over from the designated key */
202         memcpy(key+3, wlandev->wep_keys[keyidx], keylen);
203
204         keylen+=3;  /* add in IV bytes */
205
206 #ifdef WEP_DEBUG
207         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]);
208 #endif
209
210         /* set up the RC4 state */
211         for (i = 0; i < 256; i++)
212                 s[i] = i;
213         j = 0;
214         for (i = 0; i < 256; i++) {
215                 j = (j + s[i] + key[i % keylen]) & 0xff;
216                 SSWAP(i,j);
217         }
218
219         /* Apply the RC4 to the data, update the CRC32 */
220         crc = ~0;
221         i = j = 0;
222         for (k = 0; k < len; k++) {
223                 i = (i+1) & 0xff;
224                 j = (j+s[i]) & 0xff;
225                 SSWAP(i,j);
226                 buf[k] ^= s[(s[i] + s[j]) & 0xff];
227                 crc = wep_crc32_table[(crc ^ buf[k]) & 0xff] ^ (crc >> 8);
228         }
229         crc = ~crc;
230
231         /* now let's check the crc */
232         c_crc[0] = crc;
233         c_crc[1] = crc >> 8;
234         c_crc[2] = crc >> 16;
235         c_crc[3] = crc >> 24;
236
237         for (k = 0; k < 4; k++) {
238                 i = (i + 1) & 0xff;
239                 j = (j+s[i]) & 0xff;
240                 SSWAP(i,j);
241                 if ((c_crc[k] ^ s[(s[i] + s[j]) & 0xff]) != icv[k])
242                         return -(4 | (k << 4)) ; /* ICV mismatch */
243         }
244
245         return 0;
246 }
247
248 /* encrypts in-place. */
249 int wep_encrypt(wlandevice_t *wlandev, UINT8 *buf, UINT8 *dst, UINT32 len, int keynum, UINT8 *iv, UINT8 *icv)
250 {
251         UINT32 i, j, k, crc, keylen;
252         UINT8 s[256], key[64];
253
254         /* no point in WEPping an empty frame */
255         if (len <= 0) return -1;
256
257         /* we need to have a real key.. */
258         if (keynum >= NUM_WEPKEYS) return -2;
259         keylen = wlandev->wep_keylens[keynum];
260         if (keylen <= 0) return -3;
261
262         /* use a random IV.  And skip known weak ones. */
263         get_random_bytes(iv, 3);
264         while ((iv[1] == 0xff) && (iv[0] >= 3) && (iv[0] < keylen))
265                 get_random_bytes(iv, 3);
266
267         iv[3] = (keynum & 0x03) << 6;
268
269         key[0] = iv[0];
270         key[1] = iv[1];
271         key[2] = iv[2];
272
273         /* copy the rest of the key over from the designated key */
274         memcpy(key+3, wlandev->wep_keys[keynum], keylen);
275
276         keylen+=3;  /* add in IV bytes */
277
278 #ifdef WEP_DEBUG
279         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]);
280 #endif
281
282         /* set up the RC4 state */
283         for (i = 0; i < 256; i++)
284                 s[i] = i;
285         j = 0;
286         for (i = 0; i < 256; i++) {
287                 j = (j + s[i] + key[i % keylen]) & 0xff;
288                 SSWAP(i,j);
289         }
290
291         /* Update CRC32 then apply RC4 to the data */
292         crc = ~0;
293         i = j = 0;
294         for (k = 0; k < len; k++) {
295                 crc = wep_crc32_table[(crc ^ buf[k]) & 0xff] ^ (crc >> 8);
296                 i = (i+1) & 0xff;
297                 j = (j+s[i]) & 0xff;
298                 SSWAP(i,j);
299                 dst[k] = buf[k] ^ s[(s[i] + s[j]) & 0xff];
300         }
301         crc = ~crc;
302
303         /* now let's encrypt the crc */
304         icv[0] = crc;
305         icv[1] = crc >> 8;
306         icv[2] = crc >> 16;
307         icv[3] = crc >> 24;
308
309         for (k = 0; k < 4; k++) {
310                 i = (i + 1) & 0xff;
311                 j = (j+s[i]) & 0xff;
312                 SSWAP(i,j);
313                 icv[k] ^= s[(s[i] + s[j]) & 0xff];
314         }
315
316         return 0;
317 }