00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #include <linux/netdevice.h>
00012 #include <linux/types.h>
00013 #include <linux/random.h>
00014 #include <linux/compiler.h>
00015 #include <linux/crc32.h>
00016 #include <linux/crypto.h>
00017 #include <linux/err.h>
00018 #include <linux/mm.h>
00019 #include <linux/scatterlist.h>
00020 #include <linux/slab.h>
00021 #include <asm/unaligned.h>
00022
00023 #include <net/mac80211.h>
00024 #include "ieee80211_i.h"
00025 #include "wep.h"
00026
00027
00028 int ieee80211_wep_init(struct ieee80211_local *local)
00029 {
00030
00031 get_random_bytes(&local->wep_iv, WEP_IV_LEN);
00032
00033 local->wep_tx_tfm = crypto_alloc_cipher("arc4", 0, CRYPTO_ALG_ASYNC);
00034 if (IS_ERR(local->wep_tx_tfm)) {
00035 local->wep_rx_tfm = ERR_PTR(-EINVAL);
00036 return PTR_ERR(local->wep_tx_tfm);
00037 }
00038
00039 local->wep_rx_tfm = crypto_alloc_cipher("arc4", 0, CRYPTO_ALG_ASYNC);
00040 if (IS_ERR(local->wep_rx_tfm)) {
00041 crypto_free_cipher(local->wep_tx_tfm);
00042 local->wep_tx_tfm = ERR_PTR(-EINVAL);
00043 return PTR_ERR(local->wep_rx_tfm);
00044 }
00045
00046 return 0;
00047 }
00048
00049 void ieee80211_wep_free(struct ieee80211_local *local)
00050 {
00051 if (!IS_ERR(local->wep_tx_tfm))
00052 crypto_free_cipher(local->wep_tx_tfm);
00053 if (!IS_ERR(local->wep_rx_tfm))
00054 crypto_free_cipher(local->wep_rx_tfm);
00055 }
00056
00057 static inline bool ieee80211_wep_weak_iv(u32 iv, int keylen)
00058 {
00059
00060
00061
00062
00063
00064 if ((iv & 0xff00) == 0xff00) {
00065 u8 B = (iv >> 16) & 0xff;
00066 if (B >= 3 && B < 3 + keylen)
00067 return true;
00068 }
00069 return false;
00070 }
00071
00072
00073 static void ieee80211_wep_get_iv(struct ieee80211_local *local,
00074 int keylen, int keyidx, u8 *iv)
00075 {
00076 local->wep_iv++;
00077 if (ieee80211_wep_weak_iv(local->wep_iv, keylen))
00078 local->wep_iv += 0x0100;
00079
00080 if (!iv)
00081 return;
00082
00083 *iv++ = (local->wep_iv >> 16) & 0xff;
00084 *iv++ = (local->wep_iv >> 8) & 0xff;
00085 *iv++ = local->wep_iv & 0xff;
00086 *iv++ = keyidx << 6;
00087 }
00088
00089
00090 static u8 *ieee80211_wep_add_iv(struct ieee80211_local *local,
00091 struct sk_buff *skb,
00092 int keylen, int keyidx)
00093 {
00094 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
00095 unsigned int hdrlen;
00096 u8 *newhdr;
00097
00098 hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
00099
00100 if (WARN_ON(skb_tailroom(skb) < WEP_ICV_LEN ||
00101 skb_headroom(skb) < WEP_IV_LEN))
00102 return NULL;
00103
00104 hdrlen = ieee80211_hdrlen(hdr->frame_control);
00105 newhdr = skb_push(skb, WEP_IV_LEN);
00106 memmove(newhdr, newhdr + WEP_IV_LEN, hdrlen);
00107 ieee80211_wep_get_iv(local, keylen, keyidx, newhdr + hdrlen);
00108 return newhdr + hdrlen;
00109 }
00110
00111
00112 static void ieee80211_wep_remove_iv(struct ieee80211_local *local,
00113 struct sk_buff *skb,
00114 struct ieee80211_key *key)
00115 {
00116 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
00117 unsigned int hdrlen;
00118
00119 hdrlen = ieee80211_hdrlen(hdr->frame_control);
00120 memmove(skb->data + WEP_IV_LEN, skb->data, hdrlen);
00121 skb_pull(skb, WEP_IV_LEN);
00122 }
00123
00124
00125
00126
00127
00128 int ieee80211_wep_encrypt_data(struct crypto_cipher *tfm, u8 *rc4key,
00129 size_t klen, u8 *data, size_t data_len)
00130 {
00131 __le32 icv;
00132 int i;
00133
00134 if (IS_ERR(tfm))
00135 return -1;
00136
00137 icv = cpu_to_le32(~crc32_le(~0, data, data_len));
00138 put_unaligned(icv, (__le32 *)(data + data_len));
00139
00140 crypto_cipher_setkey(tfm, rc4key, klen);
00141 for (i = 0; i < data_len + WEP_ICV_LEN; i++)
00142 crypto_cipher_encrypt_one(tfm, data + i, data + i);
00143
00144 return 0;
00145 }
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155 int ieee80211_wep_encrypt(struct ieee80211_local *local,
00156 struct sk_buff *skb,
00157 const u8 *key, int keylen, int keyidx)
00158 {
00159 u8 *iv;
00160 size_t len;
00161 u8 rc4key[3 + WLAN_KEY_LEN_WEP104];
00162
00163 iv = ieee80211_wep_add_iv(local, skb, keylen, keyidx);
00164 if (!iv)
00165 return -1;
00166
00167 len = skb->len - (iv + WEP_IV_LEN - skb->data);
00168
00169
00170 memcpy(rc4key, iv, 3);
00171
00172
00173 memcpy(rc4key + 3, key, keylen);
00174
00175
00176 skb_put(skb, WEP_ICV_LEN);
00177
00178 return ieee80211_wep_encrypt_data(local->wep_tx_tfm, rc4key, keylen + 3,
00179 iv + WEP_IV_LEN, len);
00180 }
00181
00182
00183
00184
00185
00186 int ieee80211_wep_decrypt_data(struct crypto_cipher *tfm, u8 *rc4key,
00187 size_t klen, u8 *data, size_t data_len)
00188 {
00189 __le32 crc;
00190 int i;
00191
00192 if (IS_ERR(tfm))
00193 return -1;
00194
00195 crypto_cipher_setkey(tfm, rc4key, klen);
00196 for (i = 0; i < data_len + WEP_ICV_LEN; i++)
00197 crypto_cipher_decrypt_one(tfm, data + i, data + i);
00198
00199 crc = cpu_to_le32(~crc32_le(~0, data, data_len));
00200 if (memcmp(&crc, data + data_len, WEP_ICV_LEN) != 0)
00201
00202 return -1;
00203
00204 return 0;
00205 }
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216 static int ieee80211_wep_decrypt(struct ieee80211_local *local,
00217 struct sk_buff *skb,
00218 struct ieee80211_key *key)
00219 {
00220 u32 klen;
00221 u8 rc4key[3 + WLAN_KEY_LEN_WEP104];
00222 u8 keyidx;
00223 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
00224 unsigned int hdrlen;
00225 size_t len;
00226 int ret = 0;
00227
00228 if (!ieee80211_has_protected(hdr->frame_control))
00229 return -1;
00230
00231 hdrlen = ieee80211_hdrlen(hdr->frame_control);
00232 if (skb->len < hdrlen + WEP_IV_LEN + WEP_ICV_LEN)
00233 return -1;
00234
00235 len = skb->len - hdrlen - WEP_IV_LEN - WEP_ICV_LEN;
00236
00237 keyidx = skb->data[hdrlen + 3] >> 6;
00238
00239 if (!key || keyidx != key->conf.keyidx)
00240 return -1;
00241
00242 klen = 3 + key->conf.keylen;
00243
00244
00245 memcpy(rc4key, skb->data + hdrlen, 3);
00246
00247
00248 memcpy(rc4key + 3, key->conf.key, key->conf.keylen);
00249
00250 if (ieee80211_wep_decrypt_data(local->wep_rx_tfm, rc4key, klen,
00251 skb->data + hdrlen + WEP_IV_LEN,
00252 len))
00253 ret = -1;
00254
00255
00256 skb_trim(skb, skb->len - WEP_ICV_LEN);
00257
00258
00259 memmove(skb->data + WEP_IV_LEN, skb->data, hdrlen);
00260 skb_pull(skb, WEP_IV_LEN);
00261
00262 return ret;
00263 }
00264
00265
00266 bool ieee80211_wep_is_weak_iv(struct sk_buff *skb, struct ieee80211_key *key)
00267 {
00268 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
00269 unsigned int hdrlen;
00270 u8 *ivpos;
00271 u32 iv;
00272
00273 if (!ieee80211_has_protected(hdr->frame_control))
00274 return false;
00275
00276 hdrlen = ieee80211_hdrlen(hdr->frame_control);
00277 ivpos = skb->data + hdrlen;
00278 iv = (ivpos[0] << 16) | (ivpos[1] << 8) | ivpos[2];
00279
00280 return ieee80211_wep_weak_iv(iv, key->conf.keylen);
00281 }
00282
00283 ieee80211_rx_result
00284 ieee80211_crypto_wep_decrypt(struct ieee80211_rx_data *rx)
00285 {
00286 struct sk_buff *skb = rx->skb;
00287 struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
00288 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
00289
00290 if (!ieee80211_is_data(hdr->frame_control) &&
00291 !ieee80211_is_auth(hdr->frame_control))
00292 return RX_CONTINUE;
00293
00294 if (!(status->flag & RX_FLAG_DECRYPTED)) {
00295 if (ieee80211_wep_decrypt(rx->local, rx->skb, rx->key))
00296 return RX_DROP_UNUSABLE;
00297 } else if (!(status->flag & RX_FLAG_IV_STRIPPED)) {
00298 ieee80211_wep_remove_iv(rx->local, rx->skb, rx->key);
00299
00300 skb_trim(rx->skb, rx->skb->len - WEP_ICV_LEN);
00301 }
00302
00303 return RX_CONTINUE;
00304 }
00305
00306 static int wep_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb)
00307 {
00308 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
00309
00310 if (!info->control.hw_key) {
00311 if (ieee80211_wep_encrypt(tx->local, skb, tx->key->conf.key,
00312 tx->key->conf.keylen,
00313 tx->key->conf.keyidx))
00314 return -1;
00315 } else if (info->control.hw_key->flags &
00316 IEEE80211_KEY_FLAG_GENERATE_IV) {
00317 if (!ieee80211_wep_add_iv(tx->local, skb,
00318 tx->key->conf.keylen,
00319 tx->key->conf.keyidx))
00320 return -1;
00321 }
00322
00323 return 0;
00324 }
00325
00326 ieee80211_tx_result
00327 ieee80211_crypto_wep_encrypt(struct ieee80211_tx_data *tx)
00328 {
00329 struct sk_buff *skb;
00330
00331 ieee80211_tx_set_protected(tx);
00332
00333 skb = tx->skb;
00334 do {
00335 if (wep_encrypt_skb(tx, skb) < 0) {
00336 I802_DEBUG_INC(tx->local->tx_handlers_drop_wep);
00337 return TX_DROP;
00338 }
00339 } while ((skb = skb->next));
00340
00341 return TX_CONTINUE;
00342 }