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