0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/netdevice.h>
0009 #include <linux/types.h>
0010 #include <linux/random.h>
0011 #include <linux/compiler.h>
0012 #include <linux/crc32.h>
0013 #include <linux/crypto.h>
0014 #include <linux/err.h>
0015 #include <linux/mm.h>
0016 #include <linux/scatterlist.h>
0017 #include <linux/slab.h>
0018 #include <asm/unaligned.h>
0019
0020 #include <net/mac80211.h>
0021 #include "ieee80211_i.h"
0022 #include "wep.h"
0023
0024
0025 void ieee80211_wep_init(struct ieee80211_local *local)
0026 {
0027
0028 get_random_bytes(&local->wep_iv, IEEE80211_WEP_IV_LEN);
0029 }
0030
0031 static inline bool ieee80211_wep_weak_iv(u32 iv, int keylen)
0032 {
0033
0034
0035
0036
0037
0038 if ((iv & 0xff00) == 0xff00) {
0039 u8 B = (iv >> 16) & 0xff;
0040 if (B >= 3 && B < 3 + keylen)
0041 return true;
0042 }
0043 return false;
0044 }
0045
0046
0047 static void ieee80211_wep_get_iv(struct ieee80211_local *local,
0048 int keylen, int keyidx, u8 *iv)
0049 {
0050 local->wep_iv++;
0051 if (ieee80211_wep_weak_iv(local->wep_iv, keylen))
0052 local->wep_iv += 0x0100;
0053
0054 if (!iv)
0055 return;
0056
0057 *iv++ = (local->wep_iv >> 16) & 0xff;
0058 *iv++ = (local->wep_iv >> 8) & 0xff;
0059 *iv++ = local->wep_iv & 0xff;
0060 *iv++ = keyidx << 6;
0061 }
0062
0063
0064 static u8 *ieee80211_wep_add_iv(struct ieee80211_local *local,
0065 struct sk_buff *skb,
0066 int keylen, int keyidx)
0067 {
0068 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
0069 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
0070 unsigned int hdrlen;
0071 u8 *newhdr;
0072
0073 hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
0074
0075 if (WARN_ON(skb_headroom(skb) < IEEE80211_WEP_IV_LEN))
0076 return NULL;
0077
0078 hdrlen = ieee80211_hdrlen(hdr->frame_control);
0079 newhdr = skb_push(skb, IEEE80211_WEP_IV_LEN);
0080 memmove(newhdr, newhdr + IEEE80211_WEP_IV_LEN, hdrlen);
0081
0082
0083 if (info->control.hw_key &&
0084 (info->control.hw_key->flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE))
0085 return newhdr + hdrlen;
0086
0087 ieee80211_wep_get_iv(local, keylen, keyidx, newhdr + hdrlen);
0088 return newhdr + hdrlen;
0089 }
0090
0091
0092 static void ieee80211_wep_remove_iv(struct ieee80211_local *local,
0093 struct sk_buff *skb,
0094 struct ieee80211_key *key)
0095 {
0096 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
0097 unsigned int hdrlen;
0098
0099 hdrlen = ieee80211_hdrlen(hdr->frame_control);
0100 memmove(skb->data + IEEE80211_WEP_IV_LEN, skb->data, hdrlen);
0101 skb_pull(skb, IEEE80211_WEP_IV_LEN);
0102 }
0103
0104
0105
0106
0107
0108 int ieee80211_wep_encrypt_data(struct arc4_ctx *ctx, u8 *rc4key,
0109 size_t klen, u8 *data, size_t data_len)
0110 {
0111 __le32 icv;
0112
0113 icv = cpu_to_le32(~crc32_le(~0, data, data_len));
0114 put_unaligned(icv, (__le32 *)(data + data_len));
0115
0116 arc4_setkey(ctx, rc4key, klen);
0117 arc4_crypt(ctx, data, data, data_len + IEEE80211_WEP_ICV_LEN);
0118 memzero_explicit(ctx, sizeof(*ctx));
0119
0120 return 0;
0121 }
0122
0123
0124
0125
0126
0127
0128
0129
0130
0131 int ieee80211_wep_encrypt(struct ieee80211_local *local,
0132 struct sk_buff *skb,
0133 const u8 *key, int keylen, int keyidx)
0134 {
0135 u8 *iv;
0136 size_t len;
0137 u8 rc4key[3 + WLAN_KEY_LEN_WEP104];
0138
0139 if (WARN_ON(skb_tailroom(skb) < IEEE80211_WEP_ICV_LEN))
0140 return -1;
0141
0142 iv = ieee80211_wep_add_iv(local, skb, keylen, keyidx);
0143 if (!iv)
0144 return -1;
0145
0146 len = skb->len - (iv + IEEE80211_WEP_IV_LEN - skb->data);
0147
0148
0149 memcpy(rc4key, iv, 3);
0150
0151
0152 memcpy(rc4key + 3, key, keylen);
0153
0154
0155 skb_put(skb, IEEE80211_WEP_ICV_LEN);
0156
0157 return ieee80211_wep_encrypt_data(&local->wep_tx_ctx, rc4key, keylen + 3,
0158 iv + IEEE80211_WEP_IV_LEN, len);
0159 }
0160
0161
0162
0163
0164
0165 int ieee80211_wep_decrypt_data(struct arc4_ctx *ctx, u8 *rc4key,
0166 size_t klen, u8 *data, size_t data_len)
0167 {
0168 __le32 crc;
0169
0170 arc4_setkey(ctx, rc4key, klen);
0171 arc4_crypt(ctx, data, data, data_len + IEEE80211_WEP_ICV_LEN);
0172 memzero_explicit(ctx, sizeof(*ctx));
0173
0174 crc = cpu_to_le32(~crc32_le(~0, data, data_len));
0175 if (memcmp(&crc, data + data_len, IEEE80211_WEP_ICV_LEN) != 0)
0176
0177 return -1;
0178
0179 return 0;
0180 }
0181
0182
0183
0184
0185
0186
0187
0188
0189
0190
0191 static int ieee80211_wep_decrypt(struct ieee80211_local *local,
0192 struct sk_buff *skb,
0193 struct ieee80211_key *key)
0194 {
0195 u32 klen;
0196 u8 rc4key[3 + WLAN_KEY_LEN_WEP104];
0197 u8 keyidx;
0198 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
0199 unsigned int hdrlen;
0200 size_t len;
0201 int ret = 0;
0202
0203 if (!ieee80211_has_protected(hdr->frame_control))
0204 return -1;
0205
0206 hdrlen = ieee80211_hdrlen(hdr->frame_control);
0207 if (skb->len < hdrlen + IEEE80211_WEP_IV_LEN + IEEE80211_WEP_ICV_LEN)
0208 return -1;
0209
0210 len = skb->len - hdrlen - IEEE80211_WEP_IV_LEN - IEEE80211_WEP_ICV_LEN;
0211
0212 keyidx = skb->data[hdrlen + 3] >> 6;
0213
0214 if (!key || keyidx != key->conf.keyidx)
0215 return -1;
0216
0217 klen = 3 + key->conf.keylen;
0218
0219
0220 memcpy(rc4key, skb->data + hdrlen, 3);
0221
0222
0223 memcpy(rc4key + 3, key->conf.key, key->conf.keylen);
0224
0225 if (ieee80211_wep_decrypt_data(&local->wep_rx_ctx, rc4key, klen,
0226 skb->data + hdrlen +
0227 IEEE80211_WEP_IV_LEN, len))
0228 ret = -1;
0229
0230
0231 skb_trim(skb, skb->len - IEEE80211_WEP_ICV_LEN);
0232
0233
0234 memmove(skb->data + IEEE80211_WEP_IV_LEN, skb->data, hdrlen);
0235 skb_pull(skb, IEEE80211_WEP_IV_LEN);
0236
0237 return ret;
0238 }
0239
0240 ieee80211_rx_result
0241 ieee80211_crypto_wep_decrypt(struct ieee80211_rx_data *rx)
0242 {
0243 struct sk_buff *skb = rx->skb;
0244 struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
0245 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
0246 __le16 fc = hdr->frame_control;
0247
0248 if (!ieee80211_is_data(fc) && !ieee80211_is_auth(fc))
0249 return RX_CONTINUE;
0250
0251 if (!(status->flag & RX_FLAG_DECRYPTED)) {
0252 if (skb_linearize(rx->skb))
0253 return RX_DROP_UNUSABLE;
0254 if (ieee80211_wep_decrypt(rx->local, rx->skb, rx->key))
0255 return RX_DROP_UNUSABLE;
0256 } else if (!(status->flag & RX_FLAG_IV_STRIPPED)) {
0257 if (!pskb_may_pull(rx->skb, ieee80211_hdrlen(fc) +
0258 IEEE80211_WEP_IV_LEN))
0259 return RX_DROP_UNUSABLE;
0260 ieee80211_wep_remove_iv(rx->local, rx->skb, rx->key);
0261
0262 if (!(status->flag & RX_FLAG_ICV_STRIPPED) &&
0263 pskb_trim(rx->skb, rx->skb->len - IEEE80211_WEP_ICV_LEN))
0264 return RX_DROP_UNUSABLE;
0265 }
0266
0267 return RX_CONTINUE;
0268 }
0269
0270 static int wep_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb)
0271 {
0272 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
0273 struct ieee80211_key_conf *hw_key = info->control.hw_key;
0274
0275 if (!hw_key) {
0276 if (ieee80211_wep_encrypt(tx->local, skb, tx->key->conf.key,
0277 tx->key->conf.keylen,
0278 tx->key->conf.keyidx))
0279 return -1;
0280 } else if ((hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_IV) ||
0281 (hw_key->flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE)) {
0282 if (!ieee80211_wep_add_iv(tx->local, skb,
0283 tx->key->conf.keylen,
0284 tx->key->conf.keyidx))
0285 return -1;
0286 }
0287
0288 return 0;
0289 }
0290
0291 ieee80211_tx_result
0292 ieee80211_crypto_wep_encrypt(struct ieee80211_tx_data *tx)
0293 {
0294 struct sk_buff *skb;
0295
0296 ieee80211_tx_set_protected(tx);
0297
0298 skb_queue_walk(&tx->skbs, skb) {
0299 if (wep_encrypt_skb(tx, skb) < 0) {
0300 I802_DEBUG_INC(tx->local->tx_handlers_drop_wep);
0301 return TX_DROP;
0302 }
0303 }
0304
0305 return TX_CONTINUE;
0306 }