Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0-only
2 : : /*
3 : : * Software WEP encryption implementation
4 : : * Copyright 2002, Jouni Malinen <jkmaline@cc.hut.fi>
5 : : * Copyright 2003, Instant802 Networks, Inc.
6 : : */
7 : :
8 : : #include <linux/netdevice.h>
9 : : #include <linux/types.h>
10 : : #include <linux/random.h>
11 : : #include <linux/compiler.h>
12 : : #include <linux/crc32.h>
13 : : #include <linux/crypto.h>
14 : : #include <linux/err.h>
15 : : #include <linux/mm.h>
16 : : #include <linux/scatterlist.h>
17 : : #include <linux/slab.h>
18 : : #include <asm/unaligned.h>
19 : :
20 : : #include <net/mac80211.h>
21 : : #include "ieee80211_i.h"
22 : : #include "wep.h"
23 : :
24 : :
25 : 0 : int ieee80211_wep_init(struct ieee80211_local *local)
26 : : {
27 : : /* start WEP IV from a random value */
28 : 0 : get_random_bytes(&local->wep_iv, IEEE80211_WEP_IV_LEN);
29 : :
30 : 0 : return 0;
31 : : }
32 : :
33 : : static inline bool ieee80211_wep_weak_iv(u32 iv, int keylen)
34 : : {
35 : : /*
36 : : * Fluhrer, Mantin, and Shamir have reported weaknesses in the
37 : : * key scheduling algorithm of RC4. At least IVs (KeyByte + 3,
38 : : * 0xff, N) can be used to speedup attacks, so avoid using them.
39 : : */
40 : : if ((iv & 0xff00) == 0xff00) {
41 : : u8 B = (iv >> 16) & 0xff;
42 : : if (B >= 3 && B < 3 + keylen)
43 : : return true;
44 : : }
45 : : return false;
46 : : }
47 : :
48 : :
49 : : static void ieee80211_wep_get_iv(struct ieee80211_local *local,
50 : : int keylen, int keyidx, u8 *iv)
51 : : {
52 : : local->wep_iv++;
53 : : if (ieee80211_wep_weak_iv(local->wep_iv, keylen))
54 : : local->wep_iv += 0x0100;
55 : :
56 : : if (!iv)
57 : : return;
58 : :
59 : : *iv++ = (local->wep_iv >> 16) & 0xff;
60 : : *iv++ = (local->wep_iv >> 8) & 0xff;
61 : : *iv++ = local->wep_iv & 0xff;
62 : : *iv++ = keyidx << 6;
63 : : }
64 : :
65 : :
66 : 0 : static u8 *ieee80211_wep_add_iv(struct ieee80211_local *local,
67 : : struct sk_buff *skb,
68 : : int keylen, int keyidx)
69 : : {
70 : 0 : struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
71 [ # # ]: 0 : struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
72 : 0 : unsigned int hdrlen;
73 : 0 : u8 *newhdr;
74 : :
75 : 0 : hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
76 : :
77 [ # # # # ]: 0 : if (WARN_ON(skb_headroom(skb) < IEEE80211_WEP_IV_LEN))
78 : : return NULL;
79 : :
80 : 0 : hdrlen = ieee80211_hdrlen(hdr->frame_control);
81 : 0 : newhdr = skb_push(skb, IEEE80211_WEP_IV_LEN);
82 : 0 : memmove(newhdr, newhdr + IEEE80211_WEP_IV_LEN, hdrlen);
83 : :
84 : : /* the HW only needs room for the IV, but not the actual IV */
85 [ # # ]: 0 : if (info->control.hw_key &&
86 [ # # ]: 0 : (info->control.hw_key->flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE))
87 : 0 : return newhdr + hdrlen;
88 : :
89 : 0 : ieee80211_wep_get_iv(local, keylen, keyidx, newhdr + hdrlen);
90 : 0 : return newhdr + hdrlen;
91 : : }
92 : :
93 : :
94 : : static void ieee80211_wep_remove_iv(struct ieee80211_local *local,
95 : : struct sk_buff *skb,
96 : : struct ieee80211_key *key)
97 : : {
98 : : struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
99 : : unsigned int hdrlen;
100 : :
101 : : hdrlen = ieee80211_hdrlen(hdr->frame_control);
102 : : memmove(skb->data + IEEE80211_WEP_IV_LEN, skb->data, hdrlen);
103 : : skb_pull(skb, IEEE80211_WEP_IV_LEN);
104 : : }
105 : :
106 : :
107 : : /* Perform WEP encryption using given key. data buffer must have tailroom
108 : : * for 4-byte ICV. data_len must not include this ICV. Note: this function
109 : : * does _not_ add IV. data = RC4(data | CRC32(data)) */
110 : 0 : int ieee80211_wep_encrypt_data(struct arc4_ctx *ctx, u8 *rc4key,
111 : : size_t klen, u8 *data, size_t data_len)
112 : : {
113 : 0 : __le32 icv;
114 : :
115 : 0 : icv = cpu_to_le32(~crc32_le(~0, data, data_len));
116 : 0 : put_unaligned(icv, (__le32 *)(data + data_len));
117 : :
118 : 0 : arc4_setkey(ctx, rc4key, klen);
119 : 0 : arc4_crypt(ctx, data, data, data_len + IEEE80211_WEP_ICV_LEN);
120 : 0 : memzero_explicit(ctx, sizeof(*ctx));
121 : :
122 : 0 : return 0;
123 : : }
124 : :
125 : :
126 : : /* Perform WEP encryption on given skb. 4 bytes of extra space (IV) in the
127 : : * beginning of the buffer 4 bytes of extra space (ICV) in the end of the
128 : : * buffer will be added. Both IV and ICV will be transmitted, so the
129 : : * payload length increases with 8 bytes.
130 : : *
131 : : * WEP frame payload: IV + TX key idx, RC4(data), ICV = RC4(CRC32(data))
132 : : */
133 : 0 : int ieee80211_wep_encrypt(struct ieee80211_local *local,
134 : : struct sk_buff *skb,
135 : : const u8 *key, int keylen, int keyidx)
136 : : {
137 : 0 : u8 *iv;
138 : 0 : size_t len;
139 : 0 : u8 rc4key[3 + WLAN_KEY_LEN_WEP104];
140 : :
141 [ # # # # : 0 : if (WARN_ON(skb_tailroom(skb) < IEEE80211_WEP_ICV_LEN))
# # ]
142 : : return -1;
143 : :
144 : 0 : iv = ieee80211_wep_add_iv(local, skb, keylen, keyidx);
145 [ # # ]: 0 : if (!iv)
146 : : return -1;
147 : :
148 : 0 : len = skb->len - (iv + IEEE80211_WEP_IV_LEN - skb->data);
149 : :
150 : : /* Prepend 24-bit IV to RC4 key */
151 : 0 : memcpy(rc4key, iv, 3);
152 : :
153 : : /* Copy rest of the WEP key (the secret part) */
154 : 0 : memcpy(rc4key + 3, key, keylen);
155 : :
156 : : /* Add room for ICV */
157 : 0 : skb_put(skb, IEEE80211_WEP_ICV_LEN);
158 : :
159 : 0 : return ieee80211_wep_encrypt_data(&local->wep_tx_ctx, rc4key, keylen + 3,
160 : : iv + IEEE80211_WEP_IV_LEN, len);
161 : : }
162 : :
163 : :
164 : : /* Perform WEP decryption using given key. data buffer includes encrypted
165 : : * payload, including 4-byte ICV, but _not_ IV. data_len must not include ICV.
166 : : * Return 0 on success and -1 on ICV mismatch. */
167 : 0 : int ieee80211_wep_decrypt_data(struct arc4_ctx *ctx, u8 *rc4key,
168 : : size_t klen, u8 *data, size_t data_len)
169 : : {
170 : 0 : __le32 crc;
171 : :
172 : 0 : arc4_setkey(ctx, rc4key, klen);
173 : 0 : arc4_crypt(ctx, data, data, data_len + IEEE80211_WEP_ICV_LEN);
174 : 0 : memzero_explicit(ctx, sizeof(*ctx));
175 : :
176 : 0 : crc = cpu_to_le32(~crc32_le(~0, data, data_len));
177 [ # # ]: 0 : if (memcmp(&crc, data + data_len, IEEE80211_WEP_ICV_LEN) != 0)
178 : : /* ICV mismatch */
179 : 0 : return -1;
180 : :
181 : : return 0;
182 : : }
183 : :
184 : :
185 : : /* Perform WEP decryption on given skb. Buffer includes whole WEP part of
186 : : * the frame: IV (4 bytes), encrypted payload (including SNAP header),
187 : : * ICV (4 bytes). skb->len includes both IV and ICV.
188 : : *
189 : : * Returns 0 if frame was decrypted successfully and ICV was correct and -1 on
190 : : * failure. If frame is OK, IV and ICV will be removed, i.e., decrypted payload
191 : : * is moved to the beginning of the skb and skb length will be reduced.
192 : : */
193 : 0 : static int ieee80211_wep_decrypt(struct ieee80211_local *local,
194 : : struct sk_buff *skb,
195 : : struct ieee80211_key *key)
196 : : {
197 : 0 : u32 klen;
198 : 0 : u8 rc4key[3 + WLAN_KEY_LEN_WEP104];
199 : 0 : u8 keyidx;
200 : 0 : struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
201 : 0 : unsigned int hdrlen;
202 : 0 : size_t len;
203 : 0 : int ret = 0;
204 : :
205 [ # # ]: 0 : if (!ieee80211_has_protected(hdr->frame_control))
206 : : return -1;
207 : :
208 : 0 : hdrlen = ieee80211_hdrlen(hdr->frame_control);
209 [ # # ]: 0 : if (skb->len < hdrlen + IEEE80211_WEP_IV_LEN + IEEE80211_WEP_ICV_LEN)
210 : : return -1;
211 : :
212 : 0 : len = skb->len - hdrlen - IEEE80211_WEP_IV_LEN - IEEE80211_WEP_ICV_LEN;
213 : :
214 : 0 : keyidx = skb->data[hdrlen + 3] >> 6;
215 : :
216 [ # # # # ]: 0 : if (!key || keyidx != key->conf.keyidx)
217 : : return -1;
218 : :
219 : 0 : klen = 3 + key->conf.keylen;
220 : :
221 : : /* Prepend 24-bit IV to RC4 key */
222 : 0 : memcpy(rc4key, skb->data + hdrlen, 3);
223 : :
224 : : /* Copy rest of the WEP key (the secret part) */
225 : 0 : memcpy(rc4key + 3, key->conf.key, key->conf.keylen);
226 : :
227 [ # # ]: 0 : if (ieee80211_wep_decrypt_data(&local->wep_rx_ctx, rc4key, klen,
228 : 0 : skb->data + hdrlen +
229 : : IEEE80211_WEP_IV_LEN, len))
230 : 0 : ret = -1;
231 : :
232 : : /* Trim ICV */
233 : 0 : skb_trim(skb, skb->len - IEEE80211_WEP_ICV_LEN);
234 : :
235 : : /* Remove IV */
236 : 0 : memmove(skb->data + IEEE80211_WEP_IV_LEN, skb->data, hdrlen);
237 : 0 : skb_pull(skb, IEEE80211_WEP_IV_LEN);
238 : :
239 : 0 : return ret;
240 : : }
241 : :
242 : : ieee80211_rx_result
243 : 0 : ieee80211_crypto_wep_decrypt(struct ieee80211_rx_data *rx)
244 : : {
245 : 0 : struct sk_buff *skb = rx->skb;
246 [ # # ]: 0 : struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
247 : 0 : struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
248 : 0 : __le16 fc = hdr->frame_control;
249 : :
250 [ # # # # ]: 0 : if (!ieee80211_is_data(fc) && !ieee80211_is_auth(fc))
251 : : return RX_CONTINUE;
252 : :
253 [ # # ]: 0 : if (!(status->flag & RX_FLAG_DECRYPTED)) {
254 [ # # ]: 0 : if (skb_linearize(rx->skb))
255 : : return RX_DROP_UNUSABLE;
256 [ # # ]: 0 : if (ieee80211_wep_decrypt(rx->local, rx->skb, rx->key))
257 : 0 : return RX_DROP_UNUSABLE;
258 [ # # ]: 0 : } else if (!(status->flag & RX_FLAG_IV_STRIPPED)) {
259 [ # # ]: 0 : if (!pskb_may_pull(rx->skb, ieee80211_hdrlen(fc) +
260 : : IEEE80211_WEP_IV_LEN))
261 : : return RX_DROP_UNUSABLE;
262 : 0 : ieee80211_wep_remove_iv(rx->local, rx->skb, rx->key);
263 : : /* remove ICV */
264 [ # # # # ]: 0 : if (!(status->flag & RX_FLAG_ICV_STRIPPED) &&
265 : 0 : pskb_trim(rx->skb, rx->skb->len - IEEE80211_WEP_ICV_LEN))
266 : 0 : return RX_DROP_UNUSABLE;
267 : : }
268 : :
269 : : return RX_CONTINUE;
270 : : }
271 : :
272 : : static int wep_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb)
273 : : {
274 : : struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
275 : : struct ieee80211_key_conf *hw_key = info->control.hw_key;
276 : :
277 : : if (!hw_key) {
278 : : if (ieee80211_wep_encrypt(tx->local, skb, tx->key->conf.key,
279 : : tx->key->conf.keylen,
280 : : tx->key->conf.keyidx))
281 : : return -1;
282 : : } else if ((hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_IV) ||
283 : : (hw_key->flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE)) {
284 : : if (!ieee80211_wep_add_iv(tx->local, skb,
285 : : tx->key->conf.keylen,
286 : : tx->key->conf.keyidx))
287 : : return -1;
288 : : }
289 : :
290 : : return 0;
291 : : }
292 : :
293 : : ieee80211_tx_result
294 : 0 : ieee80211_crypto_wep_encrypt(struct ieee80211_tx_data *tx)
295 : : {
296 : 0 : struct sk_buff *skb;
297 : :
298 : 0 : ieee80211_tx_set_protected(tx);
299 : :
300 [ # # ]: 0 : skb_queue_walk(&tx->skbs, skb) {
301 [ # # ]: 0 : if (wep_encrypt_skb(tx, skb) < 0) {
302 : : I802_DEBUG_INC(tx->local->tx_handlers_drop_wep);
303 : : return TX_DROP;
304 : : }
305 : : }
306 : :
307 : : return TX_CONTINUE;
308 : : }
|