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 
wep_change_key(struct wlandevice * wlandev,int keynum,u8 * key,int keylen)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  */
wep_decrypt(struct wlandevice * wlandev,u8 * buf,u32 len,int key_override,u8 * iv,u8 * icv)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. */
wep_encrypt(struct wlandevice * wlandev,u8 * buf,u8 * dst,u32 len,int keynum,u8 * iv,u8 * icv)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 }
208