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
46int 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 */
69int 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(crc: ~0, p: 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. */
140int 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(buf: iv, len: 3);
159 while ((iv[1] == 0xff) && (iv[0] >= 3) && (iv[0] < keylen))
160 get_random_bytes(buf: iv, len: 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(crc: ~0, p: 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

source code of linux/drivers/staging/wlan-ng/p80211wep.c