ieee80211_crypto_tkip.c revision 203673
1138568Ssam/*- 2178354Ssam * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting 3138568Ssam * All rights reserved. 4138568Ssam * 5138568Ssam * Redistribution and use in source and binary forms, with or without 6138568Ssam * modification, are permitted provided that the following conditions 7138568Ssam * are met: 8138568Ssam * 1. Redistributions of source code must retain the above copyright 9138568Ssam * notice, this list of conditions and the following disclaimer. 10138568Ssam * 2. Redistributions in binary form must reproduce the above copyright 11138568Ssam * notice, this list of conditions and the following disclaimer in the 12138568Ssam * documentation and/or other materials provided with the distribution. 13138568Ssam * 14138568Ssam * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15138568Ssam * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16138568Ssam * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17138568Ssam * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 18138568Ssam * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19138568Ssam * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20138568Ssam * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21138568Ssam * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22138568Ssam * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23138568Ssam * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24138568Ssam */ 25138568Ssam 26138568Ssam#include <sys/cdefs.h> 27138568Ssam__FBSDID("$FreeBSD: head/sys/net80211/ieee80211_crypto_tkip.c 203673 2010-02-08 18:16:59Z bschmidt $"); 28138568Ssam 29138568Ssam/* 30138568Ssam * IEEE 802.11i TKIP crypto support. 31138568Ssam * 32138568Ssam * Part of this module is derived from similar code in the Host 33138568Ssam * AP driver. The code is used with the consent of the author and 34138568Ssam * it's license is included below. 35138568Ssam */ 36178354Ssam#include "opt_wlan.h" 37178354Ssam 38138568Ssam#include <sys/param.h> 39138568Ssam#include <sys/systm.h> 40138568Ssam#include <sys/mbuf.h> 41138568Ssam#include <sys/malloc.h> 42138568Ssam#include <sys/kernel.h> 43138568Ssam#include <sys/module.h> 44138568Ssam#include <sys/endian.h> 45138568Ssam 46138568Ssam#include <sys/socket.h> 47138568Ssam 48138568Ssam#include <net/if.h> 49138568Ssam#include <net/if_media.h> 50138568Ssam#include <net/ethernet.h> 51138568Ssam 52138568Ssam#include <net80211/ieee80211_var.h> 53138568Ssam 54178354Ssamstatic void *tkip_attach(struct ieee80211vap *, struct ieee80211_key *); 55138568Ssamstatic void tkip_detach(struct ieee80211_key *); 56138568Ssamstatic int tkip_setkey(struct ieee80211_key *); 57170530Ssamstatic int tkip_encap(struct ieee80211_key *, struct mbuf *m, uint8_t keyid); 58147045Ssamstatic int tkip_enmic(struct ieee80211_key *, struct mbuf *, int); 59147252Ssamstatic int tkip_decap(struct ieee80211_key *, struct mbuf *, int); 60147045Ssamstatic int tkip_demic(struct ieee80211_key *, struct mbuf *, int); 61138568Ssam 62138568Ssamstatic const struct ieee80211_cipher tkip = { 63138568Ssam .ic_name = "TKIP", 64138568Ssam .ic_cipher = IEEE80211_CIPHER_TKIP, 65138568Ssam .ic_header = IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN + 66138568Ssam IEEE80211_WEP_EXTIVLEN, 67138568Ssam .ic_trailer = IEEE80211_WEP_CRCLEN, 68138568Ssam .ic_miclen = IEEE80211_WEP_MICLEN, 69138568Ssam .ic_attach = tkip_attach, 70138568Ssam .ic_detach = tkip_detach, 71138568Ssam .ic_setkey = tkip_setkey, 72138568Ssam .ic_encap = tkip_encap, 73138568Ssam .ic_decap = tkip_decap, 74138568Ssam .ic_enmic = tkip_enmic, 75138568Ssam .ic_demic = tkip_demic, 76138568Ssam}; 77138568Ssam 78138568Ssamtypedef uint8_t u8; 79138568Ssamtypedef uint16_t u16; 80138568Ssamtypedef uint32_t __u32; 81138568Ssamtypedef uint32_t u32; 82138568Ssam 83138568Ssamstruct tkip_ctx { 84178354Ssam struct ieee80211vap *tc_vap; /* for diagnostics+statistics */ 85138568Ssam 86138568Ssam u16 tx_ttak[5]; 87138568Ssam int tx_phase1_done; 88138568Ssam u8 tx_rc4key[16]; /* XXX for test module; make locals? */ 89138568Ssam 90138568Ssam u16 rx_ttak[5]; 91138568Ssam int rx_phase1_done; 92138568Ssam u8 rx_rc4key[16]; /* XXX for test module; make locals? */ 93138568Ssam uint64_t rx_rsc; /* held until MIC verified */ 94138568Ssam}; 95138568Ssam 96138568Ssamstatic void michael_mic(struct tkip_ctx *, const u8 *key, 97138568Ssam struct mbuf *m, u_int off, size_t data_len, 98138568Ssam u8 mic[IEEE80211_WEP_MICLEN]); 99138568Ssamstatic int tkip_encrypt(struct tkip_ctx *, struct ieee80211_key *, 100138568Ssam struct mbuf *, int hdr_len); 101138568Ssamstatic int tkip_decrypt(struct tkip_ctx *, struct ieee80211_key *, 102138568Ssam struct mbuf *, int hdr_len); 103138568Ssam 104153353Ssam/* number of references from net80211 layer */ 105153353Ssamstatic int nrefs = 0; 106153353Ssam 107138568Ssamstatic void * 108178354Ssamtkip_attach(struct ieee80211vap *vap, struct ieee80211_key *k) 109138568Ssam{ 110138568Ssam struct tkip_ctx *ctx; 111138568Ssam 112186302Ssam ctx = (struct tkip_ctx *) malloc(sizeof(struct tkip_ctx), 113178354Ssam M_80211_CRYPTO, M_NOWAIT | M_ZERO); 114138568Ssam if (ctx == NULL) { 115178354Ssam vap->iv_stats.is_crypto_nomem++; 116138568Ssam return NULL; 117138568Ssam } 118138568Ssam 119178354Ssam ctx->tc_vap = vap; 120153353Ssam nrefs++; /* NB: we assume caller locking */ 121138568Ssam return ctx; 122138568Ssam} 123138568Ssam 124138568Ssamstatic void 125138568Ssamtkip_detach(struct ieee80211_key *k) 126138568Ssam{ 127138568Ssam struct tkip_ctx *ctx = k->wk_private; 128138568Ssam 129186302Ssam free(ctx, M_80211_CRYPTO); 130153353Ssam KASSERT(nrefs > 0, ("imbalanced attach/detach")); 131153353Ssam nrefs--; /* NB: we assume caller locking */ 132138568Ssam} 133138568Ssam 134138568Ssamstatic int 135138568Ssamtkip_setkey(struct ieee80211_key *k) 136138568Ssam{ 137138568Ssam struct tkip_ctx *ctx = k->wk_private; 138138568Ssam 139138568Ssam if (k->wk_keylen != (128/NBBY)) { 140138568Ssam (void) ctx; /* XXX */ 141178354Ssam IEEE80211_DPRINTF(ctx->tc_vap, IEEE80211_MSG_CRYPTO, 142138568Ssam "%s: Invalid key length %u, expecting %u\n", 143138568Ssam __func__, k->wk_keylen, 128/NBBY); 144138568Ssam return 0; 145138568Ssam } 146138568Ssam k->wk_keytsc = 1; /* TSC starts at 1 */ 147203673Sbschmidt ctx->rx_phase1_done = 0; 148138568Ssam return 1; 149138568Ssam} 150138568Ssam 151138568Ssam/* 152138568Ssam * Add privacy headers and do any s/w encryption required. 153138568Ssam */ 154138568Ssamstatic int 155170530Ssamtkip_encap(struct ieee80211_key *k, struct mbuf *m, uint8_t keyid) 156138568Ssam{ 157138568Ssam struct tkip_ctx *ctx = k->wk_private; 158178354Ssam struct ieee80211vap *vap = ctx->tc_vap; 159178354Ssam struct ieee80211com *ic = vap->iv_ic; 160170530Ssam uint8_t *ivp; 161138568Ssam int hdrlen; 162138568Ssam 163138568Ssam /* 164138568Ssam * Handle TKIP counter measures requirement. 165138568Ssam */ 166178354Ssam if (vap->iv_flags & IEEE80211_F_COUNTERM) { 167138568Ssam#ifdef IEEE80211_DEBUG 168138568Ssam struct ieee80211_frame *wh = mtod(m, struct ieee80211_frame *); 169138568Ssam#endif 170138568Ssam 171178354Ssam IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO, wh->i_addr2, 172178354Ssam "discard frame due to countermeasures (%s)", __func__); 173178354Ssam vap->iv_stats.is_crypto_tkipcm++; 174138568Ssam return 0; 175138568Ssam } 176139508Ssam hdrlen = ieee80211_hdrspace(ic, mtod(m, void *)); 177138568Ssam 178138568Ssam /* 179138568Ssam * Copy down 802.11 header and add the IV, KeyID, and ExtIV. 180138568Ssam */ 181138568Ssam M_PREPEND(m, tkip.ic_header, M_NOWAIT); 182138568Ssam if (m == NULL) 183138568Ssam return 0; 184170530Ssam ivp = mtod(m, uint8_t *); 185138568Ssam memmove(ivp, ivp + tkip.ic_header, hdrlen); 186138568Ssam ivp += hdrlen; 187138568Ssam 188138568Ssam ivp[0] = k->wk_keytsc >> 8; /* TSC1 */ 189138568Ssam ivp[1] = (ivp[0] | 0x20) & 0x7f; /* WEP seed */ 190138568Ssam ivp[2] = k->wk_keytsc >> 0; /* TSC0 */ 191138568Ssam ivp[3] = keyid | IEEE80211_WEP_EXTIV; /* KeyID | ExtID */ 192138568Ssam ivp[4] = k->wk_keytsc >> 16; /* TSC2 */ 193138568Ssam ivp[5] = k->wk_keytsc >> 24; /* TSC3 */ 194138568Ssam ivp[6] = k->wk_keytsc >> 32; /* TSC4 */ 195138568Ssam ivp[7] = k->wk_keytsc >> 40; /* TSC5 */ 196138568Ssam 197138568Ssam /* 198138568Ssam * Finally, do software encrypt if neeed. 199138568Ssam */ 200179394Ssam if (k->wk_flags & IEEE80211_KEY_SWENCRYPT) { 201138568Ssam if (!tkip_encrypt(ctx, k, m, hdrlen)) 202138568Ssam return 0; 203138568Ssam /* NB: tkip_encrypt handles wk_keytsc */ 204138568Ssam } else 205139510Ssam k->wk_keytsc++; 206138568Ssam 207138568Ssam return 1; 208138568Ssam} 209138568Ssam 210138568Ssam/* 211138568Ssam * Add MIC to the frame as needed. 212138568Ssam */ 213138568Ssamstatic int 214147045Ssamtkip_enmic(struct ieee80211_key *k, struct mbuf *m, int force) 215138568Ssam{ 216138568Ssam struct tkip_ctx *ctx = k->wk_private; 217138568Ssam 218179394Ssam if (force || (k->wk_flags & IEEE80211_KEY_SWENMIC)) { 219138568Ssam struct ieee80211_frame *wh = mtod(m, struct ieee80211_frame *); 220178354Ssam struct ieee80211vap *vap = ctx->tc_vap; 221178354Ssam struct ieee80211com *ic = vap->iv_ic; 222139508Ssam int hdrlen; 223138568Ssam uint8_t mic[IEEE80211_WEP_MICLEN]; 224138568Ssam 225178354Ssam vap->iv_stats.is_crypto_tkipenmic++; 226138568Ssam 227139508Ssam hdrlen = ieee80211_hdrspace(ic, wh); 228139508Ssam 229138568Ssam michael_mic(ctx, k->wk_txmic, 230138568Ssam m, hdrlen, m->m_pkthdr.len - hdrlen, mic); 231138568Ssam return m_append(m, tkip.ic_miclen, mic); 232138568Ssam } 233138568Ssam return 1; 234138568Ssam} 235138568Ssam 236138568Ssamstatic __inline uint64_t 237138568SsamREAD_6(uint8_t b0, uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4, uint8_t b5) 238138568Ssam{ 239138568Ssam uint32_t iv32 = (b0 << 0) | (b1 << 8) | (b2 << 16) | (b3 << 24); 240138568Ssam uint16_t iv16 = (b4 << 0) | (b5 << 8); 241138568Ssam return (((uint64_t)iv16) << 32) | iv32; 242138568Ssam} 243138568Ssam 244138568Ssam/* 245138568Ssam * Validate and strip privacy headers (and trailer) for a 246138568Ssam * received frame. If necessary, decrypt the frame using 247138568Ssam * the specified key. 248138568Ssam */ 249138568Ssamstatic int 250147252Ssamtkip_decap(struct ieee80211_key *k, struct mbuf *m, int hdrlen) 251138568Ssam{ 252138568Ssam struct tkip_ctx *ctx = k->wk_private; 253178354Ssam struct ieee80211vap *vap = ctx->tc_vap; 254138568Ssam struct ieee80211_frame *wh; 255178354Ssam uint8_t *ivp, tid; 256138568Ssam 257138568Ssam /* 258138568Ssam * Header should have extended IV and sequence number; 259138568Ssam * verify the former and validate the latter. 260138568Ssam */ 261138568Ssam wh = mtod(m, struct ieee80211_frame *); 262138568Ssam ivp = mtod(m, uint8_t *) + hdrlen; 263138568Ssam if ((ivp[IEEE80211_WEP_IVLEN] & IEEE80211_WEP_EXTIV) == 0) { 264138568Ssam /* 265138568Ssam * No extended IV; discard frame. 266138568Ssam */ 267178354Ssam IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO, wh->i_addr2, 268178354Ssam "%s", "missing ExtIV for TKIP cipher"); 269178354Ssam vap->iv_stats.is_rx_tkipformat++; 270138568Ssam return 0; 271138568Ssam } 272138568Ssam /* 273138568Ssam * Handle TKIP counter measures requirement. 274138568Ssam */ 275178354Ssam if (vap->iv_flags & IEEE80211_F_COUNTERM) { 276178354Ssam IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO, wh->i_addr2, 277178354Ssam "discard frame due to countermeasures (%s)", __func__); 278178354Ssam vap->iv_stats.is_crypto_tkipcm++; 279138568Ssam return 0; 280138568Ssam } 281138568Ssam 282178354Ssam tid = ieee80211_gettid(wh); 283139510Ssam ctx->rx_rsc = READ_6(ivp[2], ivp[0], ivp[4], ivp[5], ivp[6], ivp[7]); 284178354Ssam if (ctx->rx_rsc <= k->wk_keyrsc[tid]) { 285138568Ssam /* 286138568Ssam * Replay violation; notify upper layer. 287138568Ssam */ 288193541Ssam ieee80211_notify_replay_failure(vap, wh, k, ctx->rx_rsc, tid); 289178354Ssam vap->iv_stats.is_rx_tkipreplay++; 290138568Ssam return 0; 291138568Ssam } 292138568Ssam /* 293138568Ssam * NB: We can't update the rsc in the key until MIC is verified. 294138568Ssam * 295138568Ssam * We assume we are not preempted between doing the check above 296138568Ssam * and updating wk_keyrsc when stripping the MIC in tkip_demic. 297138568Ssam * Otherwise we might process another packet and discard it as 298138568Ssam * a replay. 299138568Ssam */ 300138568Ssam 301138568Ssam /* 302138568Ssam * Check if the device handled the decrypt in hardware. 303138568Ssam * If so we just strip the header; otherwise we need to 304138568Ssam * handle the decrypt in software. 305138568Ssam */ 306179394Ssam if ((k->wk_flags & IEEE80211_KEY_SWDECRYPT) && 307138568Ssam !tkip_decrypt(ctx, k, m, hdrlen)) 308138568Ssam return 0; 309138568Ssam 310138568Ssam /* 311138568Ssam * Copy up 802.11 header and strip crypto bits. 312138568Ssam */ 313138568Ssam memmove(mtod(m, uint8_t *) + tkip.ic_header, mtod(m, void *), hdrlen); 314138568Ssam m_adj(m, tkip.ic_header); 315138568Ssam m_adj(m, -tkip.ic_trailer); 316138568Ssam 317138568Ssam return 1; 318138568Ssam} 319138568Ssam 320138568Ssam/* 321138568Ssam * Verify and strip MIC from the frame. 322138568Ssam */ 323138568Ssamstatic int 324147045Ssamtkip_demic(struct ieee80211_key *k, struct mbuf *m, int force) 325138568Ssam{ 326138568Ssam struct tkip_ctx *ctx = k->wk_private; 327178354Ssam struct ieee80211_frame *wh; 328178354Ssam uint8_t tid; 329138568Ssam 330178354Ssam wh = mtod(m, struct ieee80211_frame *); 331179394Ssam if ((k->wk_flags & IEEE80211_KEY_SWDEMIC) || force) { 332178354Ssam struct ieee80211vap *vap = ctx->tc_vap; 333178354Ssam int hdrlen = ieee80211_hdrspace(vap->iv_ic, wh); 334138568Ssam u8 mic[IEEE80211_WEP_MICLEN]; 335138568Ssam u8 mic0[IEEE80211_WEP_MICLEN]; 336138568Ssam 337178354Ssam vap->iv_stats.is_crypto_tkipdemic++; 338138568Ssam 339138568Ssam michael_mic(ctx, k->wk_rxmic, 340138568Ssam m, hdrlen, m->m_pkthdr.len - (hdrlen + tkip.ic_miclen), 341138568Ssam mic); 342138568Ssam m_copydata(m, m->m_pkthdr.len - tkip.ic_miclen, 343138568Ssam tkip.ic_miclen, mic0); 344138568Ssam if (memcmp(mic, mic0, tkip.ic_miclen)) { 345138568Ssam /* NB: 802.11 layer handles statistic and debug msg */ 346178354Ssam ieee80211_notify_michael_failure(vap, wh, 347148863Ssam k->wk_rxkeyix != IEEE80211_KEYIX_NONE ? 348148863Ssam k->wk_rxkeyix : k->wk_keyix); 349138568Ssam return 0; 350138568Ssam } 351138568Ssam } 352138568Ssam /* 353138568Ssam * Strip MIC from the tail. 354138568Ssam */ 355138568Ssam m_adj(m, -tkip.ic_miclen); 356138568Ssam 357138568Ssam /* 358138568Ssam * Ok to update rsc now that MIC has been verified. 359138568Ssam */ 360178354Ssam tid = ieee80211_gettid(wh); 361178354Ssam k->wk_keyrsc[tid] = ctx->rx_rsc; 362138568Ssam 363138568Ssam return 1; 364138568Ssam} 365138568Ssam 366138568Ssam/* 367138568Ssam * Host AP crypt: host-based TKIP encryption implementation for Host AP driver 368138568Ssam * 369138568Ssam * Copyright (c) 2003-2004, Jouni Malinen <jkmaline@cc.hut.fi> 370138568Ssam * 371138568Ssam * This program is free software; you can redistribute it and/or modify 372138568Ssam * it under the terms of the GNU General Public License version 2 as 373138568Ssam * published by the Free Software Foundation. See README and COPYING for 374138568Ssam * more details. 375138568Ssam * 376138568Ssam * Alternatively, this software may be distributed under the terms of BSD 377138568Ssam * license. 378138568Ssam */ 379138568Ssam 380138568Ssamstatic const __u32 crc32_table[256] = { 381138568Ssam 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, 382138568Ssam 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, 383138568Ssam 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, 384138568Ssam 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, 385138568Ssam 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, 386138568Ssam 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, 387138568Ssam 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, 388138568Ssam 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, 389138568Ssam 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, 390138568Ssam 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, 391138568Ssam 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, 392138568Ssam 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, 393138568Ssam 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L, 394138568Ssam 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, 395138568Ssam 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, 396138568Ssam 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, 397138568Ssam 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, 398138568Ssam 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, 399138568Ssam 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, 400138568Ssam 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, 401138568Ssam 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, 402138568Ssam 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, 403138568Ssam 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, 404138568Ssam 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, 405138568Ssam 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, 406138568Ssam 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L, 407138568Ssam 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, 408138568Ssam 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, 409138568Ssam 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L, 410138568Ssam 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, 411138568Ssam 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, 412138568Ssam 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, 413138568Ssam 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, 414138568Ssam 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, 415138568Ssam 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, 416138568Ssam 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, 417138568Ssam 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL, 418138568Ssam 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, 419138568Ssam 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, 420138568Ssam 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, 421138568Ssam 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, 422138568Ssam 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, 423138568Ssam 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, 424138568Ssam 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, 425138568Ssam 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, 426138568Ssam 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, 427138568Ssam 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, 428138568Ssam 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, 429138568Ssam 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, 430138568Ssam 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L, 431138568Ssam 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, 432138568Ssam 0x2d02ef8dL 433138568Ssam}; 434138568Ssam 435138568Ssamstatic __inline u16 RotR1(u16 val) 436138568Ssam{ 437138568Ssam return (val >> 1) | (val << 15); 438138568Ssam} 439138568Ssam 440138568Ssamstatic __inline u8 Lo8(u16 val) 441138568Ssam{ 442138568Ssam return val & 0xff; 443138568Ssam} 444138568Ssam 445138568Ssamstatic __inline u8 Hi8(u16 val) 446138568Ssam{ 447138568Ssam return val >> 8; 448138568Ssam} 449138568Ssam 450138568Ssamstatic __inline u16 Lo16(u32 val) 451138568Ssam{ 452138568Ssam return val & 0xffff; 453138568Ssam} 454138568Ssam 455138568Ssamstatic __inline u16 Hi16(u32 val) 456138568Ssam{ 457138568Ssam return val >> 16; 458138568Ssam} 459138568Ssam 460138568Ssamstatic __inline u16 Mk16(u8 hi, u8 lo) 461138568Ssam{ 462138568Ssam return lo | (((u16) hi) << 8); 463138568Ssam} 464138568Ssam 465138568Ssamstatic __inline u16 Mk16_le(const u16 *v) 466138568Ssam{ 467138568Ssam return le16toh(*v); 468138568Ssam} 469138568Ssam 470138568Ssamstatic const u16 Sbox[256] = { 471138568Ssam 0xC6A5, 0xF884, 0xEE99, 0xF68D, 0xFF0D, 0xD6BD, 0xDEB1, 0x9154, 472138568Ssam 0x6050, 0x0203, 0xCEA9, 0x567D, 0xE719, 0xB562, 0x4DE6, 0xEC9A, 473138568Ssam 0x8F45, 0x1F9D, 0x8940, 0xFA87, 0xEF15, 0xB2EB, 0x8EC9, 0xFB0B, 474138568Ssam 0x41EC, 0xB367, 0x5FFD, 0x45EA, 0x23BF, 0x53F7, 0xE496, 0x9B5B, 475138568Ssam 0x75C2, 0xE11C, 0x3DAE, 0x4C6A, 0x6C5A, 0x7E41, 0xF502, 0x834F, 476138568Ssam 0x685C, 0x51F4, 0xD134, 0xF908, 0xE293, 0xAB73, 0x6253, 0x2A3F, 477138568Ssam 0x080C, 0x9552, 0x4665, 0x9D5E, 0x3028, 0x37A1, 0x0A0F, 0x2FB5, 478138568Ssam 0x0E09, 0x2436, 0x1B9B, 0xDF3D, 0xCD26, 0x4E69, 0x7FCD, 0xEA9F, 479138568Ssam 0x121B, 0x1D9E, 0x5874, 0x342E, 0x362D, 0xDCB2, 0xB4EE, 0x5BFB, 480138568Ssam 0xA4F6, 0x764D, 0xB761, 0x7DCE, 0x527B, 0xDD3E, 0x5E71, 0x1397, 481138568Ssam 0xA6F5, 0xB968, 0x0000, 0xC12C, 0x4060, 0xE31F, 0x79C8, 0xB6ED, 482138568Ssam 0xD4BE, 0x8D46, 0x67D9, 0x724B, 0x94DE, 0x98D4, 0xB0E8, 0x854A, 483138568Ssam 0xBB6B, 0xC52A, 0x4FE5, 0xED16, 0x86C5, 0x9AD7, 0x6655, 0x1194, 484138568Ssam 0x8ACF, 0xE910, 0x0406, 0xFE81, 0xA0F0, 0x7844, 0x25BA, 0x4BE3, 485138568Ssam 0xA2F3, 0x5DFE, 0x80C0, 0x058A, 0x3FAD, 0x21BC, 0x7048, 0xF104, 486138568Ssam 0x63DF, 0x77C1, 0xAF75, 0x4263, 0x2030, 0xE51A, 0xFD0E, 0xBF6D, 487138568Ssam 0x814C, 0x1814, 0x2635, 0xC32F, 0xBEE1, 0x35A2, 0x88CC, 0x2E39, 488138568Ssam 0x9357, 0x55F2, 0xFC82, 0x7A47, 0xC8AC, 0xBAE7, 0x322B, 0xE695, 489138568Ssam 0xC0A0, 0x1998, 0x9ED1, 0xA37F, 0x4466, 0x547E, 0x3BAB, 0x0B83, 490138568Ssam 0x8CCA, 0xC729, 0x6BD3, 0x283C, 0xA779, 0xBCE2, 0x161D, 0xAD76, 491138568Ssam 0xDB3B, 0x6456, 0x744E, 0x141E, 0x92DB, 0x0C0A, 0x486C, 0xB8E4, 492138568Ssam 0x9F5D, 0xBD6E, 0x43EF, 0xC4A6, 0x39A8, 0x31A4, 0xD337, 0xF28B, 493138568Ssam 0xD532, 0x8B43, 0x6E59, 0xDAB7, 0x018C, 0xB164, 0x9CD2, 0x49E0, 494138568Ssam 0xD8B4, 0xACFA, 0xF307, 0xCF25, 0xCAAF, 0xF48E, 0x47E9, 0x1018, 495138568Ssam 0x6FD5, 0xF088, 0x4A6F, 0x5C72, 0x3824, 0x57F1, 0x73C7, 0x9751, 496138568Ssam 0xCB23, 0xA17C, 0xE89C, 0x3E21, 0x96DD, 0x61DC, 0x0D86, 0x0F85, 497138568Ssam 0xE090, 0x7C42, 0x71C4, 0xCCAA, 0x90D8, 0x0605, 0xF701, 0x1C12, 498138568Ssam 0xC2A3, 0x6A5F, 0xAEF9, 0x69D0, 0x1791, 0x9958, 0x3A27, 0x27B9, 499138568Ssam 0xD938, 0xEB13, 0x2BB3, 0x2233, 0xD2BB, 0xA970, 0x0789, 0x33A7, 500138568Ssam 0x2DB6, 0x3C22, 0x1592, 0xC920, 0x8749, 0xAAFF, 0x5078, 0xA57A, 501138568Ssam 0x038F, 0x59F8, 0x0980, 0x1A17, 0x65DA, 0xD731, 0x84C6, 0xD0B8, 502138568Ssam 0x82C3, 0x29B0, 0x5A77, 0x1E11, 0x7BCB, 0xA8FC, 0x6DD6, 0x2C3A, 503138568Ssam}; 504138568Ssam 505138568Ssamstatic __inline u16 _S_(u16 v) 506138568Ssam{ 507138568Ssam u16 t = Sbox[Hi8(v)]; 508138568Ssam return Sbox[Lo8(v)] ^ ((t << 8) | (t >> 8)); 509138568Ssam} 510138568Ssam 511138568Ssam#define PHASE1_LOOP_COUNT 8 512138568Ssam 513138568Ssamstatic void tkip_mixing_phase1(u16 *TTAK, const u8 *TK, const u8 *TA, u32 IV32) 514138568Ssam{ 515138568Ssam int i, j; 516138568Ssam 517138568Ssam /* Initialize the 80-bit TTAK from TSC (IV32) and TA[0..5] */ 518138568Ssam TTAK[0] = Lo16(IV32); 519138568Ssam TTAK[1] = Hi16(IV32); 520138568Ssam TTAK[2] = Mk16(TA[1], TA[0]); 521138568Ssam TTAK[3] = Mk16(TA[3], TA[2]); 522138568Ssam TTAK[4] = Mk16(TA[5], TA[4]); 523138568Ssam 524138568Ssam for (i = 0; i < PHASE1_LOOP_COUNT; i++) { 525138568Ssam j = 2 * (i & 1); 526138568Ssam TTAK[0] += _S_(TTAK[4] ^ Mk16(TK[1 + j], TK[0 + j])); 527138568Ssam TTAK[1] += _S_(TTAK[0] ^ Mk16(TK[5 + j], TK[4 + j])); 528138568Ssam TTAK[2] += _S_(TTAK[1] ^ Mk16(TK[9 + j], TK[8 + j])); 529138568Ssam TTAK[3] += _S_(TTAK[2] ^ Mk16(TK[13 + j], TK[12 + j])); 530138568Ssam TTAK[4] += _S_(TTAK[3] ^ Mk16(TK[1 + j], TK[0 + j])) + i; 531138568Ssam } 532138568Ssam} 533138568Ssam 534138568Ssam#ifndef _BYTE_ORDER 535138568Ssam#error "Don't know native byte order" 536138568Ssam#endif 537138568Ssam 538138568Ssamstatic void tkip_mixing_phase2(u8 *WEPSeed, const u8 *TK, const u16 *TTAK, 539138568Ssam u16 IV16) 540138568Ssam{ 541138568Ssam /* Make temporary area overlap WEP seed so that the final copy can be 542138568Ssam * avoided on little endian hosts. */ 543138568Ssam u16 *PPK = (u16 *) &WEPSeed[4]; 544138568Ssam 545138568Ssam /* Step 1 - make copy of TTAK and bring in TSC */ 546138568Ssam PPK[0] = TTAK[0]; 547138568Ssam PPK[1] = TTAK[1]; 548138568Ssam PPK[2] = TTAK[2]; 549138568Ssam PPK[3] = TTAK[3]; 550138568Ssam PPK[4] = TTAK[4]; 551138568Ssam PPK[5] = TTAK[4] + IV16; 552138568Ssam 553138568Ssam /* Step 2 - 96-bit bijective mixing using S-box */ 554138568Ssam PPK[0] += _S_(PPK[5] ^ Mk16_le((const u16 *) &TK[0])); 555138568Ssam PPK[1] += _S_(PPK[0] ^ Mk16_le((const u16 *) &TK[2])); 556138568Ssam PPK[2] += _S_(PPK[1] ^ Mk16_le((const u16 *) &TK[4])); 557138568Ssam PPK[3] += _S_(PPK[2] ^ Mk16_le((const u16 *) &TK[6])); 558138568Ssam PPK[4] += _S_(PPK[3] ^ Mk16_le((const u16 *) &TK[8])); 559138568Ssam PPK[5] += _S_(PPK[4] ^ Mk16_le((const u16 *) &TK[10])); 560138568Ssam 561138568Ssam PPK[0] += RotR1(PPK[5] ^ Mk16_le((const u16 *) &TK[12])); 562138568Ssam PPK[1] += RotR1(PPK[0] ^ Mk16_le((const u16 *) &TK[14])); 563138568Ssam PPK[2] += RotR1(PPK[1]); 564138568Ssam PPK[3] += RotR1(PPK[2]); 565138568Ssam PPK[4] += RotR1(PPK[3]); 566138568Ssam PPK[5] += RotR1(PPK[4]); 567138568Ssam 568138568Ssam /* Step 3 - bring in last of TK bits, assign 24-bit WEP IV value 569138568Ssam * WEPSeed[0..2] is transmitted as WEP IV */ 570138568Ssam WEPSeed[0] = Hi8(IV16); 571138568Ssam WEPSeed[1] = (Hi8(IV16) | 0x20) & 0x7F; 572138568Ssam WEPSeed[2] = Lo8(IV16); 573138568Ssam WEPSeed[3] = Lo8((PPK[5] ^ Mk16_le((const u16 *) &TK[0])) >> 1); 574138568Ssam 575138568Ssam#if _BYTE_ORDER == _BIG_ENDIAN 576138568Ssam { 577138568Ssam int i; 578138568Ssam for (i = 0; i < 6; i++) 579138568Ssam PPK[i] = (PPK[i] << 8) | (PPK[i] >> 8); 580138568Ssam } 581138568Ssam#endif 582138568Ssam} 583138568Ssam 584138568Ssamstatic void 585138568Ssamwep_encrypt(u8 *key, struct mbuf *m0, u_int off, size_t data_len, 586138568Ssam uint8_t icv[IEEE80211_WEP_CRCLEN]) 587138568Ssam{ 588138568Ssam u32 i, j, k, crc; 589138568Ssam size_t buflen; 590138568Ssam u8 S[256]; 591138568Ssam u8 *pos; 592138568Ssam struct mbuf *m; 593138568Ssam#define S_SWAP(a,b) do { u8 t = S[a]; S[a] = S[b]; S[b] = t; } while(0) 594138568Ssam 595138568Ssam /* Setup RC4 state */ 596138568Ssam for (i = 0; i < 256; i++) 597138568Ssam S[i] = i; 598138568Ssam j = 0; 599138568Ssam for (i = 0; i < 256; i++) { 600138568Ssam j = (j + S[i] + key[i & 0x0f]) & 0xff; 601138568Ssam S_SWAP(i, j); 602138568Ssam } 603138568Ssam 604138568Ssam /* Compute CRC32 over unencrypted data and apply RC4 to data */ 605138568Ssam crc = ~0; 606138568Ssam i = j = 0; 607138568Ssam m = m0; 608138568Ssam pos = mtod(m, uint8_t *) + off; 609138568Ssam buflen = m->m_len - off; 610138568Ssam for (;;) { 611138568Ssam if (buflen > data_len) 612138568Ssam buflen = data_len; 613138568Ssam data_len -= buflen; 614138568Ssam for (k = 0; k < buflen; k++) { 615138568Ssam crc = crc32_table[(crc ^ *pos) & 0xff] ^ (crc >> 8); 616138568Ssam i = (i + 1) & 0xff; 617138568Ssam j = (j + S[i]) & 0xff; 618138568Ssam S_SWAP(i, j); 619138568Ssam *pos++ ^= S[(S[i] + S[j]) & 0xff]; 620138568Ssam } 621138568Ssam m = m->m_next; 622138568Ssam if (m == NULL) { 623138568Ssam KASSERT(data_len == 0, 624138609Ssam ("out of buffers with data_len %zu\n", data_len)); 625138568Ssam break; 626138568Ssam } 627138568Ssam pos = mtod(m, uint8_t *); 628138568Ssam buflen = m->m_len; 629138568Ssam } 630138568Ssam crc = ~crc; 631138568Ssam 632138568Ssam /* Append little-endian CRC32 and encrypt it to produce ICV */ 633138568Ssam icv[0] = crc; 634138568Ssam icv[1] = crc >> 8; 635138568Ssam icv[2] = crc >> 16; 636138568Ssam icv[3] = crc >> 24; 637138568Ssam for (k = 0; k < IEEE80211_WEP_CRCLEN; k++) { 638138568Ssam i = (i + 1) & 0xff; 639138568Ssam j = (j + S[i]) & 0xff; 640138568Ssam S_SWAP(i, j); 641138568Ssam icv[k] ^= S[(S[i] + S[j]) & 0xff]; 642138568Ssam } 643138568Ssam} 644138568Ssam 645138568Ssamstatic int 646138568Ssamwep_decrypt(u8 *key, struct mbuf *m, u_int off, size_t data_len) 647138568Ssam{ 648138568Ssam u32 i, j, k, crc; 649138568Ssam u8 S[256]; 650138568Ssam u8 *pos, icv[4]; 651138568Ssam size_t buflen; 652138568Ssam 653138568Ssam /* Setup RC4 state */ 654138568Ssam for (i = 0; i < 256; i++) 655138568Ssam S[i] = i; 656138568Ssam j = 0; 657138568Ssam for (i = 0; i < 256; i++) { 658138568Ssam j = (j + S[i] + key[i & 0x0f]) & 0xff; 659138568Ssam S_SWAP(i, j); 660138568Ssam } 661138568Ssam 662138568Ssam /* Apply RC4 to data and compute CRC32 over decrypted data */ 663138568Ssam crc = ~0; 664138568Ssam i = j = 0; 665138568Ssam pos = mtod(m, uint8_t *) + off; 666138568Ssam buflen = m->m_len - off; 667138568Ssam for (;;) { 668138568Ssam if (buflen > data_len) 669138568Ssam buflen = data_len; 670138568Ssam data_len -= buflen; 671138568Ssam for (k = 0; k < buflen; k++) { 672138568Ssam i = (i + 1) & 0xff; 673138568Ssam j = (j + S[i]) & 0xff; 674138568Ssam S_SWAP(i, j); 675138568Ssam *pos ^= S[(S[i] + S[j]) & 0xff]; 676138568Ssam crc = crc32_table[(crc ^ *pos) & 0xff] ^ (crc >> 8); 677138568Ssam pos++; 678138568Ssam } 679138568Ssam m = m->m_next; 680138568Ssam if (m == NULL) { 681138568Ssam KASSERT(data_len == 0, 682138609Ssam ("out of buffers with data_len %zu\n", data_len)); 683138568Ssam break; 684138568Ssam } 685138568Ssam pos = mtod(m, uint8_t *); 686138568Ssam buflen = m->m_len; 687138568Ssam } 688138568Ssam crc = ~crc; 689138568Ssam 690138568Ssam /* Encrypt little-endian CRC32 and verify that it matches with the 691138568Ssam * received ICV */ 692138568Ssam icv[0] = crc; 693138568Ssam icv[1] = crc >> 8; 694138568Ssam icv[2] = crc >> 16; 695138568Ssam icv[3] = crc >> 24; 696138568Ssam for (k = 0; k < 4; k++) { 697138568Ssam i = (i + 1) & 0xff; 698138568Ssam j = (j + S[i]) & 0xff; 699138568Ssam S_SWAP(i, j); 700138568Ssam if ((icv[k] ^ S[(S[i] + S[j]) & 0xff]) != *pos++) { 701138568Ssam /* ICV mismatch - drop frame */ 702138568Ssam return -1; 703138568Ssam } 704138568Ssam } 705138568Ssam 706138568Ssam return 0; 707138568Ssam} 708138568Ssam 709138568Ssam 710138568Ssamstatic __inline u32 rotl(u32 val, int bits) 711138568Ssam{ 712138568Ssam return (val << bits) | (val >> (32 - bits)); 713138568Ssam} 714138568Ssam 715138568Ssam 716138568Ssamstatic __inline u32 rotr(u32 val, int bits) 717138568Ssam{ 718138568Ssam return (val >> bits) | (val << (32 - bits)); 719138568Ssam} 720138568Ssam 721138568Ssam 722138568Ssamstatic __inline u32 xswap(u32 val) 723138568Ssam{ 724138568Ssam return ((val & 0x00ff00ff) << 8) | ((val & 0xff00ff00) >> 8); 725138568Ssam} 726138568Ssam 727138568Ssam 728138568Ssam#define michael_block(l, r) \ 729138568Ssamdo { \ 730138568Ssam r ^= rotl(l, 17); \ 731138568Ssam l += r; \ 732138568Ssam r ^= xswap(l); \ 733138568Ssam l += r; \ 734138568Ssam r ^= rotl(l, 3); \ 735138568Ssam l += r; \ 736138568Ssam r ^= rotr(l, 2); \ 737138568Ssam l += r; \ 738138568Ssam} while (0) 739138568Ssam 740138568Ssam 741138568Ssamstatic __inline u32 get_le32_split(u8 b0, u8 b1, u8 b2, u8 b3) 742138568Ssam{ 743138568Ssam return b0 | (b1 << 8) | (b2 << 16) | (b3 << 24); 744138568Ssam} 745138568Ssam 746138568Ssamstatic __inline u32 get_le32(const u8 *p) 747138568Ssam{ 748138568Ssam return get_le32_split(p[0], p[1], p[2], p[3]); 749138568Ssam} 750138568Ssam 751138568Ssam 752138568Ssamstatic __inline void put_le32(u8 *p, u32 v) 753138568Ssam{ 754138568Ssam p[0] = v; 755138568Ssam p[1] = v >> 8; 756138568Ssam p[2] = v >> 16; 757138568Ssam p[3] = v >> 24; 758138568Ssam} 759138568Ssam 760138568Ssam/* 761138568Ssam * Craft pseudo header used to calculate the MIC. 762138568Ssam */ 763138568Ssamstatic void 764138568Ssammichael_mic_hdr(const struct ieee80211_frame *wh0, uint8_t hdr[16]) 765138568Ssam{ 766138568Ssam const struct ieee80211_frame_addr4 *wh = 767138568Ssam (const struct ieee80211_frame_addr4 *) wh0; 768138568Ssam 769138568Ssam switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) { 770138568Ssam case IEEE80211_FC1_DIR_NODS: 771138568Ssam IEEE80211_ADDR_COPY(hdr, wh->i_addr1); /* DA */ 772138568Ssam IEEE80211_ADDR_COPY(hdr + IEEE80211_ADDR_LEN, wh->i_addr2); 773138568Ssam break; 774138568Ssam case IEEE80211_FC1_DIR_TODS: 775138568Ssam IEEE80211_ADDR_COPY(hdr, wh->i_addr3); /* DA */ 776138568Ssam IEEE80211_ADDR_COPY(hdr + IEEE80211_ADDR_LEN, wh->i_addr2); 777138568Ssam break; 778138568Ssam case IEEE80211_FC1_DIR_FROMDS: 779138568Ssam IEEE80211_ADDR_COPY(hdr, wh->i_addr1); /* DA */ 780138568Ssam IEEE80211_ADDR_COPY(hdr + IEEE80211_ADDR_LEN, wh->i_addr3); 781138568Ssam break; 782138568Ssam case IEEE80211_FC1_DIR_DSTODS: 783138568Ssam IEEE80211_ADDR_COPY(hdr, wh->i_addr3); /* DA */ 784138568Ssam IEEE80211_ADDR_COPY(hdr + IEEE80211_ADDR_LEN, wh->i_addr4); 785138568Ssam break; 786138568Ssam } 787138568Ssam 788139511Ssam if (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_QOS) { 789139511Ssam const struct ieee80211_qosframe *qwh = 790139511Ssam (const struct ieee80211_qosframe *) wh; 791139511Ssam hdr[12] = qwh->i_qos[0] & IEEE80211_QOS_TID; 792139511Ssam } else 793139511Ssam hdr[12] = 0; 794138568Ssam hdr[13] = hdr[14] = hdr[15] = 0; /* reserved */ 795138568Ssam} 796138568Ssam 797138568Ssamstatic void 798138568Ssammichael_mic(struct tkip_ctx *ctx, const u8 *key, 799138568Ssam struct mbuf *m, u_int off, size_t data_len, 800138568Ssam u8 mic[IEEE80211_WEP_MICLEN]) 801138568Ssam{ 802138568Ssam uint8_t hdr[16]; 803138568Ssam u32 l, r; 804138568Ssam const uint8_t *data; 805138568Ssam u_int space; 806138568Ssam 807138568Ssam michael_mic_hdr(mtod(m, struct ieee80211_frame *), hdr); 808138568Ssam 809138568Ssam l = get_le32(key); 810138568Ssam r = get_le32(key + 4); 811138568Ssam 812138568Ssam /* Michael MIC pseudo header: DA, SA, 3 x 0, Priority */ 813138568Ssam l ^= get_le32(hdr); 814138568Ssam michael_block(l, r); 815138568Ssam l ^= get_le32(&hdr[4]); 816138568Ssam michael_block(l, r); 817138568Ssam l ^= get_le32(&hdr[8]); 818138568Ssam michael_block(l, r); 819138568Ssam l ^= get_le32(&hdr[12]); 820138568Ssam michael_block(l, r); 821138568Ssam 822138568Ssam /* first buffer has special handling */ 823138568Ssam data = mtod(m, const uint8_t *) + off; 824138568Ssam space = m->m_len - off; 825138568Ssam for (;;) { 826138568Ssam if (space > data_len) 827138568Ssam space = data_len; 828138568Ssam /* collect 32-bit blocks from current buffer */ 829138568Ssam while (space >= sizeof(uint32_t)) { 830138568Ssam l ^= get_le32(data); 831138568Ssam michael_block(l, r); 832138568Ssam data += sizeof(uint32_t), space -= sizeof(uint32_t); 833138568Ssam data_len -= sizeof(uint32_t); 834138568Ssam } 835182434Ssam /* 836182434Ssam * NB: when space is zero we make one more trip around 837182434Ssam * the loop to advance to the next mbuf where there is 838182434Ssam * data. This handles the case where there are 4*n 839182434Ssam * bytes in an mbuf followed by <4 bytes in a later mbuf. 840182434Ssam * By making an extra trip we'll drop out of the loop 841182434Ssam * with m pointing at the mbuf with 3 bytes and space 842182434Ssam * set as required by the remainder handling below. 843182434Ssam */ 844182434Ssam if (data_len == 0 || 845182434Ssam (data_len < sizeof(uint32_t) && space != 0)) 846138568Ssam break; 847138568Ssam m = m->m_next; 848138568Ssam if (m == NULL) { 849138609Ssam KASSERT(0, ("out of data, data_len %zu\n", data_len)); 850138568Ssam break; 851138568Ssam } 852138568Ssam if (space != 0) { 853138568Ssam const uint8_t *data_next; 854138568Ssam /* 855138568Ssam * Block straddles buffers, split references. 856138568Ssam */ 857138568Ssam data_next = mtod(m, const uint8_t *); 858138568Ssam KASSERT(m->m_len >= sizeof(uint32_t) - space, 859138568Ssam ("not enough data in following buffer, " 860138609Ssam "m_len %u need %zu\n", m->m_len, 861138568Ssam sizeof(uint32_t) - space)); 862138568Ssam switch (space) { 863138568Ssam case 1: 864138568Ssam l ^= get_le32_split(data[0], data_next[0], 865138568Ssam data_next[1], data_next[2]); 866138568Ssam data = data_next + 3; 867138568Ssam space = m->m_len - 3; 868138568Ssam break; 869138568Ssam case 2: 870138568Ssam l ^= get_le32_split(data[0], data[1], 871138568Ssam data_next[0], data_next[1]); 872138568Ssam data = data_next + 2; 873138568Ssam space = m->m_len - 2; 874138568Ssam break; 875138568Ssam case 3: 876138568Ssam l ^= get_le32_split(data[0], data[1], 877138568Ssam data[2], data_next[0]); 878138568Ssam data = data_next + 1; 879138568Ssam space = m->m_len - 1; 880138568Ssam break; 881138568Ssam } 882138568Ssam michael_block(l, r); 883138568Ssam data_len -= sizeof(uint32_t); 884138568Ssam } else { 885138568Ssam /* 886138568Ssam * Setup for next buffer. 887138568Ssam */ 888138568Ssam data = mtod(m, const uint8_t *); 889138568Ssam space = m->m_len; 890138568Ssam } 891138568Ssam } 892182434Ssam /* 893182434Ssam * Catch degenerate cases like mbuf[4*n+1 bytes] followed by 894182434Ssam * mbuf[2 bytes]. I don't believe these should happen; if they 895182434Ssam * do then we'll need more involved logic. 896182434Ssam */ 897182434Ssam KASSERT(data_len <= space, 898182437Savatar ("not enough data, data_len %zu space %u\n", data_len, space)); 899182434Ssam 900138568Ssam /* Last block and padding (0x5a, 4..7 x 0) */ 901138568Ssam switch (data_len) { 902138568Ssam case 0: 903138568Ssam l ^= get_le32_split(0x5a, 0, 0, 0); 904138568Ssam break; 905138568Ssam case 1: 906138568Ssam l ^= get_le32_split(data[0], 0x5a, 0, 0); 907138568Ssam break; 908138568Ssam case 2: 909138568Ssam l ^= get_le32_split(data[0], data[1], 0x5a, 0); 910138568Ssam break; 911138568Ssam case 3: 912138568Ssam l ^= get_le32_split(data[0], data[1], data[2], 0x5a); 913138568Ssam break; 914138568Ssam } 915138568Ssam michael_block(l, r); 916138568Ssam /* l ^= 0; */ 917138568Ssam michael_block(l, r); 918138568Ssam 919138568Ssam put_le32(mic, l); 920138568Ssam put_le32(mic + 4, r); 921138568Ssam} 922138568Ssam 923138568Ssamstatic int 924138568Ssamtkip_encrypt(struct tkip_ctx *ctx, struct ieee80211_key *key, 925138568Ssam struct mbuf *m, int hdrlen) 926138568Ssam{ 927138568Ssam struct ieee80211_frame *wh; 928138568Ssam uint8_t icv[IEEE80211_WEP_CRCLEN]; 929138568Ssam 930178354Ssam ctx->tc_vap->iv_stats.is_crypto_tkip++; 931138568Ssam 932138568Ssam wh = mtod(m, struct ieee80211_frame *); 933138568Ssam if (!ctx->tx_phase1_done) { 934138568Ssam tkip_mixing_phase1(ctx->tx_ttak, key->wk_key, wh->i_addr2, 935138568Ssam (u32)(key->wk_keytsc >> 16)); 936138568Ssam ctx->tx_phase1_done = 1; 937138568Ssam } 938138568Ssam tkip_mixing_phase2(ctx->tx_rc4key, key->wk_key, ctx->tx_ttak, 939138568Ssam (u16) key->wk_keytsc); 940138568Ssam 941138568Ssam wep_encrypt(ctx->tx_rc4key, 942138568Ssam m, hdrlen + tkip.ic_header, 943138568Ssam m->m_pkthdr.len - (hdrlen + tkip.ic_header), 944138568Ssam icv); 945138568Ssam (void) m_append(m, IEEE80211_WEP_CRCLEN, icv); /* XXX check return */ 946138568Ssam 947139510Ssam key->wk_keytsc++; 948138568Ssam if ((u16)(key->wk_keytsc) == 0) 949138568Ssam ctx->tx_phase1_done = 0; 950138568Ssam return 1; 951138568Ssam} 952138568Ssam 953138568Ssamstatic int 954138568Ssamtkip_decrypt(struct tkip_ctx *ctx, struct ieee80211_key *key, 955138568Ssam struct mbuf *m, int hdrlen) 956138568Ssam{ 957138568Ssam struct ieee80211_frame *wh; 958178354Ssam struct ieee80211vap *vap = ctx->tc_vap; 959138568Ssam u32 iv32; 960138568Ssam u16 iv16; 961178354Ssam u8 tid; 962138568Ssam 963178354Ssam vap->iv_stats.is_crypto_tkip++; 964138568Ssam 965138568Ssam wh = mtod(m, struct ieee80211_frame *); 966138568Ssam /* NB: tkip_decap already verified header and left seq in rx_rsc */ 967138568Ssam iv16 = (u16) ctx->rx_rsc; 968138568Ssam iv32 = (u32) (ctx->rx_rsc >> 16); 969138568Ssam 970178354Ssam tid = ieee80211_gettid(wh); 971178354Ssam if (iv32 != (u32)(key->wk_keyrsc[tid] >> 16) || !ctx->rx_phase1_done) { 972138568Ssam tkip_mixing_phase1(ctx->rx_ttak, key->wk_key, 973138568Ssam wh->i_addr2, iv32); 974138568Ssam ctx->rx_phase1_done = 1; 975138568Ssam } 976138568Ssam tkip_mixing_phase2(ctx->rx_rc4key, key->wk_key, ctx->rx_ttak, iv16); 977138568Ssam 978138568Ssam /* NB: m is unstripped; deduct headers + ICV to get payload */ 979138568Ssam if (wep_decrypt(ctx->rx_rc4key, 980138568Ssam m, hdrlen + tkip.ic_header, 981138568Ssam m->m_pkthdr.len - (hdrlen + tkip.ic_header + tkip.ic_trailer))) { 982178354Ssam if (iv32 != (u32)(key->wk_keyrsc[tid] >> 16)) { 983138568Ssam /* Previously cached Phase1 result was already lost, so 984138568Ssam * it needs to be recalculated for the next packet. */ 985138568Ssam ctx->rx_phase1_done = 0; 986138568Ssam } 987178354Ssam IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO, wh->i_addr2, 988178354Ssam "%s", "TKIP ICV mismatch on decrypt"); 989178354Ssam vap->iv_stats.is_rx_tkipicv++; 990138568Ssam return 0; 991138568Ssam } 992138568Ssam return 1; 993138568Ssam} 994138568Ssam 995138568Ssam/* 996138568Ssam * Module glue. 997138568Ssam */ 998170530SsamIEEE80211_CRYPTO_MODULE(tkip, 1); 999