📄 hostap_crypt_tkip.c
字号:
for (k = 0; k < 4; k++) { i = (i + 1) & 0xff; j = (j + S[i]) & 0xff; S_SWAP(i, j); if ((icv[k] ^ S[(S[i] + S[j]) & 0xff]) != *pos++) { /* ICV mismatch - drop frame */ return -1; } } return 0;}#endif /* HOSTAP_USE_CRYPTO_API */static int hostap_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv){ struct hostap_tkip_data *tkey = priv; u8 rc4key[16]; u8 keyidx, *pos; u32 iv32; u16 iv16; struct hostap_ieee80211_hdr *hdr;#ifdef HOSTAP_USE_CRYPTO_API u8 icv[4]; u32 crc; struct scatterlist sg; int plen;#endif /* HOSTAP_USE_CRYPTO_API */ if (skb->len < hdr_len + 8 + 4) return -1; hdr = (struct hostap_ieee80211_hdr *) skb->data; pos = skb->data + hdr_len; keyidx = pos[3]; if (!(keyidx & (1 << 5))) { if (net_ratelimit()) { printk(KERN_DEBUG "TKIP: received packet without ExtIV" " flag from " MACSTR "\n", MAC2STR(hdr->addr2)); } return -2; } keyidx >>= 6; if (tkey->key_idx != keyidx) { printk(KERN_DEBUG "TKIP: RX tkey->key_idx=%d frame " "keyidx=%d priv=%p\n", tkey->key_idx, keyidx, priv); return -6; } if (!tkey->key_set) { if (net_ratelimit()) { printk(KERN_DEBUG "TKIP: received packet from " MACSTR " with keyid=%d that does not have a configured" " key\n", MAC2STR(hdr->addr2), keyidx); } return -3; } iv16 = (pos[0] << 8) | pos[2]; iv32 = pos[4] | (pos[5] << 8) | (pos[6] << 16) | (pos[7] << 24); pos += 8; if (iv32 < tkey->rx_iv32 || (iv32 == tkey->rx_iv32 && iv16 <= tkey->rx_iv16)) { if (net_ratelimit()) { printk(KERN_DEBUG "TKIP: replay detected: STA=" MACSTR " previous TSC %08x%04x received TSC " "%08x%04x\n", MAC2STR(hdr->addr2), tkey->rx_iv32, tkey->rx_iv16, iv32, iv16); } tkey->dot11RSNAStatsTKIPReplays++; return -4; } if (iv32 != tkey->rx_iv32 || !tkey->rx_phase1_done) { tkip_mixing_phase1(tkey->rx_ttak, tkey->key, hdr->addr2, iv32); tkey->rx_phase1_done = 1; } tkip_mixing_phase2(rc4key, tkey->key, tkey->rx_ttak, iv16);#ifdef HOSTAP_USE_CRYPTO_API plen = skb->len - hdr_len - 12; crypto_cipher_setkey(tkey->tfm_arc4, rc4key, 16); sg.page = virt_to_page(pos); sg.offset = offset_in_page(pos); sg.length = plen + 4; crypto_cipher_decrypt(tkey->tfm_arc4, &sg, &sg, plen + 4); crc = ~crc32_le(~0, pos, plen); icv[0] = crc; icv[1] = crc >> 8; icv[2] = crc >> 16; icv[3] = crc >> 24; if (memcmp(icv, pos + plen, 4) != 0) {#else /* HOSTAP_USE_CRYPTO_API */ if (hostap_wep_decrypt(rc4key, pos, skb->len - hdr_len - 12)) {#endif /* HOSTAP_USE_CRYPTO_API */ if (iv32 != tkey->rx_iv32) { /* Previously cached Phase1 result was already lost, so * it needs to be recalculated for the next packet. */ tkey->rx_phase1_done = 0; } if (net_ratelimit()) { printk(KERN_DEBUG "TKIP: ICV error detected: STA=" MACSTR "\n", MAC2STR(hdr->addr2)); } tkey->dot11RSNAStatsTKIPICVErrors++; return -5; } /* Update real counters only after Michael MIC verification has * completed */ tkey->rx_iv32_new = iv32; tkey->rx_iv16_new = iv16; /* Remove IV and ICV */ memmove(skb->data + 8, skb->data, hdr_len); skb_pull(skb, 8); skb_trim(skb, skb->len - 4); return keyidx;}#ifdef HOSTAP_USE_CRYPTO_APIstatic int michael_mic(struct hostap_tkip_data *tkey, u8 *key, u8 *hdr, u8 *data, size_t data_len, u8 *mic){ struct scatterlist sg[2]; if (tkey->tfm_michael == NULL) { printk(KERN_WARNING "michael_mic: tfm_michael == NULL\n"); return -1; } sg[0].page = virt_to_page(hdr); sg[0].offset = offset_in_page(hdr); sg[0].length = 16; sg[1].page = virt_to_page(data); sg[1].offset = offset_in_page(data); sg[1].length = data_len; crypto_digest_init(tkey->tfm_michael); crypto_digest_setkey(tkey->tfm_michael, key, 8); crypto_digest_update(tkey->tfm_michael, sg, 2); crypto_digest_final(tkey->tfm_michael, mic); return 0;}#else /* HOSTAP_USE_CRYPTO_API */static inline u32 rotl(u32 val, int bits){ return (val << bits) | (val >> (32 - bits));}static inline u32 rotr(u32 val, int bits){ return (val >> bits) | (val << (32 - bits));}static inline u32 xswap(u32 val){ return ((val & 0x00ff00ff) << 8) | ((val & 0xff00ff00) >> 8);}#define michael_block(l, r) \do { \ r ^= rotl(l, 17); \ l += r; \ r ^= xswap(l); \ l += r; \ r ^= rotl(l, 3); \ l += r; \ r ^= rotr(l, 2); \ l += r; \} while (0)static inline u32 get_le32(u8 *p){ return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);}static inline void put_le32(u8 *p, u32 v){ p[0] = v; p[1] = v >> 8; p[2] = v >> 16; p[3] = v >> 24;}static int michael_mic(struct hostap_tkip_data *tkey, u8 *key, u8 *hdr, u8 *data, size_t data_len, u8 *mic){ u32 l, r; int i, blocks, last; l = get_le32(key); r = get_le32(key + 4); /* Michael MIC pseudo header: DA, SA, 3 x 0, Priority */ l ^= get_le32(hdr); michael_block(l, r); l ^= get_le32(&hdr[4]); michael_block(l, r); l ^= get_le32(&hdr[8]); michael_block(l, r); l ^= get_le32(&hdr[12]); michael_block(l, r); /* 32-bit blocks of data */ blocks = data_len / 4; last = data_len % 4; for (i = 0; i < blocks; i++) { l ^= get_le32(&data[4 * i]); michael_block(l, r); } /* Last block and padding (0x5a, 4..7 x 0) */ switch (last) { case 0: l ^= 0x5a; break; case 1: l ^= data[4 * i] | 0x5a00; break; case 2: l ^= data[4 * i] | (data[4 * i + 1] << 8) | 0x5a0000; break; case 3: l ^= data[4 * i] | (data[4 * i + 1] << 8) | (data[4 * i + 2] << 16) | 0x5a000000; break; } michael_block(l, r); /* l ^= 0; */ michael_block(l, r); put_le32(mic, l); put_le32(mic + 4, r); return 0;}#endif /* HOSTAP_USE_CRYPTO_API */static void michael_mic_hdr(struct sk_buff *skb, u8 *hdr){ struct hostap_ieee80211_hdr *hdr11; hdr11 = (struct hostap_ieee80211_hdr *) skb->data; switch (le16_to_cpu(hdr11->frame_control) & (WLAN_FC_FROMDS | WLAN_FC_TODS)) { case WLAN_FC_TODS: memcpy(hdr, hdr11->addr3, ETH_ALEN); /* DA */ memcpy(hdr + ETH_ALEN, hdr11->addr2, ETH_ALEN); /* SA */ break; case WLAN_FC_FROMDS: memcpy(hdr, hdr11->addr1, ETH_ALEN); /* DA */ memcpy(hdr + ETH_ALEN, hdr11->addr3, ETH_ALEN); /* SA */ break; case WLAN_FC_FROMDS | WLAN_FC_TODS: memcpy(hdr, hdr11->addr3, ETH_ALEN); /* DA */ memcpy(hdr + ETH_ALEN, hdr11->addr4, ETH_ALEN); /* SA */ break; case 0: memcpy(hdr, hdr11->addr1, ETH_ALEN); /* DA */ memcpy(hdr + ETH_ALEN, hdr11->addr2, ETH_ALEN); /* SA */ break; } hdr[12] = 0; /* priority */ hdr[13] = hdr[14] = hdr[15] = 0; /* reserved */}static int hostap_michael_mic_add(struct sk_buff *skb, int hdr_len, void *priv){ struct hostap_tkip_data *tkey = priv; u8 *pos; if (skb_tailroom(skb) < 8 || skb->len < hdr_len) { printk(KERN_DEBUG "Invalid packet for Michael MIC add " "(tailroom=%d hdr_len=%d skb->len=%d)\n", skb_tailroom(skb), hdr_len, skb->len); return -1; } michael_mic_hdr(skb, tkey->tx_hdr); pos = skb_put(skb, 8); if (michael_mic(tkey, &tkey->key[16], tkey->tx_hdr, skb->data + hdr_len, skb->len - 8 - hdr_len, pos)) return -1; return 0;}#if WIRELESS_EXT >= 18static void hostap_michael_mic_failure(struct net_device *dev, struct hostap_ieee80211_hdr *hdr, int keyidx){ union iwreq_data wrqu; struct iw_michaelmicfailure ev; /* TODO: needed parameters: count, keyid, key type, TSC */ memset(&ev, 0, sizeof(ev)); ev.flags = keyidx & IW_MICFAILURE_KEY_ID; if (hdr->addr1[0] & 0x01) ev.flags |= IW_MICFAILURE_GROUP; else ev.flags |= IW_MICFAILURE_PAIRWISE; ev.src_addr.sa_family = ARPHRD_ETHER; memcpy(ev.src_addr.sa_data, hdr->addr2, ETH_ALEN); memset(&wrqu, 0, sizeof(wrqu)); wrqu.data.length = sizeof(ev); wireless_send_event(dev, IWEVMICHAELMICFAILURE, &wrqu, (char *) &ev);}#elif WIRELESS_EXT >= 15static void hostap_michael_mic_failure(struct net_device *dev, struct hostap_ieee80211_hdr *hdr, int keyidx){ union iwreq_data wrqu; char buf[128]; /* TODO: needed parameters: count, keyid, key type, TSC */ sprintf(buf, "MLME-MICHAELMICFAILURE.indication(keyid=%d %scast addr=" MACSTR ")", keyidx, hdr->addr1[0] & 0x01 ? "broad" : "uni", MAC2STR(hdr->addr2)); memset(&wrqu, 0, sizeof(wrqu)); wrqu.data.length = strlen(buf); wireless_send_event(dev, IWEVCUSTOM, &wrqu, buf);}#else /* WIRELESS_EXT >= 15 */static inline void hostap_michael_mic_failure(struct net_device *dev, struct hostap_ieee80211_hdr *hdr, int keyidx){}#endif /* WIRELESS_EXT >= 15 */static int hostap_michael_mic_verify(struct sk_buff *skb, int keyidx, int hdr_len, void *priv){ struct hostap_tkip_data *tkey = priv; u8 mic[8]; if (!tkey->key_set) return -1; michael_mic_hdr(skb, tkey->rx_hdr); if (michael_mic(tkey, &tkey->key[24], tkey->rx_hdr, skb->data + hdr_len, skb->len - 8 - hdr_len, mic)) return -1; if (memcmp(mic, skb->data + skb->len - 8, 8) != 0) { struct hostap_ieee80211_hdr *hdr; hdr = (struct hostap_ieee80211_hdr *) skb->data; printk(KERN_DEBUG "%s: Michael MIC verification failed for " "MSDU from " MACSTR " keyidx=%d\n", skb->dev ? skb->dev->name : "N/A", MAC2STR(hdr->addr2), keyidx); if (skb->dev) hostap_michael_mic_failure(skb->dev, hdr, keyidx); tkey->dot11RSNAStatsTKIPLocalMICFailures++; return -1; } /* Update TSC counters for RX now that the packet verification has * completed. */ tkey->rx_iv32 = tkey->rx_iv32_new; tkey->rx_iv16 = tkey->rx_iv16_new; skb_trim(skb, skb->len - 8); return 0;}static int hostap_tkip_set_key(void *key, int len, u8 *seq, void *priv){ struct hostap_tkip_data *tkey = priv; int keyidx;#ifdef HOSTAP_USE_CRYPTO_API struct crypto_tfm *tfm = tkey->tfm_michael; struct crypto_tfm *tfm2 = tkey->tfm_arc4;#endif /* HOSTAP_USE_CRYPTO_API */ keyidx = tkey->key_idx; memset(tkey, 0, sizeof(*tkey)); tkey->key_idx = keyidx;#ifdef HOSTAP_USE_CRYPTO_API tkey->tfm_michael = tfm; tkey->tfm_arc4 = tfm2;#endif /* HOSTAP_USE_CRYPTO_API */ if (len == TKIP_KEY_LEN) { memcpy(tkey->key, key, TKIP_KEY_LEN); tkey->key_set = 1; tkey->tx_iv16 = 1; /* TSC is initialized to 1 */ if (seq) { tkey->rx_iv32 = (seq[5] << 24) | (seq[4] << 16) | (seq[3] << 8) | seq[2]; tkey->rx_iv16 = (seq[1] << 8) | seq[0]; } } else if (len == 0) { tkey->key_set = 0; } else return -1; return 0;}static int hostap_tkip_get_key(void *key, int len, u8 *seq, void *priv){ struct hostap_tkip_data *tkey = priv; if (len < TKIP_KEY_LEN) return -1; if (!tkey->key_set) return 0; memcpy(key, tkey->key, TKIP_KEY_LEN); if (seq) { /* Return the sequence number of the last transmitted frame. */ u16 iv16 = tkey->tx_iv16; u32 iv32 = tkey->tx_iv32; if (iv16 == 0) iv32--; iv16--; seq[0] = tkey->tx_iv16; seq[1] = tkey->tx_iv16 >> 8; seq[2] = tkey->tx_iv32; seq[3] = tkey->tx_iv32 >> 8; seq[4] = tkey->tx_iv32 >> 16; seq[5] = tkey->tx_iv32 >> 24; } return TKIP_KEY_LEN;}static char * hostap_tkip_print_stats(char *p, void *priv){ struct hostap_tkip_data *tkip = priv; p += sprintf(p, "key[%d] alg=TKIP key_set=%d " "tx_pn=%02x%02x%02x%02x%02x%02x " "rx_pn=%02x%02x%02x%02x%02x%02x " "replays=%d icv_errors=%d local_mic_failures=%d\n", tkip->key_idx, tkip->key_set, (tkip->tx_iv32 >> 24) & 0xff, (tkip->tx_iv32 >> 16) & 0xff, (tkip->tx_iv32 >> 8) & 0xff, tkip->tx_iv32 & 0xff, (tkip->tx_iv16 >> 8) & 0xff, tkip->tx_iv16 & 0xff, (tkip->rx_iv32 >> 24) & 0xff, (tkip->rx_iv32 >> 16) & 0xff, (tkip->rx_iv32 >> 8) & 0xff, tkip->rx_iv32 & 0xff, (tkip->rx_iv16 >> 8) & 0xff, tkip->rx_iv16 & 0xff, tkip->dot11RSNAStatsTKIPReplays, tkip->dot11RSNAStatsTKIPICVErrors, tkip->dot11RSNAStatsTKIPLocalMICFailures); return p;}static struct hostap_crypto_ops hostap_crypt_tkip = { .name = "TKIP", .init = hostap_tkip_init, .deinit = hostap_tkip_deinit, .encrypt_mpdu = hostap_tkip_encrypt, .decrypt_mpdu = hostap_tkip_decrypt, .encrypt_msdu = hostap_michael_mic_add, .decrypt_msdu = hostap_michael_mic_verify, .set_key = hostap_tkip_set_key, .get_key = hostap_tkip_get_key, .print_stats = hostap_tkip_print_stats, .extra_prefix_len = 4 + 4 /* IV + ExtIV */, .extra_postfix_len = 8 + 4 /* MIC + ICV */};static int __init hostap_crypto_tkip_init(void){ if (hostap_register_crypto_ops(&hostap_crypt_tkip) < 0) return -1; return 0;}static void __exit hostap_crypto_tkip_exit(void){ hostap_unregister_crypto_ops(&hostap_crypt_tkip);}module_init(hostap_crypto_tkip_init);module_exit(hostap_crypto_tkip_exit);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -