1/* 2 * Host AP crypt: host-based WEP encryption implementation for Host AP driver 3 * 4 * Copyright (c) 2002-2004, Jouni Malinen <jkmaline@cc.hut.fi> 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 2 as 8 * published by the Free Software Foundation. See README and COPYING for 9 * more details. 10 */ 11 12#include <linux/version.h> 13#include <linux/module.h> 14#include <linux/init.h> 15#include <linux/slab.h> 16#include <linux/random.h> 17#include <linux/skbuff.h> 18#include <asm/string.h> 19 20#include "ieee80211.h" 21 22#include <linux/crypto.h> 23#include <linux/scatterlist.h> 24#include <linux/crc32.h> 25 26MODULE_AUTHOR("Jouni Malinen"); 27MODULE_DESCRIPTION("Host AP crypt: WEP"); 28MODULE_LICENSE("GPL"); 29 30struct prism2_wep_data { 31 u32 iv; 32#define WEP_KEY_LEN 13 33 u8 key[WEP_KEY_LEN + 1]; 34 u8 key_len; 35 u8 key_idx; 36 struct crypto_blkcipher *tx_tfm; 37 struct crypto_blkcipher *rx_tfm; 38}; 39 40 41static void * prism2_wep_init(int keyidx) 42{ 43 struct prism2_wep_data *priv; 44 45 priv = kzalloc(sizeof(*priv), GFP_ATOMIC); 46 if (priv == NULL) 47 goto fail; 48 priv->key_idx = keyidx; 49 50 priv->tx_tfm = crypto_alloc_blkcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC); 51 if (IS_ERR(priv->tx_tfm)) { 52 printk(KERN_DEBUG "ieee80211_crypt_wep: could not allocate " 53 "crypto API arc4\n"); 54 priv->tx_tfm = NULL; 55 goto fail; 56 } 57 priv->rx_tfm = crypto_alloc_blkcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC); 58 if (IS_ERR(priv->rx_tfm)) { 59 printk(KERN_DEBUG "ieee80211_crypt_wep: could not allocate " 60 "crypto API arc4\n"); 61 priv->rx_tfm = NULL; 62 goto fail; 63 } 64 65 /* start WEP IV from a random value */ 66 get_random_bytes(&priv->iv, 4); 67 68 return priv; 69 70fail: 71 if (priv) { 72 if (priv->tx_tfm) 73 crypto_free_blkcipher(priv->tx_tfm); 74 if (priv->rx_tfm) 75 crypto_free_blkcipher(priv->rx_tfm); 76 kfree(priv); 77 } 78 79 return NULL; 80} 81 82 83static void prism2_wep_deinit(void *priv) 84{ 85 struct prism2_wep_data *_priv = priv; 86 87 if (_priv) { 88 if (_priv->tx_tfm) 89 crypto_free_blkcipher(_priv->tx_tfm); 90 if (_priv->rx_tfm) 91 crypto_free_blkcipher(_priv->rx_tfm); 92 } 93 kfree(priv); 94} 95 96/* Perform WEP encryption on given skb that has at least 4 bytes of headroom 97 * for IV and 4 bytes of tailroom for ICV. Both IV and ICV will be transmitted, 98 * so the payload length increases with 8 bytes. 99 * 100 * WEP frame payload: IV + TX key idx, RC4(data), ICV = RC4(CRC32(data)) 101 */ 102static int prism2_wep_encrypt(struct sk_buff *skb, int hdr_len, void *priv) 103{ 104 struct prism2_wep_data *wep = priv; 105 u32 klen, len; 106 u8 key[WEP_KEY_LEN + 3]; 107 u8 *pos; 108 cb_desc *tcb_desc = (cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE); 109 struct blkcipher_desc desc = { .tfm = wep->tx_tfm }; 110 u32 crc; 111 u8 *icv; 112 struct scatterlist sg; 113 if (skb_headroom(skb) < 4 || skb_tailroom(skb) < 4 || 114 skb->len < hdr_len) 115 return -1; 116 117 len = skb->len - hdr_len; 118 pos = skb_push(skb, 4); 119 memmove(pos, pos + 4, hdr_len); 120 pos += hdr_len; 121 122 klen = 3 + wep->key_len; 123 124 wep->iv++; 125 126 /* Fluhrer, Mantin, and Shamir have reported weaknesses in the key 127 * scheduling algorithm of RC4. At least IVs (KeyByte + 3, 0xff, N) 128 * can be used to speedup attacks, so avoid using them. */ 129 if ((wep->iv & 0xff00) == 0xff00) { 130 u8 B = (wep->iv >> 16) & 0xff; 131 if (B >= 3 && B < klen) 132 wep->iv += 0x0100; 133 } 134 135 /* Prepend 24-bit IV to RC4 key and TX frame */ 136 *pos++ = key[0] = (wep->iv >> 16) & 0xff; 137 *pos++ = key[1] = (wep->iv >> 8) & 0xff; 138 *pos++ = key[2] = wep->iv & 0xff; 139 *pos++ = wep->key_idx << 6; 140 141 /* Copy rest of the WEP key (the secret part) */ 142 memcpy(key + 3, wep->key, wep->key_len); 143 144 if (!tcb_desc->bHwSec) 145 { 146 147 /* Append little-endian CRC32 and encrypt it to produce ICV */ 148 crc = ~crc32_le(~0, pos, len); 149 icv = skb_put(skb, 4); 150 icv[0] = crc; 151 icv[1] = crc >> 8; 152 icv[2] = crc >> 16; 153 icv[3] = crc >> 24; 154 155 crypto_blkcipher_setkey(wep->tx_tfm, key, klen); 156 sg_init_one(&sg, pos, len+4); 157 158 return crypto_blkcipher_encrypt(&desc, &sg, &sg, len + 4); 159 } 160 161 return 0; 162} 163 164 165/* Perform WEP decryption on given buffer. Buffer includes whole WEP part of 166 * the frame: IV (4 bytes), encrypted payload (including SNAP header), 167 * ICV (4 bytes). len includes both IV and ICV. 168 * 169 * Returns 0 if frame was decrypted successfully and ICV was correct and -1 on 170 * failure. If frame is OK, IV and ICV will be removed. 171 */ 172static int prism2_wep_decrypt(struct sk_buff *skb, int hdr_len, void *priv) 173{ 174 struct prism2_wep_data *wep = priv; 175 u32 klen, plen; 176 u8 key[WEP_KEY_LEN + 3]; 177 u8 keyidx, *pos; 178 cb_desc *tcb_desc = (cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE); 179 struct blkcipher_desc desc = { .tfm = wep->rx_tfm }; 180 u32 crc; 181 u8 icv[4]; 182 struct scatterlist sg; 183 if (skb->len < hdr_len + 8) 184 return -1; 185 186 pos = skb->data + hdr_len; 187 key[0] = *pos++; 188 key[1] = *pos++; 189 key[2] = *pos++; 190 keyidx = *pos++ >> 6; 191 if (keyidx != wep->key_idx) 192 return -1; 193 194 klen = 3 + wep->key_len; 195 196 /* Copy rest of the WEP key (the secret part) */ 197 memcpy(key + 3, wep->key, wep->key_len); 198 199 /* Apply RC4 to data and compute CRC32 over decrypted data */ 200 plen = skb->len - hdr_len - 8; 201 202 if (!tcb_desc->bHwSec) 203 { 204 crypto_blkcipher_setkey(wep->rx_tfm, key, klen); 205 sg_init_one(&sg, pos, plen + 4); 206 207 if (crypto_blkcipher_decrypt(&desc, &sg, &sg, plen + 4)) 208 return -7; 209 210 crc = ~crc32_le(~0, pos, plen); 211 icv[0] = crc; 212 icv[1] = crc >> 8; 213 icv[2] = crc >> 16; 214 icv[3] = crc >> 24; 215 if (memcmp(icv, pos + plen, 4) != 0) { 216 /* ICV mismatch - drop frame */ 217 return -2; 218 } 219 } 220 /* Remove IV and ICV */ 221 memmove(skb->data + 4, skb->data, hdr_len); 222 skb_pull(skb, 4); 223 skb_trim(skb, skb->len - 4); 224 225 return 0; 226} 227 228 229static int prism2_wep_set_key(void *key, int len, u8 *seq, void *priv) 230{ 231 struct prism2_wep_data *wep = priv; 232 233 if (len < 0 || len > WEP_KEY_LEN) 234 return -1; 235 236 memcpy(wep->key, key, len); 237 wep->key_len = len; 238 239 return 0; 240} 241 242 243static int prism2_wep_get_key(void *key, int len, u8 *seq, void *priv) 244{ 245 struct prism2_wep_data *wep = priv; 246 247 if (len < wep->key_len) 248 return -1; 249 250 memcpy(key, wep->key, wep->key_len); 251 252 return wep->key_len; 253} 254 255 256static char * prism2_wep_print_stats(char *p, void *priv) 257{ 258 struct prism2_wep_data *wep = priv; 259 p += sprintf(p, "key[%d] alg=WEP len=%d\n", 260 wep->key_idx, wep->key_len); 261 return p; 262} 263 264 265static struct ieee80211_crypto_ops ieee80211_crypt_wep = { 266 .name = "WEP", 267 .init = prism2_wep_init, 268 .deinit = prism2_wep_deinit, 269 .encrypt_mpdu = prism2_wep_encrypt, 270 .decrypt_mpdu = prism2_wep_decrypt, 271 .encrypt_msdu = NULL, 272 .decrypt_msdu = NULL, 273 .set_key = prism2_wep_set_key, 274 .get_key = prism2_wep_get_key, 275 .print_stats = prism2_wep_print_stats, 276 .extra_prefix_len = 4, /* IV */ 277 .extra_postfix_len = 4, /* ICV */ 278 .owner = THIS_MODULE, 279}; 280 281int ieee80211_crypto_wep_init(void) 282{ 283 return ieee80211_register_crypto_ops(&ieee80211_crypt_wep); 284} 285 286void ieee80211_crypto_wep_exit(void) 287{ 288 ieee80211_unregister_crypto_ops(&ieee80211_crypt_wep); 289} 290 291void ieee80211_wep_null(void) 292{ 293 return; 294} 295