]> git.proxmox.com Git - mirror_ubuntu-focal-kernel.git/blame - net/mac80211/wep.c
UBUNTU: Ubuntu-5.4.0-117.132
[mirror_ubuntu-focal-kernel.git] / net / mac80211 / wep.c
CommitLineData
d2912cb1 1// SPDX-License-Identifier: GPL-2.0-only
f0706e82
JB
2/*
3 * Software WEP encryption implementation
4 * Copyright 2002, Jouni Malinen <jkmaline@cc.hut.fi>
5 * Copyright 2003, Instant802 Networks, Inc.
f0706e82
JB
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>
11763609 16#include <linux/scatterlist.h>
5a0e3ad6 17#include <linux/slab.h>
860c6e6a 18#include <asm/unaligned.h>
f0706e82
JB
19
20#include <net/mac80211.h>
21#include "ieee80211_i.h"
22#include "wep.h"
23
24
25int ieee80211_wep_init(struct ieee80211_local *local)
26{
27 /* start WEP IV from a random value */
4325f6ca 28 get_random_bytes(&local->wep_iv, IEEE80211_WEP_IV_LEN);
f0706e82 29
f0706e82
JB
30 return 0;
31}
32
c6a1fa12 33static inline bool ieee80211_wep_weak_iv(u32 iv, int keylen)
f0706e82 34{
c6a1fa12
JB
35 /*
36 * Fluhrer, Mantin, and Shamir have reported weaknesses in the
f0706e82 37 * key scheduling algorithm of RC4. At least IVs (KeyByte + 3,
c6a1fa12
JB
38 * 0xff, N) can be used to speedup attacks, so avoid using them.
39 */
f0706e82
JB
40 if ((iv & 0xff00) == 0xff00) {
41 u8 B = (iv >> 16) & 0xff;
42 if (B >= 3 && B < 3 + keylen)
c6a1fa12 43 return true;
f0706e82 44 }
c6a1fa12 45 return false;
f0706e82
JB
46}
47
48
4f0d18e2 49static void ieee80211_wep_get_iv(struct ieee80211_local *local,
c9cf0122 50 int keylen, int keyidx, u8 *iv)
f0706e82
JB
51{
52 local->wep_iv++;
c9cf0122 53 if (ieee80211_wep_weak_iv(local->wep_iv, keylen))
f0706e82
JB
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;
c9cf0122 62 *iv++ = keyidx << 6;
f0706e82
JB
63}
64
65
6a22a59d
JB
66static u8 *ieee80211_wep_add_iv(struct ieee80211_local *local,
67 struct sk_buff *skb,
c9cf0122 68 int keylen, int keyidx)
f0706e82 69{
70217d7f 70 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
ee70108f 71 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
70217d7f 72 unsigned int hdrlen;
f0706e82
JB
73 u8 *newhdr;
74
70217d7f 75 hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
f0706e82 76
47b4e1fc 77 if (WARN_ON(skb_headroom(skb) < IEEE80211_WEP_IV_LEN))
23c0752a 78 return NULL;
f0706e82 79
70217d7f 80 hdrlen = ieee80211_hdrlen(hdr->frame_control);
4325f6ca
JB
81 newhdr = skb_push(skb, IEEE80211_WEP_IV_LEN);
82 memmove(newhdr, newhdr + IEEE80211_WEP_IV_LEN, hdrlen);
ee70108f
JD
83
84 /* the HW only needs room for the IV, but not the actual IV */
85 if (info->control.hw_key &&
86 (info->control.hw_key->flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE))
87 return newhdr + hdrlen;
88
c9cf0122 89 ieee80211_wep_get_iv(local, keylen, keyidx, newhdr + hdrlen);
f0706e82
JB
90 return newhdr + hdrlen;
91}
92
93
4f0d18e2
JB
94static void ieee80211_wep_remove_iv(struct ieee80211_local *local,
95 struct sk_buff *skb,
96 struct ieee80211_key *key)
f0706e82 97{
70217d7f
HH
98 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
99 unsigned int hdrlen;
f0706e82 100
70217d7f 101 hdrlen = ieee80211_hdrlen(hdr->frame_control);
4325f6ca
JB
102 memmove(skb->data + IEEE80211_WEP_IV_LEN, skb->data, hdrlen);
103 skb_pull(skb, IEEE80211_WEP_IV_LEN);
f0706e82
JB
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)) */
5fdb3735 110int ieee80211_wep_encrypt_data(struct arc4_ctx *ctx, u8 *rc4key,
3473187d 111 size_t klen, u8 *data, size_t data_len)
f0706e82 112{
860c6e6a 113 __le32 icv;
3473187d 114
860c6e6a
IK
115 icv = cpu_to_le32(~crc32_le(~0, data, data_len));
116 put_unaligned(icv, (__le32 *)(data + data_len));
f0706e82 117
5fdb3735
AB
118 arc4_setkey(ctx, rc4key, klen);
119 arc4_crypt(ctx, data, data, data_len + IEEE80211_WEP_ICV_LEN);
120 memzero_explicit(ctx, sizeof(*ctx));
3473187d
JL
121
122 return 0;
f0706e82
JB
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 */
fffd0934
JB
133int ieee80211_wep_encrypt(struct ieee80211_local *local,
134 struct sk_buff *skb,
135 const u8 *key, int keylen, int keyidx)
f0706e82 136{
c9cf0122 137 u8 *iv;
f0706e82 138 size_t len;
c9cf0122 139 u8 rc4key[3 + WLAN_KEY_LEN_WEP104];
f0706e82 140
47b4e1fc
JD
141 if (WARN_ON(skb_tailroom(skb) < IEEE80211_WEP_ICV_LEN))
142 return -1;
143
c9cf0122
JB
144 iv = ieee80211_wep_add_iv(local, skb, keylen, keyidx);
145 if (!iv)
f0706e82 146 return -1;
f0706e82 147
4325f6ca 148 len = skb->len - (iv + IEEE80211_WEP_IV_LEN - skb->data);
f0706e82
JB
149
150 /* Prepend 24-bit IV to RC4 key */
151 memcpy(rc4key, iv, 3);
152
153 /* Copy rest of the WEP key (the secret part) */
c9cf0122 154 memcpy(rc4key + 3, key, keylen);
f0706e82
JB
155
156 /* Add room for ICV */
4325f6ca 157 skb_put(skb, IEEE80211_WEP_ICV_LEN);
f0706e82 158
5fdb3735 159 return ieee80211_wep_encrypt_data(&local->wep_tx_ctx, rc4key, keylen + 3,
4325f6ca 160 iv + IEEE80211_WEP_IV_LEN, len);
f0706e82
JB
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. */
5fdb3735 167int ieee80211_wep_decrypt_data(struct arc4_ctx *ctx, u8 *rc4key,
f0706e82
JB
168 size_t klen, u8 *data, size_t data_len)
169{
f0706e82 170 __le32 crc;
3473187d 171
5fdb3735
AB
172 arc4_setkey(ctx, rc4key, klen);
173 arc4_crypt(ctx, data, data, data_len + IEEE80211_WEP_ICV_LEN);
174 memzero_explicit(ctx, sizeof(*ctx));
f0706e82
JB
175
176 crc = cpu_to_le32(~crc32_le(~0, data, data_len));
4325f6ca 177 if (memcmp(&crc, data + data_len, IEEE80211_WEP_ICV_LEN) != 0)
f0706e82
JB
178 /* ICV mismatch */
179 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 */
c9cf0122
JB
193static int ieee80211_wep_decrypt(struct ieee80211_local *local,
194 struct sk_buff *skb,
195 struct ieee80211_key *key)
f0706e82
JB
196{
197 u32 klen;
730bd83b 198 u8 rc4key[3 + WLAN_KEY_LEN_WEP104];
f0706e82 199 u8 keyidx;
70217d7f
HH
200 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
201 unsigned int hdrlen;
f0706e82
JB
202 size_t len;
203 int ret = 0;
204
70217d7f 205 if (!ieee80211_has_protected(hdr->frame_control))
f0706e82
JB
206 return -1;
207
70217d7f 208 hdrlen = ieee80211_hdrlen(hdr->frame_control);
4325f6ca 209 if (skb->len < hdrlen + IEEE80211_WEP_IV_LEN + IEEE80211_WEP_ICV_LEN)
f0706e82
JB
210 return -1;
211
4325f6ca 212 len = skb->len - hdrlen - IEEE80211_WEP_IV_LEN - IEEE80211_WEP_ICV_LEN;
f0706e82
JB
213
214 keyidx = skb->data[hdrlen + 3] >> 6;
215
97359d12 216 if (!key || keyidx != key->conf.keyidx)
f0706e82
JB
217 return -1;
218
8f20fc24 219 klen = 3 + key->conf.keylen;
f0706e82 220
f0706e82
JB
221 /* Prepend 24-bit IV to RC4 key */
222 memcpy(rc4key, skb->data + hdrlen, 3);
223
224 /* Copy rest of the WEP key (the secret part) */
8f20fc24 225 memcpy(rc4key + 3, key->conf.key, key->conf.keylen);
f0706e82 226
5fdb3735 227 if (ieee80211_wep_decrypt_data(&local->wep_rx_ctx, rc4key, klen,
4325f6ca
JB
228 skb->data + hdrlen +
229 IEEE80211_WEP_IV_LEN, len))
f0706e82 230 ret = -1;
f0706e82 231
f0706e82 232 /* Trim ICV */
4325f6ca 233 skb_trim(skb, skb->len - IEEE80211_WEP_ICV_LEN);
f0706e82
JB
234
235 /* Remove IV */
4325f6ca
JB
236 memmove(skb->data + IEEE80211_WEP_IV_LEN, skb->data, hdrlen);
237 skb_pull(skb, IEEE80211_WEP_IV_LEN);
f0706e82
JB
238
239 return ret;
240}
241
9ae54c84 242ieee80211_rx_result
5cf121c3 243ieee80211_crypto_wep_decrypt(struct ieee80211_rx_data *rx)
4f0d18e2 244{
eb9fb5b8
JB
245 struct sk_buff *skb = rx->skb;
246 struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
247 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
a8286911 248 __le16 fc = hdr->frame_control;
358c8d9d 249
a8286911 250 if (!ieee80211_is_data(fc) && !ieee80211_is_auth(fc))
9ae54c84 251 return RX_CONTINUE;
4f0d18e2 252
eb9fb5b8 253 if (!(status->flag & RX_FLAG_DECRYPTED)) {
a8286911
JB
254 if (skb_linearize(rx->skb))
255 return RX_DROP_UNUSABLE;
f4ea83dd 256 if (ieee80211_wep_decrypt(rx->local, rx->skb, rx->key))
e4c26add 257 return RX_DROP_UNUSABLE;
eb9fb5b8 258 } else if (!(status->flag & RX_FLAG_IV_STRIPPED)) {
4325f6ca
JB
259 if (!pskb_may_pull(rx->skb, ieee80211_hdrlen(fc) +
260 IEEE80211_WEP_IV_LEN))
a8286911 261 return RX_DROP_UNUSABLE;
4f0d18e2
JB
262 ieee80211_wep_remove_iv(rx->local, rx->skb, rx->key);
263 /* remove ICV */
cef0acd4
DS
264 if (!(status->flag & RX_FLAG_ICV_STRIPPED) &&
265 pskb_trim(rx->skb, rx->skb->len - IEEE80211_WEP_ICV_LEN))
a8286911 266 return RX_DROP_UNUSABLE;
4f0d18e2
JB
267 }
268
9ae54c84 269 return RX_CONTINUE;
4f0d18e2 270}
6a22a59d 271
5cf121c3 272static int wep_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb)
6a22a59d 273{
e039fa4a 274 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
ee70108f 275 struct ieee80211_key_conf *hw_key = info->control.hw_key;
e039fa4a 276
ee70108f 277 if (!hw_key) {
c9cf0122
JB
278 if (ieee80211_wep_encrypt(tx->local, skb, tx->key->conf.key,
279 tx->key->conf.keylen,
280 tx->key->conf.keyidx))
6a22a59d 281 return -1;
ee70108f
JD
282 } else if ((hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_IV) ||
283 (hw_key->flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE)) {
813d7669
JB
284 if (!ieee80211_wep_add_iv(tx->local, skb,
285 tx->key->conf.keylen,
286 tx->key->conf.keyidx))
287 return -1;
288 }
289
6a22a59d
JB
290 return 0;
291}
292
9ae54c84 293ieee80211_tx_result
5cf121c3 294ieee80211_crypto_wep_encrypt(struct ieee80211_tx_data *tx)
6a22a59d 295{
2de8e0d9 296 struct sk_buff *skb;
c6a1fa12 297
5cf121c3 298 ieee80211_tx_set_protected(tx);
6a22a59d 299
252b86c4 300 skb_queue_walk(&tx->skbs, skb) {
2de8e0d9
JB
301 if (wep_encrypt_skb(tx, skb) < 0) {
302 I802_DEBUG_INC(tx->local->tx_handlers_drop_wep);
303 return TX_DROP;
6a22a59d 304 }
252b86c4 305 }
6a22a59d 306
9ae54c84 307 return TX_CONTINUE;
6a22a59d 308}