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