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(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. */ |
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(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 | |