Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * lib80211 crypt: host-based WEP encryption implementation for lib80211
0004  *
0005  * Copyright (c) 2002-2004, Jouni Malinen <j@w1.fi>
0006  * Copyright (c) 2008, John W. Linville <linville@tuxdriver.com>
0007  */
0008 
0009 #include <linux/err.h>
0010 #include <linux/fips.h>
0011 #include <linux/module.h>
0012 #include <linux/init.h>
0013 #include <linux/slab.h>
0014 #include <linux/random.h>
0015 #include <linux/scatterlist.h>
0016 #include <linux/skbuff.h>
0017 #include <linux/mm.h>
0018 #include <asm/string.h>
0019 
0020 #include <net/lib80211.h>
0021 
0022 #include <crypto/arc4.h>
0023 #include <linux/crc32.h>
0024 
0025 MODULE_AUTHOR("Jouni Malinen");
0026 MODULE_DESCRIPTION("lib80211 crypt: WEP");
0027 MODULE_LICENSE("GPL");
0028 
0029 struct lib80211_wep_data {
0030     u32 iv;
0031 #define WEP_KEY_LEN 13
0032     u8 key[WEP_KEY_LEN + 1];
0033     u8 key_len;
0034     u8 key_idx;
0035     struct arc4_ctx tx_ctx;
0036     struct arc4_ctx rx_ctx;
0037 };
0038 
0039 static void *lib80211_wep_init(int keyidx)
0040 {
0041     struct lib80211_wep_data *priv;
0042 
0043     if (fips_enabled)
0044         return NULL;
0045 
0046     priv = kzalloc(sizeof(*priv), GFP_ATOMIC);
0047     if (priv == NULL)
0048         return NULL;
0049     priv->key_idx = keyidx;
0050 
0051     /* start WEP IV from a random value */
0052     get_random_bytes(&priv->iv, 4);
0053 
0054     return priv;
0055 }
0056 
0057 static void lib80211_wep_deinit(void *priv)
0058 {
0059     kfree_sensitive(priv);
0060 }
0061 
0062 /* Add WEP IV/key info to a frame that has at least 4 bytes of headroom */
0063 static int lib80211_wep_build_iv(struct sk_buff *skb, int hdr_len,
0064                    u8 *key, int keylen, void *priv)
0065 {
0066     struct lib80211_wep_data *wep = priv;
0067     u32 klen;
0068     u8 *pos;
0069 
0070     if (skb_headroom(skb) < 4 || skb->len < hdr_len)
0071         return -1;
0072 
0073     pos = skb_push(skb, 4);
0074     memmove(pos, pos + 4, hdr_len);
0075     pos += hdr_len;
0076 
0077     klen = 3 + wep->key_len;
0078 
0079     wep->iv++;
0080 
0081     /* Fluhrer, Mantin, and Shamir have reported weaknesses in the key
0082      * scheduling algorithm of RC4. At least IVs (KeyByte + 3, 0xff, N)
0083      * can be used to speedup attacks, so avoid using them. */
0084     if ((wep->iv & 0xff00) == 0xff00) {
0085         u8 B = (wep->iv >> 16) & 0xff;
0086         if (B >= 3 && B < klen)
0087             wep->iv += 0x0100;
0088     }
0089 
0090     /* Prepend 24-bit IV to RC4 key and TX frame */
0091     *pos++ = (wep->iv >> 16) & 0xff;
0092     *pos++ = (wep->iv >> 8) & 0xff;
0093     *pos++ = wep->iv & 0xff;
0094     *pos++ = wep->key_idx << 6;
0095 
0096     return 0;
0097 }
0098 
0099 /* Perform WEP encryption on given skb that has at least 4 bytes of headroom
0100  * for IV and 4 bytes of tailroom for ICV. Both IV and ICV will be transmitted,
0101  * so the payload length increases with 8 bytes.
0102  *
0103  * WEP frame payload: IV + TX key idx, RC4(data), ICV = RC4(CRC32(data))
0104  */
0105 static int lib80211_wep_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
0106 {
0107     struct lib80211_wep_data *wep = priv;
0108     u32 crc, klen, len;
0109     u8 *pos, *icv;
0110     u8 key[WEP_KEY_LEN + 3];
0111 
0112     /* other checks are in lib80211_wep_build_iv */
0113     if (skb_tailroom(skb) < 4)
0114         return -1;
0115 
0116     /* add the IV to the frame */
0117     if (lib80211_wep_build_iv(skb, hdr_len, NULL, 0, priv))
0118         return -1;
0119 
0120     /* Copy the IV into the first 3 bytes of the key */
0121     skb_copy_from_linear_data_offset(skb, hdr_len, key, 3);
0122 
0123     /* Copy rest of the WEP key (the secret part) */
0124     memcpy(key + 3, wep->key, wep->key_len);
0125 
0126     len = skb->len - hdr_len - 4;
0127     pos = skb->data + hdr_len + 4;
0128     klen = 3 + wep->key_len;
0129 
0130     /* Append little-endian CRC32 over only the data and encrypt it to produce ICV */
0131     crc = ~crc32_le(~0, pos, len);
0132     icv = skb_put(skb, 4);
0133     icv[0] = crc;
0134     icv[1] = crc >> 8;
0135     icv[2] = crc >> 16;
0136     icv[3] = crc >> 24;
0137 
0138     arc4_setkey(&wep->tx_ctx, key, klen);
0139     arc4_crypt(&wep->tx_ctx, pos, pos, len + 4);
0140 
0141     return 0;
0142 }
0143 
0144 /* Perform WEP decryption on given buffer. Buffer includes whole WEP part of
0145  * the frame: IV (4 bytes), encrypted payload (including SNAP header),
0146  * ICV (4 bytes). len includes both IV and ICV.
0147  *
0148  * Returns 0 if frame was decrypted successfully and ICV was correct and -1 on
0149  * failure. If frame is OK, IV and ICV will be removed.
0150  */
0151 static int lib80211_wep_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
0152 {
0153     struct lib80211_wep_data *wep = priv;
0154     u32 crc, klen, plen;
0155     u8 key[WEP_KEY_LEN + 3];
0156     u8 keyidx, *pos, icv[4];
0157 
0158     if (skb->len < hdr_len + 8)
0159         return -1;
0160 
0161     pos = skb->data + hdr_len;
0162     key[0] = *pos++;
0163     key[1] = *pos++;
0164     key[2] = *pos++;
0165     keyidx = *pos++ >> 6;
0166     if (keyidx != wep->key_idx)
0167         return -1;
0168 
0169     klen = 3 + wep->key_len;
0170 
0171     /* Copy rest of the WEP key (the secret part) */
0172     memcpy(key + 3, wep->key, wep->key_len);
0173 
0174     /* Apply RC4 to data and compute CRC32 over decrypted data */
0175     plen = skb->len - hdr_len - 8;
0176 
0177     arc4_setkey(&wep->rx_ctx, key, klen);
0178     arc4_crypt(&wep->rx_ctx, pos, pos, plen + 4);
0179 
0180     crc = ~crc32_le(~0, pos, plen);
0181     icv[0] = crc;
0182     icv[1] = crc >> 8;
0183     icv[2] = crc >> 16;
0184     icv[3] = crc >> 24;
0185     if (memcmp(icv, pos + plen, 4) != 0) {
0186         /* ICV mismatch - drop frame */
0187         return -2;
0188     }
0189 
0190     /* Remove IV and ICV */
0191     memmove(skb->data + 4, skb->data, hdr_len);
0192     skb_pull(skb, 4);
0193     skb_trim(skb, skb->len - 4);
0194 
0195     return 0;
0196 }
0197 
0198 static int lib80211_wep_set_key(void *key, int len, u8 * seq, void *priv)
0199 {
0200     struct lib80211_wep_data *wep = priv;
0201 
0202     if (len < 0 || len > WEP_KEY_LEN)
0203         return -1;
0204 
0205     memcpy(wep->key, key, len);
0206     wep->key_len = len;
0207 
0208     return 0;
0209 }
0210 
0211 static int lib80211_wep_get_key(void *key, int len, u8 * seq, void *priv)
0212 {
0213     struct lib80211_wep_data *wep = priv;
0214 
0215     if (len < wep->key_len)
0216         return -1;
0217 
0218     memcpy(key, wep->key, wep->key_len);
0219 
0220     return wep->key_len;
0221 }
0222 
0223 static void lib80211_wep_print_stats(struct seq_file *m, void *priv)
0224 {
0225     struct lib80211_wep_data *wep = priv;
0226     seq_printf(m, "key[%d] alg=WEP len=%d\n", wep->key_idx, wep->key_len);
0227 }
0228 
0229 static struct lib80211_crypto_ops lib80211_crypt_wep = {
0230     .name = "WEP",
0231     .init = lib80211_wep_init,
0232     .deinit = lib80211_wep_deinit,
0233     .encrypt_mpdu = lib80211_wep_encrypt,
0234     .decrypt_mpdu = lib80211_wep_decrypt,
0235     .encrypt_msdu = NULL,
0236     .decrypt_msdu = NULL,
0237     .set_key = lib80211_wep_set_key,
0238     .get_key = lib80211_wep_get_key,
0239     .print_stats = lib80211_wep_print_stats,
0240     .extra_mpdu_prefix_len = 4, /* IV */
0241     .extra_mpdu_postfix_len = 4,    /* ICV */
0242     .owner = THIS_MODULE,
0243 };
0244 
0245 static int __init lib80211_crypto_wep_init(void)
0246 {
0247     return lib80211_register_crypto_ops(&lib80211_crypt_wep);
0248 }
0249 
0250 static void __exit lib80211_crypto_wep_exit(void)
0251 {
0252     lib80211_unregister_crypto_ops(&lib80211_crypt_wep);
0253 }
0254 
0255 module_init(lib80211_crypto_wep_init);
0256 module_exit(lib80211_crypto_wep_exit);