Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Software WEP encryption implementation
0004  * Copyright 2002, Jouni Malinen <jkmaline@cc.hut.fi>
0005  * Copyright 2003, Instant802 Networks, Inc.
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     /* start WEP IV from a random value */
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      * Fluhrer, Mantin, and Shamir have reported weaknesses in the
0035      * key scheduling algorithm of RC4. At least IVs (KeyByte + 3,
0036      * 0xff, N) can be used to speedup attacks, so avoid using them.
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     /* the HW only needs room for the IV, but not the actual IV */
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 /* Perform WEP encryption using given key. data buffer must have tailroom
0106  * for 4-byte ICV. data_len must not include this ICV. Note: this function
0107  * does _not_ add IV. data = RC4(data | CRC32(data)) */
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 /* Perform WEP encryption on given skb. 4 bytes of extra space (IV) in the
0125  * beginning of the buffer 4 bytes of extra space (ICV) in the end of the
0126  * buffer will be added. Both IV and ICV will be transmitted, so the
0127  * payload length increases with 8 bytes.
0128  *
0129  * WEP frame payload: IV + TX key idx, RC4(data), ICV = RC4(CRC32(data))
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     /* Prepend 24-bit IV to RC4 key */
0149     memcpy(rc4key, iv, 3);
0150 
0151     /* Copy rest of the WEP key (the secret part) */
0152     memcpy(rc4key + 3, key, keylen);
0153 
0154     /* Add room for ICV */
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 /* Perform WEP decryption using given key. data buffer includes encrypted
0163  * payload, including 4-byte ICV, but _not_ IV. data_len must not include ICV.
0164  * Return 0 on success and -1 on ICV mismatch. */
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         /* ICV mismatch */
0177         return -1;
0178 
0179     return 0;
0180 }
0181 
0182 
0183 /* Perform WEP decryption on given skb. Buffer includes whole WEP part of
0184  * the frame: IV (4 bytes), encrypted payload (including SNAP header),
0185  * ICV (4 bytes). skb->len includes both IV and ICV.
0186  *
0187  * Returns 0 if frame was decrypted successfully and ICV was correct and -1 on
0188  * failure. If frame is OK, IV and ICV will be removed, i.e., decrypted payload
0189  * is moved to the beginning of the skb and skb length will be reduced.
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     /* Prepend 24-bit IV to RC4 key */
0220     memcpy(rc4key, skb->data + hdrlen, 3);
0221 
0222     /* Copy rest of the WEP key (the secret part) */
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     /* Trim ICV */
0231     skb_trim(skb, skb->len - IEEE80211_WEP_ICV_LEN);
0232 
0233     /* Remove IV */
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         /* remove ICV */
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 }