blob: 46a2a6b3bdca56d09dfea9c4587da5c4e72fb137 [file] [log] [blame]
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -07001/* 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
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -070059#include "wlan_compat.h"
60
61// #define WEP_DEBUG
62
63/*================================================================*/
64/* Project Includes */
65
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -070066#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
Solomon Peachyaaad4302008-10-29 10:42:53 -040075#define SSWAP(a,b) {u8 tmp = s[a]; s[a] = s[b]; s[b] = tmp;}
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -070076#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
Solomon Peachyaaad4302008-10-29 10:42:53 -040089static const u32 wep_crc32_table[256] = {
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -070090 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
Solomon Peachyaaad4302008-10-29 10:42:53 -0400152int wep_change_key(wlandevice_t *wlandev, int keynum, u8* key, int keylen)
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700153{
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 */
Solomon Peachyaaad4302008-10-29 10:42:53 -0400175int wep_decrypt(wlandevice_t *wlandev, u8 *buf, u32 len, int key_override, u8 *iv, u8 *icv)
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700176{
Solomon Peachyaaad4302008-10-29 10:42:53 -0400177 u32 i, j, k, crc, keylen;
178 u8 s[256], key[64], c_crc[4];
179 u8 keyidx;
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700180
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. */
Solomon Peachyaaad4302008-10-29 10:42:53 -0400247int wep_encrypt(wlandevice_t *wlandev, u8 *buf, u8 *dst, u32 len, int keynum, u8 *iv, u8 *icv)
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700248{
Solomon Peachyaaad4302008-10-29 10:42:53 -0400249 u32 i, j, k, crc, keylen;
250 u8 s[256], key[64];
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700251
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}