ieee80211_crypto_wep.c revision 153353
1211809Sjchandra/*- 2198160Srrs * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting 3198160Srrs * All rights reserved. 4198160Srrs * 5198160Srrs * Redistribution and use in source and binary forms, with or without 6198160Srrs * modification, are permitted provided that the following conditions 7198160Srrs * are met: 8198160Srrs * 1. Redistributions of source code must retain the above copyright 9198160Srrs * notice, this list of conditions and the following disclaimer. 10198160Srrs * 2. Redistributions in binary form must reproduce the above copyright 11198160Srrs * notice, this list of conditions and the following disclaimer in the 12198160Srrs * documentation and/or other materials provided with the distribution. 13198160Srrs * 3. The name of the author may not be used to endorse or promote products 14198160Srrs * derived from this software without specific prior written permission. 15198160Srrs * 16198160Srrs * Alternatively, this software may be distributed under the terms of the 17198160Srrs * GNU General Public License ("GPL") version 2 as published by the Free 18198160Srrs * Software Foundation. 19198160Srrs * 20198160Srrs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 21198160Srrs * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 22198160Srrs * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 23198160Srrs * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 24198160Srrs * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 25198160Srrs * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26198160Srrs * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27198160Srrs * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28198160Srrs * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 29198160Srrs * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30203112Srrs */ 31203112Srrs 32198160Srrs#include <sys/cdefs.h> 33198160Srrs__FBSDID("$FreeBSD: head/sys/net80211/ieee80211_crypto_wep.c 153353 2005-12-12 19:07:48Z sam $"); 34198160Srrs 35198160Srrs/* 36198160Srrs * IEEE 802.11 WEP crypto support. 37198160Srrs */ 38198160Srrs#include <sys/param.h> 39198160Srrs#include <sys/systm.h> 40280013Sian#include <sys/mbuf.h> 41198160Srrs#include <sys/malloc.h> 42208165Srrs#include <sys/kernel.h> 43208165Srrs#include <sys/module.h> 44208165Srrs#include <sys/endian.h> 45208165Srrs 46208165Srrs#include <sys/socket.h> 47208165Srrs 48208165Srrs#include <net/if.h> 49208165Srrs#include <net/if_media.h> 50208165Srrs#include <net/ethernet.h> 51198160Srrs 52198160Srrs#include <net80211/ieee80211_var.h> 53208165Srrs 54198160Srrsstatic void *wep_attach(struct ieee80211com *, struct ieee80211_key *); 55198160Srrsstatic void wep_detach(struct ieee80211_key *); 56198160Srrsstatic int wep_setkey(struct ieee80211_key *); 57198160Srrsstatic int wep_encap(struct ieee80211_key *, struct mbuf *, u_int8_t keyid); 58198607Srrsstatic int wep_decap(struct ieee80211_key *, struct mbuf *, int hdrlen); 59198607Srrsstatic int wep_enmic(struct ieee80211_key *, struct mbuf *, int); 60198607Srrsstatic int wep_demic(struct ieee80211_key *, struct mbuf *, int); 61198607Srrs 62198160Srrsstatic const struct ieee80211_cipher wep = { 63198160Srrs .ic_name = "WEP", 64198160Srrs .ic_cipher = IEEE80211_CIPHER_WEP, 65198160Srrs .ic_header = IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN, 66198160Srrs .ic_trailer = IEEE80211_WEP_CRCLEN, 67198160Srrs .ic_miclen = 0, 68198160Srrs .ic_attach = wep_attach, 69198160Srrs .ic_detach = wep_detach, 70198160Srrs .ic_setkey = wep_setkey, 71198160Srrs .ic_encap = wep_encap, 72198160Srrs .ic_decap = wep_decap, 73198160Srrs .ic_enmic = wep_enmic, 74198160Srrs .ic_demic = wep_demic, 75198160Srrs}; 76213377Sjchandra 77213377Sjchandrastatic int wep_encrypt(struct ieee80211_key *, struct mbuf *, int hdrlen); 78213377Sjchandrastatic int wep_decrypt(struct ieee80211_key *, struct mbuf *, int hdrlen); 79213377Sjchandra 80213377Sjchandrastruct wep_ctx { 81213377Sjchandra struct ieee80211com *wc_ic; /* for diagnostics */ 82213377Sjchandra u_int32_t wc_iv; /* initial vector for crypto */ 83213377Sjchandra}; 84213377Sjchandra 85213377Sjchandra/* number of references from net80211 layer */ 86213377Sjchandrastatic int nrefs = 0; 87213377Sjchandra 88213377Sjchandrastatic void * 89213377Sjchandrawep_attach(struct ieee80211com *ic, struct ieee80211_key *k) 90213377Sjchandra{ 91213377Sjchandra struct wep_ctx *ctx; 92213377Sjchandra 93198160Srrs MALLOC(ctx, struct wep_ctx *, sizeof(struct wep_ctx), 94213377Sjchandra M_DEVBUF, M_NOWAIT | M_ZERO); 95213377Sjchandra if (ctx == NULL) { 96213443Sjchandra ic->ic_stats.is_crypto_nomem++; 97213377Sjchandra return NULL; 98213443Sjchandra } 99213377Sjchandra 100213377Sjchandra ctx->wc_ic = ic; 101213377Sjchandra get_random_bytes(&ctx->wc_iv, sizeof(ctx->wc_iv)); 102218909Sbrucec nrefs++; /* NB: we assume caller locking */ 103213377Sjchandra return ctx; 104213377Sjchandra} 105213377Sjchandra 106213377Sjchandrastatic void 107213377Sjchandrawep_detach(struct ieee80211_key *k) 108213377Sjchandra{ 109213377Sjchandra struct wep_ctx *ctx = k->wk_private; 110213377Sjchandra 111213377Sjchandra FREE(ctx, M_DEVBUF); 112213377Sjchandra KASSERT(nrefs > 0, ("imbalanced attach/detach")); 113213377Sjchandra nrefs--; /* NB: we assume caller locking */ 114213377Sjchandra} 115213377Sjchandra 116213377Sjchandrastatic int 117213377Sjchandrawep_setkey(struct ieee80211_key *k) 118198625Srrs{ 119198625Srrs return k->wk_keylen >= 40/NBBY; 120198160Srrs} 121198160Srrs 122198160Srrs/* 123213377Sjchandra * Add privacy headers appropriate for the specified key. 124198160Srrs */ 125198160Srrsstatic int 126208165Srrswep_encap(struct ieee80211_key *k, struct mbuf *m, u_int8_t keyid) 127213377Sjchandra{ 128208165Srrs struct wep_ctx *ctx = k->wk_private; 129198160Srrs struct ieee80211com *ic = ctx->wc_ic; 130198160Srrs u_int32_t iv; 131198160Srrs u_int8_t *ivp; 132213377Sjchandra int hdrlen; 133198625Srrs 134198625Srrs hdrlen = ieee80211_hdrspace(ic, mtod(m, void *)); 135213377Sjchandra 136213377Sjchandra /* 137198160Srrs * Copy down 802.11 header and add the IV + KeyID. 138198625Srrs */ 139198625Srrs M_PREPEND(m, wep.ic_header, M_NOWAIT); 140198625Srrs if (m == NULL) 141198625Srrs return 0; 142198625Srrs ivp = mtod(m, u_int8_t *); 143198625Srrs ovbcopy(ivp + wep.ic_header, ivp, hdrlen); 144198625Srrs ivp += hdrlen; 145198625Srrs 146198160Srrs /* 147213377Sjchandra * XXX 148213377Sjchandra * IV must not duplicate during the lifetime of the key. 149213377Sjchandra * But no mechanism to renew keys is defined in IEEE 802.11 150213377Sjchandra * for WEP. And the IV may be duplicated at other stations 151218909Sbrucec * because the session key itself is shared. So we use a 152213443Sjchandra * pseudo random IV for now, though it is not the right way. 153213377Sjchandra * 154213377Sjchandra * NB: Rather than use a strictly random IV we select a 155213377Sjchandra * random one to start and then increment the value for 156213377Sjchandra * each frame. This is an explicit tradeoff between 157213377Sjchandra * overhead and security. Given the basic insecurity of 158213377Sjchandra * WEP this seems worthwhile. 159213377Sjchandra */ 160213377Sjchandra 161213377Sjchandra /* 162213377Sjchandra * Skip 'bad' IVs from Fluhrer/Mantin/Shamir: 163213377Sjchandra * (B, 255, N) with 3 <= B < 16 and 0 <= N <= 255 164198160Srrs */ 165198160Srrs iv = ctx->wc_iv; 166198160Srrs if ((iv & 0xff00) == 0xff00) { 167198160Srrs int B = (iv & 0xff0000) >> 16; 168198160Srrs if (3 <= B && B < 16) 169198160Srrs iv += 0x0100; 170212321Sjchandra } 171198160Srrs ctx->wc_iv = iv + 1; 172198160Srrs 173213377Sjchandra /* 174213377Sjchandra * NB: Preserve byte order of IV for packet 175213377Sjchandra * sniffers; it doesn't matter otherwise. 176198625Srrs */ 177198625Srrs#if _BYTE_ORDER == _BIG_ENDIAN 178198160Srrs ivp[0] = iv >> 0; 179213377Sjchandra ivp[1] = iv >> 8; 180213377Sjchandra ivp[2] = iv >> 16; 181213377Sjchandra#else 182213377Sjchandra ivp[2] = iv >> 0; 183213377Sjchandra ivp[1] = iv >> 8; 184198160Srrs ivp[0] = iv >> 16; 185198160Srrs#endif 186212790Sjchandra ivp[3] = keyid; 187212790Sjchandra 188212790Sjchandra /* 189212790Sjchandra * Finally, do software encrypt if neeed. 190212790Sjchandra */ 191212790Sjchandra if ((k->wk_flags & IEEE80211_KEY_SWCRYPT) && 192198160Srrs !wep_encrypt(k, m, hdrlen)) 193198625Srrs return 0; 194213377Sjchandra 195198160Srrs return 1; 196213377Sjchandra} 197198625Srrs 198212790Sjchandra/* 199213377Sjchandra * Add MIC to the frame as needed. 200213377Sjchandra */ 201198160Srrsstatic int 202212790Sjchandrawep_enmic(struct ieee80211_key *k, struct mbuf *m, int force) 203212321Sjchandra{ 204198625Srrs 205213377Sjchandra return 1; 206198160Srrs} 207198625Srrs 208213377Sjchandra/* 209198625Srrs * Validate and strip privacy headers (and trailer) for a 210198160Srrs * received frame. If necessary, decrypt the frame using 211213377Sjchandra * the specified key. 212213377Sjchandra */ 213198625Srrsstatic int 214198625Srrswep_decap(struct ieee80211_key *k, struct mbuf *m, int hdrlen) 215213377Sjchandra{ 216213377Sjchandra struct wep_ctx *ctx = k->wk_private; 217213377Sjchandra struct ieee80211_frame *wh; 218198625Srrs 219212790Sjchandra wh = mtod(m, struct ieee80211_frame *); 220213377Sjchandra 221213377Sjchandra /* 222213377Sjchandra * Check if the device handled the decrypt in hardware. 223213377Sjchandra * If so we just strip the header; otherwise we need to 224213377Sjchandra * handle the decrypt in software. 225213377Sjchandra */ 226198625Srrs if ((k->wk_flags & IEEE80211_KEY_SWCRYPT) && 227212321Sjchandra !wep_decrypt(k, m, hdrlen)) { 228213377Sjchandra IEEE80211_DPRINTF(ctx->wc_ic, IEEE80211_MSG_CRYPTO, 229213377Sjchandra "[%s] WEP ICV mismatch on decrypt\n", 230212321Sjchandra ether_sprintf(wh->i_addr2)); 231198625Srrs ctx->wc_ic->ic_stats.is_rx_wepfail++; 232212790Sjchandra return 0; 233212790Sjchandra } 234198160Srrs 235198160Srrs /* 236212790Sjchandra * Copy up 802.11 header and strip crypto bits. 237212790Sjchandra */ 238212321Sjchandra ovbcopy(mtod(m, void *), mtod(m, u_int8_t *) + wep.ic_header, hdrlen); 239212790Sjchandra m_adj(m, wep.ic_header); 240198160Srrs m_adj(m, -wep.ic_trailer); 241198160Srrs 242213377Sjchandra return 1; 243213377Sjchandra} 244213377Sjchandra 245213377Sjchandra/* 246213377Sjchandra * Verify and strip MIC from the frame. 247213377Sjchandra */ 248213377Sjchandrastatic int 249213377Sjchandrawep_demic(struct ieee80211_key *k, struct mbuf *skb, int force) 250198160Srrs{ 251212321Sjchandra return 1; 252213377Sjchandra} 253213377Sjchandra 254198160Srrsstatic const uint32_t crc32_table[256] = { 255213377Sjchandra 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, 256213377Sjchandra 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, 257213377Sjchandra 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, 258198160Srrs 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, 259213377Sjchandra 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, 260213377Sjchandra 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, 261213377Sjchandra 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, 262213377Sjchandra 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, 263213377Sjchandra 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, 264213377Sjchandra 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, 265213443Sjchandra 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, 266213377Sjchandra 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, 267213443Sjchandra 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L, 268213377Sjchandra 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, 269213443Sjchandra 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, 270213377Sjchandra 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, 271213377Sjchandra 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, 272213377Sjchandra 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, 273212321Sjchandra 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, 274213377Sjchandra 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, 275213377Sjchandra 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, 276213443Sjchandra 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, 277213377Sjchandra 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, 278198160Srrs 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, 279212321Sjchandra 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, 280198160Srrs 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L, 281198160Srrs 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, 282213443Sjchandra 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, 283213443Sjchandra 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L, 284213443Sjchandra 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, 285213443Sjchandra 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, 286213443Sjchandra 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, 287213443Sjchandra 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, 288213443Sjchandra 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, 289208165Srrs 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, 290208165Srrs 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, 291208165Srrs 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL, 292213377Sjchandra 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, 293213377Sjchandra 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, 294213377Sjchandra 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, 295213377Sjchandra 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, 296198160Srrs 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, 297213377Sjchandra 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, 298213377Sjchandra 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, 299213443Sjchandra 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, 300213377Sjchandra 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, 301213377Sjchandra 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, 302213377Sjchandra 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, 303213443Sjchandra 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, 304213377Sjchandra 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L, 305213377Sjchandra 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, 306213377Sjchandra 0x2d02ef8dL 307213377Sjchandra}; 308213377Sjchandra 309213377Sjchandrastatic int 310213377Sjchandrawep_encrypt(struct ieee80211_key *key, struct mbuf *m0, int hdrlen) 311213377Sjchandra{ 312213377Sjchandra#define S_SWAP(a,b) do { uint8_t t = S[a]; S[a] = S[b]; S[b] = t; } while(0) 313213443Sjchandra struct wep_ctx *ctx = key->wk_private; 314213443Sjchandra struct mbuf *m = m0; 315213377Sjchandra u_int8_t rc4key[IEEE80211_WEP_IVLEN + IEEE80211_KEYBUF_SIZE]; 316213377Sjchandra uint8_t icv[IEEE80211_WEP_CRCLEN]; 317213377Sjchandra uint32_t i, j, k, crc; 318213377Sjchandra size_t buflen, data_len; 319213377Sjchandra uint8_t S[256]; 320208165Srrs uint8_t *pos; 321208165Srrs u_int off, keylen; 322213443Sjchandra 323208165Srrs ctx->wc_ic->ic_stats.is_crypto_wep++; 324208165Srrs 325213443Sjchandra /* NB: this assumes the header was pulled up */ 326213443Sjchandra memcpy(rc4key, mtod(m, u_int8_t *) + hdrlen, IEEE80211_WEP_IVLEN); 327208165Srrs memcpy(rc4key + IEEE80211_WEP_IVLEN, key->wk_key, key->wk_keylen); 328213377Sjchandra 329208165Srrs /* Setup RC4 state */ 330208165Srrs for (i = 0; i < 256; i++) 331208165Srrs S[i] = i; 332208165Srrs j = 0; 333208165Srrs keylen = key->wk_keylen + IEEE80211_WEP_IVLEN; 334213377Sjchandra for (i = 0; i < 256; i++) { 335213377Sjchandra j = (j + S[i] + rc4key[i % keylen]) & 0xff; 336213377Sjchandra S_SWAP(i, j); 337213377Sjchandra } 338208165Srrs 339213377Sjchandra off = hdrlen + wep.ic_header; 340213377Sjchandra data_len = m->m_pkthdr.len - off; 341213377Sjchandra 342213377Sjchandra /* Compute CRC32 over unencrypted data and apply RC4 to data */ 343213377Sjchandra crc = ~0; 344213377Sjchandra i = j = 0; 345213377Sjchandra pos = mtod(m, uint8_t *) + off; 346208165Srrs buflen = m->m_len - off; 347208165Srrs for (;;) { 348208165Srrs if (buflen > data_len) 349213377Sjchandra buflen = data_len; 350208165Srrs data_len -= buflen; 351208165Srrs for (k = 0; k < buflen; k++) { 352213377Sjchandra crc = crc32_table[(crc ^ *pos) & 0xff] ^ (crc >> 8); 353213443Sjchandra i = (i + 1) & 0xff; 354213377Sjchandra j = (j + S[i]) & 0xff; 355213377Sjchandra S_SWAP(i, j); 356213377Sjchandra *pos++ ^= S[(S[i] + S[j]) & 0xff]; 357213377Sjchandra } 358213377Sjchandra if (m->m_next == NULL) { 359213377Sjchandra if (data_len != 0) { /* out of data */ 360213377Sjchandra IEEE80211_DPRINTF(ctx->wc_ic, 361213377Sjchandra IEEE80211_MSG_CRYPTO, 362213377Sjchandra "[%s] out of data for WEP (data_len %zu)\n", 363213377Sjchandra ether_sprintf(mtod(m0, 364213377Sjchandra struct ieee80211_frame *)->i_addr2), 365213443Sjchandra data_len); 366213377Sjchandra return 0; 367213377Sjchandra } 368213377Sjchandra break; 369213377Sjchandra } 370213377Sjchandra m = m->m_next; 371213377Sjchandra pos = mtod(m, uint8_t *); 372213377Sjchandra buflen = m->m_len; 373213377Sjchandra } 374213377Sjchandra crc = ~crc; 375208165Srrs 376213377Sjchandra /* Append little-endian CRC32 and encrypt it to produce ICV */ 377208165Srrs icv[0] = crc; 378213377Sjchandra icv[1] = crc >> 8; 379213377Sjchandra icv[2] = crc >> 16; 380213377Sjchandra icv[3] = crc >> 24; 381213377Sjchandra for (k = 0; k < IEEE80211_WEP_CRCLEN; k++) { 382208165Srrs i = (i + 1) & 0xff; 383208165Srrs j = (j + S[i]) & 0xff; 384208165Srrs S_SWAP(i, j); 385208165Srrs icv[k] ^= S[(S[i] + S[j]) & 0xff]; 386213377Sjchandra } 387208165Srrs return m_append(m0, IEEE80211_WEP_CRCLEN, icv); 388213377Sjchandra#undef S_SWAP 389208165Srrs} 390213377Sjchandra 391213377Sjchandrastatic int 392208165Srrswep_decrypt(struct ieee80211_key *key, struct mbuf *m0, int hdrlen) 393213377Sjchandra{ 394213377Sjchandra#define S_SWAP(a,b) do { uint8_t t = S[a]; S[a] = S[b]; S[b] = t; } while(0) 395213377Sjchandra struct wep_ctx *ctx = key->wk_private; 396213377Sjchandra struct mbuf *m = m0; 397213377Sjchandra u_int8_t rc4key[IEEE80211_WEP_IVLEN + IEEE80211_KEYBUF_SIZE]; 398213377Sjchandra uint8_t icv[IEEE80211_WEP_CRCLEN]; 399213377Sjchandra uint32_t i, j, k, crc; 400213474Sjchandra size_t buflen, data_len; 401213377Sjchandra uint8_t S[256]; 402213377Sjchandra uint8_t *pos; 403208165Srrs u_int off, keylen; 404213377Sjchandra 405213377Sjchandra ctx->wc_ic->ic_stats.is_crypto_wep++; 406208165Srrs 407208165Srrs /* NB: this assumes the header was pulled up */ 408208165Srrs memcpy(rc4key, mtod(m, u_int8_t *) + hdrlen, IEEE80211_WEP_IVLEN); 409208165Srrs memcpy(rc4key + IEEE80211_WEP_IVLEN, key->wk_key, key->wk_keylen); 410208165Srrs 411210845Sjchandra /* Setup RC4 state */ 412208165Srrs for (i = 0; i < 256; i++) 413208165Srrs S[i] = i; 414198625Srrs j = 0; 415213377Sjchandra keylen = key->wk_keylen + IEEE80211_WEP_IVLEN; 416213377Sjchandra for (i = 0; i < 256; i++) { 417198160Srrs j = (j + S[i] + rc4key[i % keylen]) & 0xff; 418213377Sjchandra S_SWAP(i, j); 419213377Sjchandra } 420213377Sjchandra 421198160Srrs off = hdrlen + wep.ic_header; 422213377Sjchandra data_len = m->m_pkthdr.len - (off + wep.ic_trailer), 423213377Sjchandra 424198160Srrs /* Compute CRC32 over unencrypted data and apply RC4 to data */ 425213377Sjchandra crc = ~0; 426213377Sjchandra i = j = 0; 427213377Sjchandra pos = mtod(m, uint8_t *) + off; 428213377Sjchandra buflen = m->m_len - off; 429213377Sjchandra for (;;) { 430213377Sjchandra if (buflen > data_len) 431213377Sjchandra buflen = data_len; 432213377Sjchandra data_len -= buflen; 433198625Srrs for (k = 0; k < buflen; k++) { 434198160Srrs i = (i + 1) & 0xff; 435213377Sjchandra j = (j + S[i]) & 0xff; 436213377Sjchandra S_SWAP(i, j); 437213377Sjchandra *pos ^= S[(S[i] + S[j]) & 0xff]; 438213377Sjchandra crc = crc32_table[(crc ^ *pos) & 0xff] ^ (crc >> 8); 439203112Srrs pos++; 440217072Sjhb } 441198160Srrs m = m->m_next; 442213377Sjchandra if (m == NULL) { 443198160Srrs if (data_len != 0) { /* out of data */ 444198160Srrs IEEE80211_DPRINTF(ctx->wc_ic, 445213443Sjchandra IEEE80211_MSG_CRYPTO, 446213443Sjchandra "[%s] out of data for WEP (data_len %zu)\n", 447213443Sjchandra ether_sprintf(mtod(m0, 448208165Srrs struct ieee80211_frame *)->i_addr2), 449208165Srrs data_len); 450208165Srrs return 0; 451213377Sjchandra } 452208165Srrs break; 453213377Sjchandra } 454213377Sjchandra pos = mtod(m, uint8_t *); 455213377Sjchandra buflen = m->m_len; 456213377Sjchandra } 457213377Sjchandra crc = ~crc; 458213377Sjchandra 459213377Sjchandra /* Encrypt little-endian CRC32 and verify that it matches with 460208369Sjchandra * received ICV */ 461198160Srrs icv[0] = crc; 462208165Srrs icv[1] = crc >> 8; 463213443Sjchandra icv[2] = crc >> 16; 464213443Sjchandra icv[3] = crc >> 24; 465213443Sjchandra for (k = 0; k < IEEE80211_WEP_CRCLEN; k++) { 466213443Sjchandra i = (i + 1) & 0xff; 467213443Sjchandra j = (j + S[i]) & 0xff; 468213443Sjchandra S_SWAP(i, j); 469213443Sjchandra /* XXX assumes ICV is contiguous in mbuf */ 470213443Sjchandra if ((icv[k] ^ S[(S[i] + S[j]) & 0xff]) != *pos++) { 471213443Sjchandra /* ICV mismatch - drop frame */ 472280013Sian return 0; 473280013Sian } 474213443Sjchandra } 475280013Sian return 1; 476280013Sian#undef S_SWAP 477213443Sjchandra} 478213443Sjchandra 479213443Sjchandra/* 480213443Sjchandra * Module glue. 481280013Sian */ 482213443Sjchandrastatic int 483213443Sjchandrawep_modevent(module_t mod, int type, void *unused) 484213443Sjchandra{ 485213443Sjchandra switch (type) { 486280013Sian case MOD_LOAD: 487280013Sian ieee80211_crypto_register(&wep); 488213443Sjchandra return 0; 489213443Sjchandra case MOD_UNLOAD: 490213443Sjchandra case MOD_QUIESCE: 491213443Sjchandra if (nrefs) { 492213443Sjchandra printf("wlan_wep: still in use (%u dynamic refs)\n", 493 nrefs); 494 return EBUSY; 495 } 496 if (type == MOD_UNLOAD) 497 ieee80211_crypto_unregister(&wep); 498 return 0; 499 } 500 return EINVAL; 501} 502 503static moduledata_t wep_mod = { 504 "wlan_wep", 505 wep_modevent, 506 0 507}; 508DECLARE_MODULE(wlan_wep, wep_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST); 509MODULE_VERSION(wlan_wep, 1); 510MODULE_DEPEND(wlan_wep, wlan, 1, 1, 1); 511