ieee80211_crypto_wep.c revision 170360
1193323Sed/*- 2193323Sed * Copyright (c) 2002-2007 Sam Leffler, Errno Consulting 3193323Sed * All rights reserved. 4193323Sed * 5193323Sed * Redistribution and use in source and binary forms, with or without 6193323Sed * modification, are permitted provided that the following conditions 7193323Sed * are met: 8193323Sed * 1. Redistributions of source code must retain the above copyright 9193323Sed * notice, this list of conditions and the following disclaimer. 10193323Sed * 2. Redistributions in binary form must reproduce the above copyright 11193323Sed * notice, this list of conditions and the following disclaimer in the 12193323Sed * documentation and/or other materials provided with the distribution. 13193323Sed * 14198090Srdivacky * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15198090Srdivacky * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16193323Sed * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17193323Sed * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 18198090Srdivacky * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19193323Sed * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20193323Sed * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21193323Sed * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22193323Sed * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23193323Sed * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24193323Sed */ 25193323Sed 26193323Sed#include <sys/cdefs.h> 27193323Sed__FBSDID("$FreeBSD: head/sys/net80211/ieee80211_crypto_wep.c 170360 2007-06-06 04:56:04Z sam $"); 28193323Sed 29193323Sed/* 30193323Sed * IEEE 802.11 WEP crypto support. 31193323Sed */ 32193323Sed#include <sys/param.h> 33193323Sed#include <sys/systm.h> 34193323Sed#include <sys/mbuf.h> 35218893Sdim#include <sys/malloc.h> 36198090Srdivacky#include <sys/kernel.h> 37198090Srdivacky#include <sys/module.h> 38193323Sed#include <sys/endian.h> 39198090Srdivacky 40193323Sed#include <sys/socket.h> 41193323Sed 42193323Sed#include <net/if.h> 43193323Sed#include <net/if_media.h> 44193323Sed#include <net/ethernet.h> 45193323Sed 46193323Sed#include <net80211/ieee80211_var.h> 47193323Sed 48193323Sedstatic void *wep_attach(struct ieee80211com *, struct ieee80211_key *); 49193323Sedstatic void wep_detach(struct ieee80211_key *); 50193323Sedstatic int wep_setkey(struct ieee80211_key *); 51193323Sedstatic int wep_encap(struct ieee80211_key *, struct mbuf *, u_int8_t keyid); 52218893Sdimstatic int wep_decap(struct ieee80211_key *, struct mbuf *, int hdrlen); 53218893Sdimstatic int wep_enmic(struct ieee80211_key *, struct mbuf *, int); 54193323Sedstatic int wep_demic(struct ieee80211_key *, struct mbuf *, int); 55193323Sed 56193323Sedstatic const struct ieee80211_cipher wep = { 57193323Sed .ic_name = "WEP", 58193323Sed .ic_cipher = IEEE80211_CIPHER_WEP, 59218893Sdim .ic_header = IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN, 60218893Sdim .ic_trailer = IEEE80211_WEP_CRCLEN, 61193323Sed .ic_miclen = 0, 62193323Sed .ic_attach = wep_attach, 63193323Sed .ic_detach = wep_detach, 64198090Srdivacky .ic_setkey = wep_setkey, 65198090Srdivacky .ic_encap = wep_encap, 66218893Sdim .ic_decap = wep_decap, 67218893Sdim .ic_enmic = wep_enmic, 68198090Srdivacky .ic_demic = wep_demic, 69193323Sed}; 70193323Sed 71193323Sedstatic int wep_encrypt(struct ieee80211_key *, struct mbuf *, int hdrlen); 72218893Sdimstatic int wep_decrypt(struct ieee80211_key *, struct mbuf *, int hdrlen); 73218893Sdim 74193323Sedstruct wep_ctx { 75193323Sed struct ieee80211com *wc_ic; /* for diagnostics */ 76218893Sdim u_int32_t wc_iv; /* initial vector for crypto */ 77193323Sed}; 78198090Srdivacky 79193323Sed/* number of references from net80211 layer */ 80193323Sedstatic int nrefs = 0; 81193323Sed 82193323Sedstatic void * 83193323Sedwep_attach(struct ieee80211com *ic, struct ieee80211_key *k) 84193323Sed{ 85193323Sed struct wep_ctx *ctx; 86218893Sdim 87218893Sdim MALLOC(ctx, struct wep_ctx *, sizeof(struct wep_ctx), 88193323Sed M_DEVBUF, M_NOWAIT | M_ZERO); 89193323Sed if (ctx == NULL) { 90193323Sed ic->ic_stats.is_crypto_nomem++; 91193323Sed return NULL; 92193724Sed } 93218893Sdim 94193724Sed ctx->wc_ic = ic; 95198090Srdivacky get_random_bytes(&ctx->wc_iv, sizeof(ctx->wc_iv)); 96193724Sed nrefs++; /* NB: we assume caller locking */ 97193724Sed return ctx; 98218893Sdim} 99194612Sed 100193724Sedstatic void 101194612Sedwep_detach(struct ieee80211_key *k) 102193724Sed{ 103193724Sed struct wep_ctx *ctx = k->wk_private; 104193724Sed 105193724Sed FREE(ctx, M_DEVBUF); 106198090Srdivacky KASSERT(nrefs > 0, ("imbalanced attach/detach")); 107193724Sed nrefs--; /* NB: we assume caller locking */ 108193724Sed} 109193724Sed 110193724Sedstatic int 111193323Sedwep_setkey(struct ieee80211_key *k) 112193323Sed{ 113193323Sed return k->wk_keylen >= 40/NBBY; 114193323Sed} 115193323Sed 116193323Sed/* 117198396Srdivacky * Add privacy headers appropriate for the specified key. 118198396Srdivacky */ 119193323Sedstatic int 120193323Sedwep_encap(struct ieee80211_key *k, struct mbuf *m, u_int8_t keyid) 121218893Sdim{ 122193323Sed struct wep_ctx *ctx = k->wk_private; 123193323Sed struct ieee80211com *ic = ctx->wc_ic; 124218893Sdim u_int32_t iv; 125203954Srdivacky u_int8_t *ivp; 126193323Sed int hdrlen; 127193323Sed 128218893Sdim hdrlen = ieee80211_hdrspace(ic, mtod(m, void *)); 129193323Sed 130193323Sed /* 131193323Sed * Copy down 802.11 header and add the IV + KeyID. 132193323Sed */ 133193323Sed M_PREPEND(m, wep.ic_header, M_NOWAIT); 134193323Sed if (m == NULL) 135193323Sed return 0; 136218893Sdim ivp = mtod(m, u_int8_t *); 137218893Sdim ovbcopy(ivp + wep.ic_header, ivp, hdrlen); 138203954Srdivacky ivp += hdrlen; 139193323Sed 140193323Sed /* 141193323Sed * XXX 142193323Sed * IV must not duplicate during the lifetime of the key. 143193323Sed * But no mechanism to renew keys is defined in IEEE 802.11 144193323Sed * for WEP. And the IV may be duplicated at other stations 145193323Sed * because the session key itself is shared. So we use a 146193323Sed * pseudo random IV for now, though it is not the right way. 147193323Sed * 148193323Sed * NB: Rather than use a strictly random IV we select a 149193323Sed * random one to start and then increment the value for 150193323Sed * each frame. This is an explicit tradeoff between 151193323Sed * overhead and security. Given the basic insecurity of 152193323Sed * WEP this seems worthwhile. 153193323Sed */ 154193323Sed 155193323Sed /* 156193323Sed * Skip 'bad' IVs from Fluhrer/Mantin/Shamir: 157193323Sed * (B, 255, N) with 3 <= B < 16 and 0 <= N <= 255 158193323Sed */ 159193323Sed iv = ctx->wc_iv; 160193323Sed if ((iv & 0xff00) == 0xff00) { 161193323Sed int B = (iv & 0xff0000) >> 16; 162193323Sed if (3 <= B && B < 16) 163193323Sed iv += 0x0100; 164193323Sed } 165193323Sed ctx->wc_iv = iv + 1; 166193323Sed 167193323Sed /* 168193323Sed * NB: Preserve byte order of IV for packet 169193323Sed * sniffers; it doesn't matter otherwise. 170193323Sed */ 171193323Sed#if _BYTE_ORDER == _BIG_ENDIAN 172198090Srdivacky ivp[0] = iv >> 0; 173198090Srdivacky ivp[1] = iv >> 8; 174193323Sed ivp[2] = iv >> 16; 175218893Sdim#else 176207618Srdivacky ivp[2] = iv >> 0; 177207618Srdivacky ivp[1] = iv >> 8; 178207618Srdivacky ivp[0] = iv >> 16; 179193323Sed#endif 180193323Sed ivp[3] = keyid; 181193323Sed 182193323Sed /* 183193323Sed * Finally, do software encrypt if neeed. 184193323Sed */ 185193323Sed if ((k->wk_flags & IEEE80211_KEY_SWCRYPT) && 186193323Sed !wep_encrypt(k, m, hdrlen)) 187193323Sed return 0; 188193323Sed 189193323Sed return 1; 190193323Sed} 191193323Sed 192193323Sed/* 193193323Sed * Add MIC to the frame as needed. 194193323Sed */ 195193323Sedstatic int 196193323Sedwep_enmic(struct ieee80211_key *k, struct mbuf *m, int force) 197193323Sed{ 198193323Sed 199193323Sed return 1; 200193323Sed} 201193323Sed 202193323Sed/* 203193323Sed * Validate and strip privacy headers (and trailer) for a 204198090Srdivacky * received frame. If necessary, decrypt the frame using 205193323Sed * the specified key. 206193323Sed */ 207193323Sedstatic int 208193323Sedwep_decap(struct ieee80211_key *k, struct mbuf *m, int hdrlen) 209203954Srdivacky{ 210193323Sed struct wep_ctx *ctx = k->wk_private; 211193323Sed struct ieee80211_frame *wh; 212193323Sed 213218893Sdim wh = mtod(m, struct ieee80211_frame *); 214203954Srdivacky 215193323Sed /* 216193323Sed * Check if the device handled the decrypt in hardware. 217193323Sed * If so we just strip the header; otherwise we need to 218193323Sed * handle the decrypt in software. 219193323Sed */ 220218893Sdim if ((k->wk_flags & IEEE80211_KEY_SWCRYPT) && 221218893Sdim !wep_decrypt(k, m, hdrlen)) { 222203954Srdivacky IEEE80211_DPRINTF(ctx->wc_ic, IEEE80211_MSG_CRYPTO, 223203954Srdivacky "[%s] WEP ICV mismatch on decrypt\n", 224193323Sed ether_sprintf(wh->i_addr2)); 225193323Sed ctx->wc_ic->ic_stats.is_rx_wepfail++; 226193323Sed return 0; 227193323Sed } 228193323Sed 229193323Sed /* 230193323Sed * Copy up 802.11 header and strip crypto bits. 231193323Sed */ 232193323Sed ovbcopy(mtod(m, void *), mtod(m, u_int8_t *) + wep.ic_header, hdrlen); 233193323Sed m_adj(m, wep.ic_header); 234193323Sed m_adj(m, -wep.ic_trailer); 235193323Sed 236193323Sed return 1; 237193323Sed} 238193323Sed 239193323Sed/* 240210299Sed * Verify and strip MIC from the frame. 241210299Sed */ 242193323Sedstatic int 243193323Sedwep_demic(struct ieee80211_key *k, struct mbuf *skb, int force) 244193323Sed{ 245210299Sed return 1; 246193323Sed} 247210299Sed 248210299Sedstatic const uint32_t crc32_table[256] = { 249193323Sed 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, 250193323Sed 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, 251193323Sed 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, 252193323Sed 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, 253193323Sed 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, 254193323Sed 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, 255193323Sed 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, 256193323Sed 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, 257193323Sed 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, 258193323Sed 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, 259193323Sed 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, 260193323Sed 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, 261193323Sed 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L, 262193323Sed 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, 263193323Sed 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, 264218893Sdim 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, 265193323Sed 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, 266193323Sed 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, 267193323Sed 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, 268193323Sed 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, 269193323Sed 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, 270193323Sed 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, 271218893Sdim 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, 272198090Srdivacky 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, 273207618Srdivacky 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, 274207618Srdivacky 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L, 275207618Srdivacky 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, 276193323Sed 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, 277193323Sed 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L, 278193323Sed 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, 279193323Sed 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, 280193323Sed 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, 281193323Sed 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, 282193323Sed 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, 283193323Sed 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, 284193323Sed 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, 285218893Sdim 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL, 286193323Sed 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, 287193323Sed 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, 288193323Sed 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, 289193323Sed 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, 290193323Sed 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, 291193323Sed 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, 292193323Sed 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, 293193323Sed 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, 294193323Sed 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, 295198090Srdivacky 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, 296193323Sed 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, 297198090Srdivacky 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, 298198090Srdivacky 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L, 299193323Sed 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, 300193323Sed 0x2d02ef8dL 301193323Sed}; 302193323Sed 303193323Sedstatic int 304193323Sedwep_encrypt(struct ieee80211_key *key, struct mbuf *m0, int hdrlen) 305193323Sed{ 306193323Sed#define S_SWAP(a,b) do { uint8_t t = S[a]; S[a] = S[b]; S[b] = t; } while(0) 307193323Sed struct wep_ctx *ctx = key->wk_private; 308193323Sed struct mbuf *m = m0; 309193323Sed u_int8_t rc4key[IEEE80211_WEP_IVLEN + IEEE80211_KEYBUF_SIZE]; 310193323Sed uint8_t icv[IEEE80211_WEP_CRCLEN]; 311193323Sed uint32_t i, j, k, crc; 312193323Sed size_t buflen, data_len; 313193323Sed uint8_t S[256]; 314193323Sed uint8_t *pos; 315193323Sed u_int off, keylen; 316193323Sed 317193323Sed ctx->wc_ic->ic_stats.is_crypto_wep++; 318193323Sed 319207618Srdivacky /* NB: this assumes the header was pulled up */ 320207618Srdivacky memcpy(rc4key, mtod(m, u_int8_t *) + hdrlen, IEEE80211_WEP_IVLEN); 321207618Srdivacky memcpy(rc4key + IEEE80211_WEP_IVLEN, key->wk_key, key->wk_keylen); 322193323Sed 323193323Sed /* Setup RC4 state */ 324218893Sdim for (i = 0; i < 256; i++) 325193323Sed S[i] = i; 326193323Sed j = 0; 327193323Sed keylen = key->wk_keylen + IEEE80211_WEP_IVLEN; 328193323Sed for (i = 0; i < 256; i++) { 329193323Sed j = (j + S[i] + rc4key[i % keylen]) & 0xff; 330193323Sed S_SWAP(i, j); 331193323Sed } 332193323Sed 333193323Sed off = hdrlen + wep.ic_header; 334193323Sed data_len = m->m_pkthdr.len - off; 335198090Srdivacky 336193323Sed /* Compute CRC32 over unencrypted data and apply RC4 to data */ 337193323Sed crc = ~0; 338193323Sed i = j = 0; 339193323Sed pos = mtod(m, uint8_t *) + off; 340198090Srdivacky buflen = m->m_len - off; 341198090Srdivacky for (;;) { 342193323Sed if (buflen > data_len) 343193323Sed buflen = data_len; 344193323Sed data_len -= buflen; 345193323Sed for (k = 0; k < buflen; k++) { 346193323Sed crc = crc32_table[(crc ^ *pos) & 0xff] ^ (crc >> 8); 347193323Sed i = (i + 1) & 0xff; 348198090Srdivacky j = (j + S[i]) & 0xff; 349218893Sdim S_SWAP(i, j); 350193323Sed *pos++ ^= S[(S[i] + S[j]) & 0xff]; 351193323Sed } 352193323Sed if (m->m_next == NULL) { 353193323Sed if (data_len != 0) { /* out of data */ 354193323Sed IEEE80211_DPRINTF(ctx->wc_ic, 355193323Sed IEEE80211_MSG_CRYPTO, 356193323Sed "[%s] out of data for WEP (data_len %zu)\n", 357193323Sed ether_sprintf(mtod(m0, 358193323Sed struct ieee80211_frame *)->i_addr2), 359193323Sed data_len); 360193323Sed return 0; 361193323Sed } 362193323Sed break; 363193323Sed } 364193323Sed m = m->m_next; 365218893Sdim pos = mtod(m, uint8_t *); 366193323Sed buflen = m->m_len; 367193323Sed } 368193323Sed crc = ~crc; 369193323Sed 370198090Srdivacky /* Append little-endian CRC32 and encrypt it to produce ICV */ 371193323Sed icv[0] = crc; 372193323Sed icv[1] = crc >> 8; 373193323Sed icv[2] = crc >> 16; 374193323Sed icv[3] = crc >> 24; 375193323Sed for (k = 0; k < IEEE80211_WEP_CRCLEN; k++) { 376193323Sed i = (i + 1) & 0xff; 377193323Sed j = (j + S[i]) & 0xff; 378193323Sed S_SWAP(i, j); 379193323Sed icv[k] ^= S[(S[i] + S[j]) & 0xff]; 380193323Sed } 381193323Sed return m_append(m0, IEEE80211_WEP_CRCLEN, icv); 382193323Sed#undef S_SWAP 383193323Sed} 384193323Sed 385193323Sedstatic int 386193323Sedwep_decrypt(struct ieee80211_key *key, struct mbuf *m0, int hdrlen) 387193323Sed{ 388207618Srdivacky#define S_SWAP(a,b) do { uint8_t t = S[a]; S[a] = S[b]; S[b] = t; } while(0) 389207618Srdivacky struct wep_ctx *ctx = key->wk_private; 390193323Sed struct mbuf *m = m0; 391193323Sed u_int8_t rc4key[IEEE80211_WEP_IVLEN + IEEE80211_KEYBUF_SIZE]; 392193323Sed uint8_t icv[IEEE80211_WEP_CRCLEN]; 393193323Sed uint32_t i, j, k, crc; 394203954Srdivacky size_t buflen, data_len; 395193323Sed uint8_t S[256]; 396193323Sed uint8_t *pos; 397193323Sed u_int off, keylen; 398193323Sed 399193323Sed ctx->wc_ic->ic_stats.is_crypto_wep++; 400193323Sed 401193323Sed /* NB: this assumes the header was pulled up */ 402193323Sed memcpy(rc4key, mtod(m, u_int8_t *) + hdrlen, IEEE80211_WEP_IVLEN); 403193323Sed memcpy(rc4key + IEEE80211_WEP_IVLEN, key->wk_key, key->wk_keylen); 404193323Sed 405218893Sdim /* Setup RC4 state */ 406203954Srdivacky for (i = 0; i < 256; i++) 407193323Sed S[i] = i; 408193323Sed j = 0; 409193323Sed keylen = key->wk_keylen + IEEE80211_WEP_IVLEN; 410193323Sed for (i = 0; i < 256; i++) { 411218893Sdim j = (j + S[i] + rc4key[i % keylen]) & 0xff; 412218893Sdim S_SWAP(i, j); 413203954Srdivacky } 414203954Srdivacky 415193323Sed off = hdrlen + wep.ic_header; 416193323Sed data_len = m->m_pkthdr.len - (off + wep.ic_trailer), 417193323Sed 418193323Sed /* Compute CRC32 over unencrypted data and apply RC4 to data */ 419193323Sed crc = ~0; 420193323Sed i = j = 0; 421193323Sed pos = mtod(m, uint8_t *) + off; 422193323Sed buflen = m->m_len - off; 423193323Sed for (;;) { 424193323Sed if (buflen > data_len) 425193323Sed buflen = data_len; 426193323Sed data_len -= buflen; 427193323Sed for (k = 0; k < buflen; k++) { 428193323Sed i = (i + 1) & 0xff; 429193323Sed j = (j + S[i]) & 0xff; 430193323Sed S_SWAP(i, j); 431193323Sed *pos ^= S[(S[i] + S[j]) & 0xff]; 432193323Sed crc = crc32_table[(crc ^ *pos) & 0xff] ^ (crc >> 8); 433193323Sed pos++; 434193323Sed } 435193323Sed m = m->m_next; 436193323Sed if (m == NULL) { 437193323Sed if (data_len != 0) { /* out of data */ 438193323Sed IEEE80211_DPRINTF(ctx->wc_ic, 439193323Sed IEEE80211_MSG_CRYPTO, 440193323Sed "[%s] out of data for WEP (data_len %zu)\n", 441193323Sed ether_sprintf(mtod(m0, 442193323Sed struct ieee80211_frame *)->i_addr2), 443193323Sed data_len); 444193323Sed return 0; 445193323Sed } 446193323Sed break; 447193323Sed } 448193323Sed pos = mtod(m, uint8_t *); 449193323Sed buflen = m->m_len; 450193323Sed } 451193323Sed crc = ~crc; 452193323Sed 453193323Sed /* Encrypt little-endian CRC32 and verify that it matches with 454193323Sed * received ICV */ 455193323Sed icv[0] = crc; 456193323Sed icv[1] = crc >> 8; 457193323Sed icv[2] = crc >> 16; 458193323Sed icv[3] = crc >> 24; 459193323Sed for (k = 0; k < IEEE80211_WEP_CRCLEN; k++) { 460193323Sed i = (i + 1) & 0xff; 461193323Sed j = (j + S[i]) & 0xff; 462193323Sed S_SWAP(i, j); 463193323Sed /* XXX assumes ICV is contiguous in mbuf */ 464193323Sed if ((icv[k] ^ S[(S[i] + S[j]) & 0xff]) != *pos++) { 465193323Sed /* ICV mismatch - drop frame */ 466193323Sed return 0; 467193323Sed } 468193323Sed } 469193323Sed return 1; 470193323Sed#undef S_SWAP 471193323Sed} 472193323Sed 473193323Sed/* 474193323Sed * Module glue. 475193323Sed */ 476198090Srdivackystatic int 477193323Sedwep_modevent(module_t mod, int type, void *unused) 478193323Sed{ 479193323Sed switch (type) { 480193323Sed case MOD_LOAD: 481 ieee80211_crypto_register(&wep); 482 return 0; 483 case MOD_UNLOAD: 484 case MOD_QUIESCE: 485 if (nrefs) { 486 printf("wlan_wep: still in use (%u dynamic refs)\n", 487 nrefs); 488 return EBUSY; 489 } 490 if (type == MOD_UNLOAD) 491 ieee80211_crypto_unregister(&wep); 492 return 0; 493 } 494 return EINVAL; 495} 496 497static moduledata_t wep_mod = { 498 "wlan_wep", 499 wep_modevent, 500 0 501}; 502DECLARE_MODULE(wlan_wep, wep_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST); 503MODULE_VERSION(wlan_wep, 1); 504MODULE_DEPEND(wlan_wep, wlan, 1, 1, 1); 505