GNU Linux-libre 6.7.9-gnu
[releases.git] / drivers / staging / wlan-ng / p80211wep.c
1 // SPDX-License-Identifier: (GPL-2.0 OR MPL-1.1)
2 /*
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  * --------------------------------------------------------------------
12  *
13  * Inquiries regarding the linux-wlan Open Source project can be
14  * made directly to:
15  *
16  * AbsoluteValue Systems Inc.
17  * info@linux-wlan.com
18  * http://www.linux-wlan.com
19  *
20  * --------------------------------------------------------------------
21  *
22  * Portions of the development of this software were funded by
23  * Intersil Corporation as part of PRISM(R) chipset product development.
24  *
25  * --------------------------------------------------------------------
26  */
27
28 /*================================================================*/
29 /* System Includes */
30
31 #include <linux/crc32.h>
32 #include <linux/netdevice.h>
33 #include <linux/wireless.h>
34 #include <linux/random.h>
35 #include <linux/kernel.h>
36 #include "p80211hdr.h"
37 #include "p80211types.h"
38 #include "p80211msg.h"
39 #include "p80211conv.h"
40 #include "p80211netdev.h"
41
42 #define WEP_KEY(x)       (((x) & 0xC0) >> 6)
43
44 /* keylen in bytes! */
45
46 int wep_change_key(struct wlandevice *wlandev, int keynum, u8 *key, int keylen)
47 {
48         if (keylen < 0)
49                 return -1;
50         if (keylen >= MAX_KEYLEN)
51                 return -1;
52         if (!key)
53                 return -1;
54         if (keynum < 0)
55                 return -1;
56         if (keynum >= NUM_WEPKEYS)
57                 return -1;
58
59         wlandev->wep_keylens[keynum] = keylen;
60         memcpy(wlandev->wep_keys[keynum], key, keylen);
61
62         return 0;
63 }
64
65 /*
66  * 4-byte IV at start of buffer, 4-byte ICV at end of buffer.
67  * if successful, buf start is payload begin, length -= 8;
68  */
69 int wep_decrypt(struct wlandevice *wlandev, u8 *buf, u32 len, int key_override,
70                 u8 *iv, u8 *icv)
71 {
72         u32 i, j, k, crc, keylen;
73         u8 s[256], key[64], c_crc[4];
74         u8 keyidx;
75
76         /* Needs to be at least 8 bytes of payload */
77         if (len <= 0)
78                 return -1;
79
80         /* initialize the first bytes of the key from the IV */
81         key[0] = iv[0];
82         key[1] = iv[1];
83         key[2] = iv[2];
84         keyidx = WEP_KEY(iv[3]);
85
86         if (key_override >= 0)
87                 keyidx = key_override;
88
89         if (keyidx >= NUM_WEPKEYS)
90                 return -2;
91
92         keylen = wlandev->wep_keylens[keyidx];
93
94         if (keylen == 0)
95                 return -3;
96
97         /* copy the rest of the key over from the designated key */
98         memcpy(key + 3, wlandev->wep_keys[keyidx], keylen);
99
100         keylen += 3;            /* add in IV bytes */
101
102         /* set up the RC4 state */
103         for (i = 0; i < 256; i++)
104                 s[i] = i;
105         j = 0;
106         for (i = 0; i < 256; i++) {
107                 j = (j + s[i] + key[i % keylen]) & 0xff;
108                 swap(i, j);
109         }
110
111         /* Apply the RC4 to the data, update the CRC32 */
112         i = 0;
113         j = 0;
114         for (k = 0; k < len; k++) {
115                 i = (i + 1) & 0xff;
116                 j = (j + s[i]) & 0xff;
117                 swap(i, j);
118                 buf[k] ^= s[(s[i] + s[j]) & 0xff];
119         }
120         crc = ~crc32_le(~0, buf, len);
121
122         /* now let's check the crc */
123         c_crc[0] = crc;
124         c_crc[1] = crc >> 8;
125         c_crc[2] = crc >> 16;
126         c_crc[3] = crc >> 24;
127
128         for (k = 0; k < 4; k++) {
129                 i = (i + 1) & 0xff;
130                 j = (j + s[i]) & 0xff;
131                 swap(i, j);
132                 if ((c_crc[k] ^ s[(s[i] + s[j]) & 0xff]) != icv[k])
133                         return -(4 | (k << 4)); /* ICV mismatch */
134         }
135
136         return 0;
137 }
138
139 /* encrypts in-place. */
140 int wep_encrypt(struct wlandevice *wlandev, u8 *buf,
141                 u8 *dst, u32 len, int keynum, u8 *iv, u8 *icv)
142 {
143         u32 i, j, k, crc, keylen;
144         u8 s[256], key[64];
145
146         /* no point in WEPping an empty frame */
147         if (len <= 0)
148                 return -1;
149
150         /* we need to have a real key.. */
151         if (keynum >= NUM_WEPKEYS)
152                 return -2;
153         keylen = wlandev->wep_keylens[keynum];
154         if (keylen <= 0)
155                 return -3;
156
157         /* use a random IV.  And skip known weak ones. */
158         get_random_bytes(iv, 3);
159         while ((iv[1] == 0xff) && (iv[0] >= 3) && (iv[0] < keylen))
160                 get_random_bytes(iv, 3);
161
162         iv[3] = (keynum & 0x03) << 6;
163
164         key[0] = iv[0];
165         key[1] = iv[1];
166         key[2] = iv[2];
167
168         /* copy the rest of the key over from the designated key */
169         memcpy(key + 3, wlandev->wep_keys[keynum], keylen);
170
171         keylen += 3;            /* add in IV bytes */
172
173         /* set up the RC4 state */
174         for (i = 0; i < 256; i++)
175                 s[i] = i;
176         j = 0;
177         for (i = 0; i < 256; i++) {
178                 j = (j + s[i] + key[i % keylen]) & 0xff;
179                 swap(i, j);
180         }
181
182         /* Update CRC32 then apply RC4 to the data */
183         i = 0;
184         j = 0;
185         for (k = 0; k < len; k++) {
186                 i = (i + 1) & 0xff;
187                 j = (j + s[i]) & 0xff;
188                 swap(i, j);
189                 dst[k] = buf[k] ^ s[(s[i] + s[j]) & 0xff];
190         }
191         crc = ~crc32_le(~0, buf, len);
192
193         /* now let's encrypt the crc */
194         icv[0] = crc;
195         icv[1] = crc >> 8;
196         icv[2] = crc >> 16;
197         icv[3] = crc >> 24;
198
199         for (k = 0; k < 4; k++) {
200                 i = (i + 1) & 0xff;
201                 j = (j + s[i]) & 0xff;
202                 swap(i, j);
203                 icv[k] ^= s[(s[i] + s[j]) & 0xff];
204         }
205
206         return 0;
207 }