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