关于Wi-Fi的加密认证过程,可以参考如下链接,今天我们来理解如何生成GTK。
WLAN数据加密机制_tls加密wifi-CSDN博客
1 GTK
GTK(Group Temporal Key)是由AP通过GMK生成,长度为128位,并在四次握手的第三步中通过加密的方式发送给STA。具体步骤如下:
- GTK生成:AP生成一个新的GTK。这个GTK是AP自己生成的随机密钥,用于加密多播和广播通信。
- Note:所以连接到同一个AP的STA都拥有相同GTK。
- GTK分发:在四次握手的第三步,AP将GTK加密后发送给STA。加密使用的是PTK中的KEK(Key Encryption Key)部分。
- Note:关于KEK请参考链接:WLAN 4-Way Handshake如何生成PTK?-CSDN博客
1.1 GTK生成的具体步骤
Wi-Fi使用伪随机函数(PRF)生成GTK。常用的PRF实现基于HMAC-SHA1或HMAC-SHA256,如下图所示:
- 在WPA和WPA2中,通常使用HMAC-SHA1。
- 在WPA3中,使用更强的HMAC-SHA256。
Note:
- 当前GMK由随机数代替;
- 为了防止GTK泄露,AP应定期生成新的GTK并分发给所有STA。
如上图所示,GTK密钥生成的层级,我们这里重点讲解下生成算法,我们可以看到生成的算法是PRF-Length,其中Length的计算方法如下所示:
- Length =TK_bits.
- 其中TK_bits的值参考下图:
1.2 GTK的传递过程
四次握手的具体步骤包括以下内容:
- 消息1:AP生成ANonce,并发送给STA。
- 消息2:STA生成SNonce,并发送给AP。STA和AP都计算出PTK。
- 消息3:
- AP生成GTK。
- AP使用PTK中的KEK加密GTK。
- AP将加密的GTK和一个MIC(Message Integrity Code)发送给STA,以保证消息的完整性和保密性。
- 消息4:STA接收到加密的GTK后,使用PTK中的KEK解密,得到GTK,并发送确认消息给AP。
1.3 GTK更新和重新分发
AP定期生成新的GTK,并通过以下过程重新分发:
- 生成新的GTK:使用上述算法和步骤生成新的GTK。
- 通知STA:通过新的EAPOL-Key消息通知所有连接的STA。
- 加密传输:使用PTK中的KEK加密新的GTK,并发送给STA。
- 确认:STA接收到新的GTK后,解密并确认接收。
1.4 hostapd code
static void wpa_group_ensure_init(struct wpa_authenticator *wpa_auth,
struct wpa_group *group)
{
if (group->first_sta_seen)
return;
/*
* System has run bit further than at the time hostapd was started
* potentially very early during boot up. This provides better chances
* of collecting more randomness on embedded systems. Re-initialize the
* GMK and Counter here to improve their strength if there was not
* enough entropy available immediately after system startup.
*/
wpa_printf(MSG_DEBUG,
"WPA: Re-initialize GMK/Counter on first station");
if (random_pool_ready() != 1) {
wpa_printf(MSG_INFO,
"WPA: Not enough entropy in random pool to proceed - reject first 4-way handshake");
group->reject_4way_hs_for_entropy = true;
} else {
group->first_sta_seen = true;
group->reject_4way_hs_for_entropy = false;
}
if (wpa_group_init_gmk_and_counter(wpa_auth, group) < 0 ||
wpa_gtk_update(wpa_auth, group) < 0 ||
wpa_group_config_group_keys(wpa_auth, group) < 0) {
wpa_printf(MSG_INFO, "WPA: GMK/GTK setup failed");
group->first_sta_seen = false;
group->reject_4way_hs_for_entropy = true;
}
}
static int wpa_gtk_update(struct wpa_authenticator *wpa_auth,
struct wpa_group *group)
{
struct wpa_auth_config *conf = &wpa_auth->conf;
int ret = 0;
size_t len;
os_memcpy(group->GNonce, group->Counter, WPA_NONCE_LEN);
inc_byte_array(group->Counter, WPA_NONCE_LEN);
if (wpa_gmk_to_gtk(group->GMK, "Group key expansion",
wpa_auth->addr, group->GNonce,
group->GTK[group->GN - 1], group->GTK_len) < 0)
ret = -1;
wpa_hexdump_key(MSG_DEBUG, "GTK",
group->GTK[group->GN - 1], group->GTK_len);
if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
len = wpa_cipher_key_len(conf->group_mgmt_cipher);
os_memcpy(group->GNonce, group->Counter, WPA_NONCE_LEN);
inc_byte_array(group->Counter, WPA_NONCE_LEN);
if (wpa_gmk_to_gtk(group->GMK, "IGTK key expansion",
wpa_auth->addr, group->GNonce,
group->IGTK[group->GN_igtk - 4], len) < 0)
ret = -1;
wpa_hexdump_key(MSG_DEBUG, "IGTK",
group->IGTK[group->GN_igtk - 4], len);
}
if (!wpa_auth->non_tx_beacon_prot &&
conf->ieee80211w == NO_MGMT_FRAME_PROTECTION)
return ret;
if (!conf->beacon_prot)
return ret;
if (wpa_auth->conf.tx_bss_auth) {
group = wpa_auth->conf.tx_bss_auth->group;
if (group->bigtk_set)
return ret;
wpa_printf(MSG_DEBUG, "Set up BIGTK for TX BSS");
}
len = wpa_cipher_key_len(conf->group_mgmt_cipher);
os_memcpy(group->GNonce, group->Counter, WPA_NONCE_LEN);
inc_byte_array(group->Counter, WPA_NONCE_LEN);
if (wpa_gmk_to_gtk(group->GMK, "BIGTK key expansion",
wpa_auth->addr, group->GNonce,
group->BIGTK[group->GN_bigtk - 6], len) < 0)
return -1;
group->bigtk_set = true;
wpa_hexdump_key(MSG_DEBUG, "BIGTK",
group->BIGTK[group->GN_bigtk - 6], len);
return ret;
}