WLAN 4-Way Handshake如何生成PTK?

关于Wi-Fi的加密认证过程,可以参考如下链接,今天我们来理解如何生成PTK。

WLAN数据加密机制_tls加密wifi-CSDN博客

1. PTK的生成是如何选择相关算法的?

生成PTK的具体算法在Wi-Fi协议中规定,并且不同的协议版本可能使用不同的算法。以下是一些常用的算法:

  • HMAC-SHA1:在WPA和WPA2中用于生成PTK。
  • HMAC-SHA256:在WPA3中用于生成PTK,以提供更高的安全性。

如上图所示,PTK密钥生成的层级,我们这里重点讲解下生成算法,我们可以看到生成的算法是PRF-Length,其中Length的计算方法如下所示:

  • Length =KCK bits + KEK bits + TK bits.
    • 其中KCK_bits和KEK_bits的值参考下图:

    • 其中TK_bits的值参考下图:

      • 上图的Cipher_suite参考下图:

2. hostapd/wpa_supplicant code

其hostapd和wpa_supplicant中利用pmk生成ptk的代码如下所示:

/**
 * wpa_pmk_to_ptk - Calculate PTK from PMK, addresses, and nonces
 * @pmk: Pairwise master key
 * @pmk_len: Length of PMK
 * @label: Label to use in derivation
 * @addr1: AA or SA
 * @addr2: SA or AA
 * @nonce1: ANonce or SNonce
 * @nonce2: SNonce or ANonce
 * @ptk: Buffer for pairwise transient key
 * @akmp: Negotiated AKM
 * @cipher: Negotiated pairwise cipher
 * @kdk_len: The length in octets that should be derived for KDK
 * Returns: 0 on success, -1 on failure
 *
 * IEEE Std 802.11i-2004 - 8.5.1.2 Pairwise key hierarchy
 * PTK = PRF-X(PMK, "Pairwise key expansion",
 *             Min(AA, SA) || Max(AA, SA) ||
 *             Min(ANonce, SNonce) || Max(ANonce, SNonce)
 *             [ || Z.x ])
 *
 * The optional Z.x component is used only with DPP and that part is not defined
 * in IEEE 802.11.
 */
int wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label,
           const u8 *addr1, const u8 *addr2,
           const u8 *nonce1, const u8 *nonce2,
           struct wpa_ptk *ptk, int akmp, int cipher,
           const u8 *z, size_t z_len, size_t kdk_len)
{
#define MAX_Z_LEN 66 /* with NIST P-521 */
    u8 data[2 * ETH_ALEN + 2 * WPA_NONCE_LEN + MAX_Z_LEN];
    size_t data_len = 2 * ETH_ALEN + 2 * WPA_NONCE_LEN;
    u8 tmp[WPA_KCK_MAX_LEN + WPA_KEK_MAX_LEN + WPA_TK_MAX_LEN +
        WPA_KDK_MAX_LEN];
    size_t ptk_len;
#ifdef CONFIG_OWE
    int owe_ptk_workaround = 0;

    if (akmp == (WPA_KEY_MGMT_OWE | WPA_KEY_MGMT_PSK_SHA256)) {
        owe_ptk_workaround = 1;
        akmp = WPA_KEY_MGMT_OWE;
    }
#endif /* CONFIG_OWE */

    if (pmk_len == 0) {
        wpa_printf(MSG_ERROR, "WPA: No PMK set for PTK derivation");
        return -1;
    }

    if (z_len > MAX_Z_LEN)
        return -1;

    if (os_memcmp(addr1, addr2, ETH_ALEN) < 0) {
        os_memcpy(data, addr1, ETH_ALEN);
        os_memcpy(data + ETH_ALEN, addr2, ETH_ALEN);
    } else {
        os_memcpy(data, addr2, ETH_ALEN);
        os_memcpy(data + ETH_ALEN, addr1, ETH_ALEN);
    }

    if (os_memcmp(nonce1, nonce2, WPA_NONCE_LEN) < 0) {
        os_memcpy(data + 2 * ETH_ALEN, nonce1, WPA_NONCE_LEN);
        os_memcpy(data + 2 * ETH_ALEN + WPA_NONCE_LEN, nonce2,
              WPA_NONCE_LEN);
    } else {
        os_memcpy(data + 2 * ETH_ALEN, nonce2, WPA_NONCE_LEN);
        os_memcpy(data + 2 * ETH_ALEN + WPA_NONCE_LEN, nonce1,
              WPA_NONCE_LEN);
    }

    if (z && z_len) {
        os_memcpy(data + 2 * ETH_ALEN + 2 * WPA_NONCE_LEN, z, z_len);
        data_len += z_len;
    }

    if (kdk_len > WPA_KDK_MAX_LEN) {
        wpa_printf(MSG_ERROR,
               "WPA: KDK len=%zu exceeds max supported len",
               kdk_len);
        return -1;
    }

    ptk->kck_len = wpa_kck_len(akmp, pmk_len);
    ptk->kek_len = wpa_kek_len(akmp, pmk_len);
    ptk->tk_len = wpa_cipher_key_len(cipher);
    ptk->kdk_len = kdk_len;
    if (ptk->tk_len == 0) {
        wpa_printf(MSG_ERROR,
               "WPA: Unsupported cipher (0x%x) used in PTK derivation",
               cipher);
        return -1;
    }
    ptk_len = ptk->kck_len + ptk->kek_len + ptk->tk_len + ptk->kdk_len;

    if (wpa_key_mgmt_sha384(akmp)) {
#ifdef CONFIG_SHA384
        wpa_printf(MSG_DEBUG, "WPA: PTK derivation using PRF(SHA384)");
        if (sha384_prf(pmk, pmk_len, label, data, data_len,
                   tmp, ptk_len) < 0)
            return -1;
#else /* CONFIG_SHA384 */
        return -1;
#endif /* CONFIG_SHA384 */
    } else if (wpa_key_mgmt_sha256(akmp)) {
        wpa_printf(MSG_DEBUG, "WPA: PTK derivation using PRF(SHA256)");
        if (sha256_prf(pmk, pmk_len, label, data, data_len,
                   tmp, ptk_len) < 0)
            return -1;
#ifdef CONFIG_OWE
    } else if (akmp == WPA_KEY_MGMT_OWE && (pmk_len == 32 ||
                        owe_ptk_workaround)) {
        wpa_printf(MSG_DEBUG, "WPA: PTK derivation using PRF(SHA256)");
        if (sha256_prf(pmk, pmk_len, label, data, data_len,
                   tmp, ptk_len) < 0)
            return -1;
    } else if (akmp == WPA_KEY_MGMT_OWE && pmk_len == 48) {
        wpa_printf(MSG_DEBUG, "WPA: PTK derivation using PRF(SHA384)");
        if (sha384_prf(pmk, pmk_len, label, data, data_len,
                   tmp, ptk_len) < 0)
            return -1;
    } else if (akmp == WPA_KEY_MGMT_OWE && pmk_len == 64) {
        wpa_printf(MSG_DEBUG, "WPA: PTK derivation using PRF(SHA512)");
        if (sha512_prf(pmk, pmk_len, label, data, data_len,
                   tmp, ptk_len) < 0)
            return -1;
    } else if (akmp == WPA_KEY_MGMT_OWE) {
        wpa_printf(MSG_INFO, "OWE: Unknown PMK length %u",
               (unsigned int) pmk_len);
        return -1;
#endif /* CONFIG_OWE */
#ifdef CONFIG_DPP
    } else if (akmp == WPA_KEY_MGMT_DPP && pmk_len == 32) {
        wpa_printf(MSG_DEBUG, "WPA: PTK derivation using PRF(SHA256)");
        if (sha256_prf(pmk, pmk_len, label, data, data_len,
                   tmp, ptk_len) < 0)
            return -1;
    } else if (akmp == WPA_KEY_MGMT_DPP && pmk_len == 48) {
        wpa_printf(MSG_DEBUG, "WPA: PTK derivation using PRF(SHA384)");
        if (sha384_prf(pmk, pmk_len, label, data, data_len,
                   tmp, ptk_len) < 0)
            return -1;
    } else if (akmp == WPA_KEY_MGMT_DPP && pmk_len == 64) {
        wpa_printf(MSG_DEBUG, "WPA: PTK derivation using PRF(SHA512)");
        if (sha512_prf(pmk, pmk_len, label, data, data_len,
                   tmp, ptk_len) < 0)
            return -1;
    } else if (akmp == WPA_KEY_MGMT_DPP) {
        wpa_printf(MSG_INFO, "DPP: Unknown PMK length %u",
               (unsigned int) pmk_len);
        return -1;
#endif /* CONFIG_DPP */
#ifdef CONFIG_SAE
    } else if (wpa_key_mgmt_sae_ext_key(akmp)) {
        if (pmk_len == 32) {
            wpa_printf(MSG_DEBUG,
                   "SAE: PTK derivation using PRF(SHA256)");
            if (sha256_prf(pmk, pmk_len, label, data, data_len,
                       tmp, ptk_len) < 0)
                return -1;
#ifdef CONFIG_SHA384
        } else if (pmk_len == 48) {
            wpa_printf(MSG_DEBUG,
                   "SAE: PTK derivation using PRF(SHA384)");
            if (sha384_prf(pmk, pmk_len, label, data, data_len,
                       tmp, ptk_len) < 0)
                return -1;
#endif /* CONFIG_SHA384 */
#ifdef CONFIG_SHA512
        } else if (pmk_len == 64) {
            wpa_printf(MSG_DEBUG,
                   "SAE: PTK derivation using PRF(SHA512)");
            if (sha512_prf(pmk, pmk_len, label, data, data_len,
                       tmp, ptk_len) < 0)
                return -1;
#endif /* CONFIG_SHA512 */
        } else {
            wpa_printf(MSG_INFO, "SAE: Unknown PMK length %u",
                   (unsigned int) pmk_len);
            return -1;
        }
#endif /* CONFIG_SAE */
    } else {
        wpa_printf(MSG_DEBUG, "WPA: PTK derivation using PRF(SHA1)");
        if (sha1_prf(pmk, pmk_len, label, data, data_len, tmp,
                 ptk_len) < 0)
            return -1;
    }

    wpa_printf(MSG_DEBUG, "WPA: PTK derivation - A1=" MACSTR " A2=" MACSTR,
           MAC2STR(addr1), MAC2STR(addr2));
    wpa_hexdump(MSG_DEBUG, "WPA: Nonce1", nonce1, WPA_NONCE_LEN);
    wpa_hexdump(MSG_DEBUG, "WPA: Nonce2", nonce2, WPA_NONCE_LEN);
    if (z && z_len)
        wpa_hexdump_key(MSG_DEBUG, "WPA: Z.x", z, z_len);
    wpa_hexdump_key(MSG_DEBUG, "WPA: PMK", pmk, pmk_len);
    wpa_hexdump_key(MSG_DEBUG, "WPA: PTK", tmp, ptk_len);

    os_memcpy(ptk->kck, tmp, ptk->kck_len);
    wpa_hexdump_key(MSG_DEBUG, "WPA: KCK", ptk->kck, ptk->kck_len);

    os_memcpy(ptk->kek, tmp + ptk->kck_len, ptk->kek_len);
    wpa_hexdump_key(MSG_DEBUG, "WPA: KEK", ptk->kek, ptk->kek_len);

    os_memcpy(ptk->tk, tmp + ptk->kck_len + ptk->kek_len, ptk->tk_len);
    wpa_hexdump_key(MSG_DEBUG, "WPA: TK", ptk->tk, ptk->tk_len);

    if (kdk_len) {
        os_memcpy(ptk->kdk, tmp + ptk->kck_len + ptk->kek_len +
              ptk->tk_len, ptk->kdk_len);
        wpa_hexdump_key(MSG_DEBUG, "WPA: KDK", ptk->kdk, ptk->kdk_len);
    }

    ptk->kek2_len = 0;
    ptk->kck2_len = 0;

    os_memset(tmp, 0, sizeof(tmp));
    os_memset(data, 0, data_len);
    return 0;
}

  • 8
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值