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