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