18a1b9b6aSSam Leffler /*- 2fe267a55SPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3fe267a55SPedro F. Giffuni * 4b032f27cSSam Leffler * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting 58a1b9b6aSSam Leffler * All rights reserved. 68a1b9b6aSSam Leffler * 78a1b9b6aSSam Leffler * Redistribution and use in source and binary forms, with or without 88a1b9b6aSSam Leffler * modification, are permitted provided that the following conditions 98a1b9b6aSSam Leffler * are met: 108a1b9b6aSSam Leffler * 1. Redistributions of source code must retain the above copyright 118a1b9b6aSSam Leffler * notice, this list of conditions and the following disclaimer. 128a1b9b6aSSam Leffler * 2. Redistributions in binary form must reproduce the above copyright 138a1b9b6aSSam Leffler * notice, this list of conditions and the following disclaimer in the 148a1b9b6aSSam Leffler * documentation and/or other materials provided with the distribution. 158a1b9b6aSSam Leffler * 168a1b9b6aSSam Leffler * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 178a1b9b6aSSam Leffler * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 188a1b9b6aSSam Leffler * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 198a1b9b6aSSam Leffler * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 208a1b9b6aSSam Leffler * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 218a1b9b6aSSam Leffler * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 228a1b9b6aSSam Leffler * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 238a1b9b6aSSam Leffler * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 248a1b9b6aSSam Leffler * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 258a1b9b6aSSam Leffler * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 268a1b9b6aSSam Leffler */ 278a1b9b6aSSam Leffler 288a1b9b6aSSam Leffler #include <sys/cdefs.h> 298a1b9b6aSSam Leffler __FBSDID("$FreeBSD$"); 308a1b9b6aSSam Leffler 318a1b9b6aSSam Leffler /* 328a1b9b6aSSam Leffler * IEEE 802.11i TKIP crypto support. 338a1b9b6aSSam Leffler * 348a1b9b6aSSam Leffler * Part of this module is derived from similar code in the Host 358a1b9b6aSSam Leffler * AP driver. The code is used with the consent of the author and 368a1b9b6aSSam Leffler * it's license is included below. 378a1b9b6aSSam Leffler */ 38b032f27cSSam Leffler #include "opt_wlan.h" 39b032f27cSSam Leffler 408a1b9b6aSSam Leffler #include <sys/param.h> 418a1b9b6aSSam Leffler #include <sys/systm.h> 428a1b9b6aSSam Leffler #include <sys/mbuf.h> 438a1b9b6aSSam Leffler #include <sys/malloc.h> 448a1b9b6aSSam Leffler #include <sys/kernel.h> 458a1b9b6aSSam Leffler #include <sys/module.h> 468a1b9b6aSSam Leffler #include <sys/endian.h> 478a1b9b6aSSam Leffler 488a1b9b6aSSam Leffler #include <sys/socket.h> 498a1b9b6aSSam Leffler 508a1b9b6aSSam Leffler #include <net/if.h> 518a1b9b6aSSam Leffler #include <net/if_media.h> 528a1b9b6aSSam Leffler #include <net/ethernet.h> 538a1b9b6aSSam Leffler 548a1b9b6aSSam Leffler #include <net80211/ieee80211_var.h> 558a1b9b6aSSam Leffler 56b032f27cSSam Leffler static void *tkip_attach(struct ieee80211vap *, struct ieee80211_key *); 578a1b9b6aSSam Leffler static void tkip_detach(struct ieee80211_key *); 588a1b9b6aSSam Leffler static int tkip_setkey(struct ieee80211_key *); 59c0cb9349SAdrian Chadd static void tkip_setiv(struct ieee80211_key *, uint8_t *); 60ef0d8f63SAdrian Chadd static int tkip_encap(struct ieee80211_key *, struct mbuf *); 6196d88463SSam Leffler static int tkip_enmic(struct ieee80211_key *, struct mbuf *, int); 622cc12adeSSam Leffler static int tkip_decap(struct ieee80211_key *, struct mbuf *, int); 6396d88463SSam Leffler static int tkip_demic(struct ieee80211_key *, struct mbuf *, int); 648a1b9b6aSSam Leffler 658a1b9b6aSSam Leffler static const struct ieee80211_cipher tkip = { 668a1b9b6aSSam Leffler .ic_name = "TKIP", 678a1b9b6aSSam Leffler .ic_cipher = IEEE80211_CIPHER_TKIP, 688a1b9b6aSSam Leffler .ic_header = IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN + 698a1b9b6aSSam Leffler IEEE80211_WEP_EXTIVLEN, 708a1b9b6aSSam Leffler .ic_trailer = IEEE80211_WEP_CRCLEN, 718a1b9b6aSSam Leffler .ic_miclen = IEEE80211_WEP_MICLEN, 728a1b9b6aSSam Leffler .ic_attach = tkip_attach, 738a1b9b6aSSam Leffler .ic_detach = tkip_detach, 748a1b9b6aSSam Leffler .ic_setkey = tkip_setkey, 75c0cb9349SAdrian Chadd .ic_setiv = tkip_setiv, 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 878a1b9b6aSSam Leffler struct tkip_ctx { 88b032f27cSSam Leffler struct ieee80211vap *tc_vap; /* for diagnostics+statistics */ 898a1b9b6aSSam Leffler 908a1b9b6aSSam Leffler u16 tx_ttak[5]; 918a1b9b6aSSam Leffler u8 tx_rc4key[16]; /* XXX for test module; make locals? */ 928a1b9b6aSSam Leffler 938a1b9b6aSSam Leffler u16 rx_ttak[5]; 948a1b9b6aSSam Leffler int rx_phase1_done; 958a1b9b6aSSam Leffler u8 rx_rc4key[16]; /* XXX for test module; make locals? */ 968a1b9b6aSSam Leffler uint64_t rx_rsc; /* held until MIC verified */ 978a1b9b6aSSam Leffler }; 988a1b9b6aSSam Leffler 998a1b9b6aSSam Leffler static void michael_mic(struct tkip_ctx *, const u8 *key, 1008a1b9b6aSSam Leffler struct mbuf *m, u_int off, size_t data_len, 1018a1b9b6aSSam Leffler u8 mic[IEEE80211_WEP_MICLEN]); 1028a1b9b6aSSam Leffler static int tkip_encrypt(struct tkip_ctx *, struct ieee80211_key *, 1038a1b9b6aSSam Leffler struct mbuf *, int hdr_len); 1048a1b9b6aSSam Leffler static int tkip_decrypt(struct tkip_ctx *, struct ieee80211_key *, 1058a1b9b6aSSam Leffler struct mbuf *, int hdr_len); 1068a1b9b6aSSam Leffler 107d16441fdSSam Leffler /* number of references from net80211 layer */ 108d16441fdSSam Leffler static int nrefs = 0; 109d16441fdSSam Leffler 1108a1b9b6aSSam Leffler static void * 111b032f27cSSam Leffler tkip_attach(struct ieee80211vap *vap, struct ieee80211_key *k) 1128a1b9b6aSSam Leffler { 1138a1b9b6aSSam Leffler struct tkip_ctx *ctx; 1148a1b9b6aSSam Leffler 115b9b53389SAdrian Chadd ctx = (struct tkip_ctx *) IEEE80211_MALLOC(sizeof(struct tkip_ctx), 116b9b53389SAdrian Chadd M_80211_CRYPTO, IEEE80211_M_NOWAIT | IEEE80211_M_ZERO); 1178a1b9b6aSSam Leffler if (ctx == NULL) { 118b032f27cSSam Leffler vap->iv_stats.is_crypto_nomem++; 1198a1b9b6aSSam Leffler return NULL; 1208a1b9b6aSSam Leffler } 1218a1b9b6aSSam Leffler 122b032f27cSSam Leffler ctx->tc_vap = vap; 123d16441fdSSam Leffler nrefs++; /* NB: we assume caller locking */ 1248a1b9b6aSSam Leffler return ctx; 1258a1b9b6aSSam Leffler } 1268a1b9b6aSSam Leffler 1278a1b9b6aSSam Leffler static void 1288a1b9b6aSSam Leffler tkip_detach(struct ieee80211_key *k) 1298a1b9b6aSSam Leffler { 1308a1b9b6aSSam Leffler struct tkip_ctx *ctx = k->wk_private; 1318a1b9b6aSSam Leffler 132b9b53389SAdrian Chadd IEEE80211_FREE(ctx, M_80211_CRYPTO); 133d16441fdSSam Leffler KASSERT(nrefs > 0, ("imbalanced attach/detach")); 134d16441fdSSam Leffler nrefs--; /* NB: we assume caller locking */ 1358a1b9b6aSSam Leffler } 1368a1b9b6aSSam Leffler 1378a1b9b6aSSam Leffler static int 1388a1b9b6aSSam Leffler tkip_setkey(struct ieee80211_key *k) 1398a1b9b6aSSam Leffler { 1408a1b9b6aSSam Leffler struct tkip_ctx *ctx = k->wk_private; 1418a1b9b6aSSam Leffler 1428a1b9b6aSSam Leffler if (k->wk_keylen != (128/NBBY)) { 1438a1b9b6aSSam Leffler (void) ctx; /* XXX */ 144b032f27cSSam Leffler IEEE80211_DPRINTF(ctx->tc_vap, IEEE80211_MSG_CRYPTO, 1458a1b9b6aSSam Leffler "%s: Invalid key length %u, expecting %u\n", 1468a1b9b6aSSam Leffler __func__, k->wk_keylen, 128/NBBY); 1478a1b9b6aSSam Leffler return 0; 1488a1b9b6aSSam Leffler } 14998f160d9SBernhard Schmidt ctx->rx_phase1_done = 0; 1508a1b9b6aSSam Leffler return 1; 1518a1b9b6aSSam Leffler } 1528a1b9b6aSSam Leffler 153c0cb9349SAdrian Chadd static void 154c0cb9349SAdrian Chadd tkip_setiv(struct ieee80211_key *k, uint8_t *ivp) 155c0cb9349SAdrian Chadd { 156c0cb9349SAdrian Chadd struct tkip_ctx *ctx = k->wk_private; 157c0cb9349SAdrian Chadd struct ieee80211vap *vap = ctx->tc_vap; 158c0cb9349SAdrian Chadd uint8_t keyid; 159c0cb9349SAdrian Chadd 160c0cb9349SAdrian Chadd keyid = ieee80211_crypto_get_keyid(vap, k) << 6; 161c0cb9349SAdrian Chadd 162c0cb9349SAdrian Chadd k->wk_keytsc++; 163c0cb9349SAdrian Chadd ivp[0] = k->wk_keytsc >> 8; /* TSC1 */ 164c0cb9349SAdrian Chadd ivp[1] = (ivp[0] | 0x20) & 0x7f; /* WEP seed */ 165c0cb9349SAdrian Chadd ivp[2] = k->wk_keytsc >> 0; /* TSC0 */ 166c0cb9349SAdrian Chadd ivp[3] = keyid | IEEE80211_WEP_EXTIV; /* KeyID | ExtID */ 167c0cb9349SAdrian Chadd ivp[4] = k->wk_keytsc >> 16; /* TSC2 */ 168c0cb9349SAdrian Chadd ivp[5] = k->wk_keytsc >> 24; /* TSC3 */ 169c0cb9349SAdrian Chadd ivp[6] = k->wk_keytsc >> 32; /* TSC4 */ 170c0cb9349SAdrian Chadd ivp[7] = k->wk_keytsc >> 40; /* TSC5 */ 171c0cb9349SAdrian Chadd } 172c0cb9349SAdrian Chadd 1738a1b9b6aSSam Leffler /* 1748a1b9b6aSSam Leffler * Add privacy headers and do any s/w encryption required. 1758a1b9b6aSSam Leffler */ 1768a1b9b6aSSam Leffler static int 177ef0d8f63SAdrian Chadd tkip_encap(struct ieee80211_key *k, struct mbuf *m) 1788a1b9b6aSSam Leffler { 1798a1b9b6aSSam Leffler struct tkip_ctx *ctx = k->wk_private; 180b032f27cSSam Leffler struct ieee80211vap *vap = ctx->tc_vap; 181b032f27cSSam Leffler struct ieee80211com *ic = vap->iv_ic; 182fe75b452SAdrian Chadd struct ieee80211_frame *wh; 18368e8e04eSSam Leffler uint8_t *ivp; 1848a1b9b6aSSam Leffler int hdrlen; 185fe75b452SAdrian Chadd int is_mgmt; 186fe75b452SAdrian Chadd 187fe75b452SAdrian Chadd wh = mtod(m, struct ieee80211_frame *); 188fe75b452SAdrian Chadd is_mgmt = IEEE80211_IS_MGMT(wh); 1898a1b9b6aSSam Leffler 1908a1b9b6aSSam Leffler /* 1918a1b9b6aSSam Leffler * Handle TKIP counter measures requirement. 1928a1b9b6aSSam Leffler */ 193b032f27cSSam Leffler if (vap->iv_flags & IEEE80211_F_COUNTERM) { 1948a1b9b6aSSam Leffler #ifdef IEEE80211_DEBUG 1958a1b9b6aSSam Leffler struct ieee80211_frame *wh = mtod(m, struct ieee80211_frame *); 1968a1b9b6aSSam Leffler #endif 1978a1b9b6aSSam Leffler 198b032f27cSSam Leffler IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO, wh->i_addr2, 199b032f27cSSam Leffler "discard frame due to countermeasures (%s)", __func__); 200b032f27cSSam Leffler vap->iv_stats.is_crypto_tkipcm++; 2018a1b9b6aSSam Leffler return 0; 2028a1b9b6aSSam Leffler } 203fe75b452SAdrian Chadd 204fe75b452SAdrian Chadd /* 205fe75b452SAdrian Chadd * Check to see whether IV needs to be included. 206fe75b452SAdrian Chadd */ 207fe75b452SAdrian Chadd if (is_mgmt && (k->wk_flags & IEEE80211_KEY_NOIVMGT)) 208fe75b452SAdrian Chadd return 1; 209fe75b452SAdrian Chadd if ((! is_mgmt) && (k->wk_flags & IEEE80211_KEY_NOIV)) 210fe75b452SAdrian Chadd return 1; 211fe75b452SAdrian Chadd 2124e844c94SSam Leffler hdrlen = ieee80211_hdrspace(ic, mtod(m, void *)); 2138a1b9b6aSSam Leffler 2148a1b9b6aSSam Leffler /* 2158a1b9b6aSSam Leffler * Copy down 802.11 header and add the IV, KeyID, and ExtIV. 2168a1b9b6aSSam Leffler */ 217*bd29f817SBjoern A. Zeeb M_PREPEND(m, tkip.ic_header, IEEE80211_M_NOWAIT); 2188a1b9b6aSSam Leffler if (m == NULL) 2198a1b9b6aSSam Leffler return 0; 22068e8e04eSSam Leffler ivp = mtod(m, uint8_t *); 2218a1b9b6aSSam Leffler memmove(ivp, ivp + tkip.ic_header, hdrlen); 2228a1b9b6aSSam Leffler ivp += hdrlen; 2238a1b9b6aSSam Leffler 224c0cb9349SAdrian Chadd tkip_setiv(k, ivp); 2258a1b9b6aSSam Leffler 2268a1b9b6aSSam Leffler /* 227bf0b7b45SAdrian Chadd * Finally, do software encrypt if needed. 2288a1b9b6aSSam Leffler */ 229483755beSAdrian Chadd if ((k->wk_flags & IEEE80211_KEY_SWENCRYPT) && 230483755beSAdrian Chadd !tkip_encrypt(ctx, k, m, hdrlen)) 2318a1b9b6aSSam Leffler return 0; 2328a1b9b6aSSam Leffler 2338a1b9b6aSSam Leffler return 1; 2348a1b9b6aSSam Leffler } 2358a1b9b6aSSam Leffler 2368a1b9b6aSSam Leffler /* 2378a1b9b6aSSam Leffler * Add MIC to the frame as needed. 2388a1b9b6aSSam Leffler */ 2398a1b9b6aSSam Leffler static int 24096d88463SSam Leffler tkip_enmic(struct ieee80211_key *k, struct mbuf *m, int force) 2418a1b9b6aSSam Leffler { 2428a1b9b6aSSam Leffler struct tkip_ctx *ctx = k->wk_private; 243fe75b452SAdrian Chadd struct ieee80211_frame *wh; 244fe75b452SAdrian Chadd int is_mgmt; 245fe75b452SAdrian Chadd 246fe75b452SAdrian Chadd wh = mtod(m, struct ieee80211_frame *); 247fe75b452SAdrian Chadd is_mgmt = IEEE80211_IS_MGMT(wh); 248fe75b452SAdrian Chadd 249fe75b452SAdrian Chadd /* 250fe75b452SAdrian Chadd * Check to see whether MIC needs to be included. 251fe75b452SAdrian Chadd */ 252fe75b452SAdrian Chadd if (is_mgmt && (k->wk_flags & IEEE80211_KEY_NOMICMGT)) 253fe75b452SAdrian Chadd return 1; 254fe75b452SAdrian Chadd if ((! is_mgmt) && (k->wk_flags & IEEE80211_KEY_NOMIC)) 255fe75b452SAdrian Chadd return 1; 2568a1b9b6aSSam Leffler 2575c1f7f19SSam Leffler if (force || (k->wk_flags & IEEE80211_KEY_SWENMIC)) { 2588a1b9b6aSSam Leffler struct ieee80211_frame *wh = mtod(m, struct ieee80211_frame *); 259b032f27cSSam Leffler struct ieee80211vap *vap = ctx->tc_vap; 260b032f27cSSam Leffler struct ieee80211com *ic = vap->iv_ic; 2614e844c94SSam Leffler int hdrlen; 2628a1b9b6aSSam Leffler uint8_t mic[IEEE80211_WEP_MICLEN]; 2638a1b9b6aSSam Leffler 264b032f27cSSam Leffler vap->iv_stats.is_crypto_tkipenmic++; 2654e844c94SSam Leffler 2664e844c94SSam Leffler hdrlen = ieee80211_hdrspace(ic, wh); 2678a1b9b6aSSam Leffler 2688a1b9b6aSSam Leffler michael_mic(ctx, k->wk_txmic, 2698a1b9b6aSSam Leffler m, hdrlen, m->m_pkthdr.len - hdrlen, mic); 2708a1b9b6aSSam Leffler return m_append(m, tkip.ic_miclen, mic); 2718a1b9b6aSSam Leffler } 2728a1b9b6aSSam Leffler return 1; 2738a1b9b6aSSam Leffler } 2748a1b9b6aSSam Leffler 2758a1b9b6aSSam Leffler static __inline uint64_t 2768a1b9b6aSSam Leffler READ_6(uint8_t b0, uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4, uint8_t b5) 2778a1b9b6aSSam Leffler { 2788a1b9b6aSSam Leffler uint32_t iv32 = (b0 << 0) | (b1 << 8) | (b2 << 16) | (b3 << 24); 2798a1b9b6aSSam Leffler uint16_t iv16 = (b4 << 0) | (b5 << 8); 2808a1b9b6aSSam Leffler return (((uint64_t)iv16) << 32) | iv32; 2818a1b9b6aSSam Leffler } 2828a1b9b6aSSam Leffler 2838a1b9b6aSSam Leffler /* 2848a1b9b6aSSam Leffler * Validate and strip privacy headers (and trailer) for a 2858a1b9b6aSSam Leffler * received frame. If necessary, decrypt the frame using 2868a1b9b6aSSam Leffler * the specified key. 2878a1b9b6aSSam Leffler */ 2888a1b9b6aSSam Leffler static int 2892cc12adeSSam Leffler tkip_decap(struct ieee80211_key *k, struct mbuf *m, int hdrlen) 2908a1b9b6aSSam Leffler { 291fe75b452SAdrian Chadd const struct ieee80211_rx_stats *rxs; 2928a1b9b6aSSam Leffler struct tkip_ctx *ctx = k->wk_private; 293b032f27cSSam Leffler struct ieee80211vap *vap = ctx->tc_vap; 2948a1b9b6aSSam Leffler struct ieee80211_frame *wh; 295b032f27cSSam Leffler uint8_t *ivp, tid; 2968a1b9b6aSSam Leffler 297fe75b452SAdrian Chadd rxs = ieee80211_get_rx_params_ptr(m); 298fe75b452SAdrian Chadd 299fe75b452SAdrian Chadd /* 300fe75b452SAdrian Chadd * If IV has been stripped, we skip most of the below. 301fe75b452SAdrian Chadd */ 302fe75b452SAdrian Chadd if ((rxs != NULL) && (rxs->c_pktflags & IEEE80211_RX_F_IV_STRIP)) 303fe75b452SAdrian Chadd goto finish; 304fe75b452SAdrian Chadd 3058a1b9b6aSSam Leffler /* 3068a1b9b6aSSam Leffler * Header should have extended IV and sequence number; 3078a1b9b6aSSam Leffler * verify the former and validate the latter. 3088a1b9b6aSSam Leffler */ 3098a1b9b6aSSam Leffler wh = mtod(m, struct ieee80211_frame *); 3108a1b9b6aSSam Leffler ivp = mtod(m, uint8_t *) + hdrlen; 3118a1b9b6aSSam Leffler if ((ivp[IEEE80211_WEP_IVLEN] & IEEE80211_WEP_EXTIV) == 0) { 3128a1b9b6aSSam Leffler /* 3138a1b9b6aSSam Leffler * No extended IV; discard frame. 3148a1b9b6aSSam Leffler */ 315b032f27cSSam Leffler IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO, wh->i_addr2, 316b032f27cSSam Leffler "%s", "missing ExtIV for TKIP cipher"); 317b032f27cSSam Leffler vap->iv_stats.is_rx_tkipformat++; 3188a1b9b6aSSam Leffler return 0; 3198a1b9b6aSSam Leffler } 3208a1b9b6aSSam Leffler /* 3218a1b9b6aSSam Leffler * Handle TKIP counter measures requirement. 3228a1b9b6aSSam Leffler */ 323b032f27cSSam Leffler if (vap->iv_flags & IEEE80211_F_COUNTERM) { 324b032f27cSSam Leffler IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO, wh->i_addr2, 325b032f27cSSam Leffler "discard frame due to countermeasures (%s)", __func__); 326b032f27cSSam Leffler vap->iv_stats.is_crypto_tkipcm++; 3278a1b9b6aSSam Leffler return 0; 3288a1b9b6aSSam Leffler } 3298a1b9b6aSSam Leffler 330b032f27cSSam Leffler tid = ieee80211_gettid(wh); 331f287c95bSSam Leffler ctx->rx_rsc = READ_6(ivp[2], ivp[0], ivp[4], ivp[5], ivp[6], ivp[7]); 3325d766a09SBernhard Schmidt if (ctx->rx_rsc <= k->wk_keyrsc[tid] && 3335d766a09SBernhard Schmidt (k->wk_flags & IEEE80211_KEY_NOREPLAY) == 0) { 3348a1b9b6aSSam Leffler /* 3358a1b9b6aSSam Leffler * Replay violation; notify upper layer. 3368a1b9b6aSSam Leffler */ 337ebaf87ebSSam Leffler ieee80211_notify_replay_failure(vap, wh, k, ctx->rx_rsc, tid); 338b032f27cSSam Leffler vap->iv_stats.is_rx_tkipreplay++; 3398a1b9b6aSSam Leffler return 0; 3408a1b9b6aSSam Leffler } 3418a1b9b6aSSam Leffler /* 3428a1b9b6aSSam Leffler * NB: We can't update the rsc in the key until MIC is verified. 3438a1b9b6aSSam Leffler * 3448a1b9b6aSSam Leffler * We assume we are not preempted between doing the check above 3458a1b9b6aSSam Leffler * and updating wk_keyrsc when stripping the MIC in tkip_demic. 3468a1b9b6aSSam Leffler * Otherwise we might process another packet and discard it as 3478a1b9b6aSSam Leffler * a replay. 3488a1b9b6aSSam Leffler */ 3498a1b9b6aSSam Leffler 3508a1b9b6aSSam Leffler /* 3518a1b9b6aSSam Leffler * Check if the device handled the decrypt in hardware. 3528a1b9b6aSSam Leffler * If so we just strip the header; otherwise we need to 3538a1b9b6aSSam Leffler * handle the decrypt in software. 3548a1b9b6aSSam Leffler */ 3555c1f7f19SSam Leffler if ((k->wk_flags & IEEE80211_KEY_SWDECRYPT) && 3568a1b9b6aSSam Leffler !tkip_decrypt(ctx, k, m, hdrlen)) 3578a1b9b6aSSam Leffler return 0; 3588a1b9b6aSSam Leffler 359fe75b452SAdrian Chadd finish: 360fe75b452SAdrian Chadd 3618a1b9b6aSSam Leffler /* 362fe75b452SAdrian Chadd * Copy up 802.11 header and strip crypto bits - but only if we 363fe75b452SAdrian Chadd * are required to. 3648a1b9b6aSSam Leffler */ 365fe75b452SAdrian Chadd if (! ((rxs != NULL) && (rxs->c_pktflags & IEEE80211_RX_F_IV_STRIP))) { 366fe75b452SAdrian Chadd memmove(mtod(m, uint8_t *) + tkip.ic_header, mtod(m, void *), 367fe75b452SAdrian Chadd hdrlen); 3688a1b9b6aSSam Leffler m_adj(m, tkip.ic_header); 369fe75b452SAdrian Chadd } 370fe75b452SAdrian Chadd 371fe75b452SAdrian Chadd /* 372fe75b452SAdrian Chadd * XXX TODO: do we need an option to potentially not strip the 373fe75b452SAdrian Chadd * WEP trailer? Does "MMIC_STRIP" also mean this? Or? 374fe75b452SAdrian Chadd */ 3758a1b9b6aSSam Leffler m_adj(m, -tkip.ic_trailer); 3768a1b9b6aSSam Leffler 3778a1b9b6aSSam Leffler return 1; 3788a1b9b6aSSam Leffler } 3798a1b9b6aSSam Leffler 3808a1b9b6aSSam Leffler /* 3818a1b9b6aSSam Leffler * Verify and strip MIC from the frame. 3828a1b9b6aSSam Leffler */ 3838a1b9b6aSSam Leffler static int 38496d88463SSam Leffler tkip_demic(struct ieee80211_key *k, struct mbuf *m, int force) 3858a1b9b6aSSam Leffler { 386fe75b452SAdrian Chadd const struct ieee80211_rx_stats *rxs; 3878a1b9b6aSSam Leffler struct tkip_ctx *ctx = k->wk_private; 388b032f27cSSam Leffler struct ieee80211_frame *wh; 389b032f27cSSam Leffler uint8_t tid; 3908a1b9b6aSSam Leffler 391b032f27cSSam Leffler wh = mtod(m, struct ieee80211_frame *); 392fe75b452SAdrian Chadd rxs = ieee80211_get_rx_params_ptr(m); 393fe75b452SAdrian Chadd 394fe75b452SAdrian Chadd /* 395fe75b452SAdrian Chadd * If we are told about a MIC failure from the driver, 396fe75b452SAdrian Chadd * directly notify as a michael failure to the upper 397fe75b452SAdrian Chadd * layers. 398fe75b452SAdrian Chadd */ 399fe75b452SAdrian Chadd if ((rxs != NULL) && (rxs->c_pktflags & IEEE80211_RX_F_FAIL_MIC)) { 400fe75b452SAdrian Chadd struct ieee80211vap *vap = ctx->tc_vap; 401fe75b452SAdrian Chadd ieee80211_notify_michael_failure(vap, wh, 402fe75b452SAdrian Chadd k->wk_rxkeyix != IEEE80211_KEYIX_NONE ? 403fe75b452SAdrian Chadd k->wk_rxkeyix : k->wk_keyix); 404fe75b452SAdrian Chadd return 0; 405fe75b452SAdrian Chadd } 406fe75b452SAdrian Chadd 407fe75b452SAdrian Chadd /* 408fe75b452SAdrian Chadd * If IV has been stripped, we skip most of the below. 409fe75b452SAdrian Chadd */ 410fe75b452SAdrian Chadd if ((rxs != NULL) && (rxs->c_pktflags & IEEE80211_RX_F_MMIC_STRIP)) 411fe75b452SAdrian Chadd goto finish; 412fe75b452SAdrian Chadd 4135c1f7f19SSam Leffler if ((k->wk_flags & IEEE80211_KEY_SWDEMIC) || force) { 414b032f27cSSam Leffler struct ieee80211vap *vap = ctx->tc_vap; 415b032f27cSSam Leffler int hdrlen = ieee80211_hdrspace(vap->iv_ic, wh); 4168a1b9b6aSSam Leffler u8 mic[IEEE80211_WEP_MICLEN]; 4178a1b9b6aSSam Leffler u8 mic0[IEEE80211_WEP_MICLEN]; 4188a1b9b6aSSam Leffler 419b032f27cSSam Leffler vap->iv_stats.is_crypto_tkipdemic++; 4208a1b9b6aSSam Leffler 4218a1b9b6aSSam Leffler michael_mic(ctx, k->wk_rxmic, 4228a1b9b6aSSam Leffler m, hdrlen, m->m_pkthdr.len - (hdrlen + tkip.ic_miclen), 4238a1b9b6aSSam Leffler mic); 4248a1b9b6aSSam Leffler m_copydata(m, m->m_pkthdr.len - tkip.ic_miclen, 4258a1b9b6aSSam Leffler tkip.ic_miclen, mic0); 4268a1b9b6aSSam Leffler if (memcmp(mic, mic0, tkip.ic_miclen)) { 4278a1b9b6aSSam Leffler /* NB: 802.11 layer handles statistic and debug msg */ 428b032f27cSSam Leffler ieee80211_notify_michael_failure(vap, wh, 429c1225b52SSam Leffler k->wk_rxkeyix != IEEE80211_KEYIX_NONE ? 430c1225b52SSam Leffler k->wk_rxkeyix : k->wk_keyix); 4318a1b9b6aSSam Leffler return 0; 4328a1b9b6aSSam Leffler } 4338a1b9b6aSSam Leffler } 4348a1b9b6aSSam Leffler /* 4358a1b9b6aSSam Leffler * Strip MIC from the tail. 4368a1b9b6aSSam Leffler */ 4378a1b9b6aSSam Leffler m_adj(m, -tkip.ic_miclen); 4388a1b9b6aSSam Leffler 4398a1b9b6aSSam Leffler /* 4408a1b9b6aSSam Leffler * Ok to update rsc now that MIC has been verified. 4418a1b9b6aSSam Leffler */ 442b032f27cSSam Leffler tid = ieee80211_gettid(wh); 443b032f27cSSam Leffler k->wk_keyrsc[tid] = ctx->rx_rsc; 4448a1b9b6aSSam Leffler 445fe75b452SAdrian Chadd finish: 4468a1b9b6aSSam Leffler return 1; 4478a1b9b6aSSam Leffler } 4488a1b9b6aSSam Leffler 4498a1b9b6aSSam Leffler /* 4508a1b9b6aSSam Leffler * Host AP crypt: host-based TKIP encryption implementation for Host AP driver 4518a1b9b6aSSam Leffler * 4528a1b9b6aSSam Leffler * Copyright (c) 2003-2004, Jouni Malinen <jkmaline@cc.hut.fi> 4538a1b9b6aSSam Leffler * 4548a1b9b6aSSam Leffler * This program is free software; you can redistribute it and/or modify 4558a1b9b6aSSam Leffler * it under the terms of the GNU General Public License version 2 as 4568a1b9b6aSSam Leffler * published by the Free Software Foundation. See README and COPYING for 4578a1b9b6aSSam Leffler * more details. 4588a1b9b6aSSam Leffler * 4598a1b9b6aSSam Leffler * Alternatively, this software may be distributed under the terms of BSD 4608a1b9b6aSSam Leffler * license. 4618a1b9b6aSSam Leffler */ 4628a1b9b6aSSam Leffler 4638a1b9b6aSSam Leffler static const __u32 crc32_table[256] = { 4648a1b9b6aSSam Leffler 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, 4658a1b9b6aSSam Leffler 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, 4668a1b9b6aSSam Leffler 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, 4678a1b9b6aSSam Leffler 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, 4688a1b9b6aSSam Leffler 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, 4698a1b9b6aSSam Leffler 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, 4708a1b9b6aSSam Leffler 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, 4718a1b9b6aSSam Leffler 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, 4728a1b9b6aSSam Leffler 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, 4738a1b9b6aSSam Leffler 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, 4748a1b9b6aSSam Leffler 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, 4758a1b9b6aSSam Leffler 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, 4768a1b9b6aSSam Leffler 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L, 4778a1b9b6aSSam Leffler 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, 4788a1b9b6aSSam Leffler 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, 4798a1b9b6aSSam Leffler 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, 4808a1b9b6aSSam Leffler 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, 4818a1b9b6aSSam Leffler 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, 4828a1b9b6aSSam Leffler 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, 4838a1b9b6aSSam Leffler 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, 4848a1b9b6aSSam Leffler 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, 4858a1b9b6aSSam Leffler 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, 4868a1b9b6aSSam Leffler 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, 4878a1b9b6aSSam Leffler 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, 4888a1b9b6aSSam Leffler 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, 4898a1b9b6aSSam Leffler 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L, 4908a1b9b6aSSam Leffler 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, 4918a1b9b6aSSam Leffler 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, 4928a1b9b6aSSam Leffler 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L, 4938a1b9b6aSSam Leffler 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, 4948a1b9b6aSSam Leffler 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, 4958a1b9b6aSSam Leffler 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, 4968a1b9b6aSSam Leffler 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, 4978a1b9b6aSSam Leffler 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, 4988a1b9b6aSSam Leffler 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, 4998a1b9b6aSSam Leffler 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, 5008a1b9b6aSSam Leffler 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL, 5018a1b9b6aSSam Leffler 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, 5028a1b9b6aSSam Leffler 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, 5038a1b9b6aSSam Leffler 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, 5048a1b9b6aSSam Leffler 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, 5058a1b9b6aSSam Leffler 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, 5068a1b9b6aSSam Leffler 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, 5078a1b9b6aSSam Leffler 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, 5088a1b9b6aSSam Leffler 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, 5098a1b9b6aSSam Leffler 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, 5108a1b9b6aSSam Leffler 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, 5118a1b9b6aSSam Leffler 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, 5128a1b9b6aSSam Leffler 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, 5138a1b9b6aSSam Leffler 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L, 5148a1b9b6aSSam Leffler 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, 5158a1b9b6aSSam Leffler 0x2d02ef8dL 5168a1b9b6aSSam Leffler }; 5178a1b9b6aSSam Leffler 5188a1b9b6aSSam Leffler static __inline u16 RotR1(u16 val) 5198a1b9b6aSSam Leffler { 5208a1b9b6aSSam Leffler return (val >> 1) | (val << 15); 5218a1b9b6aSSam Leffler } 5228a1b9b6aSSam Leffler 5238a1b9b6aSSam Leffler static __inline u8 Lo8(u16 val) 5248a1b9b6aSSam Leffler { 5258a1b9b6aSSam Leffler return val & 0xff; 5268a1b9b6aSSam Leffler } 5278a1b9b6aSSam Leffler 5288a1b9b6aSSam Leffler static __inline u8 Hi8(u16 val) 5298a1b9b6aSSam Leffler { 5308a1b9b6aSSam Leffler return val >> 8; 5318a1b9b6aSSam Leffler } 5328a1b9b6aSSam Leffler 5338a1b9b6aSSam Leffler static __inline u16 Lo16(u32 val) 5348a1b9b6aSSam Leffler { 5358a1b9b6aSSam Leffler return val & 0xffff; 5368a1b9b6aSSam Leffler } 5378a1b9b6aSSam Leffler 5388a1b9b6aSSam Leffler static __inline u16 Hi16(u32 val) 5398a1b9b6aSSam Leffler { 5408a1b9b6aSSam Leffler return val >> 16; 5418a1b9b6aSSam Leffler } 5428a1b9b6aSSam Leffler 5438a1b9b6aSSam Leffler static __inline u16 Mk16(u8 hi, u8 lo) 5448a1b9b6aSSam Leffler { 5458a1b9b6aSSam Leffler return lo | (((u16) hi) << 8); 5468a1b9b6aSSam Leffler } 5478a1b9b6aSSam Leffler 5488a1b9b6aSSam Leffler static __inline u16 Mk16_le(const u16 *v) 5498a1b9b6aSSam Leffler { 5508a1b9b6aSSam Leffler return le16toh(*v); 5518a1b9b6aSSam Leffler } 5528a1b9b6aSSam Leffler 5538a1b9b6aSSam Leffler static const u16 Sbox[256] = { 5548a1b9b6aSSam Leffler 0xC6A5, 0xF884, 0xEE99, 0xF68D, 0xFF0D, 0xD6BD, 0xDEB1, 0x9154, 5558a1b9b6aSSam Leffler 0x6050, 0x0203, 0xCEA9, 0x567D, 0xE719, 0xB562, 0x4DE6, 0xEC9A, 5568a1b9b6aSSam Leffler 0x8F45, 0x1F9D, 0x8940, 0xFA87, 0xEF15, 0xB2EB, 0x8EC9, 0xFB0B, 5578a1b9b6aSSam Leffler 0x41EC, 0xB367, 0x5FFD, 0x45EA, 0x23BF, 0x53F7, 0xE496, 0x9B5B, 5588a1b9b6aSSam Leffler 0x75C2, 0xE11C, 0x3DAE, 0x4C6A, 0x6C5A, 0x7E41, 0xF502, 0x834F, 5598a1b9b6aSSam Leffler 0x685C, 0x51F4, 0xD134, 0xF908, 0xE293, 0xAB73, 0x6253, 0x2A3F, 5608a1b9b6aSSam Leffler 0x080C, 0x9552, 0x4665, 0x9D5E, 0x3028, 0x37A1, 0x0A0F, 0x2FB5, 5618a1b9b6aSSam Leffler 0x0E09, 0x2436, 0x1B9B, 0xDF3D, 0xCD26, 0x4E69, 0x7FCD, 0xEA9F, 5628a1b9b6aSSam Leffler 0x121B, 0x1D9E, 0x5874, 0x342E, 0x362D, 0xDCB2, 0xB4EE, 0x5BFB, 5638a1b9b6aSSam Leffler 0xA4F6, 0x764D, 0xB761, 0x7DCE, 0x527B, 0xDD3E, 0x5E71, 0x1397, 5648a1b9b6aSSam Leffler 0xA6F5, 0xB968, 0x0000, 0xC12C, 0x4060, 0xE31F, 0x79C8, 0xB6ED, 5658a1b9b6aSSam Leffler 0xD4BE, 0x8D46, 0x67D9, 0x724B, 0x94DE, 0x98D4, 0xB0E8, 0x854A, 5668a1b9b6aSSam Leffler 0xBB6B, 0xC52A, 0x4FE5, 0xED16, 0x86C5, 0x9AD7, 0x6655, 0x1194, 5678a1b9b6aSSam Leffler 0x8ACF, 0xE910, 0x0406, 0xFE81, 0xA0F0, 0x7844, 0x25BA, 0x4BE3, 5688a1b9b6aSSam Leffler 0xA2F3, 0x5DFE, 0x80C0, 0x058A, 0x3FAD, 0x21BC, 0x7048, 0xF104, 5698a1b9b6aSSam Leffler 0x63DF, 0x77C1, 0xAF75, 0x4263, 0x2030, 0xE51A, 0xFD0E, 0xBF6D, 5708a1b9b6aSSam Leffler 0x814C, 0x1814, 0x2635, 0xC32F, 0xBEE1, 0x35A2, 0x88CC, 0x2E39, 5718a1b9b6aSSam Leffler 0x9357, 0x55F2, 0xFC82, 0x7A47, 0xC8AC, 0xBAE7, 0x322B, 0xE695, 5728a1b9b6aSSam Leffler 0xC0A0, 0x1998, 0x9ED1, 0xA37F, 0x4466, 0x547E, 0x3BAB, 0x0B83, 5738a1b9b6aSSam Leffler 0x8CCA, 0xC729, 0x6BD3, 0x283C, 0xA779, 0xBCE2, 0x161D, 0xAD76, 5748a1b9b6aSSam Leffler 0xDB3B, 0x6456, 0x744E, 0x141E, 0x92DB, 0x0C0A, 0x486C, 0xB8E4, 5758a1b9b6aSSam Leffler 0x9F5D, 0xBD6E, 0x43EF, 0xC4A6, 0x39A8, 0x31A4, 0xD337, 0xF28B, 5768a1b9b6aSSam Leffler 0xD532, 0x8B43, 0x6E59, 0xDAB7, 0x018C, 0xB164, 0x9CD2, 0x49E0, 5778a1b9b6aSSam Leffler 0xD8B4, 0xACFA, 0xF307, 0xCF25, 0xCAAF, 0xF48E, 0x47E9, 0x1018, 5788a1b9b6aSSam Leffler 0x6FD5, 0xF088, 0x4A6F, 0x5C72, 0x3824, 0x57F1, 0x73C7, 0x9751, 5798a1b9b6aSSam Leffler 0xCB23, 0xA17C, 0xE89C, 0x3E21, 0x96DD, 0x61DC, 0x0D86, 0x0F85, 5808a1b9b6aSSam Leffler 0xE090, 0x7C42, 0x71C4, 0xCCAA, 0x90D8, 0x0605, 0xF701, 0x1C12, 5818a1b9b6aSSam Leffler 0xC2A3, 0x6A5F, 0xAEF9, 0x69D0, 0x1791, 0x9958, 0x3A27, 0x27B9, 5828a1b9b6aSSam Leffler 0xD938, 0xEB13, 0x2BB3, 0x2233, 0xD2BB, 0xA970, 0x0789, 0x33A7, 5838a1b9b6aSSam Leffler 0x2DB6, 0x3C22, 0x1592, 0xC920, 0x8749, 0xAAFF, 0x5078, 0xA57A, 5848a1b9b6aSSam Leffler 0x038F, 0x59F8, 0x0980, 0x1A17, 0x65DA, 0xD731, 0x84C6, 0xD0B8, 5858a1b9b6aSSam Leffler 0x82C3, 0x29B0, 0x5A77, 0x1E11, 0x7BCB, 0xA8FC, 0x6DD6, 0x2C3A, 5868a1b9b6aSSam Leffler }; 5878a1b9b6aSSam Leffler 5888a1b9b6aSSam Leffler static __inline u16 _S_(u16 v) 5898a1b9b6aSSam Leffler { 5908a1b9b6aSSam Leffler u16 t = Sbox[Hi8(v)]; 5918a1b9b6aSSam Leffler return Sbox[Lo8(v)] ^ ((t << 8) | (t >> 8)); 5928a1b9b6aSSam Leffler } 5938a1b9b6aSSam Leffler 5948a1b9b6aSSam Leffler #define PHASE1_LOOP_COUNT 8 5958a1b9b6aSSam Leffler 5968a1b9b6aSSam Leffler static void tkip_mixing_phase1(u16 *TTAK, const u8 *TK, const u8 *TA, u32 IV32) 5978a1b9b6aSSam Leffler { 5988a1b9b6aSSam Leffler int i, j; 5998a1b9b6aSSam Leffler 6008a1b9b6aSSam Leffler /* Initialize the 80-bit TTAK from TSC (IV32) and TA[0..5] */ 6018a1b9b6aSSam Leffler TTAK[0] = Lo16(IV32); 6028a1b9b6aSSam Leffler TTAK[1] = Hi16(IV32); 6038a1b9b6aSSam Leffler TTAK[2] = Mk16(TA[1], TA[0]); 6048a1b9b6aSSam Leffler TTAK[3] = Mk16(TA[3], TA[2]); 6058a1b9b6aSSam Leffler TTAK[4] = Mk16(TA[5], TA[4]); 6068a1b9b6aSSam Leffler 6078a1b9b6aSSam Leffler for (i = 0; i < PHASE1_LOOP_COUNT; i++) { 6088a1b9b6aSSam Leffler j = 2 * (i & 1); 6098a1b9b6aSSam Leffler TTAK[0] += _S_(TTAK[4] ^ Mk16(TK[1 + j], TK[0 + j])); 6108a1b9b6aSSam Leffler TTAK[1] += _S_(TTAK[0] ^ Mk16(TK[5 + j], TK[4 + j])); 6118a1b9b6aSSam Leffler TTAK[2] += _S_(TTAK[1] ^ Mk16(TK[9 + j], TK[8 + j])); 6128a1b9b6aSSam Leffler TTAK[3] += _S_(TTAK[2] ^ Mk16(TK[13 + j], TK[12 + j])); 6138a1b9b6aSSam Leffler TTAK[4] += _S_(TTAK[3] ^ Mk16(TK[1 + j], TK[0 + j])) + i; 6148a1b9b6aSSam Leffler } 6158a1b9b6aSSam Leffler } 6168a1b9b6aSSam Leffler 6178a1b9b6aSSam Leffler #ifndef _BYTE_ORDER 6188a1b9b6aSSam Leffler #error "Don't know native byte order" 6198a1b9b6aSSam Leffler #endif 6208a1b9b6aSSam Leffler 6218a1b9b6aSSam Leffler static void tkip_mixing_phase2(u8 *WEPSeed, const u8 *TK, const u16 *TTAK, 6228a1b9b6aSSam Leffler u16 IV16) 6238a1b9b6aSSam Leffler { 6248a1b9b6aSSam Leffler /* Make temporary area overlap WEP seed so that the final copy can be 6258a1b9b6aSSam Leffler * avoided on little endian hosts. */ 6268a1b9b6aSSam Leffler u16 *PPK = (u16 *) &WEPSeed[4]; 6278a1b9b6aSSam Leffler 6288a1b9b6aSSam Leffler /* Step 1 - make copy of TTAK and bring in TSC */ 6298a1b9b6aSSam Leffler PPK[0] = TTAK[0]; 6308a1b9b6aSSam Leffler PPK[1] = TTAK[1]; 6318a1b9b6aSSam Leffler PPK[2] = TTAK[2]; 6328a1b9b6aSSam Leffler PPK[3] = TTAK[3]; 6338a1b9b6aSSam Leffler PPK[4] = TTAK[4]; 6348a1b9b6aSSam Leffler PPK[5] = TTAK[4] + IV16; 6358a1b9b6aSSam Leffler 6368a1b9b6aSSam Leffler /* Step 2 - 96-bit bijective mixing using S-box */ 6378a1b9b6aSSam Leffler PPK[0] += _S_(PPK[5] ^ Mk16_le((const u16 *) &TK[0])); 6388a1b9b6aSSam Leffler PPK[1] += _S_(PPK[0] ^ Mk16_le((const u16 *) &TK[2])); 6398a1b9b6aSSam Leffler PPK[2] += _S_(PPK[1] ^ Mk16_le((const u16 *) &TK[4])); 6408a1b9b6aSSam Leffler PPK[3] += _S_(PPK[2] ^ Mk16_le((const u16 *) &TK[6])); 6418a1b9b6aSSam Leffler PPK[4] += _S_(PPK[3] ^ Mk16_le((const u16 *) &TK[8])); 6428a1b9b6aSSam Leffler PPK[5] += _S_(PPK[4] ^ Mk16_le((const u16 *) &TK[10])); 6438a1b9b6aSSam Leffler 6448a1b9b6aSSam Leffler PPK[0] += RotR1(PPK[5] ^ Mk16_le((const u16 *) &TK[12])); 6458a1b9b6aSSam Leffler PPK[1] += RotR1(PPK[0] ^ Mk16_le((const u16 *) &TK[14])); 6468a1b9b6aSSam Leffler PPK[2] += RotR1(PPK[1]); 6478a1b9b6aSSam Leffler PPK[3] += RotR1(PPK[2]); 6488a1b9b6aSSam Leffler PPK[4] += RotR1(PPK[3]); 6498a1b9b6aSSam Leffler PPK[5] += RotR1(PPK[4]); 6508a1b9b6aSSam Leffler 6518a1b9b6aSSam Leffler /* Step 3 - bring in last of TK bits, assign 24-bit WEP IV value 6528a1b9b6aSSam Leffler * WEPSeed[0..2] is transmitted as WEP IV */ 6538a1b9b6aSSam Leffler WEPSeed[0] = Hi8(IV16); 6548a1b9b6aSSam Leffler WEPSeed[1] = (Hi8(IV16) | 0x20) & 0x7F; 6558a1b9b6aSSam Leffler WEPSeed[2] = Lo8(IV16); 6568a1b9b6aSSam Leffler WEPSeed[3] = Lo8((PPK[5] ^ Mk16_le((const u16 *) &TK[0])) >> 1); 6578a1b9b6aSSam Leffler 6588a1b9b6aSSam Leffler #if _BYTE_ORDER == _BIG_ENDIAN 6598a1b9b6aSSam Leffler { 6608a1b9b6aSSam Leffler int i; 6618a1b9b6aSSam Leffler for (i = 0; i < 6; i++) 6628a1b9b6aSSam Leffler PPK[i] = (PPK[i] << 8) | (PPK[i] >> 8); 6638a1b9b6aSSam Leffler } 6648a1b9b6aSSam Leffler #endif 6658a1b9b6aSSam Leffler } 6668a1b9b6aSSam Leffler 6678a1b9b6aSSam Leffler static void 6688a1b9b6aSSam Leffler wep_encrypt(u8 *key, struct mbuf *m0, u_int off, size_t data_len, 6698a1b9b6aSSam Leffler uint8_t icv[IEEE80211_WEP_CRCLEN]) 6708a1b9b6aSSam Leffler { 6718a1b9b6aSSam Leffler u32 i, j, k, crc; 6728a1b9b6aSSam Leffler size_t buflen; 6738a1b9b6aSSam Leffler u8 S[256]; 6748a1b9b6aSSam Leffler u8 *pos; 6758a1b9b6aSSam Leffler struct mbuf *m; 6768a1b9b6aSSam Leffler #define S_SWAP(a,b) do { u8 t = S[a]; S[a] = S[b]; S[b] = t; } while(0) 6778a1b9b6aSSam Leffler 6788a1b9b6aSSam Leffler /* Setup RC4 state */ 6798a1b9b6aSSam Leffler for (i = 0; i < 256; i++) 6808a1b9b6aSSam Leffler S[i] = i; 6818a1b9b6aSSam Leffler j = 0; 6828a1b9b6aSSam Leffler for (i = 0; i < 256; i++) { 6838a1b9b6aSSam Leffler j = (j + S[i] + key[i & 0x0f]) & 0xff; 6848a1b9b6aSSam Leffler S_SWAP(i, j); 6858a1b9b6aSSam Leffler } 6868a1b9b6aSSam Leffler 6878a1b9b6aSSam Leffler /* Compute CRC32 over unencrypted data and apply RC4 to data */ 6888a1b9b6aSSam Leffler crc = ~0; 6898a1b9b6aSSam Leffler i = j = 0; 6908a1b9b6aSSam Leffler m = m0; 6918a1b9b6aSSam Leffler pos = mtod(m, uint8_t *) + off; 6928a1b9b6aSSam Leffler buflen = m->m_len - off; 6938a1b9b6aSSam Leffler for (;;) { 6948a1b9b6aSSam Leffler if (buflen > data_len) 6958a1b9b6aSSam Leffler buflen = data_len; 6968a1b9b6aSSam Leffler data_len -= buflen; 6978a1b9b6aSSam Leffler for (k = 0; k < buflen; k++) { 6988a1b9b6aSSam Leffler crc = crc32_table[(crc ^ *pos) & 0xff] ^ (crc >> 8); 6998a1b9b6aSSam Leffler i = (i + 1) & 0xff; 7008a1b9b6aSSam Leffler j = (j + S[i]) & 0xff; 7018a1b9b6aSSam Leffler S_SWAP(i, j); 7028a1b9b6aSSam Leffler *pos++ ^= S[(S[i] + S[j]) & 0xff]; 7038a1b9b6aSSam Leffler } 7048a1b9b6aSSam Leffler m = m->m_next; 7058a1b9b6aSSam Leffler if (m == NULL) { 7068a1b9b6aSSam Leffler KASSERT(data_len == 0, 70716574882SSam Leffler ("out of buffers with data_len %zu\n", data_len)); 7088a1b9b6aSSam Leffler break; 7098a1b9b6aSSam Leffler } 7108a1b9b6aSSam Leffler pos = mtod(m, uint8_t *); 7118a1b9b6aSSam Leffler buflen = m->m_len; 7128a1b9b6aSSam Leffler } 7138a1b9b6aSSam Leffler crc = ~crc; 7148a1b9b6aSSam Leffler 7158a1b9b6aSSam Leffler /* Append little-endian CRC32 and encrypt it to produce ICV */ 7168a1b9b6aSSam Leffler icv[0] = crc; 7178a1b9b6aSSam Leffler icv[1] = crc >> 8; 7188a1b9b6aSSam Leffler icv[2] = crc >> 16; 7198a1b9b6aSSam Leffler icv[3] = crc >> 24; 7208a1b9b6aSSam Leffler for (k = 0; k < IEEE80211_WEP_CRCLEN; k++) { 7218a1b9b6aSSam Leffler i = (i + 1) & 0xff; 7228a1b9b6aSSam Leffler j = (j + S[i]) & 0xff; 7238a1b9b6aSSam Leffler S_SWAP(i, j); 7248a1b9b6aSSam Leffler icv[k] ^= S[(S[i] + S[j]) & 0xff]; 7258a1b9b6aSSam Leffler } 7268a1b9b6aSSam Leffler } 7278a1b9b6aSSam Leffler 7288a1b9b6aSSam Leffler static int 7298a1b9b6aSSam Leffler wep_decrypt(u8 *key, struct mbuf *m, u_int off, size_t data_len) 7308a1b9b6aSSam Leffler { 7318a1b9b6aSSam Leffler u32 i, j, k, crc; 7328a1b9b6aSSam Leffler u8 S[256]; 7338a1b9b6aSSam Leffler u8 *pos, icv[4]; 7348a1b9b6aSSam Leffler size_t buflen; 7358a1b9b6aSSam Leffler 7368a1b9b6aSSam Leffler /* Setup RC4 state */ 7378a1b9b6aSSam Leffler for (i = 0; i < 256; i++) 7388a1b9b6aSSam Leffler S[i] = i; 7398a1b9b6aSSam Leffler j = 0; 7408a1b9b6aSSam Leffler for (i = 0; i < 256; i++) { 7418a1b9b6aSSam Leffler j = (j + S[i] + key[i & 0x0f]) & 0xff; 7428a1b9b6aSSam Leffler S_SWAP(i, j); 7438a1b9b6aSSam Leffler } 7448a1b9b6aSSam Leffler 7458a1b9b6aSSam Leffler /* Apply RC4 to data and compute CRC32 over decrypted data */ 7468a1b9b6aSSam Leffler crc = ~0; 7478a1b9b6aSSam Leffler i = j = 0; 7488a1b9b6aSSam Leffler pos = mtod(m, uint8_t *) + off; 7498a1b9b6aSSam Leffler buflen = m->m_len - off; 7508a1b9b6aSSam Leffler for (;;) { 7518a1b9b6aSSam Leffler if (buflen > data_len) 7528a1b9b6aSSam Leffler buflen = data_len; 7538a1b9b6aSSam Leffler data_len -= buflen; 7548a1b9b6aSSam Leffler for (k = 0; k < buflen; k++) { 7558a1b9b6aSSam Leffler i = (i + 1) & 0xff; 7568a1b9b6aSSam Leffler j = (j + S[i]) & 0xff; 7578a1b9b6aSSam Leffler S_SWAP(i, j); 7588a1b9b6aSSam Leffler *pos ^= S[(S[i] + S[j]) & 0xff]; 7598a1b9b6aSSam Leffler crc = crc32_table[(crc ^ *pos) & 0xff] ^ (crc >> 8); 7608a1b9b6aSSam Leffler pos++; 7618a1b9b6aSSam Leffler } 7628a1b9b6aSSam Leffler m = m->m_next; 7638a1b9b6aSSam Leffler if (m == NULL) { 7648a1b9b6aSSam Leffler KASSERT(data_len == 0, 76516574882SSam Leffler ("out of buffers with data_len %zu\n", data_len)); 7668a1b9b6aSSam Leffler break; 7678a1b9b6aSSam Leffler } 7688a1b9b6aSSam Leffler pos = mtod(m, uint8_t *); 7698a1b9b6aSSam Leffler buflen = m->m_len; 7708a1b9b6aSSam Leffler } 7718a1b9b6aSSam Leffler crc = ~crc; 7728a1b9b6aSSam Leffler 7738a1b9b6aSSam Leffler /* Encrypt little-endian CRC32 and verify that it matches with the 7748a1b9b6aSSam Leffler * received ICV */ 7758a1b9b6aSSam Leffler icv[0] = crc; 7768a1b9b6aSSam Leffler icv[1] = crc >> 8; 7778a1b9b6aSSam Leffler icv[2] = crc >> 16; 7788a1b9b6aSSam Leffler icv[3] = crc >> 24; 7798a1b9b6aSSam Leffler for (k = 0; k < 4; k++) { 7808a1b9b6aSSam Leffler i = (i + 1) & 0xff; 7818a1b9b6aSSam Leffler j = (j + S[i]) & 0xff; 7828a1b9b6aSSam Leffler S_SWAP(i, j); 7838a1b9b6aSSam Leffler if ((icv[k] ^ S[(S[i] + S[j]) & 0xff]) != *pos++) { 7848a1b9b6aSSam Leffler /* ICV mismatch - drop frame */ 7858a1b9b6aSSam Leffler return -1; 7868a1b9b6aSSam Leffler } 7878a1b9b6aSSam Leffler } 7888a1b9b6aSSam Leffler 7898a1b9b6aSSam Leffler return 0; 7908a1b9b6aSSam Leffler } 7918a1b9b6aSSam Leffler 7928a1b9b6aSSam Leffler static __inline u32 rotl(u32 val, int bits) 7938a1b9b6aSSam Leffler { 7948a1b9b6aSSam Leffler return (val << bits) | (val >> (32 - bits)); 7958a1b9b6aSSam Leffler } 7968a1b9b6aSSam Leffler 7978a1b9b6aSSam Leffler static __inline u32 rotr(u32 val, int bits) 7988a1b9b6aSSam Leffler { 7998a1b9b6aSSam Leffler return (val >> bits) | (val << (32 - bits)); 8008a1b9b6aSSam Leffler } 8018a1b9b6aSSam Leffler 8028a1b9b6aSSam Leffler static __inline u32 xswap(u32 val) 8038a1b9b6aSSam Leffler { 8048a1b9b6aSSam Leffler return ((val & 0x00ff00ff) << 8) | ((val & 0xff00ff00) >> 8); 8058a1b9b6aSSam Leffler } 8068a1b9b6aSSam Leffler 8078a1b9b6aSSam Leffler #define michael_block(l, r) \ 8088a1b9b6aSSam Leffler do { \ 8098a1b9b6aSSam Leffler r ^= rotl(l, 17); \ 8108a1b9b6aSSam Leffler l += r; \ 8118a1b9b6aSSam Leffler r ^= xswap(l); \ 8128a1b9b6aSSam Leffler l += r; \ 8138a1b9b6aSSam Leffler r ^= rotl(l, 3); \ 8148a1b9b6aSSam Leffler l += r; \ 8158a1b9b6aSSam Leffler r ^= rotr(l, 2); \ 8168a1b9b6aSSam Leffler l += r; \ 8178a1b9b6aSSam Leffler } while (0) 8188a1b9b6aSSam Leffler 8198a1b9b6aSSam Leffler static __inline u32 get_le32_split(u8 b0, u8 b1, u8 b2, u8 b3) 8208a1b9b6aSSam Leffler { 8218a1b9b6aSSam Leffler return b0 | (b1 << 8) | (b2 << 16) | (b3 << 24); 8228a1b9b6aSSam Leffler } 8238a1b9b6aSSam Leffler 8248a1b9b6aSSam Leffler static __inline u32 get_le32(const u8 *p) 8258a1b9b6aSSam Leffler { 8268a1b9b6aSSam Leffler return get_le32_split(p[0], p[1], p[2], p[3]); 8278a1b9b6aSSam Leffler } 8288a1b9b6aSSam Leffler 8298a1b9b6aSSam Leffler static __inline void put_le32(u8 *p, u32 v) 8308a1b9b6aSSam Leffler { 8318a1b9b6aSSam Leffler p[0] = v; 8328a1b9b6aSSam Leffler p[1] = v >> 8; 8338a1b9b6aSSam Leffler p[2] = v >> 16; 8348a1b9b6aSSam Leffler p[3] = v >> 24; 8358a1b9b6aSSam Leffler } 8368a1b9b6aSSam Leffler 8378a1b9b6aSSam Leffler /* 8388a1b9b6aSSam Leffler * Craft pseudo header used to calculate the MIC. 8398a1b9b6aSSam Leffler */ 8408a1b9b6aSSam Leffler static void 8418a1b9b6aSSam Leffler michael_mic_hdr(const struct ieee80211_frame *wh0, uint8_t hdr[16]) 8428a1b9b6aSSam Leffler { 8438a1b9b6aSSam Leffler const struct ieee80211_frame_addr4 *wh = 8448a1b9b6aSSam Leffler (const struct ieee80211_frame_addr4 *) wh0; 8458a1b9b6aSSam Leffler 8468a1b9b6aSSam Leffler switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) { 8478a1b9b6aSSam Leffler case IEEE80211_FC1_DIR_NODS: 8488a1b9b6aSSam Leffler IEEE80211_ADDR_COPY(hdr, wh->i_addr1); /* DA */ 8498a1b9b6aSSam Leffler IEEE80211_ADDR_COPY(hdr + IEEE80211_ADDR_LEN, wh->i_addr2); 8508a1b9b6aSSam Leffler break; 8518a1b9b6aSSam Leffler case IEEE80211_FC1_DIR_TODS: 8528a1b9b6aSSam Leffler IEEE80211_ADDR_COPY(hdr, wh->i_addr3); /* DA */ 8538a1b9b6aSSam Leffler IEEE80211_ADDR_COPY(hdr + IEEE80211_ADDR_LEN, wh->i_addr2); 8548a1b9b6aSSam Leffler break; 8558a1b9b6aSSam Leffler case IEEE80211_FC1_DIR_FROMDS: 8568a1b9b6aSSam Leffler IEEE80211_ADDR_COPY(hdr, wh->i_addr1); /* DA */ 8578a1b9b6aSSam Leffler IEEE80211_ADDR_COPY(hdr + IEEE80211_ADDR_LEN, wh->i_addr3); 8588a1b9b6aSSam Leffler break; 8598a1b9b6aSSam Leffler case IEEE80211_FC1_DIR_DSTODS: 8608a1b9b6aSSam Leffler IEEE80211_ADDR_COPY(hdr, wh->i_addr3); /* DA */ 8618a1b9b6aSSam Leffler IEEE80211_ADDR_COPY(hdr + IEEE80211_ADDR_LEN, wh->i_addr4); 8628a1b9b6aSSam Leffler break; 8638a1b9b6aSSam Leffler } 8648a1b9b6aSSam Leffler 865ecca7ea2SSam Leffler if (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_QOS) { 866ecca7ea2SSam Leffler const struct ieee80211_qosframe *qwh = 867ecca7ea2SSam Leffler (const struct ieee80211_qosframe *) wh; 868ecca7ea2SSam Leffler hdr[12] = qwh->i_qos[0] & IEEE80211_QOS_TID; 869ecca7ea2SSam Leffler } else 870ecca7ea2SSam Leffler hdr[12] = 0; 8718a1b9b6aSSam Leffler hdr[13] = hdr[14] = hdr[15] = 0; /* reserved */ 8728a1b9b6aSSam Leffler } 8738a1b9b6aSSam Leffler 8748a1b9b6aSSam Leffler static void 8758a1b9b6aSSam Leffler michael_mic(struct tkip_ctx *ctx, const u8 *key, 8768a1b9b6aSSam Leffler struct mbuf *m, u_int off, size_t data_len, 8778a1b9b6aSSam Leffler u8 mic[IEEE80211_WEP_MICLEN]) 8788a1b9b6aSSam Leffler { 8798a1b9b6aSSam Leffler uint8_t hdr[16]; 8808a1b9b6aSSam Leffler u32 l, r; 8818a1b9b6aSSam Leffler const uint8_t *data; 8828a1b9b6aSSam Leffler u_int space; 8838a1b9b6aSSam Leffler 8848a1b9b6aSSam Leffler michael_mic_hdr(mtod(m, struct ieee80211_frame *), hdr); 8858a1b9b6aSSam Leffler 8868a1b9b6aSSam Leffler l = get_le32(key); 8878a1b9b6aSSam Leffler r = get_le32(key + 4); 8888a1b9b6aSSam Leffler 8898a1b9b6aSSam Leffler /* Michael MIC pseudo header: DA, SA, 3 x 0, Priority */ 8908a1b9b6aSSam Leffler l ^= get_le32(hdr); 8918a1b9b6aSSam Leffler michael_block(l, r); 8928a1b9b6aSSam Leffler l ^= get_le32(&hdr[4]); 8938a1b9b6aSSam Leffler michael_block(l, r); 8948a1b9b6aSSam Leffler l ^= get_le32(&hdr[8]); 8958a1b9b6aSSam Leffler michael_block(l, r); 8968a1b9b6aSSam Leffler l ^= get_le32(&hdr[12]); 8978a1b9b6aSSam Leffler michael_block(l, r); 8988a1b9b6aSSam Leffler 8998a1b9b6aSSam Leffler /* first buffer has special handling */ 9008a1b9b6aSSam Leffler data = mtod(m, const uint8_t *) + off; 9018a1b9b6aSSam Leffler space = m->m_len - off; 9028a1b9b6aSSam Leffler for (;;) { 9038a1b9b6aSSam Leffler if (space > data_len) 9048a1b9b6aSSam Leffler space = data_len; 9058a1b9b6aSSam Leffler /* collect 32-bit blocks from current buffer */ 9068a1b9b6aSSam Leffler while (space >= sizeof(uint32_t)) { 9078a1b9b6aSSam Leffler l ^= get_le32(data); 9088a1b9b6aSSam Leffler michael_block(l, r); 9098a1b9b6aSSam Leffler data += sizeof(uint32_t), space -= sizeof(uint32_t); 9108a1b9b6aSSam Leffler data_len -= sizeof(uint32_t); 9118a1b9b6aSSam Leffler } 91202a1ebb4SSam Leffler /* 91302a1ebb4SSam Leffler * NB: when space is zero we make one more trip around 91402a1ebb4SSam Leffler * the loop to advance to the next mbuf where there is 91502a1ebb4SSam Leffler * data. This handles the case where there are 4*n 91602a1ebb4SSam Leffler * bytes in an mbuf followed by <4 bytes in a later mbuf. 91702a1ebb4SSam Leffler * By making an extra trip we'll drop out of the loop 91802a1ebb4SSam Leffler * with m pointing at the mbuf with 3 bytes and space 91902a1ebb4SSam Leffler * set as required by the remainder handling below. 92002a1ebb4SSam Leffler */ 92102a1ebb4SSam Leffler if (data_len == 0 || 92202a1ebb4SSam Leffler (data_len < sizeof(uint32_t) && space != 0)) 9238a1b9b6aSSam Leffler break; 9248a1b9b6aSSam Leffler m = m->m_next; 9258a1b9b6aSSam Leffler if (m == NULL) { 92616574882SSam Leffler KASSERT(0, ("out of data, data_len %zu\n", data_len)); 9278a1b9b6aSSam Leffler break; 9288a1b9b6aSSam Leffler } 9298a1b9b6aSSam Leffler if (space != 0) { 9308a1b9b6aSSam Leffler const uint8_t *data_next; 9318a1b9b6aSSam Leffler /* 9328a1b9b6aSSam Leffler * Block straddles buffers, split references. 9338a1b9b6aSSam Leffler */ 9348a1b9b6aSSam Leffler data_next = mtod(m, const uint8_t *); 9358a1b9b6aSSam Leffler KASSERT(m->m_len >= sizeof(uint32_t) - space, 9368a1b9b6aSSam Leffler ("not enough data in following buffer, " 93716574882SSam Leffler "m_len %u need %zu\n", m->m_len, 9388a1b9b6aSSam Leffler sizeof(uint32_t) - space)); 9398a1b9b6aSSam Leffler switch (space) { 9408a1b9b6aSSam Leffler case 1: 9418a1b9b6aSSam Leffler l ^= get_le32_split(data[0], data_next[0], 9428a1b9b6aSSam Leffler data_next[1], data_next[2]); 9438a1b9b6aSSam Leffler data = data_next + 3; 9448a1b9b6aSSam Leffler space = m->m_len - 3; 9458a1b9b6aSSam Leffler break; 9468a1b9b6aSSam Leffler case 2: 9478a1b9b6aSSam Leffler l ^= get_le32_split(data[0], data[1], 9488a1b9b6aSSam Leffler data_next[0], data_next[1]); 9498a1b9b6aSSam Leffler data = data_next + 2; 9508a1b9b6aSSam Leffler space = m->m_len - 2; 9518a1b9b6aSSam Leffler break; 9528a1b9b6aSSam Leffler case 3: 9538a1b9b6aSSam Leffler l ^= get_le32_split(data[0], data[1], 9548a1b9b6aSSam Leffler data[2], data_next[0]); 9558a1b9b6aSSam Leffler data = data_next + 1; 9568a1b9b6aSSam Leffler space = m->m_len - 1; 9578a1b9b6aSSam Leffler break; 9588a1b9b6aSSam Leffler } 9598a1b9b6aSSam Leffler michael_block(l, r); 9608a1b9b6aSSam Leffler data_len -= sizeof(uint32_t); 9618a1b9b6aSSam Leffler } else { 9628a1b9b6aSSam Leffler /* 9638a1b9b6aSSam Leffler * Setup for next buffer. 9648a1b9b6aSSam Leffler */ 9658a1b9b6aSSam Leffler data = mtod(m, const uint8_t *); 9668a1b9b6aSSam Leffler space = m->m_len; 9678a1b9b6aSSam Leffler } 9688a1b9b6aSSam Leffler } 96902a1ebb4SSam Leffler /* 97002a1ebb4SSam Leffler * Catch degenerate cases like mbuf[4*n+1 bytes] followed by 97102a1ebb4SSam Leffler * mbuf[2 bytes]. I don't believe these should happen; if they 97202a1ebb4SSam Leffler * do then we'll need more involved logic. 97302a1ebb4SSam Leffler */ 97402a1ebb4SSam Leffler KASSERT(data_len <= space, 9752bc01c3aSTai-hwa Liang ("not enough data, data_len %zu space %u\n", data_len, space)); 97602a1ebb4SSam Leffler 9778a1b9b6aSSam Leffler /* Last block and padding (0x5a, 4..7 x 0) */ 9788a1b9b6aSSam Leffler switch (data_len) { 9798a1b9b6aSSam Leffler case 0: 9808a1b9b6aSSam Leffler l ^= get_le32_split(0x5a, 0, 0, 0); 9818a1b9b6aSSam Leffler break; 9828a1b9b6aSSam Leffler case 1: 9838a1b9b6aSSam Leffler l ^= get_le32_split(data[0], 0x5a, 0, 0); 9848a1b9b6aSSam Leffler break; 9858a1b9b6aSSam Leffler case 2: 9868a1b9b6aSSam Leffler l ^= get_le32_split(data[0], data[1], 0x5a, 0); 9878a1b9b6aSSam Leffler break; 9888a1b9b6aSSam Leffler case 3: 9898a1b9b6aSSam Leffler l ^= get_le32_split(data[0], data[1], data[2], 0x5a); 9908a1b9b6aSSam Leffler break; 9918a1b9b6aSSam Leffler } 9928a1b9b6aSSam Leffler michael_block(l, r); 9938a1b9b6aSSam Leffler /* l ^= 0; */ 9948a1b9b6aSSam Leffler michael_block(l, r); 9958a1b9b6aSSam Leffler 9968a1b9b6aSSam Leffler put_le32(mic, l); 9978a1b9b6aSSam Leffler put_le32(mic + 4, r); 9988a1b9b6aSSam Leffler } 9998a1b9b6aSSam Leffler 10008a1b9b6aSSam Leffler static int 10018a1b9b6aSSam Leffler tkip_encrypt(struct tkip_ctx *ctx, struct ieee80211_key *key, 10028a1b9b6aSSam Leffler struct mbuf *m, int hdrlen) 10038a1b9b6aSSam Leffler { 10048a1b9b6aSSam Leffler struct ieee80211_frame *wh; 10058a1b9b6aSSam Leffler uint8_t icv[IEEE80211_WEP_CRCLEN]; 10068a1b9b6aSSam Leffler 1007b032f27cSSam Leffler ctx->tc_vap->iv_stats.is_crypto_tkip++; 10088a1b9b6aSSam Leffler 10098a1b9b6aSSam Leffler wh = mtod(m, struct ieee80211_frame *); 1010483755beSAdrian Chadd if ((u16)(key->wk_keytsc) == 0 || key->wk_keytsc == 1) { 10118a1b9b6aSSam Leffler tkip_mixing_phase1(ctx->tx_ttak, key->wk_key, wh->i_addr2, 10128a1b9b6aSSam Leffler (u32)(key->wk_keytsc >> 16)); 10138a1b9b6aSSam Leffler } 10148a1b9b6aSSam Leffler tkip_mixing_phase2(ctx->tx_rc4key, key->wk_key, ctx->tx_ttak, 10158a1b9b6aSSam Leffler (u16) key->wk_keytsc); 10168a1b9b6aSSam Leffler 10178a1b9b6aSSam Leffler wep_encrypt(ctx->tx_rc4key, 10188a1b9b6aSSam Leffler m, hdrlen + tkip.ic_header, 10198a1b9b6aSSam Leffler m->m_pkthdr.len - (hdrlen + tkip.ic_header), 10208a1b9b6aSSam Leffler icv); 10218a1b9b6aSSam Leffler (void) m_append(m, IEEE80211_WEP_CRCLEN, icv); /* XXX check return */ 10228a1b9b6aSSam Leffler 10238a1b9b6aSSam Leffler return 1; 10248a1b9b6aSSam Leffler } 10258a1b9b6aSSam Leffler 10268a1b9b6aSSam Leffler static int 10278a1b9b6aSSam Leffler tkip_decrypt(struct tkip_ctx *ctx, struct ieee80211_key *key, 10288a1b9b6aSSam Leffler struct mbuf *m, int hdrlen) 10298a1b9b6aSSam Leffler { 10308a1b9b6aSSam Leffler struct ieee80211_frame *wh; 1031b032f27cSSam Leffler struct ieee80211vap *vap = ctx->tc_vap; 10328a1b9b6aSSam Leffler u32 iv32; 10338a1b9b6aSSam Leffler u16 iv16; 1034b032f27cSSam Leffler u8 tid; 10358a1b9b6aSSam Leffler 1036b032f27cSSam Leffler vap->iv_stats.is_crypto_tkip++; 10378a1b9b6aSSam Leffler 10388a1b9b6aSSam Leffler wh = mtod(m, struct ieee80211_frame *); 10398a1b9b6aSSam Leffler /* NB: tkip_decap already verified header and left seq in rx_rsc */ 10408a1b9b6aSSam Leffler iv16 = (u16) ctx->rx_rsc; 10418a1b9b6aSSam Leffler iv32 = (u32) (ctx->rx_rsc >> 16); 10428a1b9b6aSSam Leffler 1043b032f27cSSam Leffler tid = ieee80211_gettid(wh); 1044b032f27cSSam Leffler if (iv32 != (u32)(key->wk_keyrsc[tid] >> 16) || !ctx->rx_phase1_done) { 10458a1b9b6aSSam Leffler tkip_mixing_phase1(ctx->rx_ttak, key->wk_key, 10468a1b9b6aSSam Leffler wh->i_addr2, iv32); 10478a1b9b6aSSam Leffler ctx->rx_phase1_done = 1; 10488a1b9b6aSSam Leffler } 10498a1b9b6aSSam Leffler tkip_mixing_phase2(ctx->rx_rc4key, key->wk_key, ctx->rx_ttak, iv16); 10508a1b9b6aSSam Leffler 10518a1b9b6aSSam Leffler /* NB: m is unstripped; deduct headers + ICV to get payload */ 10528a1b9b6aSSam Leffler if (wep_decrypt(ctx->rx_rc4key, 10538a1b9b6aSSam Leffler m, hdrlen + tkip.ic_header, 10548a1b9b6aSSam Leffler m->m_pkthdr.len - (hdrlen + tkip.ic_header + tkip.ic_trailer))) { 1055b032f27cSSam Leffler if (iv32 != (u32)(key->wk_keyrsc[tid] >> 16)) { 10568a1b9b6aSSam Leffler /* Previously cached Phase1 result was already lost, so 10578a1b9b6aSSam Leffler * it needs to be recalculated for the next packet. */ 10588a1b9b6aSSam Leffler ctx->rx_phase1_done = 0; 10598a1b9b6aSSam Leffler } 1060b032f27cSSam Leffler IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO, wh->i_addr2, 1061b032f27cSSam Leffler "%s", "TKIP ICV mismatch on decrypt"); 1062b032f27cSSam Leffler vap->iv_stats.is_rx_tkipicv++; 10638a1b9b6aSSam Leffler return 0; 10648a1b9b6aSSam Leffler } 10658a1b9b6aSSam Leffler return 1; 10668a1b9b6aSSam Leffler } 10678a1b9b6aSSam Leffler 10688a1b9b6aSSam Leffler /* 10698a1b9b6aSSam Leffler * Module glue. 10708a1b9b6aSSam Leffler */ 107168e8e04eSSam Leffler IEEE80211_CRYPTO_MODULE(tkip, 1); 1072