Wifi_认证 关联 和 四次握手(WPA/WPA2)

Posted 少歌

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Wifi_认证 关联 和 四次握手(WPA/WPA2)相关的知识,希望对你有一定的参考价值。

概述

什么是 四次握手

四次握手是 AP (authenticator) 和 (supplicant)进行四次信息交互,生成一个用于加密无线数据的秘钥。

Wifi的连接

让我们 从一次Wifi连接的过程入手。

用事实说话(先抓个包)

  • 这个图的确是很抽象,可能有点劝退,不过不用担心,这个图可以先不看。
  • 这个图只是想说明一点,WIFI建立连接的时候,在空气中传播的就是这些数据包。
  • 而我们接下来就是要解释一下为什么要传这些包,包中都有一些什么比较重要的数据。

再重申一遍,四次握手是为了生成一个秘钥。

  • 为什么要生成这个秘钥?

    • 当然是为了加密 之后传输的数据包啊,不然你在网上冲浪的小秘密不就被发现了!!

WPA认证过程

先上图(上述抓包图的精简版):

先说明一下 上图的虚线部分(为什么是虚线呢?)

  • WPA2 是没有后续的那四次数据交互的 ,WPA才有。(当 设备同时支持WPA/WPA2时,默认选择更新一代的 WPA2)
  • 首先是 认证 (Authentication):STA 和 AP 互相认证一下对方是不是 802.11设备。
    • 当然,主要是 AP 对 STA 做一下链路认证,确认其的合法性。
  • 其次是 关联 (Association):关联总是由STA发起的,实际上关联就是STA和AP间无线链路服务协商的过程。
    • AP 在这时就已经将连接数 +1了(后续握手失败了 再 -1)
    • 由 STA 发出请求包(内含 STA 支持的速率、信道、QoS 的能力,以及选择的接入认证和加密算法等等)
    • 关联完成之后,就标志着 STA 与 AP 之间已经建立好了 无线链路,如果 STA 没有选择安全认证机制,STA 获得 IP 之后就可以直接进行数据交互了。(这就是链接数为什么在这就可以 +1 了。)

接下来就是重点了。

四次握手

还是先上图,后解释。

大家放心,图中的文字说明,后续会提取出来,方便大家阅读。

我错了,我还是先说一下图中出现的 “名词”吧。

  • STA:就是客户端,最常见的一个实例就是——“手机”
  • AP:接入点,无线局域网构建者,通常情况下就是——“路由器”
  • PSK:STA 与 AP 直接约定的 “暗语” ,用于认证(Authentication)的,通常情况下就是 WIFI密码。
  • SNonce:STA 生成的随机数。
  • ANonce:AP生成的随机数。
  • PMK:PMK 是由 ESSID + PSK(通俗的密码) 通过 SHA-1 (一个Hash 算法) 计算出来的。
  • PTK:Pairwise Transit Key,用来加密 AP 和 STA 通讯的单播数据包,AP 与每个 STA 通讯的PTK都是唯一的。
  • PTK = PRF(PMK + ANonce + SNonce + Mac(AA) + Mac (SA))
  • PRF:是一个随机的函数
  • PMK:Pairwise Master Key,PMK 会驻留在 AP 和 所有的 STA 中。
  • MAC(AA/SA):AP 和 STA 对应的 Mac 地址。
  • MIC:Message Integrity Check,PTK 的前 16 位通过Hash算法得出,用于校验消息的完整性。

STA 和 AP 利用各自已知的 SSID 和 PSK 生成 PMK。

AP 的 SSID 和 PSK 是不会出现问题的;

SSID 也是 在扫描过程中 告知STA的,一般也不会有出入;

但 PSK(Wifi密码) 就不一定了,存在输入错误的可能。

  • 如果STA端 PSK 错误,生成的 PMK 必然也会和 AP 生成的有出入,这会导致后续握手失败。
  • 至于为什么失败,后续解释。

在第一次握手过程中,STA 利用自己生成的 PMK 和 SNonce 与 从 AP 那里拿到的 ASonce 生成了 PTK。

这里我们为了做区分,将这里的 PTK 叫做 —— sta_PTK。

在第二次握手过程中,AP 利用自己生成的 PMK 和 ANonce 与 从 STA 那里拿到的 SNonce 生成了PTK。

同样,我们把这里的 PTK 叫做——ap_PTK。

在第二次握手过程中,STA 将 自己生成 MIC 传给了AP。

MIC 是 sta_PTK 的前16位通过一个Hash算法算出来的,它会去和 ap_PTK 的前16位算出来的MIC去比对

  • 如果校对失败,则握手失败,AP 将不会在理 STA 了。
  • 如果校对成功,则进行后续确认环节,从这之后,每个数据包中都会包含 MIC。

小细节:大家有没有发现,重要的 PMK 和 PTK 是不会在数据包中体现的。

总结

说实话,我不太爱写最后的总结,一般都是 这样草草了事:

  • That’s all , , thank you ! !

但这次还是稍微写一点吧,因为这次准备的时间比较长,但看上去并不充分,很多细节都被忽略了,只是简单聊了聊 “四次握手” 这回事儿,说的也不是很详细,但基本上把大致的结构说清楚了,也加了一些自己的理解,分享了一些自己发现的小细节。

当然,如有纰漏 欢迎指正。

That’s all , , thank you ! ! !

Android wpa_supplicant 四次握手 流程分析

记录wpa_supplicant四次握手的过程。

相关log:https://www.cnblogs.com/helloworldtoyou/p/9633603.html

接收到第一次握手,会设置一个认证超时时间,根据情况,设置成10s或者70s。
四次握手,如果出错,将会等待这个超时时间后,才会判断认证失败。然后从新连接。

wpa_supplicant/wpa_supplicant.c
void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr,
			     const u8 *buf, size_t len)
{
	struct wpa_supplicant *wpa_s = ctx;
	// 接受到EAPOL帧
	wpa_dbg(wpa_s, MSG_DEBUG, "RX EAPOL from " MACSTR, MAC2STR(src_addr));
	wpa_hexdump(MSG_MSGDUMP, "RX EAPOL", buf, len);

#ifdef CONFIG_TESTING_OPTIONS
	if (wpa_s->ignore_auth_resp) {
		wpa_printf(MSG_INFO, "RX EAPOL - ignore_auth_resp active!");
		return;
	}
#endif /* CONFIG_TESTING_OPTIONS */

#ifdef CONFIG_PEERKEY
	if (wpa_s->wpa_state > WPA_ASSOCIATED && wpa_s->current_ssid &&
	    wpa_s->current_ssid->peerkey &&
	    !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE) &&
	    wpa_sm_rx_eapol_peerkey(wpa_s->wpa, src_addr, buf, len) == 1) {
		wpa_dbg(wpa_s, MSG_DEBUG, "RSN: Processed PeerKey EAPOL-Key");
		return;
	}
#endif /* CONFIG_PEERKEY */

	if (wpa_s->wpa_state < WPA_ASSOCIATED ||
	    (wpa_s->last_eapol_matches_bssid &&
#ifdef CONFIG_AP
	     !wpa_s->ap_iface &&
#endif /* CONFIG_AP */
	     os_memcmp(src_addr, wpa_s->bssid, ETH_ALEN) != 0)) {
		/*
		 * There is possible race condition between receiving the
		 * association event and the EAPOL frame since they are coming
		 * through different paths from the driver. In order to avoid
		 * issues in trying to process the EAPOL frame before receiving
		 * association information, lets queue it for processing until
		 * the association event is received. This may also be needed in
		 * driver-based roaming case, so also use src_addr != BSSID as a
		 * trigger if we have previously confirmed that the
		 * Authenticator uses BSSID as the src_addr (which is not the
		 * case with wired IEEE 802.1X).
		 */
		wpa_dbg(wpa_s, MSG_DEBUG, "Not associated - Delay processing "
			"of received EAPOL frame (state=%s bssid=" MACSTR ")",
			wpa_supplicant_state_txt(wpa_s->wpa_state),
			MAC2STR(wpa_s->bssid));
		wpabuf_free(wpa_s->pending_eapol_rx);
		wpa_s->pending_eapol_rx = wpabuf_alloc_copy(buf, len);
		if (wpa_s->pending_eapol_rx) {
			os_get_reltime(&wpa_s->pending_eapol_rx_time);
			os_memcpy(wpa_s->pending_eapol_rx_src, src_addr,
				  ETH_ALEN);
		}
		return;
	}

	wpa_s->last_eapol_matches_bssid =
		os_memcmp(src_addr, wpa_s->bssid, ETH_ALEN) == 0;

#ifdef CONFIG_AP
	if (wpa_s->ap_iface) {
		wpa_supplicant_ap_rx_eapol(wpa_s, src_addr, buf, len);
		return;
	}
#endif /* CONFIG_AP */
															// 没有配置密钥,退出
	if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE) {
		wpa_dbg(wpa_s, MSG_DEBUG, "Ignored received EAPOL frame since "
			"no key management is configured");
		return;
	}
															// 第一次收到EAPOL帧,设置认证超时时间,
	if (wpa_s->eapol_received == 0 &&
	    (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE) ||
	     !wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt) ||
	     wpa_s->wpa_state != WPA_COMPLETED) &&
	    (wpa_s->current_ssid == NULL ||
	     wpa_s->current_ssid->mode != IEEE80211_MODE_IBSS)) {
		/* Timeout for completing IEEE 802.1X and WPA authentication */
		int timeout = 10;									// 认证超时时间10s

		if (wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) ||
		    wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA ||
		    wpa_s->key_mgmt == WPA_KEY_MGMT_WPS) {
			/* Use longer timeout for IEEE 802.1X/EAP */
			timeout = 70;									// 802.1X/EAP认证超时时间设置成70s
		}
															// WPS相关设置
#ifdef CONFIG_WPS
		if (wpa_s->current_ssid && wpa_s->current_bss &&
		    (wpa_s->current_ssid->key_mgmt & WPA_KEY_MGMT_WPS) &&
		    eap_is_wps_pin_enrollee(&wpa_s->current_ssid->eap)) {
			/*
			 * Use shorter timeout if going through WPS AP iteration
			 * for PIN config method with an AP that does not
			 * advertise Selected Registrar.
			 */
			struct wpabuf *wps_ie;

			wps_ie = wpa_bss_get_vendor_ie_multi(
				wpa_s->current_bss, WPS_IE_VENDOR_TYPE);
			if (wps_ie &&
			    !wps_is_addr_authorized(wps_ie, wpa_s->own_addr, 1))
				timeout = 10;
			else {
			    /* We should apply a flexible timeout value,
                * becasue some AP which send M2D MSG
                * need more time to complete EAP auth,such as Marvell.
                * */
		        timeout = 70;
			}
			wpabuf_free(wps_ie);
		}
#endif /* CONFIG_WPS */

		wpa_supplicant_req_auth_timeout(wpa_s, timeout, 0);			// 设置认证超时,10s或者70s
	}
	wpa_s->eapol_received++;										// 接受到的EAPOL计数加一

	if (wpa_s->countermeasures) {
		wpa_msg(wpa_s, MSG_INFO, "WPA: Countermeasures - dropped "
			"EAPOL packet");
		return;
	}

#ifdef CONFIG_IBSS_RSN
	if (wpa_s->current_ssid &&
	    wpa_s->current_ssid->mode == WPAS_MODE_IBSS) {
		ibss_rsn_rx_eapol(wpa_s->ibss_rsn, src_addr, buf, len);
		return;
	}
#endif /* CONFIG_IBSS_RSN */

	/* Source address of the incoming EAPOL frame could be compared to the
	 * current BSSID. However, it is possible that a centralized
	 * Authenticator could be using another MAC address than the BSSID of
	 * an AP, so just allow any address to be used for now. The replies are
	 * still sent to the current BSSID (if available), though. */

	os_memcpy(wpa_s->last_eapol_src, src_addr, ETH_ALEN);
	if (!wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt) &&
	    wpa_s->key_mgmt != WPA_KEY_MGMT_OWE &&
	    wpa_s->key_mgmt != WPA_KEY_MGMT_DPP &&
	    eapol_sm_rx_eapol(wpa_s->eapol, src_addr, buf, len) > 0)
		return;
	wpa_drv_poll(wpa_s);
	if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE))
		wpa_sm_rx_eapol(wpa_s->wpa, src_addr, buf, len);				// 处理接受的EAPOL帧
	else if (wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt)) {
		/*
		 * Set portValid = TRUE here since we are going to skip 4-way
		 * handshake processing which would normally set portValid. We
		 * need this to allow the EAPOL state machines to be completed
		 * without going through EAPOL-Key handshake.
		 */
		eapol_sm_notify_portValid(wpa_s->eapol, TRUE);
	}
}

src/rsn_supp/wpa.c
int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
            const u8 *buf, size_t len)
{
	各种帧内容判断
...
    if (key_info & WPA_KEY_INFO_KEY_TYPE) {
        if (key_info & WPA_KEY_INFO_KEY_INDEX_MASK) {
            wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
                "WPA: Ignored EAPOL-Key (Pairwise) with "
                "non-zero key index");
            goto out; 
        }    
        if (peerkey) {
            /* PeerKey 4-Way Handshake */               
            peerkey_rx_eapol_4way(sm, peerkey, key, key_info, ver, 
                          key_data, key_data_len);
        } else if (key_info & (WPA_KEY_INFO_MIC |
                       WPA_KEY_INFO_ENCR_KEY_DATA)) {
            /* 3/4 4-Way Handshake */                        // 第三次握手
            wpa_supplicant_process_3_of_4(sm, key, ver, key_data,
                              key_data_len);
        } else {
            /* 1/4 4-Way Handshake */                        // 第一次握手
            wpa_supplicant_process_1_of_4(sm, src_addr, key, 
                              ver, key_data,
                              key_data_len);
        }    
    } else if (key_info & WPA_KEY_INFO_SMK_MESSAGE) {
        /* PeerKey SMK Handshake */
        peerkey_rx_eapol_smk(sm, src_addr, key, key_data, key_data_len,
                     key_info, ver);
    } else {
        if ((mic_len && (key_info & WPA_KEY_INFO_MIC)) ||
            (!mic_len && (key_info & WPA_KEY_INFO_ENCR_KEY_DATA))) {
            /* 1/2 Group Key Handshake */
            wpa_supplicant_process_1_of_2(sm, src_addr, key, 
                              key_data, key_data_len,
                              ver);
        } else {
            wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
                "WPA: EAPOL-Key (Group) without Mic/Encr bit - "
                "dropped");
        }    
    }    
... 
}


static void wpa_supplicant_process_1_of_4(struct wpa_sm *sm,
                      const unsigned char *src_addr,
                      const struct wpa_eapol_key *key,
                      u16 ver, const u8 *key_data,
                      size_t key_data_len)
{
    struct wpa_eapol_ie_parse ie;
    struct wpa_ptk *ptk;
    int res;
    u8 *kde, *kde_buf = NULL;
    size_t kde_len;

    if (wpa_sm_get_network_ctx(sm) == NULL) {
        wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, "WPA: No SSID info "
            "found (msg 1 of 4)");
        return;
    }

    wpa_sm_set_state(sm, WPA_4WAY_HANDSHAKE);
    wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: RX message 1 of 4-Way "
        "Handshake from " MACSTR " (ver=%d)", MAC2STR(src_addr), ver);

    os_memset(&ie, 0, sizeof(ie));

    if (sm->proto == WPA_PROTO_RSN || sm->proto == WPA_PROTO_OSEN) {
        /* RSN: msg 1/4 should contain PMKID for the selected PMK */
        wpa_hexdump(MSG_DEBUG, "RSN: msg 1/4 key data",
                key_data, key_data_len);
        if (wpa_supplicant_parse_ies(key_data, key_data_len, &ie) < 0)
            goto failed;
        if (ie.pmkid) {
            wpa_hexdump(MSG_DEBUG, "RSN: PMKID from "
                    "Authenticator", ie.pmkid, PMKID_LEN);
        }
    }

    res = wpa_supplicant_get_pmk(sm, src_addr, ie.pmkid);
    if (res == -2) {
        wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: Do not reply to "
            "msg 1/4 - requesting full EAP authentication");
        return;
    }
    if (res)
        goto failed;

    if (sm->renew_snonce) {
        if (random_get_bytes(sm->snonce, WPA_NONCE_LEN)) {
            wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
                "WPA: Failed to get random data for SNonce");
            goto failed;
        }
        sm->renew_snonce = 0;
        wpa_hexdump(MSG_DEBUG, "WPA: Renewed SNonce",
                sm->snonce, WPA_NONCE_LEN);
    }

    /* Calculate PTK which will be stored as a temporary PTK until it has
     * been verified when processing message 3/4. */
    ptk = &sm->tptk;
    wpa_derive_ptk(sm, src_addr, key, ptk);
    if (sm->pairwise_cipher == WPA_CIPHER_TKIP) {
        u8 buf[8];
        /* Supplicant: swap tx/rx Mic keys */
        os_memcpy(buf, &ptk->tk[16], 8);
        os_memcpy(&ptk->tk[16], &ptk->tk[24], 8);
        os_memcpy(&ptk->tk[24], buf, 8);
        os_memset(buf, 0, sizeof(buf));
    }
    sm->tptk_set = 1;

    kde = sm->assoc_wpa_ie;
    kde_len = sm->assoc_wpa_ie_len;

...
                            // 发送第二次握手的包
    if (wpa_supplicant_send_2_of_4(sm, sm->bssid, key, ver, sm->snonce,
                       kde, kde_len, ptk) < 0)
        goto failed;

    os_free(kde_buf);
    os_memcpy(sm->anonce, key->key_nonce, WPA_NONCE_LEN);
    return;

failed:
    os_free(kde_buf);
    wpa_sm_deauthenticate(sm, WLAN_REASON_UNSPECIFIED);
}

Liutao

2018-11-22

以上是关于Wifi_认证 关联 和 四次握手(WPA/WPA2)的主要内容,如果未能解决你的问题,请参考以下文章

RK3399使用rtl8821cu wifi芯片

WiFi无线渗透 WPA2-PSK密码破解笔记

使用WIFI网卡 wpa_supplicant

怎么攻击别人wifi?

Android框架WiFi架构

用kali linux抓取wifi握手包并暴力破解