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