18a1b9b6aSSam Leffler /*- 28a1b9b6aSSam Leffler * Copyright (c) 2002-2004 Sam Leffler, Errno Consulting 38a1b9b6aSSam Leffler * All rights reserved. 48a1b9b6aSSam Leffler * 58a1b9b6aSSam Leffler * Redistribution and use in source and binary forms, with or without 68a1b9b6aSSam Leffler * modification, are permitted provided that the following conditions 78a1b9b6aSSam Leffler * are met: 88a1b9b6aSSam Leffler * 1. Redistributions of source code must retain the above copyright 98a1b9b6aSSam Leffler * notice, this list of conditions and the following disclaimer. 108a1b9b6aSSam Leffler * 2. Redistributions in binary form must reproduce the above copyright 118a1b9b6aSSam Leffler * notice, this list of conditions and the following disclaimer in the 128a1b9b6aSSam Leffler * documentation and/or other materials provided with the distribution. 138a1b9b6aSSam Leffler * 3. The name of the author may not be used to endorse or promote products 148a1b9b6aSSam Leffler * derived from this software without specific prior written permission. 158a1b9b6aSSam Leffler * 168a1b9b6aSSam Leffler * Alternatively, this software may be distributed under the terms of the 178a1b9b6aSSam Leffler * GNU General Public License ("GPL") version 2 as published by the Free 188a1b9b6aSSam Leffler * Software Foundation. 198a1b9b6aSSam Leffler * 208a1b9b6aSSam Leffler * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 218a1b9b6aSSam Leffler * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 228a1b9b6aSSam Leffler * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 238a1b9b6aSSam Leffler * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 248a1b9b6aSSam Leffler * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 258a1b9b6aSSam Leffler * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 268a1b9b6aSSam Leffler * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 278a1b9b6aSSam Leffler * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 288a1b9b6aSSam Leffler * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 298a1b9b6aSSam Leffler * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 308a1b9b6aSSam Leffler */ 318a1b9b6aSSam Leffler 328a1b9b6aSSam Leffler #include <sys/cdefs.h> 338a1b9b6aSSam Leffler __FBSDID("$FreeBSD$"); 348a1b9b6aSSam Leffler 358a1b9b6aSSam Leffler /* 368a1b9b6aSSam Leffler * IEEE 802.11i TKIP crypto support. 378a1b9b6aSSam Leffler * 388a1b9b6aSSam Leffler * Part of this module is derived from similar code in the Host 398a1b9b6aSSam Leffler * AP driver. The code is used with the consent of the author and 408a1b9b6aSSam Leffler * it's license is included below. 418a1b9b6aSSam Leffler */ 428a1b9b6aSSam Leffler #include <sys/param.h> 438a1b9b6aSSam Leffler #include <sys/systm.h> 448a1b9b6aSSam Leffler #include <sys/mbuf.h> 458a1b9b6aSSam Leffler #include <sys/malloc.h> 468a1b9b6aSSam Leffler #include <sys/kernel.h> 478a1b9b6aSSam Leffler #include <sys/module.h> 488a1b9b6aSSam Leffler #include <sys/endian.h> 498a1b9b6aSSam Leffler 508a1b9b6aSSam Leffler #include <sys/socket.h> 518a1b9b6aSSam Leffler 528a1b9b6aSSam Leffler #include <net/if.h> 538a1b9b6aSSam Leffler #include <net/if_media.h> 548a1b9b6aSSam Leffler #include <net/ethernet.h> 558a1b9b6aSSam Leffler 568a1b9b6aSSam Leffler #include <net80211/ieee80211_var.h> 578a1b9b6aSSam Leffler 588a1b9b6aSSam Leffler static void *tkip_attach(struct ieee80211com *, struct ieee80211_key *); 598a1b9b6aSSam Leffler static void tkip_detach(struct ieee80211_key *); 608a1b9b6aSSam Leffler static int tkip_setkey(struct ieee80211_key *); 618a1b9b6aSSam Leffler static int tkip_encap(struct ieee80211_key *, struct mbuf *m, u_int8_t keyid); 628a1b9b6aSSam Leffler static int tkip_enmic(struct ieee80211_key *, struct mbuf *); 638a1b9b6aSSam Leffler static int tkip_decap(struct ieee80211_key *, struct mbuf *); 648a1b9b6aSSam Leffler static int tkip_demic(struct ieee80211_key *, struct mbuf *); 658a1b9b6aSSam Leffler 668a1b9b6aSSam Leffler static const struct ieee80211_cipher tkip = { 678a1b9b6aSSam Leffler .ic_name = "TKIP", 688a1b9b6aSSam Leffler .ic_cipher = IEEE80211_CIPHER_TKIP, 698a1b9b6aSSam Leffler .ic_header = IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN + 708a1b9b6aSSam Leffler IEEE80211_WEP_EXTIVLEN, 718a1b9b6aSSam Leffler .ic_trailer = IEEE80211_WEP_CRCLEN, 728a1b9b6aSSam Leffler .ic_miclen = IEEE80211_WEP_MICLEN, 738a1b9b6aSSam Leffler .ic_attach = tkip_attach, 748a1b9b6aSSam Leffler .ic_detach = tkip_detach, 758a1b9b6aSSam Leffler .ic_setkey = tkip_setkey, 768a1b9b6aSSam Leffler .ic_encap = tkip_encap, 778a1b9b6aSSam Leffler .ic_decap = tkip_decap, 788a1b9b6aSSam Leffler .ic_enmic = tkip_enmic, 798a1b9b6aSSam Leffler .ic_demic = tkip_demic, 808a1b9b6aSSam Leffler }; 818a1b9b6aSSam Leffler 828a1b9b6aSSam Leffler typedef uint8_t u8; 838a1b9b6aSSam Leffler typedef uint16_t u16; 848a1b9b6aSSam Leffler typedef uint32_t __u32; 858a1b9b6aSSam Leffler typedef uint32_t u32; 868a1b9b6aSSam Leffler #define memmove(dst, src, n) ovbcopy(src, dst, n) 878a1b9b6aSSam Leffler 888a1b9b6aSSam Leffler struct tkip_ctx { 898a1b9b6aSSam Leffler struct ieee80211com *tc_ic; /* for diagnostics */ 908a1b9b6aSSam Leffler 918a1b9b6aSSam Leffler u16 tx_ttak[5]; 928a1b9b6aSSam Leffler int tx_phase1_done; 938a1b9b6aSSam Leffler u8 tx_rc4key[16]; /* XXX for test module; make locals? */ 948a1b9b6aSSam Leffler 958a1b9b6aSSam Leffler u16 rx_ttak[5]; 968a1b9b6aSSam Leffler int rx_phase1_done; 978a1b9b6aSSam Leffler u8 rx_rc4key[16]; /* XXX for test module; make locals? */ 988a1b9b6aSSam Leffler uint64_t rx_rsc; /* held until MIC verified */ 998a1b9b6aSSam Leffler }; 1008a1b9b6aSSam Leffler 1018a1b9b6aSSam Leffler static void michael_mic(struct tkip_ctx *, const u8 *key, 1028a1b9b6aSSam Leffler struct mbuf *m, u_int off, size_t data_len, 1038a1b9b6aSSam Leffler u8 mic[IEEE80211_WEP_MICLEN]); 1048a1b9b6aSSam Leffler static int tkip_encrypt(struct tkip_ctx *, struct ieee80211_key *, 1058a1b9b6aSSam Leffler struct mbuf *, int hdr_len); 1068a1b9b6aSSam Leffler static int tkip_decrypt(struct tkip_ctx *, struct ieee80211_key *, 1078a1b9b6aSSam Leffler struct mbuf *, int hdr_len); 1088a1b9b6aSSam Leffler 1098a1b9b6aSSam Leffler static void * 1108a1b9b6aSSam Leffler tkip_attach(struct ieee80211com *ic, struct ieee80211_key *k) 1118a1b9b6aSSam Leffler { 1128a1b9b6aSSam Leffler struct tkip_ctx *ctx; 1138a1b9b6aSSam Leffler 1148a1b9b6aSSam Leffler MALLOC(ctx, struct tkip_ctx *, sizeof(struct tkip_ctx), 1158a1b9b6aSSam Leffler M_DEVBUF, M_NOWAIT | M_ZERO); 1168a1b9b6aSSam Leffler if (ctx == NULL) { 1178a1b9b6aSSam Leffler ic->ic_stats.is_crypto_nomem++; 1188a1b9b6aSSam Leffler return NULL; 1198a1b9b6aSSam Leffler } 1208a1b9b6aSSam Leffler 1218a1b9b6aSSam Leffler ctx->tc_ic = ic; 1228a1b9b6aSSam Leffler return ctx; 1238a1b9b6aSSam Leffler } 1248a1b9b6aSSam Leffler 1258a1b9b6aSSam Leffler static void 1268a1b9b6aSSam Leffler tkip_detach(struct ieee80211_key *k) 1278a1b9b6aSSam Leffler { 1288a1b9b6aSSam Leffler struct tkip_ctx *ctx = k->wk_private; 1298a1b9b6aSSam Leffler 1308a1b9b6aSSam Leffler FREE(ctx, M_DEVBUF); 1318a1b9b6aSSam Leffler } 1328a1b9b6aSSam Leffler 1338a1b9b6aSSam Leffler static int 1348a1b9b6aSSam Leffler tkip_setkey(struct ieee80211_key *k) 1358a1b9b6aSSam Leffler { 1368a1b9b6aSSam Leffler struct tkip_ctx *ctx = k->wk_private; 1378a1b9b6aSSam Leffler 1388a1b9b6aSSam Leffler if (k->wk_keylen != (128/NBBY)) { 1398a1b9b6aSSam Leffler (void) ctx; /* XXX */ 1408a1b9b6aSSam Leffler IEEE80211_DPRINTF(ctx->tc_ic, IEEE80211_MSG_CRYPTO, 1418a1b9b6aSSam Leffler "%s: Invalid key length %u, expecting %u\n", 1428a1b9b6aSSam Leffler __func__, k->wk_keylen, 128/NBBY); 1438a1b9b6aSSam Leffler return 0; 1448a1b9b6aSSam Leffler } 1458a1b9b6aSSam Leffler k->wk_keytsc = 1; /* TSC starts at 1 */ 1468a1b9b6aSSam Leffler return 1; 1478a1b9b6aSSam Leffler } 1488a1b9b6aSSam Leffler 1498a1b9b6aSSam Leffler /* 1508a1b9b6aSSam Leffler * Add privacy headers and do any s/w encryption required. 1518a1b9b6aSSam Leffler */ 1528a1b9b6aSSam Leffler static int 1538a1b9b6aSSam Leffler tkip_encap(struct ieee80211_key *k, struct mbuf *m, u_int8_t keyid) 1548a1b9b6aSSam Leffler { 1558a1b9b6aSSam Leffler struct tkip_ctx *ctx = k->wk_private; 1568a1b9b6aSSam Leffler struct ieee80211com *ic = ctx->tc_ic; 1578a1b9b6aSSam Leffler u_int8_t *ivp; 1588a1b9b6aSSam Leffler int hdrlen; 1598a1b9b6aSSam Leffler 1608a1b9b6aSSam Leffler /* 1618a1b9b6aSSam Leffler * Handle TKIP counter measures requirement. 1628a1b9b6aSSam Leffler */ 1638a1b9b6aSSam Leffler if (ic->ic_flags & IEEE80211_F_COUNTERM) { 1648a1b9b6aSSam Leffler #ifdef IEEE80211_DEBUG 1658a1b9b6aSSam Leffler struct ieee80211_frame *wh = mtod(m, struct ieee80211_frame *); 1668a1b9b6aSSam Leffler #endif 1678a1b9b6aSSam Leffler 1688a1b9b6aSSam Leffler IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO, 1698a1b9b6aSSam Leffler "[%s] Discard frame due to countermeasures (%s)\n", 1708a1b9b6aSSam Leffler ether_sprintf(wh->i_addr2), __func__); 1718a1b9b6aSSam Leffler ic->ic_stats.is_crypto_tkipcm++; 1728a1b9b6aSSam Leffler return 0; 1738a1b9b6aSSam Leffler } 1748a1b9b6aSSam Leffler hdrlen = ieee80211_hdrsize(mtod(m, void *)); 1758a1b9b6aSSam Leffler 1768a1b9b6aSSam Leffler /* 1778a1b9b6aSSam Leffler * Copy down 802.11 header and add the IV, KeyID, and ExtIV. 1788a1b9b6aSSam Leffler */ 1798a1b9b6aSSam Leffler M_PREPEND(m, tkip.ic_header, M_NOWAIT); 1808a1b9b6aSSam Leffler if (m == NULL) 1818a1b9b6aSSam Leffler return 0; 1828a1b9b6aSSam Leffler ivp = mtod(m, u_int8_t *); 1838a1b9b6aSSam Leffler memmove(ivp, ivp + tkip.ic_header, hdrlen); 1848a1b9b6aSSam Leffler ivp += hdrlen; 1858a1b9b6aSSam Leffler 1868a1b9b6aSSam Leffler ivp[0] = k->wk_keytsc >> 8; /* TSC1 */ 1878a1b9b6aSSam Leffler ivp[1] = (ivp[0] | 0x20) & 0x7f; /* WEP seed */ 1888a1b9b6aSSam Leffler ivp[2] = k->wk_keytsc >> 0; /* TSC0 */ 1898a1b9b6aSSam Leffler ivp[3] = keyid | IEEE80211_WEP_EXTIV; /* KeyID | ExtID */ 1908a1b9b6aSSam Leffler ivp[4] = k->wk_keytsc >> 16; /* TSC2 */ 1918a1b9b6aSSam Leffler ivp[5] = k->wk_keytsc >> 24; /* TSC3 */ 1928a1b9b6aSSam Leffler ivp[6] = k->wk_keytsc >> 32; /* TSC4 */ 1938a1b9b6aSSam Leffler ivp[7] = k->wk_keytsc >> 40; /* TSC5 */ 1948a1b9b6aSSam Leffler 1958a1b9b6aSSam Leffler /* 1968a1b9b6aSSam Leffler * Finally, do software encrypt if neeed. 1978a1b9b6aSSam Leffler */ 1988a1b9b6aSSam Leffler if (k->wk_flags & IEEE80211_KEY_SWCRYPT) { 1998a1b9b6aSSam Leffler if (!tkip_encrypt(ctx, k, m, hdrlen)) 2008a1b9b6aSSam Leffler return 0; 2018a1b9b6aSSam Leffler /* NB: tkip_encrypt handles wk_keytsc */ 2028a1b9b6aSSam Leffler } else 2038a1b9b6aSSam Leffler k->wk_keytsc++; /* XXX wrap at 48 bits */ 2048a1b9b6aSSam Leffler 2058a1b9b6aSSam Leffler return 1; 2068a1b9b6aSSam Leffler } 2078a1b9b6aSSam Leffler 2088a1b9b6aSSam Leffler /* 2098a1b9b6aSSam Leffler * Add MIC to the frame as needed. 2108a1b9b6aSSam Leffler */ 2118a1b9b6aSSam Leffler static int 2128a1b9b6aSSam Leffler tkip_enmic(struct ieee80211_key *k, struct mbuf *m) 2138a1b9b6aSSam Leffler { 2148a1b9b6aSSam Leffler struct tkip_ctx *ctx = k->wk_private; 2158a1b9b6aSSam Leffler 2168a1b9b6aSSam Leffler if (k->wk_flags & IEEE80211_KEY_SWMIC) { 2178a1b9b6aSSam Leffler struct ieee80211_frame *wh = mtod(m, struct ieee80211_frame *); 2188a1b9b6aSSam Leffler int hdrlen = ieee80211_hdrsize(wh); 2198a1b9b6aSSam Leffler uint8_t mic[IEEE80211_WEP_MICLEN]; 2208a1b9b6aSSam Leffler 2218a1b9b6aSSam Leffler ctx->tc_ic->ic_stats.is_crypto_tkipenmic++; 2228a1b9b6aSSam Leffler 2238a1b9b6aSSam Leffler michael_mic(ctx, k->wk_txmic, 2248a1b9b6aSSam Leffler m, hdrlen, m->m_pkthdr.len - hdrlen, mic); 2258a1b9b6aSSam Leffler return m_append(m, tkip.ic_miclen, mic); 2268a1b9b6aSSam Leffler } 2278a1b9b6aSSam Leffler return 1; 2288a1b9b6aSSam Leffler } 2298a1b9b6aSSam Leffler 2308a1b9b6aSSam Leffler static __inline uint64_t 2318a1b9b6aSSam Leffler READ_6(uint8_t b0, uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4, uint8_t b5) 2328a1b9b6aSSam Leffler { 2338a1b9b6aSSam Leffler uint32_t iv32 = (b0 << 0) | (b1 << 8) | (b2 << 16) | (b3 << 24); 2348a1b9b6aSSam Leffler uint16_t iv16 = (b4 << 0) | (b5 << 8); 2358a1b9b6aSSam Leffler return (((uint64_t)iv16) << 32) | iv32; 2368a1b9b6aSSam Leffler } 2378a1b9b6aSSam Leffler 2388a1b9b6aSSam Leffler /* 2398a1b9b6aSSam Leffler * Validate and strip privacy headers (and trailer) for a 2408a1b9b6aSSam Leffler * received frame. If necessary, decrypt the frame using 2418a1b9b6aSSam Leffler * the specified key. 2428a1b9b6aSSam Leffler */ 2438a1b9b6aSSam Leffler static int 2448a1b9b6aSSam Leffler tkip_decap(struct ieee80211_key *k, struct mbuf *m) 2458a1b9b6aSSam Leffler { 2468a1b9b6aSSam Leffler struct tkip_ctx *ctx = k->wk_private; 2478a1b9b6aSSam Leffler struct ieee80211com *ic = ctx->tc_ic; 2488a1b9b6aSSam Leffler struct ieee80211_frame *wh; 2498a1b9b6aSSam Leffler uint8_t *ivp; 2508a1b9b6aSSam Leffler int hdrlen; 2518a1b9b6aSSam Leffler 2528a1b9b6aSSam Leffler /* 2538a1b9b6aSSam Leffler * Header should have extended IV and sequence number; 2548a1b9b6aSSam Leffler * verify the former and validate the latter. 2558a1b9b6aSSam Leffler */ 2568a1b9b6aSSam Leffler wh = mtod(m, struct ieee80211_frame *); 2578a1b9b6aSSam Leffler hdrlen = ieee80211_hdrsize(wh); 2588a1b9b6aSSam Leffler ivp = mtod(m, uint8_t *) + hdrlen; 2598a1b9b6aSSam Leffler if ((ivp[IEEE80211_WEP_IVLEN] & IEEE80211_WEP_EXTIV) == 0) { 2608a1b9b6aSSam Leffler /* 2618a1b9b6aSSam Leffler * No extended IV; discard frame. 2628a1b9b6aSSam Leffler */ 2638a1b9b6aSSam Leffler IEEE80211_DPRINTF(ctx->tc_ic, IEEE80211_MSG_CRYPTO, 2648a1b9b6aSSam Leffler "[%s] Missing ExtIV for TKIP cipher\n", 2658a1b9b6aSSam Leffler ether_sprintf(wh->i_addr2)); 2668a1b9b6aSSam Leffler ctx->tc_ic->ic_stats.is_rx_tkipformat++; 2678a1b9b6aSSam Leffler return 0; 2688a1b9b6aSSam Leffler } 2698a1b9b6aSSam Leffler /* 2708a1b9b6aSSam Leffler * Handle TKIP counter measures requirement. 2718a1b9b6aSSam Leffler */ 2728a1b9b6aSSam Leffler if (ic->ic_flags & IEEE80211_F_COUNTERM) { 2738a1b9b6aSSam Leffler IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO, 2748a1b9b6aSSam Leffler "[%s] Discard frame due to countermeasures (%s)\n", 2758a1b9b6aSSam Leffler ether_sprintf(wh->i_addr2), __func__); 2768a1b9b6aSSam Leffler ic->ic_stats.is_crypto_tkipcm++; 2778a1b9b6aSSam Leffler return 0; 2788a1b9b6aSSam Leffler } 2798a1b9b6aSSam Leffler 2808a1b9b6aSSam Leffler ctx->rx_rsc = READ_6(ivp[2], ivp[0], ivp[4], ivp[5], 2818a1b9b6aSSam Leffler ivp[6], ivp[7]); 2828a1b9b6aSSam Leffler if (ctx->rx_rsc <= k->wk_keyrsc) { 2838a1b9b6aSSam Leffler /* 2848a1b9b6aSSam Leffler * Replay violation; notify upper layer. 2858a1b9b6aSSam Leffler */ 2868a1b9b6aSSam Leffler ieee80211_notify_replay_failure(ctx->tc_ic, wh, k, ctx->rx_rsc); 2878a1b9b6aSSam Leffler ctx->tc_ic->ic_stats.is_rx_tkipreplay++; 2888a1b9b6aSSam Leffler return 0; 2898a1b9b6aSSam Leffler } 2908a1b9b6aSSam Leffler /* 2918a1b9b6aSSam Leffler * NB: We can't update the rsc in the key until MIC is verified. 2928a1b9b6aSSam Leffler * 2938a1b9b6aSSam Leffler * We assume we are not preempted between doing the check above 2948a1b9b6aSSam Leffler * and updating wk_keyrsc when stripping the MIC in tkip_demic. 2958a1b9b6aSSam Leffler * Otherwise we might process another packet and discard it as 2968a1b9b6aSSam Leffler * a replay. 2978a1b9b6aSSam Leffler */ 2988a1b9b6aSSam Leffler 2998a1b9b6aSSam Leffler /* 3008a1b9b6aSSam Leffler * Check if the device handled the decrypt in hardware. 3018a1b9b6aSSam Leffler * If so we just strip the header; otherwise we need to 3028a1b9b6aSSam Leffler * handle the decrypt in software. 3038a1b9b6aSSam Leffler */ 3048a1b9b6aSSam Leffler if ((k->wk_flags & IEEE80211_KEY_SWCRYPT) && 3058a1b9b6aSSam Leffler !tkip_decrypt(ctx, k, m, hdrlen)) 3068a1b9b6aSSam Leffler return 0; 3078a1b9b6aSSam Leffler 3088a1b9b6aSSam Leffler /* 3098a1b9b6aSSam Leffler * Copy up 802.11 header and strip crypto bits. 3108a1b9b6aSSam Leffler */ 3118a1b9b6aSSam Leffler memmove(mtod(m, uint8_t *) + tkip.ic_header, mtod(m, void *), hdrlen); 3128a1b9b6aSSam Leffler m_adj(m, tkip.ic_header); 3138a1b9b6aSSam Leffler m_adj(m, -tkip.ic_trailer); 3148a1b9b6aSSam Leffler 3158a1b9b6aSSam Leffler return 1; 3168a1b9b6aSSam Leffler } 3178a1b9b6aSSam Leffler 3188a1b9b6aSSam Leffler /* 3198a1b9b6aSSam Leffler * Verify and strip MIC from the frame. 3208a1b9b6aSSam Leffler */ 3218a1b9b6aSSam Leffler static int 3228a1b9b6aSSam Leffler tkip_demic(struct ieee80211_key *k, struct mbuf *m) 3238a1b9b6aSSam Leffler { 3248a1b9b6aSSam Leffler struct tkip_ctx *ctx = k->wk_private; 3258a1b9b6aSSam Leffler 3268a1b9b6aSSam Leffler if (k->wk_flags & IEEE80211_KEY_SWMIC) { 3278a1b9b6aSSam Leffler struct ieee80211_frame *wh = mtod(m, struct ieee80211_frame *); 3288a1b9b6aSSam Leffler int hdrlen = ieee80211_hdrsize(wh); 3298a1b9b6aSSam Leffler u8 mic[IEEE80211_WEP_MICLEN]; 3308a1b9b6aSSam Leffler u8 mic0[IEEE80211_WEP_MICLEN]; 3318a1b9b6aSSam Leffler 3328a1b9b6aSSam Leffler ctx->tc_ic->ic_stats.is_crypto_tkipdemic++; 3338a1b9b6aSSam Leffler 3348a1b9b6aSSam Leffler michael_mic(ctx, k->wk_rxmic, 3358a1b9b6aSSam Leffler m, hdrlen, m->m_pkthdr.len - (hdrlen + tkip.ic_miclen), 3368a1b9b6aSSam Leffler mic); 3378a1b9b6aSSam Leffler m_copydata(m, m->m_pkthdr.len - tkip.ic_miclen, 3388a1b9b6aSSam Leffler tkip.ic_miclen, mic0); 3398a1b9b6aSSam Leffler if (memcmp(mic, mic0, tkip.ic_miclen)) { 3408a1b9b6aSSam Leffler /* NB: 802.11 layer handles statistic and debug msg */ 3418a1b9b6aSSam Leffler ieee80211_notify_michael_failure(ctx->tc_ic, wh, 3428a1b9b6aSSam Leffler k->wk_keyix); 3438a1b9b6aSSam Leffler return 0; 3448a1b9b6aSSam Leffler } 3458a1b9b6aSSam Leffler } 3468a1b9b6aSSam Leffler /* 3478a1b9b6aSSam Leffler * Strip MIC from the tail. 3488a1b9b6aSSam Leffler */ 3498a1b9b6aSSam Leffler m_adj(m, -tkip.ic_miclen); 3508a1b9b6aSSam Leffler 3518a1b9b6aSSam Leffler /* 3528a1b9b6aSSam Leffler * Ok to update rsc now that MIC has been verified. 3538a1b9b6aSSam Leffler */ 3548a1b9b6aSSam Leffler k->wk_keyrsc = ctx->rx_rsc; 3558a1b9b6aSSam Leffler 3568a1b9b6aSSam Leffler return 1; 3578a1b9b6aSSam Leffler } 3588a1b9b6aSSam Leffler 3598a1b9b6aSSam Leffler /* 3608a1b9b6aSSam Leffler * Host AP crypt: host-based TKIP encryption implementation for Host AP driver 3618a1b9b6aSSam Leffler * 3628a1b9b6aSSam Leffler * Copyright (c) 2003-2004, Jouni Malinen <jkmaline@cc.hut.fi> 3638a1b9b6aSSam Leffler * 3648a1b9b6aSSam Leffler * This program is free software; you can redistribute it and/or modify 3658a1b9b6aSSam Leffler * it under the terms of the GNU General Public License version 2 as 3668a1b9b6aSSam Leffler * published by the Free Software Foundation. See README and COPYING for 3678a1b9b6aSSam Leffler * more details. 3688a1b9b6aSSam Leffler * 3698a1b9b6aSSam Leffler * Alternatively, this software may be distributed under the terms of BSD 3708a1b9b6aSSam Leffler * license. 3718a1b9b6aSSam Leffler */ 3728a1b9b6aSSam Leffler 3738a1b9b6aSSam Leffler static const __u32 crc32_table[256] = { 3748a1b9b6aSSam Leffler 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, 3758a1b9b6aSSam Leffler 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, 3768a1b9b6aSSam Leffler 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, 3778a1b9b6aSSam Leffler 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, 3788a1b9b6aSSam Leffler 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, 3798a1b9b6aSSam Leffler 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, 3808a1b9b6aSSam Leffler 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, 3818a1b9b6aSSam Leffler 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, 3828a1b9b6aSSam Leffler 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, 3838a1b9b6aSSam Leffler 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, 3848a1b9b6aSSam Leffler 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, 3858a1b9b6aSSam Leffler 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, 3868a1b9b6aSSam Leffler 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L, 3878a1b9b6aSSam Leffler 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, 3888a1b9b6aSSam Leffler 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, 3898a1b9b6aSSam Leffler 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, 3908a1b9b6aSSam Leffler 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, 3918a1b9b6aSSam Leffler 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, 3928a1b9b6aSSam Leffler 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, 3938a1b9b6aSSam Leffler 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, 3948a1b9b6aSSam Leffler 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, 3958a1b9b6aSSam Leffler 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, 3968a1b9b6aSSam Leffler 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, 3978a1b9b6aSSam Leffler 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, 3988a1b9b6aSSam Leffler 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, 3998a1b9b6aSSam Leffler 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L, 4008a1b9b6aSSam Leffler 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, 4018a1b9b6aSSam Leffler 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, 4028a1b9b6aSSam Leffler 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L, 4038a1b9b6aSSam Leffler 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, 4048a1b9b6aSSam Leffler 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, 4058a1b9b6aSSam Leffler 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, 4068a1b9b6aSSam Leffler 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, 4078a1b9b6aSSam Leffler 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, 4088a1b9b6aSSam Leffler 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, 4098a1b9b6aSSam Leffler 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, 4108a1b9b6aSSam Leffler 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL, 4118a1b9b6aSSam Leffler 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, 4128a1b9b6aSSam Leffler 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, 4138a1b9b6aSSam Leffler 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, 4148a1b9b6aSSam Leffler 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, 4158a1b9b6aSSam Leffler 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, 4168a1b9b6aSSam Leffler 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, 4178a1b9b6aSSam Leffler 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, 4188a1b9b6aSSam Leffler 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, 4198a1b9b6aSSam Leffler 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, 4208a1b9b6aSSam Leffler 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, 4218a1b9b6aSSam Leffler 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, 4228a1b9b6aSSam Leffler 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, 4238a1b9b6aSSam Leffler 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L, 4248a1b9b6aSSam Leffler 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, 4258a1b9b6aSSam Leffler 0x2d02ef8dL 4268a1b9b6aSSam Leffler }; 4278a1b9b6aSSam Leffler 4288a1b9b6aSSam Leffler static __inline u16 RotR1(u16 val) 4298a1b9b6aSSam Leffler { 4308a1b9b6aSSam Leffler return (val >> 1) | (val << 15); 4318a1b9b6aSSam Leffler } 4328a1b9b6aSSam Leffler 4338a1b9b6aSSam Leffler static __inline u8 Lo8(u16 val) 4348a1b9b6aSSam Leffler { 4358a1b9b6aSSam Leffler return val & 0xff; 4368a1b9b6aSSam Leffler } 4378a1b9b6aSSam Leffler 4388a1b9b6aSSam Leffler static __inline u8 Hi8(u16 val) 4398a1b9b6aSSam Leffler { 4408a1b9b6aSSam Leffler return val >> 8; 4418a1b9b6aSSam Leffler } 4428a1b9b6aSSam Leffler 4438a1b9b6aSSam Leffler static __inline u16 Lo16(u32 val) 4448a1b9b6aSSam Leffler { 4458a1b9b6aSSam Leffler return val & 0xffff; 4468a1b9b6aSSam Leffler } 4478a1b9b6aSSam Leffler 4488a1b9b6aSSam Leffler static __inline u16 Hi16(u32 val) 4498a1b9b6aSSam Leffler { 4508a1b9b6aSSam Leffler return val >> 16; 4518a1b9b6aSSam Leffler } 4528a1b9b6aSSam Leffler 4538a1b9b6aSSam Leffler static __inline u16 Mk16(u8 hi, u8 lo) 4548a1b9b6aSSam Leffler { 4558a1b9b6aSSam Leffler return lo | (((u16) hi) << 8); 4568a1b9b6aSSam Leffler } 4578a1b9b6aSSam Leffler 4588a1b9b6aSSam Leffler static __inline u16 Mk16_le(const u16 *v) 4598a1b9b6aSSam Leffler { 4608a1b9b6aSSam Leffler return le16toh(*v); 4618a1b9b6aSSam Leffler } 4628a1b9b6aSSam Leffler 4638a1b9b6aSSam Leffler static const u16 Sbox[256] = { 4648a1b9b6aSSam Leffler 0xC6A5, 0xF884, 0xEE99, 0xF68D, 0xFF0D, 0xD6BD, 0xDEB1, 0x9154, 4658a1b9b6aSSam Leffler 0x6050, 0x0203, 0xCEA9, 0x567D, 0xE719, 0xB562, 0x4DE6, 0xEC9A, 4668a1b9b6aSSam Leffler 0x8F45, 0x1F9D, 0x8940, 0xFA87, 0xEF15, 0xB2EB, 0x8EC9, 0xFB0B, 4678a1b9b6aSSam Leffler 0x41EC, 0xB367, 0x5FFD, 0x45EA, 0x23BF, 0x53F7, 0xE496, 0x9B5B, 4688a1b9b6aSSam Leffler 0x75C2, 0xE11C, 0x3DAE, 0x4C6A, 0x6C5A, 0x7E41, 0xF502, 0x834F, 4698a1b9b6aSSam Leffler 0x685C, 0x51F4, 0xD134, 0xF908, 0xE293, 0xAB73, 0x6253, 0x2A3F, 4708a1b9b6aSSam Leffler 0x080C, 0x9552, 0x4665, 0x9D5E, 0x3028, 0x37A1, 0x0A0F, 0x2FB5, 4718a1b9b6aSSam Leffler 0x0E09, 0x2436, 0x1B9B, 0xDF3D, 0xCD26, 0x4E69, 0x7FCD, 0xEA9F, 4728a1b9b6aSSam Leffler 0x121B, 0x1D9E, 0x5874, 0x342E, 0x362D, 0xDCB2, 0xB4EE, 0x5BFB, 4738a1b9b6aSSam Leffler 0xA4F6, 0x764D, 0xB761, 0x7DCE, 0x527B, 0xDD3E, 0x5E71, 0x1397, 4748a1b9b6aSSam Leffler 0xA6F5, 0xB968, 0x0000, 0xC12C, 0x4060, 0xE31F, 0x79C8, 0xB6ED, 4758a1b9b6aSSam Leffler 0xD4BE, 0x8D46, 0x67D9, 0x724B, 0x94DE, 0x98D4, 0xB0E8, 0x854A, 4768a1b9b6aSSam Leffler 0xBB6B, 0xC52A, 0x4FE5, 0xED16, 0x86C5, 0x9AD7, 0x6655, 0x1194, 4778a1b9b6aSSam Leffler 0x8ACF, 0xE910, 0x0406, 0xFE81, 0xA0F0, 0x7844, 0x25BA, 0x4BE3, 4788a1b9b6aSSam Leffler 0xA2F3, 0x5DFE, 0x80C0, 0x058A, 0x3FAD, 0x21BC, 0x7048, 0xF104, 4798a1b9b6aSSam Leffler 0x63DF, 0x77C1, 0xAF75, 0x4263, 0x2030, 0xE51A, 0xFD0E, 0xBF6D, 4808a1b9b6aSSam Leffler 0x814C, 0x1814, 0x2635, 0xC32F, 0xBEE1, 0x35A2, 0x88CC, 0x2E39, 4818a1b9b6aSSam Leffler 0x9357, 0x55F2, 0xFC82, 0x7A47, 0xC8AC, 0xBAE7, 0x322B, 0xE695, 4828a1b9b6aSSam Leffler 0xC0A0, 0x1998, 0x9ED1, 0xA37F, 0x4466, 0x547E, 0x3BAB, 0x0B83, 4838a1b9b6aSSam Leffler 0x8CCA, 0xC729, 0x6BD3, 0x283C, 0xA779, 0xBCE2, 0x161D, 0xAD76, 4848a1b9b6aSSam Leffler 0xDB3B, 0x6456, 0x744E, 0x141E, 0x92DB, 0x0C0A, 0x486C, 0xB8E4, 4858a1b9b6aSSam Leffler 0x9F5D, 0xBD6E, 0x43EF, 0xC4A6, 0x39A8, 0x31A4, 0xD337, 0xF28B, 4868a1b9b6aSSam Leffler 0xD532, 0x8B43, 0x6E59, 0xDAB7, 0x018C, 0xB164, 0x9CD2, 0x49E0, 4878a1b9b6aSSam Leffler 0xD8B4, 0xACFA, 0xF307, 0xCF25, 0xCAAF, 0xF48E, 0x47E9, 0x1018, 4888a1b9b6aSSam Leffler 0x6FD5, 0xF088, 0x4A6F, 0x5C72, 0x3824, 0x57F1, 0x73C7, 0x9751, 4898a1b9b6aSSam Leffler 0xCB23, 0xA17C, 0xE89C, 0x3E21, 0x96DD, 0x61DC, 0x0D86, 0x0F85, 4908a1b9b6aSSam Leffler 0xE090, 0x7C42, 0x71C4, 0xCCAA, 0x90D8, 0x0605, 0xF701, 0x1C12, 4918a1b9b6aSSam Leffler 0xC2A3, 0x6A5F, 0xAEF9, 0x69D0, 0x1791, 0x9958, 0x3A27, 0x27B9, 4928a1b9b6aSSam Leffler 0xD938, 0xEB13, 0x2BB3, 0x2233, 0xD2BB, 0xA970, 0x0789, 0x33A7, 4938a1b9b6aSSam Leffler 0x2DB6, 0x3C22, 0x1592, 0xC920, 0x8749, 0xAAFF, 0x5078, 0xA57A, 4948a1b9b6aSSam Leffler 0x038F, 0x59F8, 0x0980, 0x1A17, 0x65DA, 0xD731, 0x84C6, 0xD0B8, 4958a1b9b6aSSam Leffler 0x82C3, 0x29B0, 0x5A77, 0x1E11, 0x7BCB, 0xA8FC, 0x6DD6, 0x2C3A, 4968a1b9b6aSSam Leffler }; 4978a1b9b6aSSam Leffler 4988a1b9b6aSSam Leffler static __inline u16 _S_(u16 v) 4998a1b9b6aSSam Leffler { 5008a1b9b6aSSam Leffler u16 t = Sbox[Hi8(v)]; 5018a1b9b6aSSam Leffler return Sbox[Lo8(v)] ^ ((t << 8) | (t >> 8)); 5028a1b9b6aSSam Leffler } 5038a1b9b6aSSam Leffler 5048a1b9b6aSSam Leffler #define PHASE1_LOOP_COUNT 8 5058a1b9b6aSSam Leffler 5068a1b9b6aSSam Leffler static void tkip_mixing_phase1(u16 *TTAK, const u8 *TK, const u8 *TA, u32 IV32) 5078a1b9b6aSSam Leffler { 5088a1b9b6aSSam Leffler int i, j; 5098a1b9b6aSSam Leffler 5108a1b9b6aSSam Leffler /* Initialize the 80-bit TTAK from TSC (IV32) and TA[0..5] */ 5118a1b9b6aSSam Leffler TTAK[0] = Lo16(IV32); 5128a1b9b6aSSam Leffler TTAK[1] = Hi16(IV32); 5138a1b9b6aSSam Leffler TTAK[2] = Mk16(TA[1], TA[0]); 5148a1b9b6aSSam Leffler TTAK[3] = Mk16(TA[3], TA[2]); 5158a1b9b6aSSam Leffler TTAK[4] = Mk16(TA[5], TA[4]); 5168a1b9b6aSSam Leffler 5178a1b9b6aSSam Leffler for (i = 0; i < PHASE1_LOOP_COUNT; i++) { 5188a1b9b6aSSam Leffler j = 2 * (i & 1); 5198a1b9b6aSSam Leffler TTAK[0] += _S_(TTAK[4] ^ Mk16(TK[1 + j], TK[0 + j])); 5208a1b9b6aSSam Leffler TTAK[1] += _S_(TTAK[0] ^ Mk16(TK[5 + j], TK[4 + j])); 5218a1b9b6aSSam Leffler TTAK[2] += _S_(TTAK[1] ^ Mk16(TK[9 + j], TK[8 + j])); 5228a1b9b6aSSam Leffler TTAK[3] += _S_(TTAK[2] ^ Mk16(TK[13 + j], TK[12 + j])); 5238a1b9b6aSSam Leffler TTAK[4] += _S_(TTAK[3] ^ Mk16(TK[1 + j], TK[0 + j])) + i; 5248a1b9b6aSSam Leffler } 5258a1b9b6aSSam Leffler } 5268a1b9b6aSSam Leffler 5278a1b9b6aSSam Leffler #ifndef _BYTE_ORDER 5288a1b9b6aSSam Leffler #error "Don't know native byte order" 5298a1b9b6aSSam Leffler #endif 5308a1b9b6aSSam Leffler 5318a1b9b6aSSam Leffler static void tkip_mixing_phase2(u8 *WEPSeed, const u8 *TK, const u16 *TTAK, 5328a1b9b6aSSam Leffler u16 IV16) 5338a1b9b6aSSam Leffler { 5348a1b9b6aSSam Leffler /* Make temporary area overlap WEP seed so that the final copy can be 5358a1b9b6aSSam Leffler * avoided on little endian hosts. */ 5368a1b9b6aSSam Leffler u16 *PPK = (u16 *) &WEPSeed[4]; 5378a1b9b6aSSam Leffler 5388a1b9b6aSSam Leffler /* Step 1 - make copy of TTAK and bring in TSC */ 5398a1b9b6aSSam Leffler PPK[0] = TTAK[0]; 5408a1b9b6aSSam Leffler PPK[1] = TTAK[1]; 5418a1b9b6aSSam Leffler PPK[2] = TTAK[2]; 5428a1b9b6aSSam Leffler PPK[3] = TTAK[3]; 5438a1b9b6aSSam Leffler PPK[4] = TTAK[4]; 5448a1b9b6aSSam Leffler PPK[5] = TTAK[4] + IV16; 5458a1b9b6aSSam Leffler 5468a1b9b6aSSam Leffler /* Step 2 - 96-bit bijective mixing using S-box */ 5478a1b9b6aSSam Leffler PPK[0] += _S_(PPK[5] ^ Mk16_le((const u16 *) &TK[0])); 5488a1b9b6aSSam Leffler PPK[1] += _S_(PPK[0] ^ Mk16_le((const u16 *) &TK[2])); 5498a1b9b6aSSam Leffler PPK[2] += _S_(PPK[1] ^ Mk16_le((const u16 *) &TK[4])); 5508a1b9b6aSSam Leffler PPK[3] += _S_(PPK[2] ^ Mk16_le((const u16 *) &TK[6])); 5518a1b9b6aSSam Leffler PPK[4] += _S_(PPK[3] ^ Mk16_le((const u16 *) &TK[8])); 5528a1b9b6aSSam Leffler PPK[5] += _S_(PPK[4] ^ Mk16_le((const u16 *) &TK[10])); 5538a1b9b6aSSam Leffler 5548a1b9b6aSSam Leffler PPK[0] += RotR1(PPK[5] ^ Mk16_le((const u16 *) &TK[12])); 5558a1b9b6aSSam Leffler PPK[1] += RotR1(PPK[0] ^ Mk16_le((const u16 *) &TK[14])); 5568a1b9b6aSSam Leffler PPK[2] += RotR1(PPK[1]); 5578a1b9b6aSSam Leffler PPK[3] += RotR1(PPK[2]); 5588a1b9b6aSSam Leffler PPK[4] += RotR1(PPK[3]); 5598a1b9b6aSSam Leffler PPK[5] += RotR1(PPK[4]); 5608a1b9b6aSSam Leffler 5618a1b9b6aSSam Leffler /* Step 3 - bring in last of TK bits, assign 24-bit WEP IV value 5628a1b9b6aSSam Leffler * WEPSeed[0..2] is transmitted as WEP IV */ 5638a1b9b6aSSam Leffler WEPSeed[0] = Hi8(IV16); 5648a1b9b6aSSam Leffler WEPSeed[1] = (Hi8(IV16) | 0x20) & 0x7F; 5658a1b9b6aSSam Leffler WEPSeed[2] = Lo8(IV16); 5668a1b9b6aSSam Leffler WEPSeed[3] = Lo8((PPK[5] ^ Mk16_le((const u16 *) &TK[0])) >> 1); 5678a1b9b6aSSam Leffler 5688a1b9b6aSSam Leffler #if _BYTE_ORDER == _BIG_ENDIAN 5698a1b9b6aSSam Leffler { 5708a1b9b6aSSam Leffler int i; 5718a1b9b6aSSam Leffler for (i = 0; i < 6; i++) 5728a1b9b6aSSam Leffler PPK[i] = (PPK[i] << 8) | (PPK[i] >> 8); 5738a1b9b6aSSam Leffler } 5748a1b9b6aSSam Leffler #endif 5758a1b9b6aSSam Leffler } 5768a1b9b6aSSam Leffler 5778a1b9b6aSSam Leffler static void 5788a1b9b6aSSam Leffler wep_encrypt(u8 *key, struct mbuf *m0, u_int off, size_t data_len, 5798a1b9b6aSSam Leffler uint8_t icv[IEEE80211_WEP_CRCLEN]) 5808a1b9b6aSSam Leffler { 5818a1b9b6aSSam Leffler u32 i, j, k, crc; 5828a1b9b6aSSam Leffler size_t buflen; 5838a1b9b6aSSam Leffler u8 S[256]; 5848a1b9b6aSSam Leffler u8 *pos; 5858a1b9b6aSSam Leffler struct mbuf *m; 5868a1b9b6aSSam Leffler #define S_SWAP(a,b) do { u8 t = S[a]; S[a] = S[b]; S[b] = t; } while(0) 5878a1b9b6aSSam Leffler 5888a1b9b6aSSam Leffler /* Setup RC4 state */ 5898a1b9b6aSSam Leffler for (i = 0; i < 256; i++) 5908a1b9b6aSSam Leffler S[i] = i; 5918a1b9b6aSSam Leffler j = 0; 5928a1b9b6aSSam Leffler for (i = 0; i < 256; i++) { 5938a1b9b6aSSam Leffler j = (j + S[i] + key[i & 0x0f]) & 0xff; 5948a1b9b6aSSam Leffler S_SWAP(i, j); 5958a1b9b6aSSam Leffler } 5968a1b9b6aSSam Leffler 5978a1b9b6aSSam Leffler /* Compute CRC32 over unencrypted data and apply RC4 to data */ 5988a1b9b6aSSam Leffler crc = ~0; 5998a1b9b6aSSam Leffler i = j = 0; 6008a1b9b6aSSam Leffler m = m0; 6018a1b9b6aSSam Leffler pos = mtod(m, uint8_t *) + off; 6028a1b9b6aSSam Leffler buflen = m->m_len - off; 6038a1b9b6aSSam Leffler for (;;) { 6048a1b9b6aSSam Leffler if (buflen > data_len) 6058a1b9b6aSSam Leffler buflen = data_len; 6068a1b9b6aSSam Leffler data_len -= buflen; 6078a1b9b6aSSam Leffler for (k = 0; k < buflen; k++) { 6088a1b9b6aSSam Leffler crc = crc32_table[(crc ^ *pos) & 0xff] ^ (crc >> 8); 6098a1b9b6aSSam Leffler i = (i + 1) & 0xff; 6108a1b9b6aSSam Leffler j = (j + S[i]) & 0xff; 6118a1b9b6aSSam Leffler S_SWAP(i, j); 6128a1b9b6aSSam Leffler *pos++ ^= S[(S[i] + S[j]) & 0xff]; 6138a1b9b6aSSam Leffler } 6148a1b9b6aSSam Leffler m = m->m_next; 6158a1b9b6aSSam Leffler if (m == NULL) { 6168a1b9b6aSSam Leffler KASSERT(data_len == 0, 6178a1b9b6aSSam Leffler ("out of buffers with data_len %u\n", data_len)); 6188a1b9b6aSSam Leffler break; 6198a1b9b6aSSam Leffler } 6208a1b9b6aSSam Leffler pos = mtod(m, uint8_t *); 6218a1b9b6aSSam Leffler buflen = m->m_len; 6228a1b9b6aSSam Leffler } 6238a1b9b6aSSam Leffler crc = ~crc; 6248a1b9b6aSSam Leffler 6258a1b9b6aSSam Leffler /* Append little-endian CRC32 and encrypt it to produce ICV */ 6268a1b9b6aSSam Leffler icv[0] = crc; 6278a1b9b6aSSam Leffler icv[1] = crc >> 8; 6288a1b9b6aSSam Leffler icv[2] = crc >> 16; 6298a1b9b6aSSam Leffler icv[3] = crc >> 24; 6308a1b9b6aSSam Leffler for (k = 0; k < IEEE80211_WEP_CRCLEN; k++) { 6318a1b9b6aSSam Leffler i = (i + 1) & 0xff; 6328a1b9b6aSSam Leffler j = (j + S[i]) & 0xff; 6338a1b9b6aSSam Leffler S_SWAP(i, j); 6348a1b9b6aSSam Leffler icv[k] ^= S[(S[i] + S[j]) & 0xff]; 6358a1b9b6aSSam Leffler } 6368a1b9b6aSSam Leffler } 6378a1b9b6aSSam Leffler 6388a1b9b6aSSam Leffler static int 6398a1b9b6aSSam Leffler wep_decrypt(u8 *key, struct mbuf *m, u_int off, size_t data_len) 6408a1b9b6aSSam Leffler { 6418a1b9b6aSSam Leffler u32 i, j, k, crc; 6428a1b9b6aSSam Leffler u8 S[256]; 6438a1b9b6aSSam Leffler u8 *pos, icv[4]; 6448a1b9b6aSSam Leffler size_t buflen; 6458a1b9b6aSSam Leffler 6468a1b9b6aSSam Leffler /* Setup RC4 state */ 6478a1b9b6aSSam Leffler for (i = 0; i < 256; i++) 6488a1b9b6aSSam Leffler S[i] = i; 6498a1b9b6aSSam Leffler j = 0; 6508a1b9b6aSSam Leffler for (i = 0; i < 256; i++) { 6518a1b9b6aSSam Leffler j = (j + S[i] + key[i & 0x0f]) & 0xff; 6528a1b9b6aSSam Leffler S_SWAP(i, j); 6538a1b9b6aSSam Leffler } 6548a1b9b6aSSam Leffler 6558a1b9b6aSSam Leffler /* Apply RC4 to data and compute CRC32 over decrypted data */ 6568a1b9b6aSSam Leffler crc = ~0; 6578a1b9b6aSSam Leffler i = j = 0; 6588a1b9b6aSSam Leffler pos = mtod(m, uint8_t *) + off; 6598a1b9b6aSSam Leffler buflen = m->m_len - off; 6608a1b9b6aSSam Leffler for (;;) { 6618a1b9b6aSSam Leffler if (buflen > data_len) 6628a1b9b6aSSam Leffler buflen = data_len; 6638a1b9b6aSSam Leffler data_len -= buflen; 6648a1b9b6aSSam Leffler for (k = 0; k < buflen; k++) { 6658a1b9b6aSSam Leffler i = (i + 1) & 0xff; 6668a1b9b6aSSam Leffler j = (j + S[i]) & 0xff; 6678a1b9b6aSSam Leffler S_SWAP(i, j); 6688a1b9b6aSSam Leffler *pos ^= S[(S[i] + S[j]) & 0xff]; 6698a1b9b6aSSam Leffler crc = crc32_table[(crc ^ *pos) & 0xff] ^ (crc >> 8); 6708a1b9b6aSSam Leffler pos++; 6718a1b9b6aSSam Leffler } 6728a1b9b6aSSam Leffler m = m->m_next; 6738a1b9b6aSSam Leffler if (m == NULL) { 6748a1b9b6aSSam Leffler KASSERT(data_len == 0, 6758a1b9b6aSSam Leffler ("out of buffers with data_len %u\n", data_len)); 6768a1b9b6aSSam Leffler break; 6778a1b9b6aSSam Leffler } 6788a1b9b6aSSam Leffler pos = mtod(m, uint8_t *); 6798a1b9b6aSSam Leffler buflen = m->m_len; 6808a1b9b6aSSam Leffler } 6818a1b9b6aSSam Leffler crc = ~crc; 6828a1b9b6aSSam Leffler 6838a1b9b6aSSam Leffler /* Encrypt little-endian CRC32 and verify that it matches with the 6848a1b9b6aSSam Leffler * received ICV */ 6858a1b9b6aSSam Leffler icv[0] = crc; 6868a1b9b6aSSam Leffler icv[1] = crc >> 8; 6878a1b9b6aSSam Leffler icv[2] = crc >> 16; 6888a1b9b6aSSam Leffler icv[3] = crc >> 24; 6898a1b9b6aSSam Leffler for (k = 0; k < 4; k++) { 6908a1b9b6aSSam Leffler i = (i + 1) & 0xff; 6918a1b9b6aSSam Leffler j = (j + S[i]) & 0xff; 6928a1b9b6aSSam Leffler S_SWAP(i, j); 6938a1b9b6aSSam Leffler if ((icv[k] ^ S[(S[i] + S[j]) & 0xff]) != *pos++) { 6948a1b9b6aSSam Leffler /* ICV mismatch - drop frame */ 6958a1b9b6aSSam Leffler return -1; 6968a1b9b6aSSam Leffler } 6978a1b9b6aSSam Leffler } 6988a1b9b6aSSam Leffler 6998a1b9b6aSSam Leffler return 0; 7008a1b9b6aSSam Leffler } 7018a1b9b6aSSam Leffler 7028a1b9b6aSSam Leffler 7038a1b9b6aSSam Leffler static __inline u32 rotl(u32 val, int bits) 7048a1b9b6aSSam Leffler { 7058a1b9b6aSSam Leffler return (val << bits) | (val >> (32 - bits)); 7068a1b9b6aSSam Leffler } 7078a1b9b6aSSam Leffler 7088a1b9b6aSSam Leffler 7098a1b9b6aSSam Leffler static __inline u32 rotr(u32 val, int bits) 7108a1b9b6aSSam Leffler { 7118a1b9b6aSSam Leffler return (val >> bits) | (val << (32 - bits)); 7128a1b9b6aSSam Leffler } 7138a1b9b6aSSam Leffler 7148a1b9b6aSSam Leffler 7158a1b9b6aSSam Leffler static __inline u32 xswap(u32 val) 7168a1b9b6aSSam Leffler { 7178a1b9b6aSSam Leffler return ((val & 0x00ff00ff) << 8) | ((val & 0xff00ff00) >> 8); 7188a1b9b6aSSam Leffler } 7198a1b9b6aSSam Leffler 7208a1b9b6aSSam Leffler 7218a1b9b6aSSam Leffler #define michael_block(l, r) \ 7228a1b9b6aSSam Leffler do { \ 7238a1b9b6aSSam Leffler r ^= rotl(l, 17); \ 7248a1b9b6aSSam Leffler l += r; \ 7258a1b9b6aSSam Leffler r ^= xswap(l); \ 7268a1b9b6aSSam Leffler l += r; \ 7278a1b9b6aSSam Leffler r ^= rotl(l, 3); \ 7288a1b9b6aSSam Leffler l += r; \ 7298a1b9b6aSSam Leffler r ^= rotr(l, 2); \ 7308a1b9b6aSSam Leffler l += r; \ 7318a1b9b6aSSam Leffler } while (0) 7328a1b9b6aSSam Leffler 7338a1b9b6aSSam Leffler 7348a1b9b6aSSam Leffler static __inline u32 get_le32_split(u8 b0, u8 b1, u8 b2, u8 b3) 7358a1b9b6aSSam Leffler { 7368a1b9b6aSSam Leffler return b0 | (b1 << 8) | (b2 << 16) | (b3 << 24); 7378a1b9b6aSSam Leffler } 7388a1b9b6aSSam Leffler 7398a1b9b6aSSam Leffler static __inline u32 get_le32(const u8 *p) 7408a1b9b6aSSam Leffler { 7418a1b9b6aSSam Leffler return get_le32_split(p[0], p[1], p[2], p[3]); 7428a1b9b6aSSam Leffler } 7438a1b9b6aSSam Leffler 7448a1b9b6aSSam Leffler 7458a1b9b6aSSam Leffler static __inline void put_le32(u8 *p, u32 v) 7468a1b9b6aSSam Leffler { 7478a1b9b6aSSam Leffler p[0] = v; 7488a1b9b6aSSam Leffler p[1] = v >> 8; 7498a1b9b6aSSam Leffler p[2] = v >> 16; 7508a1b9b6aSSam Leffler p[3] = v >> 24; 7518a1b9b6aSSam Leffler } 7528a1b9b6aSSam Leffler 7538a1b9b6aSSam Leffler /* 7548a1b9b6aSSam Leffler * Craft pseudo header used to calculate the MIC. 7558a1b9b6aSSam Leffler */ 7568a1b9b6aSSam Leffler static void 7578a1b9b6aSSam Leffler michael_mic_hdr(const struct ieee80211_frame *wh0, uint8_t hdr[16]) 7588a1b9b6aSSam Leffler { 7598a1b9b6aSSam Leffler const struct ieee80211_frame_addr4 *wh = 7608a1b9b6aSSam Leffler (const struct ieee80211_frame_addr4 *) wh0; 7618a1b9b6aSSam Leffler 7628a1b9b6aSSam Leffler switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) { 7638a1b9b6aSSam Leffler case IEEE80211_FC1_DIR_NODS: 7648a1b9b6aSSam Leffler IEEE80211_ADDR_COPY(hdr, wh->i_addr1); /* DA */ 7658a1b9b6aSSam Leffler IEEE80211_ADDR_COPY(hdr + IEEE80211_ADDR_LEN, wh->i_addr2); 7668a1b9b6aSSam Leffler break; 7678a1b9b6aSSam Leffler case IEEE80211_FC1_DIR_TODS: 7688a1b9b6aSSam Leffler IEEE80211_ADDR_COPY(hdr, wh->i_addr3); /* DA */ 7698a1b9b6aSSam Leffler IEEE80211_ADDR_COPY(hdr + IEEE80211_ADDR_LEN, wh->i_addr2); 7708a1b9b6aSSam Leffler break; 7718a1b9b6aSSam Leffler case IEEE80211_FC1_DIR_FROMDS: 7728a1b9b6aSSam Leffler IEEE80211_ADDR_COPY(hdr, wh->i_addr1); /* DA */ 7738a1b9b6aSSam Leffler IEEE80211_ADDR_COPY(hdr + IEEE80211_ADDR_LEN, wh->i_addr3); 7748a1b9b6aSSam Leffler break; 7758a1b9b6aSSam Leffler case IEEE80211_FC1_DIR_DSTODS: 7768a1b9b6aSSam Leffler IEEE80211_ADDR_COPY(hdr, wh->i_addr3); /* DA */ 7778a1b9b6aSSam Leffler IEEE80211_ADDR_COPY(hdr + IEEE80211_ADDR_LEN, wh->i_addr4); 7788a1b9b6aSSam Leffler break; 7798a1b9b6aSSam Leffler } 7808a1b9b6aSSam Leffler 7818a1b9b6aSSam Leffler hdr[12] = 0; /* XXX qos priority */ 7828a1b9b6aSSam Leffler hdr[13] = hdr[14] = hdr[15] = 0; /* reserved */ 7838a1b9b6aSSam Leffler } 7848a1b9b6aSSam Leffler 7858a1b9b6aSSam Leffler static void 7868a1b9b6aSSam Leffler michael_mic(struct tkip_ctx *ctx, const u8 *key, 7878a1b9b6aSSam Leffler struct mbuf *m, u_int off, size_t data_len, 7888a1b9b6aSSam Leffler u8 mic[IEEE80211_WEP_MICLEN]) 7898a1b9b6aSSam Leffler { 7908a1b9b6aSSam Leffler uint8_t hdr[16]; 7918a1b9b6aSSam Leffler u32 l, r; 7928a1b9b6aSSam Leffler const uint8_t *data; 7938a1b9b6aSSam Leffler u_int space; 7948a1b9b6aSSam Leffler 7958a1b9b6aSSam Leffler michael_mic_hdr(mtod(m, struct ieee80211_frame *), hdr); 7968a1b9b6aSSam Leffler 7978a1b9b6aSSam Leffler l = get_le32(key); 7988a1b9b6aSSam Leffler r = get_le32(key + 4); 7998a1b9b6aSSam Leffler 8008a1b9b6aSSam Leffler /* Michael MIC pseudo header: DA, SA, 3 x 0, Priority */ 8018a1b9b6aSSam Leffler l ^= get_le32(hdr); 8028a1b9b6aSSam Leffler michael_block(l, r); 8038a1b9b6aSSam Leffler l ^= get_le32(&hdr[4]); 8048a1b9b6aSSam Leffler michael_block(l, r); 8058a1b9b6aSSam Leffler l ^= get_le32(&hdr[8]); 8068a1b9b6aSSam Leffler michael_block(l, r); 8078a1b9b6aSSam Leffler l ^= get_le32(&hdr[12]); 8088a1b9b6aSSam Leffler michael_block(l, r); 8098a1b9b6aSSam Leffler 8108a1b9b6aSSam Leffler /* first buffer has special handling */ 8118a1b9b6aSSam Leffler data = mtod(m, const uint8_t *) + off; 8128a1b9b6aSSam Leffler space = m->m_len - off; 8138a1b9b6aSSam Leffler for (;;) { 8148a1b9b6aSSam Leffler if (space > data_len) 8158a1b9b6aSSam Leffler space = data_len; 8168a1b9b6aSSam Leffler /* collect 32-bit blocks from current buffer */ 8178a1b9b6aSSam Leffler while (space >= sizeof(uint32_t)) { 8188a1b9b6aSSam Leffler l ^= get_le32(data); 8198a1b9b6aSSam Leffler michael_block(l, r); 8208a1b9b6aSSam Leffler data += sizeof(uint32_t), space -= sizeof(uint32_t); 8218a1b9b6aSSam Leffler data_len -= sizeof(uint32_t); 8228a1b9b6aSSam Leffler } 8238a1b9b6aSSam Leffler if (data_len < sizeof(uint32_t)) 8248a1b9b6aSSam Leffler break; 8258a1b9b6aSSam Leffler m = m->m_next; 8268a1b9b6aSSam Leffler if (m == NULL) { 8278a1b9b6aSSam Leffler KASSERT(0, ("out of data, data_len %u\n", data_len)); 8288a1b9b6aSSam Leffler break; 8298a1b9b6aSSam Leffler } 8308a1b9b6aSSam Leffler if (space != 0) { 8318a1b9b6aSSam Leffler const uint8_t *data_next; 8328a1b9b6aSSam Leffler /* 8338a1b9b6aSSam Leffler * Block straddles buffers, split references. 8348a1b9b6aSSam Leffler */ 8358a1b9b6aSSam Leffler data_next = mtod(m, const uint8_t *); 8368a1b9b6aSSam Leffler KASSERT(m->m_len >= sizeof(uint32_t) - space, 8378a1b9b6aSSam Leffler ("not enough data in following buffer, " 8388a1b9b6aSSam Leffler "m_len %u need %u\n", m->m_len, 8398a1b9b6aSSam Leffler sizeof(uint32_t) - space)); 8408a1b9b6aSSam Leffler switch (space) { 8418a1b9b6aSSam Leffler case 1: 8428a1b9b6aSSam Leffler l ^= get_le32_split(data[0], data_next[0], 8438a1b9b6aSSam Leffler data_next[1], data_next[2]); 8448a1b9b6aSSam Leffler data = data_next + 3; 8458a1b9b6aSSam Leffler space = m->m_len - 3; 8468a1b9b6aSSam Leffler break; 8478a1b9b6aSSam Leffler case 2: 8488a1b9b6aSSam Leffler l ^= get_le32_split(data[0], data[1], 8498a1b9b6aSSam Leffler data_next[0], data_next[1]); 8508a1b9b6aSSam Leffler data = data_next + 2; 8518a1b9b6aSSam Leffler space = m->m_len - 2; 8528a1b9b6aSSam Leffler break; 8538a1b9b6aSSam Leffler case 3: 8548a1b9b6aSSam Leffler l ^= get_le32_split(data[0], data[1], 8558a1b9b6aSSam Leffler data[2], data_next[0]); 8568a1b9b6aSSam Leffler data = data_next + 1; 8578a1b9b6aSSam Leffler space = m->m_len - 1; 8588a1b9b6aSSam Leffler break; 8598a1b9b6aSSam Leffler } 8608a1b9b6aSSam Leffler michael_block(l, r); 8618a1b9b6aSSam Leffler data_len -= sizeof(uint32_t); 8628a1b9b6aSSam Leffler } else { 8638a1b9b6aSSam Leffler /* 8648a1b9b6aSSam Leffler * Setup for next buffer. 8658a1b9b6aSSam Leffler */ 8668a1b9b6aSSam Leffler data = mtod(m, const uint8_t *); 8678a1b9b6aSSam Leffler space = m->m_len; 8688a1b9b6aSSam Leffler } 8698a1b9b6aSSam Leffler } 8708a1b9b6aSSam Leffler /* Last block and padding (0x5a, 4..7 x 0) */ 8718a1b9b6aSSam Leffler switch (data_len) { 8728a1b9b6aSSam Leffler case 0: 8738a1b9b6aSSam Leffler l ^= get_le32_split(0x5a, 0, 0, 0); 8748a1b9b6aSSam Leffler break; 8758a1b9b6aSSam Leffler case 1: 8768a1b9b6aSSam Leffler l ^= get_le32_split(data[0], 0x5a, 0, 0); 8778a1b9b6aSSam Leffler break; 8788a1b9b6aSSam Leffler case 2: 8798a1b9b6aSSam Leffler l ^= get_le32_split(data[0], data[1], 0x5a, 0); 8808a1b9b6aSSam Leffler break; 8818a1b9b6aSSam Leffler case 3: 8828a1b9b6aSSam Leffler l ^= get_le32_split(data[0], data[1], data[2], 0x5a); 8838a1b9b6aSSam Leffler break; 8848a1b9b6aSSam Leffler } 8858a1b9b6aSSam Leffler michael_block(l, r); 8868a1b9b6aSSam Leffler /* l ^= 0; */ 8878a1b9b6aSSam Leffler michael_block(l, r); 8888a1b9b6aSSam Leffler 8898a1b9b6aSSam Leffler put_le32(mic, l); 8908a1b9b6aSSam Leffler put_le32(mic + 4, r); 8918a1b9b6aSSam Leffler } 8928a1b9b6aSSam Leffler 8938a1b9b6aSSam Leffler static int 8948a1b9b6aSSam Leffler tkip_encrypt(struct tkip_ctx *ctx, struct ieee80211_key *key, 8958a1b9b6aSSam Leffler struct mbuf *m, int hdrlen) 8968a1b9b6aSSam Leffler { 8978a1b9b6aSSam Leffler struct ieee80211_frame *wh; 8988a1b9b6aSSam Leffler uint8_t icv[IEEE80211_WEP_CRCLEN]; 8998a1b9b6aSSam Leffler 9008a1b9b6aSSam Leffler ctx->tc_ic->ic_stats.is_crypto_tkip++; 9018a1b9b6aSSam Leffler 9028a1b9b6aSSam Leffler wh = mtod(m, struct ieee80211_frame *); 9038a1b9b6aSSam Leffler if (!ctx->tx_phase1_done) { 9048a1b9b6aSSam Leffler tkip_mixing_phase1(ctx->tx_ttak, key->wk_key, wh->i_addr2, 9058a1b9b6aSSam Leffler (u32)(key->wk_keytsc >> 16)); 9068a1b9b6aSSam Leffler ctx->tx_phase1_done = 1; 9078a1b9b6aSSam Leffler } 9088a1b9b6aSSam Leffler tkip_mixing_phase2(ctx->tx_rc4key, key->wk_key, ctx->tx_ttak, 9098a1b9b6aSSam Leffler (u16) key->wk_keytsc); 9108a1b9b6aSSam Leffler 9118a1b9b6aSSam Leffler wep_encrypt(ctx->tx_rc4key, 9128a1b9b6aSSam Leffler m, hdrlen + tkip.ic_header, 9138a1b9b6aSSam Leffler m->m_pkthdr.len - (hdrlen + tkip.ic_header), 9148a1b9b6aSSam Leffler icv); 9158a1b9b6aSSam Leffler (void) m_append(m, IEEE80211_WEP_CRCLEN, icv); /* XXX check return */ 9168a1b9b6aSSam Leffler 9178a1b9b6aSSam Leffler key->wk_keytsc++; /* XXX wrap at 48 bits */ 9188a1b9b6aSSam Leffler if ((u16)(key->wk_keytsc) == 0) 9198a1b9b6aSSam Leffler ctx->tx_phase1_done = 0; 9208a1b9b6aSSam Leffler return 1; 9218a1b9b6aSSam Leffler } 9228a1b9b6aSSam Leffler 9238a1b9b6aSSam Leffler static int 9248a1b9b6aSSam Leffler tkip_decrypt(struct tkip_ctx *ctx, struct ieee80211_key *key, 9258a1b9b6aSSam Leffler struct mbuf *m, int hdrlen) 9268a1b9b6aSSam Leffler { 9278a1b9b6aSSam Leffler struct ieee80211_frame *wh; 9288a1b9b6aSSam Leffler u32 iv32; 9298a1b9b6aSSam Leffler u16 iv16; 9308a1b9b6aSSam Leffler 9318a1b9b6aSSam Leffler ctx->tc_ic->ic_stats.is_crypto_tkip++; 9328a1b9b6aSSam Leffler 9338a1b9b6aSSam Leffler wh = mtod(m, struct ieee80211_frame *); 9348a1b9b6aSSam Leffler /* NB: tkip_decap already verified header and left seq in rx_rsc */ 9358a1b9b6aSSam Leffler iv16 = (u16) ctx->rx_rsc; 9368a1b9b6aSSam Leffler iv32 = (u32) (ctx->rx_rsc >> 16); 9378a1b9b6aSSam Leffler 9388a1b9b6aSSam Leffler if (iv32 != (u32)(key->wk_keyrsc >> 16) || !ctx->rx_phase1_done) { 9398a1b9b6aSSam Leffler tkip_mixing_phase1(ctx->rx_ttak, key->wk_key, 9408a1b9b6aSSam Leffler wh->i_addr2, iv32); 9418a1b9b6aSSam Leffler ctx->rx_phase1_done = 1; 9428a1b9b6aSSam Leffler } 9438a1b9b6aSSam Leffler tkip_mixing_phase2(ctx->rx_rc4key, key->wk_key, ctx->rx_ttak, iv16); 9448a1b9b6aSSam Leffler 9458a1b9b6aSSam Leffler /* NB: m is unstripped; deduct headers + ICV to get payload */ 9468a1b9b6aSSam Leffler if (wep_decrypt(ctx->rx_rc4key, 9478a1b9b6aSSam Leffler m, hdrlen + tkip.ic_header, 9488a1b9b6aSSam Leffler m->m_pkthdr.len - (hdrlen + tkip.ic_header + tkip.ic_trailer))) { 9498a1b9b6aSSam Leffler if (iv32 != (u32)(key->wk_keyrsc >> 16)) { 9508a1b9b6aSSam Leffler /* Previously cached Phase1 result was already lost, so 9518a1b9b6aSSam Leffler * it needs to be recalculated for the next packet. */ 9528a1b9b6aSSam Leffler ctx->rx_phase1_done = 0; 9538a1b9b6aSSam Leffler } 9548a1b9b6aSSam Leffler IEEE80211_DPRINTF(ctx->tc_ic, IEEE80211_MSG_CRYPTO, 9558a1b9b6aSSam Leffler "[%s] TKIP ICV mismatch on decrypt\n", 9568a1b9b6aSSam Leffler ether_sprintf(wh->i_addr2)); 9578a1b9b6aSSam Leffler ctx->tc_ic->ic_stats.is_rx_tkipicv++; 9588a1b9b6aSSam Leffler return 0; 9598a1b9b6aSSam Leffler } 9608a1b9b6aSSam Leffler return 1; 9618a1b9b6aSSam Leffler } 9628a1b9b6aSSam Leffler 9638a1b9b6aSSam Leffler /* 9648a1b9b6aSSam Leffler * Module glue. 9658a1b9b6aSSam Leffler */ 9668a1b9b6aSSam Leffler static int 9678a1b9b6aSSam Leffler tkip_modevent(module_t mod, int type, void *unused) 9688a1b9b6aSSam Leffler { 9698a1b9b6aSSam Leffler switch (type) { 9708a1b9b6aSSam Leffler case MOD_LOAD: 9718a1b9b6aSSam Leffler ieee80211_crypto_register(&tkip); 9728a1b9b6aSSam Leffler return 0; 9738a1b9b6aSSam Leffler case MOD_UNLOAD: 9748a1b9b6aSSam Leffler ieee80211_crypto_unregister(&tkip); 9758a1b9b6aSSam Leffler return 0; 9768a1b9b6aSSam Leffler } 9778a1b9b6aSSam Leffler return EINVAL; 9788a1b9b6aSSam Leffler } 9798a1b9b6aSSam Leffler 9808a1b9b6aSSam Leffler static moduledata_t tkip_mod = { 9818a1b9b6aSSam Leffler "wlan_tkip", 9828a1b9b6aSSam Leffler tkip_modevent, 9838a1b9b6aSSam Leffler 0 9848a1b9b6aSSam Leffler }; 9858a1b9b6aSSam Leffler DECLARE_MODULE(wlan_tkip, tkip_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST); 9868a1b9b6aSSam Leffler MODULE_VERSION(wlan_tkip, 1); 9878a1b9b6aSSam Leffler MODULE_DEPEND(wlan_wep, wlan, 1, 1, 1); 988