1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * lib80211 crypt: host-based WEP encryption implementation for lib80211 4 * 5 * Copyright (c) 2002-2004, Jouni Malinen <j@w1.fi> 6 * Copyright (c) 2008, John W. Linville <linville@tuxdriver.com> 7 */ 8 9 #include <linux/err.h> 10 #include <linux/module.h> 11 #include <linux/init.h> 12 #include <linux/slab.h> 13 #include <linux/random.h> 14 #include <linux/scatterlist.h> 15 #include <linux/skbuff.h> 16 #include <linux/mm.h> 17 #include <asm/string.h> 18 19 #include <net/lib80211.h> 20 21 #include <linux/crypto.h> 22 #include <linux/crc32.h> 23 24 MODULE_AUTHOR("Jouni Malinen"); 25 MODULE_DESCRIPTION("lib80211 crypt: WEP"); 26 MODULE_LICENSE("GPL"); 27 28 struct lib80211_wep_data { 29 u32 iv; 30 #define WEP_KEY_LEN 13 31 u8 key[WEP_KEY_LEN + 1]; 32 u8 key_len; 33 u8 key_idx; 34 struct crypto_cipher *tx_tfm; 35 struct crypto_cipher *rx_tfm; 36 }; 37 38 static void *lib80211_wep_init(int keyidx) 39 { 40 struct lib80211_wep_data *priv; 41 42 priv = kzalloc(sizeof(*priv), GFP_ATOMIC); 43 if (priv == NULL) 44 goto fail; 45 priv->key_idx = keyidx; 46 47 priv->tx_tfm = crypto_alloc_cipher("arc4", 0, 0); 48 if (IS_ERR(priv->tx_tfm)) { 49 priv->tx_tfm = NULL; 50 goto fail; 51 } 52 53 priv->rx_tfm = crypto_alloc_cipher("arc4", 0, 0); 54 if (IS_ERR(priv->rx_tfm)) { 55 priv->rx_tfm = NULL; 56 goto fail; 57 } 58 /* start WEP IV from a random value */ 59 get_random_bytes(&priv->iv, 4); 60 61 return priv; 62 63 fail: 64 if (priv) { 65 crypto_free_cipher(priv->tx_tfm); 66 crypto_free_cipher(priv->rx_tfm); 67 kfree(priv); 68 } 69 return NULL; 70 } 71 72 static void lib80211_wep_deinit(void *priv) 73 { 74 struct lib80211_wep_data *_priv = priv; 75 if (_priv) { 76 crypto_free_cipher(_priv->tx_tfm); 77 crypto_free_cipher(_priv->rx_tfm); 78 } 79 kfree(priv); 80 } 81 82 /* Add WEP IV/key info to a frame that has at least 4 bytes of headroom */ 83 static int lib80211_wep_build_iv(struct sk_buff *skb, int hdr_len, 84 u8 *key, int keylen, void *priv) 85 { 86 struct lib80211_wep_data *wep = priv; 87 u32 klen; 88 u8 *pos; 89 90 if (skb_headroom(skb) < 4 || skb->len < hdr_len) 91 return -1; 92 93 pos = skb_push(skb, 4); 94 memmove(pos, pos + 4, hdr_len); 95 pos += hdr_len; 96 97 klen = 3 + wep->key_len; 98 99 wep->iv++; 100 101 /* Fluhrer, Mantin, and Shamir have reported weaknesses in the key 102 * scheduling algorithm of RC4. At least IVs (KeyByte + 3, 0xff, N) 103 * can be used to speedup attacks, so avoid using them. */ 104 if ((wep->iv & 0xff00) == 0xff00) { 105 u8 B = (wep->iv >> 16) & 0xff; 106 if (B >= 3 && B < klen) 107 wep->iv += 0x0100; 108 } 109 110 /* Prepend 24-bit IV to RC4 key and TX frame */ 111 *pos++ = (wep->iv >> 16) & 0xff; 112 *pos++ = (wep->iv >> 8) & 0xff; 113 *pos++ = wep->iv & 0xff; 114 *pos++ = wep->key_idx << 6; 115 116 return 0; 117 } 118 119 /* Perform WEP encryption on given skb that has at least 4 bytes of headroom 120 * for IV and 4 bytes of tailroom for ICV. Both IV and ICV will be transmitted, 121 * so the payload length increases with 8 bytes. 122 * 123 * WEP frame payload: IV + TX key idx, RC4(data), ICV = RC4(CRC32(data)) 124 */ 125 static int lib80211_wep_encrypt(struct sk_buff *skb, int hdr_len, void *priv) 126 { 127 struct lib80211_wep_data *wep = priv; 128 u32 crc, klen, len; 129 u8 *pos, *icv; 130 u8 key[WEP_KEY_LEN + 3]; 131 int i; 132 133 /* other checks are in lib80211_wep_build_iv */ 134 if (skb_tailroom(skb) < 4) 135 return -1; 136 137 /* add the IV to the frame */ 138 if (lib80211_wep_build_iv(skb, hdr_len, NULL, 0, priv)) 139 return -1; 140 141 /* Copy the IV into the first 3 bytes of the key */ 142 skb_copy_from_linear_data_offset(skb, hdr_len, key, 3); 143 144 /* Copy rest of the WEP key (the secret part) */ 145 memcpy(key + 3, wep->key, wep->key_len); 146 147 len = skb->len - hdr_len - 4; 148 pos = skb->data + hdr_len + 4; 149 klen = 3 + wep->key_len; 150 151 /* Append little-endian CRC32 over only the data and encrypt it to produce ICV */ 152 crc = ~crc32_le(~0, pos, len); 153 icv = skb_put(skb, 4); 154 icv[0] = crc; 155 icv[1] = crc >> 8; 156 icv[2] = crc >> 16; 157 icv[3] = crc >> 24; 158 159 crypto_cipher_setkey(wep->tx_tfm, key, klen); 160 161 for (i = 0; i < len + 4; i++) 162 crypto_cipher_encrypt_one(wep->tx_tfm, pos + i, pos + i); 163 164 return 0; 165 } 166 167 /* Perform WEP decryption on given buffer. Buffer includes whole WEP part of 168 * the frame: IV (4 bytes), encrypted payload (including SNAP header), 169 * ICV (4 bytes). len includes both IV and ICV. 170 * 171 * Returns 0 if frame was decrypted successfully and ICV was correct and -1 on 172 * failure. If frame is OK, IV and ICV will be removed. 173 */ 174 static int lib80211_wep_decrypt(struct sk_buff *skb, int hdr_len, void *priv) 175 { 176 struct lib80211_wep_data *wep = priv; 177 u32 crc, klen, plen; 178 u8 key[WEP_KEY_LEN + 3]; 179 u8 keyidx, *pos, icv[4]; 180 int i; 181 182 if (skb->len < hdr_len + 8) 183 return -1; 184 185 pos = skb->data + hdr_len; 186 key[0] = *pos++; 187 key[1] = *pos++; 188 key[2] = *pos++; 189 keyidx = *pos++ >> 6; 190 if (keyidx != wep->key_idx) 191 return -1; 192 193 klen = 3 + wep->key_len; 194 195 /* Copy rest of the WEP key (the secret part) */ 196 memcpy(key + 3, wep->key, wep->key_len); 197 198 /* Apply RC4 to data and compute CRC32 over decrypted data */ 199 plen = skb->len - hdr_len - 8; 200 201 crypto_cipher_setkey(wep->rx_tfm, key, klen); 202 for (i = 0; i < plen + 4; i++) 203 crypto_cipher_decrypt_one(wep->rx_tfm, pos + i, pos + i); 204 205 crc = ~crc32_le(~0, pos, plen); 206 icv[0] = crc; 207 icv[1] = crc >> 8; 208 icv[2] = crc >> 16; 209 icv[3] = crc >> 24; 210 if (memcmp(icv, pos + plen, 4) != 0) { 211 /* ICV mismatch - drop frame */ 212 return -2; 213 } 214 215 /* Remove IV and ICV */ 216 memmove(skb->data + 4, skb->data, hdr_len); 217 skb_pull(skb, 4); 218 skb_trim(skb, skb->len - 4); 219 220 return 0; 221 } 222 223 static int lib80211_wep_set_key(void *key, int len, u8 * seq, void *priv) 224 { 225 struct lib80211_wep_data *wep = priv; 226 227 if (len < 0 || len > WEP_KEY_LEN) 228 return -1; 229 230 memcpy(wep->key, key, len); 231 wep->key_len = len; 232 233 return 0; 234 } 235 236 static int lib80211_wep_get_key(void *key, int len, u8 * seq, void *priv) 237 { 238 struct lib80211_wep_data *wep = priv; 239 240 if (len < wep->key_len) 241 return -1; 242 243 memcpy(key, wep->key, wep->key_len); 244 245 return wep->key_len; 246 } 247 248 static void lib80211_wep_print_stats(struct seq_file *m, void *priv) 249 { 250 struct lib80211_wep_data *wep = priv; 251 seq_printf(m, "key[%d] alg=WEP len=%d\n", wep->key_idx, wep->key_len); 252 } 253 254 static struct lib80211_crypto_ops lib80211_crypt_wep = { 255 .name = "WEP", 256 .init = lib80211_wep_init, 257 .deinit = lib80211_wep_deinit, 258 .encrypt_mpdu = lib80211_wep_encrypt, 259 .decrypt_mpdu = lib80211_wep_decrypt, 260 .encrypt_msdu = NULL, 261 .decrypt_msdu = NULL, 262 .set_key = lib80211_wep_set_key, 263 .get_key = lib80211_wep_get_key, 264 .print_stats = lib80211_wep_print_stats, 265 .extra_mpdu_prefix_len = 4, /* IV */ 266 .extra_mpdu_postfix_len = 4, /* ICV */ 267 .owner = THIS_MODULE, 268 }; 269 270 static int __init lib80211_crypto_wep_init(void) 271 { 272 return lib80211_register_crypto_ops(&lib80211_crypt_wep); 273 } 274 275 static void __exit lib80211_crypto_wep_exit(void) 276 { 277 lib80211_unregister_crypto_ops(&lib80211_crypt_wep); 278 } 279 280 module_init(lib80211_crypto_wep_init); 281 module_exit(lib80211_crypto_wep_exit); 282