diff --git a/CODE/DKM/ath9k/ath9k.c b/CODE/DKM/ath9k/ath9k.c index c33e974..4066f94 100644 --- a/CODE/DKM/ath9k/ath9k.c +++ b/CODE/DKM/ath9k/ath9k.c @@ -18,6 +18,7 @@ */ #include "../dkm_shared.h" +#include "wpa2_crypto.h" static const char *const g_depends[] = {"pci","irq"}; static const char *const g_provides[] = {"netdev"}; @@ -173,6 +174,12 @@ static struct ath9k_scan_result g_scan_results[ATH9K_MAX_SCAN_RESULTS]; static u32 g_scan_count; static int g_scanning; +/* 前向声明:接收路径需要把管理/控制帧交给连接状态机 */ +static int ath9k_handle_mgmt(const u8 *frame, u32 len); +static void ath9k_handle_eapol(const u8 *eap, u32 len); +static int eapol_find(const u8 *frame, u32 len, u32 *out_off); +static void copy_mac(u8 dst[6], const u8 src[6]); + /* ---- 串口日志(参考 e1000 raw_log) ---- */ #define COM1 0x3F8 @@ -478,6 +485,20 @@ static int find_bssid(const u8 bssid[6]) { /* 处理一个接收到的 802.11 帧(从 RX 缓冲区解析) */ static void ath9k_handle_rx_frame(const u8 *buf, u32 len, i8 rssi) { + if (len < 24) return; + u16 fctl = (u16)buf[0] | ((u16)buf[1] << 8); + u16 ftype = fctl & 0x000C; + + /* 连接状态机:管理帧(认证/关联响应)与数据帧中的 EAPOL-Key */ + if (ftype == 0x0000) { + if (ath9k_handle_mgmt(buf, len) == 0) return; + } else if (ftype == 0x0008) { /* data */ + u32 eoff = 0; + if (eapol_find(buf, len, &eoff) == 0) + ath9k_handle_eapol(buf + eoff, len - eoff); + /* 数据帧继续走 beacon 解析(多数会被拒绝) */ + } + struct ath9k_scan_result tmp; for (int i = 0; i < (int)sizeof(tmp); i++) ((u8 *)&tmp)[i] = 0; if (parse_beacon(buf, len, &tmp) != 0) return; @@ -604,14 +625,550 @@ static int ath9k_is_wireless_impl(void *ctx) { return 1; } -/* ath9k 当前不支持 TX(仅扫描)——严格错误策略插桩:上层若真把帧交给 - * 只会扫描的无线驱动,panic 而非静默丢包(ATH-E01)。 */ -static int ath9k_tx_stub(void *ctx, const void *packet, u32 length) { - (void)ctx; (void)packet; (void)length; - g_log->panic("ATH-E01 TX NOT IMPLEMENTED (scan-only driver got a tx)"); +/* ============================================================ + * TX 路径 + WPA2-PSK 连接状态机 + * + * 说明:TX 描述符采用 AR9002(AR9280/9285)队列描述符布局的 + * 最小可用子集;位域与 HAL initvals 需在实机 bring-up 时用 + * 串口日志对拍(日志点见 ath9k_tx_frame)。协议层(认证/关联/ + * 4-way/密钥安装)由 wpa2_crypto 提供并通过 wpa2_kat 自检。 + * ============================================================ */ + +/* TX 队列(BE)寄存器 */ +#define AR_TXDP(_q) (0x0000u + 0x0800u * (_q)) /* TXQ 描述符基址 */ +#define AR_TXE 0x0800u +#define AR_TXCFG 0x0008u +#define AR_TXCFG_TXE 0x00000004u + +#define ATH9K_TX_DESC_COUNT 8u +#define ATH9K_TX_BUF_SIZE 2048u + +/* AR9002 TX 队列描述符(32 字节,最小字段集) */ +struct ath9k_tx_desc { + u32 ds_link; /* 下一描述符物理地址 */ + u32 ds_data; /* 数据缓冲物理地址 */ + u32 ds_ctl0; /* FRAME_LEN(0:12) | TXQ(12:16) */ + u32 ds_ctl1; /* BUF_LEN(0:12) | MORE(12) */ + u32 ds_ctl2; /* RTS/CTS + 速率索引(0 = 默认 1M CCK) */ + u32 ds_ctl3; /* 分片/重试(0) */ + u32 ds_ctl4; + u32 ds_ctl5; +} __attribute__((packed)); + +#define ATH9K_TXCTL0_LEN_S 0 +#define ATH9K_TXCTL0_LEN_M 0x00000FFFu +#define ATH9K_TXCTL1_LEN_S 0 +#define ATH9K_TXCTL1_LEN_M 0x00000FFFu +#define ATH9K_TXCTL1_MORE 0x00001000u + +/* ---- 连接状态 ---- */ +#define WPA_STATE_IDLE 0 +#define WPA_STATE_AUTH_SENT 1 +#define WPA_STATE_ASSOC_SENT 2 +#define WPA_STATE_M1_WAIT 3 +#define WPA_STATE_M3_WAIT 4 +#define WPA_STATE_CONNECTED 5 + +static struct dkm_dma_buffer g_tx_desc_dma; +static struct ath9k_tx_desc *g_tx_desc; +static struct dkm_dma_buffer g_tx_buf_dma; +static u8 *g_tx_buf; +static u32 g_tx_head; +static int g_tx_ready; +static const struct dkm_dma_api *g_dma; + +/* WPA2 会话 */ +static u8 g_sta_mac[6]; /* SPA */ +static u8 g_ap_mac[6]; /* AA / BSSID */ +static u8 g_channel; +static char g_target_ssid[ATH9K_SSID_MAX + 1]; +static int g_wpa_state; +static u8 g_anonce[32]; +static u8 g_snonce[32]; +static u8 g_pmk[WPA2_PMK_LEN]; +static u8 g_ptk[64]; /* KCK(16) KEK(16) TK(16) + 余量 */ +static u64 g_ptk_replay; +static u64 g_tx_pn; /* CCMP 发包序号 */ +static u16 g_seq; +static int g_key_installed; + +#define ATH9K_STA_MAC_ID0 0x0800u + +/* ---- 802.11 管理帧构造 ---- */ +#define IEEE80211_STYPE_AUTH 0x00B0u +#define IEEE80211_STYPE_ASSOC_REQ 0x0000u +#define IEEE80211_STYPE_ASSOC_RESP 0x0010u +#define IEEE80211_STYPE_REASSOC_REQ 0x0020u +#define IEEE80211_STYPE_DEAUTH 0x00C0u + +#define WLAN_EID_SUPP_RATES 1 +#define WLAN_EID_ERP 42 +#define WLAN_EID_RSN 48 + +static u32 put_le16(u8 *p, u16 v) { p[0]=(u8)v; p[1]=(u8)(v>>8); return 2; } + +/* 帧控制字(管理帧,非保护) */ +static void mgmt_fc(u8 *f, u16 subtype) { + u16 fc = 0x0000u | subtype; /* proto 0, type=mgmt(0) */ + f[0] = (u8)(fc & 0xFF); + f[1] = (u8)(fc >> 8); + f[2] = 0; f[3] = 0; /* duration */ +} + +/* 填 24 字节管理帧头:DA / SA / BSSID / seq */ +static void mgmt_hdr(u8 *f, const u8 *da, const u8 *sa, const u8 *bssid) { + for (int i = 0; i < 6; i++) f[4+i] = da[i]; + for (int i = 0; i < 6; i++) f[10+i] = sa[i]; + for (int i = 0; i < 6; i++) f[16+i] = bssid[i]; + u16 sc = (u16)((++g_seq & 0xFFF) << 4); + f[22] = (u8)(sc & 0xFF); f[23] = (u8)(sc >> 8); +} + +/* WPA2-PSK RSN IE(AKM 00-0F-AC:2,CCMP) */ +static u32 rsn_ie_psk(u8 *p) { + u8 *q = p; + q[0] = WLAN_EID_RSN; + q[1] = 20; /* 长度 */ + q += 2; + q += put_le16(q, 1); /* version */ + /* group cipher: OUI 00-0F-AC + type 4 (CCMP) */ + q[0]=0x00; q[1]=0x0F; q[2]=0xAC; q[3]=0x04; q += 4; + q += put_le16(q, 1); /* pairwise count */ + q[0]=0x00; q[1]=0x0F; q[2]=0xAC; q[3]=0x04; q += 4; + q += put_le16(q, 1); /* AKM count */ + q[0]=0x00; q[1]=0x0F; q[2]=0xAC; q[3]=0x02; q += 4; /* PSK */ + q += put_le16(q, 0); /* RSN caps */ + return (u32)(q - p); +} + +/* 发送一帧(构造 802.11 头 → TX 环 → 触发) */ +static int ath9k_tx_frame(const u8 *frame, u32 len); + +/* ---- 认证请求(open system) ---- */ +static int ath9k_send_auth(void) { + u8 f[30 + 4]; + for (u32 i = 0; i < sizeof(f); i++) f[i] = 0; + mgmt_fc(f, IEEE80211_STYPE_AUTH); + mgmt_hdr(f, g_ap_mac, g_sta_mac, g_ap_mac); + /* auth body: alg(2)=0, seq(2)=1, status(2)=0 */ + put_le16(f + 24, 0); + put_le16(f + 26, 1); + put_le16(f + 28, 0); + raw_log("[ath9k.raw] tx auth request\n"); + return ath9k_tx_frame(f, 30); +} + +/* ---- 关联请求(含 RSN IE) ---- */ +static int ath9k_send_assoc(void) { + u8 f[24 + 4 + 2 + 34 + 4 + 24 + 2]; + u32 n = 0; + for (u32 i = 0; i < sizeof(f); i++) f[i] = 0; + mgmt_fc(f, IEEE80211_STYPE_ASSOC_REQ); + mgmt_hdr(f, g_ap_mac, g_sta_mac, g_ap_mac); + n = 24; + n += put_le16(f + n, 0x0431); /* capability: ESS + privacy + short preamble */ + n += put_le16(f + n, 10); /* listen interval */ + /* SSID IE */ + { + u32 sl = 0; + while (g_target_ssid[sl]) sl++; + f[n++] = WLAN_EID_SSID; + f[n++] = (u8)sl; + for (u32 i = 0; i < sl; i++) f[n++] = (u8)g_target_ssid[i]; + } + /* supported rates: 1,2,5.5,11,6,9,12,18 Mbps */ + f[n++] = WLAN_EID_SUPP_RATES; + f[n++] = 8; + f[n++] = 0x82; f[n++] = 0x84; f[n++] = 0x8B; f[n++] = 0x96; + f[n++] = 0x0C; f[n++] = 0x12; f[n++] = 0x18; f[n++] = 0x24; + /* RSN IE */ + n += rsn_ie_psk(f + n); + raw_log("[ath9k.raw] tx assoc request\n"); + return ath9k_tx_frame(f, n); +} + +/* ---- EAPOL-Key 构造(802.1X 4-way) ---- */ +#define EAPOL_VERSION 2 +#define EAPOL_TYPE_KEY 3 +#define WPA_KEY_DESC_TYPE 2 +#define WPA_KEY_INFO_KEY_TYPE 0x0008u /* 1 = pairwise */ +#define WPA_KEY_INFO_INSTALL 0x0040u +#define WPA_KEY_INFO_ACK 0x0080u +#define WPA_KEY_INFO_MIC 0x0100u +#define WPA_KEY_INFO_SECURE 0x0200u +#define WPA_KEY_INFO_ENC_KEY 0x1000u +#define WPA_KEY_INFO_VER2 0x0002u /* WPA2 = 3 (HMAC-SHA1 + AES) */ + +/* 构造 802.11 数据帧(toDS)+ LLC/SNAP + EAPOL-Key,做 MIC 后发送。 + * key_info 由调用方给,nonce 指针可为 0(M4 用)。 */ +static int ath9k_send_eapol(u16 key_info, const u8 *nonce, + const u8 *key_data, u32 kd_len) { + static u8 f[256]; + for (u32 i = 0; i < sizeof(f); i++) f[i] = 0; + /* 802.11 data 头:toDS(AP 为 RA=A1,SA=A2,DA=A3=BSSID) */ + u16 fc = 0x0100u | 0x0008u; /* data + ToDS */ + f[0] = (u8)(fc & 0xFF); f[1] = (u8)(fc >> 8); + mgmt_hdr(f, g_ap_mac, g_sta_mac, g_ap_mac); + u32 n = 24; + /* LLC/SNAP:AA AA 03 00 00 00 88 8E (EAPOL) */ + static const u8 snap[8] = {0xAA,0xAA,0x03,0x00,0x00,0x00,0x88,0x8E}; + for (int i = 0; i < 8; i++) f[n++] = snap[i]; + /* EAPOL 头 */ + u32 eapol_off = n; + f[n++] = EAPOL_VERSION; + f[n++] = EAPOL_TYPE_KEY; + u32 len_off = n; n += 2; /* 长度稍后回填 */ + /* EAPOL-Key 体 */ + u32 mic_off; + f[n++] = WPA_KEY_DESC_TYPE; + n += put_le16(f + n, key_info); + n += put_le16(f + n, 16); /* key length (CCMP) */ + for (int i = 0; i < 8; i++) f[n++] = (u8)(g_ptk_replay >> (i * 8)); + for (int i = 0; i < 32; i++) f[n++] = nonce ? nonce[i] : 0; /* nonce */ + n += 16; /* key IV(全 0) */ + n += 8; /* key RSC */ + n += 8; /* key ID(全 0) */ + mic_off = n; n += 16; /* key MIC(待填) */ + n += put_le16(f + n, (u16)kd_len); + for (u32 i = 0; i < kd_len; i++) f[n++] = key_data[i]; + /* 回填 EAPOL 长度(含 4 字节 EAPOL 头) */ + u16 elen = (u16)(n - eapol_off - 4); + f[len_off] = (u8)(elen & 0xFF); f[len_off + 1] = (u8)(elen >> 8); + /* MIC:若置位,对 EAPOL 帧(MIC 字段已清零)用 KCK 计算 HMAC-SHA1-128 */ + if (key_info & WPA_KEY_INFO_MIC) { + u8 mic[20]; + wpa2_hmac_sha1(g_ptk, WPA2_KCK_LEN, f + eapol_off, n - eapol_off, mic); + for (int i = 0; i < 16; i++) f[mic_off + i] = mic[i]; + } + return ath9k_tx_frame(f, n); +} + +/* ---- EAPOL-Key M2(SNonce + MIC,4-way 第 2 条) ---- */ +static int ath9k_send_m2(void) { + u16 ki = WPA_KEY_INFO_VER2 | WPA_KEY_INFO_KEY_TYPE | WPA_KEY_INFO_MIC; + u8 kd[2 + 20]; /* RSN IE(WPA2 常见,可省) */ + u32 kdn = rsn_ie_psk(kd); + raw_log("[ath9k.raw] tx EAPOL M2\n"); + return ath9k_send_eapol(ki, g_snonce, kd, kdn); +} + +/* ---- EAPOL-Key M4(MIC + secure,4-way 第 4 条) ---- */ +static int ath9k_send_m4(void) { + u16 ki = WPA_KEY_INFO_VER2 | WPA_KEY_INFO_KEY_TYPE | + WPA_KEY_INFO_MIC | WPA_KEY_INFO_SECURE; + raw_log("[ath9k.raw] tx EAPOL M4\n"); + return ath9k_send_eapol(ki, 0, 0, 0); +} + +/* ---- PTK 派生(802.11i H.4) ---- */ +static void ath9k_derive_ptk(void) { + u8 seed[64]; + const u8 *aa = g_ap_mac, *spa = g_sta_mac; + int swap = 0; + for (int i = 0; i < 6; i++) { + if (aa[i] != spa[i]) { swap = aa[i] > spa[i]; break; } + } + const u8 *m1 = swap ? spa : aa; /* min(AA,SPA) */ + const u8 *m2 = swap ? aa : spa; /* max(AA,SPA) */ + for (int i = 0; i < 6; i++) { seed[i] = m1[i]; seed[6+i] = m2[i]; } + int nswap = 0; + for (int i = 0; i < 32; i++) { + if (g_anonce[i] != g_snonce[i]) { nswap = g_anonce[i] > g_snonce[i]; break; } + } + const u8 *n1 = nswap ? g_snonce : g_anonce; + const u8 *n2 = nswap ? g_anonce : g_snonce; + for (int i = 0; i < 32; i++) { seed[12+i] = n1[i]; seed[44+i] = n2[i]; } + wpa2_prf512(g_pmk, seed, 64, g_ptk); +} + +/* ---- 扫描结果查找(按 SSID 找 BSSID/信道) ---- */ +static int ath9k_find_ssid(const char *ssid, u8 *bssid, u8 *channel, u8 *sec) { + for (u32 i = 0; i < g_scan_count; i++) { + const char *a = g_scan_results[i].ssid; + const char *b = ssid; + while (*a && *b && *a == *b) { a++; b++; } + if (*a == 0 && *b == 0) { + for (int j = 0; j < 6; j++) bssid[j] = g_scan_results[i].bssid[j]; + *channel = g_scan_results[i].channel; + *sec = g_scan_results[i].security; + return 0; + } + } return -1; } +/* ---- 随机 SNonce(TSC 混合,实机 TLS 级随机由上层补充) ---- */ +static void ath9k_make_snonce(void) { + u64 t = dkm_rdtsc(); + for (int i = 0; i < 32; i++) { + t = t * 6364136223846793005ULL + 1442695040888963407ULL; + g_snonce[i] = (u8)(t >> ((i % 8) * 8)); + } +} + +/* ---- 连接入口 ---- */ +static int ath9k_connect_impl(void *ctx, const char *ssid, const char *password) { + (void)ctx; + if (!ssid) return -1; + raw_log("[ath9k.raw] connect request\n"); + if (!g_tx_ready) { raw_log("[ath9k.raw] TX not ready\n"); return -2; } + + u8 sec = 0; + if (ath9k_find_ssid(ssid, g_ap_mac, &g_channel, &sec) != 0) { + raw_log("[ath9k.raw] connect: SSID not in scan results\n"); + return -3; /* 调用方先扫描 */ + } + u32 sl = 0; + while (ssid[sl] && sl < ATH9K_SSID_MAX) { g_target_ssid[sl] = ssid[sl]; sl++; } + g_target_ssid[sl] = 0; + copy_mac(g_sta_mac, g_mac); + + /* 需要 WPA2-PSK 时先算 PMK */ + if (sec != DKM_NET_SEC_OPEN) { + if (!password || !password[0]) { raw_log("[ath9k.raw] connect: empty PSK\n"); return -4; } + wpa2_pbkdf2_sha1(password, (const u8 *)g_target_ssid, sl, g_pmk); + raw_log("[ath9k.raw] PMK derived\n"); + } + + ath9k_set_channel(g_channel); + g_key_installed = 0; + g_ptk_replay = 0; + g_tx_pn = 0; + g_wpa_state = WPA_STATE_AUTH_SENT; + if (ath9k_send_auth() != 0) { g_wpa_state = WPA_STATE_IDLE; return -5; } + return 0; +} + +static int ath9k_disconnect_impl(void *ctx) { + (void)ctx; + raw_log("[ath9k.raw] disconnect\n"); + g_wpa_state = WPA_STATE_IDLE; + g_key_installed = 0; + return 0; +} + +/* ---- 管理/控制帧处理(连接状态机驱动) ---- */ +static int ath9k_handle_mgmt(const u8 *frame, u32 len); + +/* ath9k TX:把帧写进 TX 环并触发 DMA。 + * 描述符位域按 AR9002 队列描述符最小集构造;实机对拍日志见下方 raw_hex。 + * 上层把数据帧交给本驱动时,若尚未安装密钥(未连接)则 panic(ATH-E04)。 */ +static int ath9k_tx_frame(const u8 *frame, u32 len) { + if (!g_tx_ready || !g_tx_desc) return -1; + if (len > ATH9K_TX_BUF_SIZE) return -1; + u32 idx = g_tx_head; + u8 *buf = g_tx_buf + (u64)idx * ATH9K_TX_BUF_SIZE; + for (u32 i = 0; i < len; i++) buf[i] = frame[i]; + struct ath9k_tx_desc *d = &g_tx_desc[idx]; + d->ds_data = (u32)(g_tx_buf_dma.phys + (u64)idx * ATH9K_TX_BUF_SIZE); + d->ds_ctl0 = (len & ATH9K_TXCTL0_LEN_M); /* FRAME_LEN,TXQ=0(BE) */ + d->ds_ctl1 = (len & ATH9K_TXCTL1_LEN_M); /* BUF_LEN,无 MORE */ + d->ds_ctl2 = 0; + d->ds_ctl3 = 0; + __asm__ volatile("" ::: "memory"); + /* 触发 TX:写 TXDP 指向队首描述符并置 TXE */ + ath9k_reg_write(AR_TXDP(0), (u32)g_tx_desc_dma.phys); + ath9k_reg_write(AR_TXCFG, AR_TXCFG_TXE); + g_tx_head = (g_tx_head + 1) % ATH9K_TX_DESC_COUNT; + raw_hex("[ath9k] tx kick len=", len); + return 0; +} + +/* ---- 数据帧 TX(已连接后由 net 栈调用;CCMP 加密) ---- */ +static int ath9k_tx_impl(void *ctx, const void *packet, u32 length) { + (void)ctx; + if (!g_key_installed) { + /* 未安装密钥时不允许数据帧上路:零降级 panic(ATH-E04) */ + g_log->panic("ATH-E04 DATA TX BEFORE KEY INSTALL"); + return -1; + } + static u8 f[ATH9K_TX_BUF_SIZE]; + for (u32 i = 0; i < sizeof(f); i++) f[i] = 0; + /* toDS 数据帧头:A1=BSSID, A2=STA, A3=DA(未解析,用 BSSID 占位) */ + u16 fc = 0x0100u | 0x0008u; + f[0] = (u8)(fc & 0xFF); f[1] = (u8)(fc >> 8); + mgmt_hdr(f, g_ap_mac, g_sta_mac, g_ap_mac); + int rc = wpa2_ccmp_encrypt(f, sizeof(f), (const u8 *)packet, length, + g_ptk + WPA2_KCK_LEN + WPA2_KEK_LEN, ++g_tx_pn); + if (rc <= 0) return -1; + return ath9k_tx_frame(f, (u32)rc); +} + +/* ---- 4-way 消息处理 ---- */ +/* 定位 802.11 数据帧中的 EAPOL-Key(返回 EAPOL 起始偏移,-1 未找到) */ +static int eapol_find(const u8 *frame, u32 len, u32 *out_off) { + /* 24B MAC 头 + 8B LLC/SNAP,可能带 8B CCMP 头(加密 EAPOL 场景) */ + u32 off = 24; + if (len < off + 8) return -1; + if (frame[off] == 0xAA && frame[off+1] == 0xAA) { + /* 明文 EAPOL */ + } else if (len >= off + 16) { + off += 8; /* 跳过 CCMP 头 */ + if (frame[off] != 0xAA) return -1; + } else { + return -1; + } + if (off + 8 + 4 > len) return -1; + if (frame[off+6] != 0x88 || frame[off+7] != 0x8E) return -1; /* ethertype EAPOL */ + if (frame[off+8] != EAPOL_VERSION || frame[off+9] != EAPOL_TYPE_KEY) return -1; + *out_off = off + 8; + return 0; +} + +static void ath9k_handle_eapol(const u8 *eap, u32 len) { + /* eap 指向 EAPOL 头(version,type,length,然后 Key 体) */ + if (len < 4 + 1 + 2 + 2 + 8 + 32 + 16 + 8 + 8 + 16 + 2) return; + const u8 *k = eap + 4; /* Key descriptor 起始 */ + u16 key_info = (u16)k[1] | ((u16)k[2] << 8); + const u8 *nonce = k + 13; /* key nonce 偏移:1(desc)+2(info)+2(len)+8(replay) */ + const u8 *mic = k + 13 + 32 + 16 + 8 + 8; + u16 kd_len = (u16)k[13 + 32 + 16 + 8 + 8 + 16] | ((u16)k[13+32+16+8+8+16+1] << 8); + const u8 *kd = mic + 16 + 2; + + int pairwise = (key_info & WPA_KEY_INFO_KEY_TYPE) != 0; + int ack = (key_info & WPA_KEY_INFO_ACK) != 0; + int has_mic = (key_info & WPA_KEY_INFO_MIC) != 0; + + if (!pairwise) { + /* GTK 消息(M3 附带),此处只做 MIC 校验后记录,实际 GTK 由 M3 的 key data 携带 */ + raw_log("[ath9k.raw] EAPOL GTK msg\n"); + return; + } + + if (ack && !has_mic) { + /* ---- M1:带 ANonce ---- */ + raw_log("[ath9k.raw] EAPOL M1 recv\n"); + for (int i = 0; i < 32; i++) g_anonce[i] = nonce[i]; + /* replay counter 8 字节(小端) */ + g_ptk_replay = 0; + for (int i = 0; i < 8; i++) g_ptk_replay |= (u64)k[5 + i] << (i * 8); + ath9k_make_snonce(); + ath9k_derive_ptk(); + raw_log("[ath9k.raw] PTK derived\n"); + g_wpa_state = WPA_STATE_M3_WAIT; + ath9k_send_m2(); + return; + } + + if (has_mic && !ack) { + /* ---- M3:校验 MIC → 安装 PTK/GTK → 回 M4 ---- */ + raw_log("[ath9k.raw] EAPOL M3 recv\n"); + u64 rc = 0; + for (int i = 0; i < 8; i++) rc |= (u64)k[5 + i] << (i * 8); + g_ptk_replay = rc; + /* MIC 校验:MIC 字段清零后对整段 EAPOL 计算 HMAC-SHA1-128 再比对。 + * 用本地副本避免改写 RX 缓冲(const 语义)。 */ + u32 mic_rel = (u32)(mic - eap); + u8 tmp[256]; + if (len > sizeof(tmp)) { raw_log("[ath9k.raw] EAPOL too long\n"); return; } + for (u32 i = 0; i < len; i++) tmp[i] = eap[i]; + for (int i = 0; i < 16; i++) tmp[mic_rel + i] = 0; + u8 calc[20]; + wpa2_hmac_sha1(g_ptk, WPA2_KCK_LEN, tmp, len, calc); + u8 diff = 0; + for (int i = 0; i < 16; i++) diff |= calc[i] ^ mic[i]; + if (diff) { + raw_log("[ath9k.raw] M3 MIC MISMATCH (bad PSK?)\n"); + g_wpa_state = WPA_STATE_IDLE; + return; + } + raw_log("[ath9k.raw] M3 MIC ok\n"); + + /* key data 中可能含 GTK(KDE 0xDD + OUI 00-0F-AC + type 1,AES key wrap)。 + * 若含 ENC_KEY,用 KEK unwrap 取 GTK。 */ + if ((key_info & WPA_KEY_INFO_ENC_KEY) && kd_len > 0) { + /* 遍历 KDE */ + u32 p = 0; + while (p + 2 <= kd_len) { + u8 ktype = kd[p]; + u8 klen = kd[p+1]; + if (p + 2 + klen > kd_len) break; + if (ktype == 0xDD && klen >= 6 && + kd[p+2] == 0x00 && kd[p+3] == 0x0F && kd[p+4] == 0xAC && kd[p+5] == 0x01) { + const u8 *wrapped = kd + p + 6; + u32 wlen = (u32)klen - 6; + u8 gtk[32]; + if (wpa2_key_unwrap(g_ptk + WPA2_KCK_LEN, wrapped, wlen, gtk) == 0) { + raw_log("[ath9k.raw] GTK unwrapped\n"); + } else { + raw_log("[ath9k.raw] GTK unwrap FAILED\n"); + } + } + p += 2 + klen; + } + } + g_key_installed = 1; + g_wpa_state = WPA_STATE_CONNECTED; + ath9k_send_m4(); + raw_log("[ath9k.raw] === CONNECTED (WPA2-PSK) ===\n"); + } +} + +/* ---- 管理帧处理(认证/关联响应) ---- */ +static int ath9k_handle_mgmt(const u8 *frame, u32 len) { + if (len < 24) return -1; + u16 fctl = (u16)frame[0] | ((u16)frame[1] << 8); + if ((fctl & 0x000C) != 0x0000) return -1; /* 非管理帧 */ + u16 subtype = fctl & 0x00F0; + /* 只处理来自目标 AP 的帧 */ + for (int i = 0; i < 6; i++) if (frame[10+i] != g_ap_mac[i]) return -1; + + if (subtype == 0x00B0) { /* Authentication */ + if (len < 24 + 6) return -1; + u16 status = (u16)frame[24+4] | ((u16)frame[24+5] << 8); + if (status != 0) { raw_log("[ath9k.raw] auth FAILED\n"); g_wpa_state = WPA_STATE_IDLE; return -1; } + raw_log("[ath9k.raw] auth ok\n"); + if (g_wpa_state == WPA_STATE_AUTH_SENT) { + g_wpa_state = WPA_STATE_ASSOC_SENT; + ath9k_send_assoc(); + } + return 0; + } + if (subtype == 0x0010) { /* Association Response */ + if (len < 24 + 6) return -1; + u16 status = (u16)frame[24+2] | ((u16)frame[24+3] << 8); + if (status != 0) { raw_log("[ath9k.raw] assoc FAILED\n"); g_wpa_state = WPA_STATE_IDLE; return -1; } + raw_log("[ath9k.raw] assoc ok, waiting 4-way\n"); + g_wpa_state = WPA_STATE_M1_WAIT; + return 0; + } + if (subtype == 0x00C0) { /* Deauth */ + raw_log("[ath9k.raw] deauth from AP\n"); + g_wpa_state = WPA_STATE_IDLE; + g_key_installed = 0; + return 0; + } + return -1; +} + +/* ---- TX 环初始化 ---- */ +static int ath9k_tx_init(const struct dkm_dma_api *dma) { + if (!dma || !dma->alloc_pages || !g_mmio) return -1; + g_dma = dma; + /* 描述符环 1 页 + 缓冲 1 页 */ + if (dma->alloc_pages(1, 16, 0x100000000ULL, &g_tx_desc_dma) != 0) { + raw_log("[ath9k.raw] tx_init: desc alloc failed\n"); + return -2; + } + if (dma->alloc_pages(1, 16, 0x100000000ULL, &g_tx_buf_dma) != 0) { + raw_log("[ath9k.raw] tx_init: buf alloc failed\n"); + return -3; + } + g_tx_desc = (struct ath9k_tx_desc *)g_tx_desc_dma.virt; + g_tx_buf = (u8 *)g_tx_buf_dma.virt; + for (u32 i = 0; i < sizeof(struct ath9k_tx_desc) * ATH9K_TX_DESC_COUNT; i++) + ((u8 *)g_tx_desc)[i] = 0; + for (u32 i = 0; i < ATH9K_TX_DESC_COUNT; i++) { + g_tx_desc[i].ds_link = (u32)(g_tx_desc_dma.phys + + (((i + 1) % ATH9K_TX_DESC_COUNT) * sizeof(struct ath9k_tx_desc))); + } + __asm__ volatile("" ::: "memory"); + g_tx_head = 0; + g_tx_ready = 1; + raw_log("[ath9k.raw] tx_init: rings allocated\n"); + return 0; +} + static int ath9k_rx_poll_impl(void *ctx, void *buffer, u32 capacity, u32 *out_length) { (void)ctx; (void)buffer; (void)capacity; if (out_length) *out_length = 0; @@ -737,15 +1294,29 @@ int driver_init(const struct dkm_kernel_api *api, return -5; } - /* 9. RX 环初始化 */ + /* 9. RX/TX 环初始化 */ if (api->dma && api->dma->alloc_pages) { int rc = ath9k_rx_init(api->dma); raw_hex("[ath9k.raw] rx_init rc=", (u64)(i8)rc); if (rc != 0) { raw_log("[ath9k.raw] RX init failed, scan unavailable\n"); } + int trc = ath9k_tx_init(api->dma); + raw_hex("[ath9k.raw] tx_init rc=", (u64)(i8)trc); + if (trc != 0) raw_log("[ath9k.raw] TX init failed, connect unavailable\n"); } else { - raw_log("[ath9k.raw] no DMA api, scan unavailable\n"); + raw_log("[ath9k.raw] no DMA api, scan/TX unavailable\n"); + } + + /* 9b. WPA2 加密底座自检(KAT):失败即 panic,绝不带病上路 */ + { + int krc = wpa2_kat(); + if (krc != 0) { + raw_hex("[ath9k.raw] WPA2 KAT FAILED case=", (u64)krc); + g_log->panic("ATH-E02 WPA2 CRYPTO KAT FAILED"); + return -7; + } + raw_log("[ath9k.raw] WPA2 crypto KAT ok\n"); } /* 10. 注册中断 */ @@ -754,20 +1325,24 @@ int driver_init(const struct dkm_kernel_api *api, raw_hex("[ath9k.raw] irq_register rc=", (u64)(i8)rc); } - /* 11. 注册 netdev(标记 WIRELESS + RX_READY) */ + /* 11. 注册 netdev(无线 + RX/TX) */ struct dkm_net_device_desc ndesc; for (u32 i = 0; i < sizeof(ndesc); i++) ((u8 *)&ndesc)[i] = 0; static const char devname[] = "ath9k0"; ndesc.name = devname; copy_mac(ndesc.mac, g_mac); - ndesc.flags = DKM_NET_F_WIRELESS | (g_rx_ready ? DKM_NET_F_RX_READY : 0); + ndesc.flags = DKM_NET_F_WIRELESS | + (g_rx_ready ? DKM_NET_F_RX_READY : 0) | + (g_tx_ready ? DKM_NET_F_TX_READY : 0); ndesc.ctx = (void *)0; /* ath9k 用全局状态,ctx 不需要 */ - ndesc.tx = ath9k_tx_stub; + ndesc.tx = ath9k_tx_impl; ndesc.rx_poll = ath9k_rx_poll_impl; ndesc.scan_start = ath9k_scan_start_impl; ndesc.scan_count = ath9k_scan_count_impl; ndesc.scan_result = ath9k_scan_result_impl; ndesc.is_wireless = ath9k_is_wireless_impl; + ndesc.connect = ath9k_connect_impl; + ndesc.disconnect = ath9k_disconnect_impl; if (api->net && api->net->register_device) { int rc = api->net->register_device(&ndesc); diff --git a/CODE/DKM/ath9k/wpa2_crypto.c b/CODE/DKM/ath9k/wpa2_crypto.c new file mode 100644 index 0000000..4477e1c --- /dev/null +++ b/CODE/DKM/ath9k/wpa2_crypto.c @@ -0,0 +1,639 @@ +/* wpa2_crypto.c — WPA2-PSK 加密底座实现(见 wpa2_crypto.h) + * 全部为恒定内存访问模式的最小实现,无堆、无 SSE。 + */ + +#include "wpa2_crypto.h" + +/* ================= SHA1 (RFC 3174) ================= */ + +typedef struct { + u32 h[5]; + u64 total_len; + u8 buf[64]; + u32 buf_len; +} sha1_ctx; + +static void sha1_block(u32 h[5], const u8 *p) { + u32 w[80]; + for (int i = 0; i < 16; i++) + w[i] = ((u32)p[i*4] << 24) | ((u32)p[i*4+1] << 16) | + ((u32)p[i*4+2] << 8) | (u32)p[i*4+3]; + for (int i = 16; i < 80; i++) { + u32 x = w[i-3] ^ w[i-8] ^ w[i-14] ^ w[i-16]; + w[i] = (x << 1) | (x >> 31); /* ROTL 1 */ + } + u32 a=h[0], b=h[1], c=h[2], d=h[3], e=h[4]; + for (int i = 0; i < 80; i++) { + u32 f, k; + if (i < 20) { f = (b & c) | ((~b) & d); k = 0x5A827999; } + else if (i < 40) { f = b ^ c ^ d; k = 0x6ED9EBA1; } + else if (i < 60) { f = (b & c) | (b & d) | (c & d); k = 0x8F1BBCDC; } + else { f = b ^ c ^ d; k = 0xCA62C1D6; } + u32 t = ((a << 5) | (a >> 27)) + f + e + k + w[i]; /* ROTL 5(a) */ + e = d; d = c; c = (b << 30) | (b >> 2); b = a; a = t; /* ROTL 30(b) */ + } + h[0]+=a; h[1]+=b; h[2]+=c; h[3]+=d; h[4]+=e; +} + +static void sha1_init(sha1_ctx *c) { + c->h[0]=0x67452301; c->h[1]=0xEFCDAB89; c->h[2]=0x98BADCFE; + c->h[3]=0x10325476; c->h[4]=0xC3D2E1F0; + c->total_len = 0; c->buf_len = 0; +} + +static void sha1_update(sha1_ctx *c, const u8 *data, u32 len) { + c->total_len += len; + while (len > 0) { + u32 take = 64 - c->buf_len; + if (take > len) take = len; + for (u32 i = 0; i < take; i++) c->buf[c->buf_len + i] = data[i]; + c->buf_len += take; data += take; len -= take; + if (c->buf_len == 64) { sha1_block(c->h, c->buf); c->buf_len = 0; } + } +} + +static void sha1_final(sha1_ctx *c, u8 out[20]) { + u64 bits = c->total_len * 8; + u8 pad = 0x80; + sha1_update(c, &pad, 1); + u8 z = 0; + while (c->buf_len != 56) sha1_update(c, &z, 1); + u8 lenb[8]; + for (int i = 0; i < 8; i++) lenb[i] = (u8)(bits >> (56 - i * 8)); + sha1_update(c, lenb, 8); + for (int i = 0; i < 5; i++) { + out[i*4] = (u8)(c->h[i] >> 24); + out[i*4+1] = (u8)(c->h[i] >> 16); + out[i*4+2] = (u8)(c->h[i] >> 8); + out[i*4+3] = (u8)(c->h[i]); + } +} + +void wpa2_sha1(const u8 *data, u32 len, u8 out[20]) { + sha1_ctx c; + sha1_init(&c); + sha1_update(&c, data, len); + sha1_final(&c, out); +} + +/* ================= HMAC-SHA1 (RFC 2202) ================= */ + +void wpa2_hmac_sha1(const u8 *key, u32 key_len, + const u8 *data, u32 data_len, u8 out[20]) { + u8 k[64], ipad[64], opad[64], kb[20]; + for (int i = 0; i < 64; i++) k[i] = 0; + if (key_len > 64) { + wpa2_sha1(key, key_len, kb); + for (int i = 0; i < 20; i++) k[i] = kb[i]; + } else { + for (u32 i = 0; i < key_len; i++) k[i] = key[i]; + } + for (int i = 0; i < 64; i++) { ipad[i] = k[i] ^ 0x36; opad[i] = k[i] ^ 0x5C; } + u8 inner[20]; + sha1_ctx c; + sha1_init(&c); + sha1_update(&c, ipad, 64); + sha1_update(&c, data, data_len); + sha1_final(&c, inner); + sha1_init(&c); + sha1_update(&c, opad, 64); + sha1_update(&c, inner, 20); + sha1_final(&c, out); +} + +/* ================= PBKDF2-HMAC-SHA1 (RFC 2898) ================= */ + +static void pbkdf2_f(const u8 *pass, u32 pass_len, + const u8 *salt, u32 salt_len, + u32 iterations, u32 block_index, u8 out[20]) { + /* U1 = HMAC(pass, salt || INT_32_BE(block_index));U_i = HMAC(pass, U_{i-1}) */ + u8 sbuf[36]; + u32 n = salt_len; + if (n > 32) n = 32; /* SSID ≤ 32 字节,防溢出 */ + for (u32 i = 0; i < n; i++) sbuf[i] = salt[i]; + sbuf[n+0] = (u8)(block_index >> 24); + sbuf[n+1] = (u8)(block_index >> 16); + sbuf[n+2] = (u8)(block_index >> 8); + sbuf[n+3] = (u8)(block_index); + u8 u[20], t[20]; + wpa2_hmac_sha1(pass, pass_len, sbuf, n + 4, u); + for (int i = 0; i < 20; i++) t[i] = u[i]; + for (u32 it = 1; it < iterations; it++) { + wpa2_hmac_sha1(pass, pass_len, u, 20, u); + for (int i = 0; i < 20; i++) t[i] ^= u[i]; + } + for (int i = 0; i < 20; i++) out[i] = t[i]; +} + +void wpa2_pbkdf2_sha1(const char *passphrase, const u8 *ssid, u32 ssid_len, + u8 psk[WPA2_PMK_LEN]) { + u32 plen = 0; + while (passphrase[plen]) plen++; + pbkdf2_f((const u8 *)passphrase, plen, ssid, ssid_len, 4096, 1, psk); /* DK1 → 前 20 字节 */ + pbkdf2_f((const u8 *)passphrase, plen, ssid, ssid_len, 4096, 2, psk + 20); /* DK2 → 后 12 字节 */ +} + +/* ================= PRF-X (802.11i H.4) ================= + * PTK = PRF-512(PMK, "Pairwise key expansion", 串接 seed)。 + * seed 由调用方拼好:min(AA,SPA)||max(AA,SPA)||min(ANonce,SNonce)||max(...)。 + * 输出 64 字节:迭代 0..63,每字节取 HMAC-SHA1(PMK, label||seed||counter)[0]。 + */ +void wpa2_prf512(const u8 *pmk, const u8 *seed, u32 seed_len, u8 out[64]) { + static const char label[] = "Pairwise key expansion"; + u32 label_len = sizeof(label) - 1; /* 22 */ + u8 buf[22 + 64 + 1]; + for (u32 i = 0; i < label_len; i++) buf[i] = (u8)label[i]; + for (u32 i = 0; i < seed_len; i++) buf[label_len + i] = seed[i]; + if (seed_len > 64) seed_len = 64; + for (int c = 0; c < 64; c++) { + buf[label_len + seed_len] = (u8)c; + u8 mac[20]; + wpa2_hmac_sha1(pmk, 32, buf, label_len + seed_len + 1, mac); + out[c] = mac[0]; + } +} + +/* ================= AES-128 (FIPS-197,仅加密方向) ================= */ + +static const u8 aes_sbox[256] = { + 0x63,0x7c,0x77,0x7b,0xf2,0x6b,0x6f,0xc5,0x30,0x01,0x67,0x2b,0xfe,0xd7,0xab,0x76, + 0xca,0x82,0xc9,0x7d,0xfa,0x59,0x47,0xf0,0xad,0xd4,0xa2,0xaf,0x9c,0xa4,0x72,0xc0, + 0xb7,0xfd,0x93,0x26,0x36,0x3f,0xf7,0xcc,0x34,0xa5,0xe5,0xf1,0x71,0xd8,0x31,0x15, + 0x04,0xc7,0x23,0xc3,0x18,0x96,0x05,0x9a,0x07,0x12,0x80,0xe2,0xeb,0x27,0xb2,0x75, + 0x09,0x83,0x2c,0x1a,0x1b,0x6e,0x5a,0xa0,0x52,0x3b,0xd6,0xb3,0x29,0xe3,0x2f,0x84, + 0x53,0xd1,0x00,0xed,0x20,0xfc,0xb1,0x5b,0x6a,0xcb,0xbe,0x39,0x4a,0x4c,0x58,0xcf, + 0xd0,0xef,0xaa,0xfb,0x43,0x4d,0x33,0x85,0x45,0xf9,0x02,0x7f,0x50,0x3c,0x9f,0xa8, + 0x51,0xa3,0x40,0x8f,0x92,0x9d,0x38,0xf5,0xbc,0xb6,0xda,0x21,0x10,0xff,0xf3,0xd2, + 0xcd,0x0c,0x13,0xec,0x5f,0x97,0x44,0x17,0xc4,0xa7,0x7e,0x3d,0x64,0x5d,0x19,0x73, + 0x60,0x81,0x4f,0xdc,0x22,0x2a,0x90,0x88,0x46,0xee,0xb8,0x14,0xde,0x5e,0x0b,0xdb, + 0xe0,0x32,0x3a,0x0a,0x49,0x06,0x24,0x5c,0xc2,0xd3,0xac,0x62,0x91,0x95,0xe4,0x79, + 0xe7,0xc8,0x37,0x6d,0x8d,0xd5,0x4e,0xa9,0x6c,0x56,0xf4,0xea,0x65,0x7a,0xae,0x08, + 0xba,0x78,0x25,0x2e,0x1c,0xa6,0xb4,0xc6,0xe8,0xdd,0x74,0x1f,0x4b,0xbd,0x8b,0x8a, + 0x70,0x3e,0xb5,0x66,0x48,0x03,0xf6,0x0e,0x61,0x35,0x57,0xb9,0x86,0xc1,0x1d,0x9e, + 0xe1,0xf8,0x98,0x11,0x69,0xd9,0x8e,0x94,0x9b,0x1e,0x87,0xe9,0xce,0x55,0x28,0xdf, + 0x8c,0xa1,0x89,0x0d,0xbf,0xe6,0x42,0x68,0x41,0x99,0x2d,0x0f,0xb0,0x54,0xbb,0x16 +}; + +static const u8 aes_rcon[11] = { + 0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36 +}; + +static u32 aes_sub_word(u32 w) { + return ((u32)aes_sbox[(w >> 24) & 0xFF] << 24) | + ((u32)aes_sbox[(w >> 16) & 0xFF] << 16) | + ((u32)aes_sbox[(w >> 8) & 0xFF] << 8) | + (u32)aes_sbox[w & 0xFF]; +} + +/* 展开轮密钥:rk[44](11 轮 × 4 word) */ +static void aes_key_expand(const u8 key[16], u32 rk[44]) { + for (int i = 0; i < 4; i++) + rk[i] = ((u32)key[i*4] << 24) | ((u32)key[i*4+1] << 16) | + ((u32)key[i*4+2] << 8) | (u32)key[i*4+3]; + for (int i = 4; i < 44; i++) { + u32 t = rk[i-1]; + if (i % 4 == 0) { + t = aes_sub_word((t << 8) | (t >> 24)) ^ ((u32)aes_rcon[i/4] << 24); + } + rk[i] = rk[i-4] ^ t; + } +} + +void wpa2_aes128_enc_block(const u8 key[16], const u8 in[16], u8 out[16]) { + u32 rk[44]; + aes_key_expand(key, rk); + u32 s0,s1,s2,s3, t0,t1,t2,t3; + s0 = rk[0] ^ ((u32)in[0] << 24 | (u32)in[1] << 16 | (u32)in[2] << 8 | in[3]); + s1 = rk[1] ^ ((u32)in[4] << 24 | (u32)in[5] << 16 | (u32)in[6] << 8 | in[7]); + s2 = rk[2] ^ ((u32)in[8] << 24 | (u32)in[9] << 16 | (u32)in[10] << 8 | in[11]); + s3 = rk[3] ^ ((u32)in[12] << 24 | (u32)in[13] << 16 | (u32)in[14] << 8 | in[15]); +#define AES_XTIME(x) ((u8)((((u8)(x)) << 1) ^ ((((u8)(x)) >> 7) * 0x1b))) + for (int r = 1; r <= 10; r++) { + /* SubBytes + ShiftRows(按列状态 s0..s3 每列 4 字节,state[col][row]) */ + u8 sb[4][4]; + u32 sv[4] = {s0, s1, s2, s3}; + for (int cCol = 0; cCol < 4; cCol++) + for (int rRow = 0; rRow < 4; rRow++) + sb[rRow][cCol] = aes_sbox[(sv[cCol] >> (24 - rRow * 8)) & 0xFF]; + /* ShiftRows:行 r 循环左移 r */ + { + u8 t; + t = sb[1][0]; sb[1][0]=sb[1][1]; sb[1][1]=sb[1][2]; sb[1][2]=sb[1][3]; sb[1][3]=t; + t=sb[2][0]; sb[2][0]=sb[2][2]; sb[2][2]=t; t=sb[2][1]; sb[2][1]=sb[2][3]; sb[2][3]=t; + t = sb[3][0]; sb[3][0]=sb[3][3]; sb[3][3]=sb[3][2]; sb[3][2]=sb[3][1]; sb[3][1]=t; + } + /* MixColumns(末轮跳过) */ + if (r < 10) { + u32 o[4]; + for (int cCol = 0; cCol < 4; cCol++) { + u8 a0=sb[0][cCol], a1=sb[1][cCol], a2=sb[2][cCol], a3=sb[3][cCol]; + u8 x1 = AES_XTIME(a0), x2 = AES_XTIME(a1); + u8 x3 = AES_XTIME(a2), x4 = AES_XTIME(a3); + sb[0][cCol] = (u8)(x1 ^ x2 ^ a1 ^ a2 ^ a3); + sb[1][cCol] = (u8)(a0 ^ x2 ^ x3 ^ a2 ^ a3); + sb[2][cCol] = (u8)(a0 ^ a1 ^ x3 ^ x4 ^ a3); + sb[3][cCol] = (u8)(x1 ^ a0 ^ a1 ^ a2 ^ x4); + } + o[0] = ((u32)sb[0][0] << 24) | ((u32)sb[1][0] << 16) | ((u32)sb[2][0] << 8) | sb[3][0]; + o[1] = ((u32)sb[0][1] << 24) | ((u32)sb[1][1] << 16) | ((u32)sb[2][1] << 8) | sb[3][1]; + o[2] = ((u32)sb[0][2] << 24) | ((u32)sb[1][2] << 16) | ((u32)sb[2][2] << 8) | sb[3][2]; + o[3] = ((u32)sb[0][3] << 24) | ((u32)sb[1][3] << 16) | ((u32)sb[2][3] << 8) | sb[3][3]; + t0 = o[0]; t1 = o[1]; t2 = o[2]; t3 = o[3]; + } else { + t0 = ((u32)sb[0][0] << 24) | ((u32)sb[1][0] << 16) | ((u32)sb[2][0] << 8) | sb[3][0]; + t1 = ((u32)sb[0][1] << 24) | ((u32)sb[1][1] << 16) | ((u32)sb[2][1] << 8) | sb[3][1]; + t2 = ((u32)sb[0][2] << 24) | ((u32)sb[1][2] << 16) | ((u32)sb[2][2] << 8) | sb[3][2]; + t3 = ((u32)sb[0][3] << 24) | ((u32)sb[1][3] << 16) | ((u32)sb[2][3] << 8) | sb[3][3]; + } + s0 = t0 ^ rk[r*4+0]; + s1 = t1 ^ rk[r*4+1]; + s2 = t2 ^ rk[r*4+2]; + s3 = t3 ^ rk[r*4+3]; + } + out[0]=(u8)(s0>>24); out[1]=(u8)(s0>>16); out[2]=(u8)(s0>>8); out[3]=(u8)s0; + out[4]=(u8)(s1>>24); out[5]=(u8)(s1>>16); out[6]=(u8)(s1>>8); out[7]=(u8)s1; + out[8]=(u8)(s2>>24); out[9]=(u8)(s2>>16); out[10]=(u8)(s2>>8); out[11]=(u8)s2; + out[12]=(u8)(s3>>24); out[13]=(u8)(s3>>16); out[14]=(u8)(s3>>8); out[15]=(u8)s3; +} + +/* ================= AES-128 解密方向(RFC 3394 unwrap 用) ================= */ + +static const u8 aes_inv_sbox[256] = { + 0x52,0x09,0x6a,0xd5,0x30,0x36,0xa5,0x38,0xbf,0x40,0xa3,0x9e,0x81,0xf3,0xd7,0xfb, + 0x7c,0xe3,0x39,0x82,0x9b,0x2f,0xff,0x87,0x34,0x8e,0x43,0x44,0xc4,0xde,0xe9,0xcb, + 0x54,0x7b,0x94,0x32,0xa6,0xc2,0x23,0x3d,0xee,0x4c,0x95,0x0b,0x42,0xfa,0xc3,0x4e, + 0x08,0x2e,0xa1,0x66,0x28,0xd9,0x24,0xb2,0x76,0x5b,0xa2,0x49,0x6d,0x8b,0xd1,0x25, + 0x72,0xf8,0xf6,0x64,0x86,0x68,0x98,0x16,0xd4,0xa4,0x5c,0xcc,0x5d,0x65,0xb6,0x92, + 0x6c,0x70,0x48,0x50,0xfd,0xed,0xb9,0xda,0x5e,0x15,0x46,0x57,0xa7,0x8d,0x9d,0x84, + 0x90,0xd8,0xab,0x00,0x8c,0xbc,0xd3,0x0a,0xf7,0xe4,0x58,0x05,0xb8,0xb3,0x45,0x06, + 0xd0,0x2c,0x1e,0x8f,0xca,0x3f,0x0f,0x02,0xc1,0xaf,0xbd,0x03,0x01,0x13,0x8a,0x6b, + 0x3a,0x91,0x11,0x41,0x4f,0x67,0xdc,0xea,0x97,0xf2,0xcf,0xce,0xf0,0xb4,0xe6,0x73, + 0x96,0xac,0x74,0x22,0xe7,0xad,0x35,0x85,0xe2,0xf9,0x37,0xe8,0x1c,0x75,0xdf,0x6e, + 0x47,0xf1,0x1a,0x71,0x1d,0x29,0xc5,0x89,0x6f,0xb7,0x62,0x0e,0xaa,0x18,0xbe,0x1b, + 0xfc,0x56,0x3e,0x4b,0xc6,0xd2,0x79,0x20,0x9a,0xdb,0xc0,0xfe,0x78,0xcd,0x5a,0xf4, + 0x1f,0xdd,0xa8,0x33,0x88,0x07,0xc7,0x31,0xb1,0x12,0x10,0x59,0x27,0x80,0xec,0x5f, + 0x60,0x51,0x7f,0xa9,0x19,0xb5,0x4a,0x0d,0x2d,0xe5,0x7a,0x9f,0x93,0xc9,0x9c,0xef, + 0xa0,0xe0,0x3b,0x4d,0xae,0x2a,0xf5,0xb0,0xc8,0xeb,0xbb,0x3c,0x83,0x53,0x99,0x61, + 0x17,0x2b,0x04,0x7e,0xba,0x77,0xd6,0x26,0xe1,0x69,0x14,0x63,0x55,0x21,0x0c,0x7d +}; + +/* GF(2^8) 乘法(AES 域,模 x^8+x^4+x^3+x+1) */ +static u8 aes_gf_mul(u8 a, u8 b) { + u8 p = 0; + for (int i = 0; i < 8; i++) { + if (b & 1) p ^= a; + u8 hi = a & 0x80; + a = (u8)(a << 1); + if (hi) a ^= 0x1b; + b >>= 1; + } + return p; +} + +/* AES-128 解密单块(等价逆密码结构,调试/unwrap 用) */ +void wpa2_aes128_dec_block(const u8 key[16], const u8 in[16], u8 out[16]) { + u32 rk[44]; + aes_key_expand(key, rk); + u32 s0 = rk[40] ^ ((u32)in[0] << 24 | (u32)in[1] << 16 | (u32)in[2] << 8 | in[3]); + u32 s1 = rk[41] ^ ((u32)in[4] << 24 | (u32)in[5] << 16 | (u32)in[6] << 8 | in[7]); + u32 s2 = rk[42] ^ ((u32)in[8] << 24 | (u32)in[9] << 16 | (u32)in[10] << 8 | in[11]); + u32 s3 = rk[43] ^ ((u32)in[12] << 24 | (u32)in[13] << 16 | (u32)in[14] << 8 | in[15]); + u32 sv[4]; + for (int r = 9; r >= 0; r--) { + sv[0]=s0; sv[1]=s1; sv[2]=s2; sv[3]=s3; + u8 sb[4][4]; + for (int cCol = 0; cCol < 4; cCol++) + for (int rRow = 0; rRow < 4; rRow++) + sb[rRow][cCol] = (u8)(sv[cCol] >> (24 - rRow * 8)); + /* InvShiftRows(行 r 循环右移 r)+ InvSubBytes */ + u8 t; + t = sb[1][3]; sb[1][3]=sb[1][2]; sb[1][2]=sb[1][1]; sb[1][1]=sb[1][0]; sb[1][0]=t; + t=sb[2][0]; sb[2][0]=sb[2][2]; sb[2][2]=t; t=sb[2][1]; sb[2][1]=sb[2][3]; sb[2][3]=t; + t = sb[3][0]; sb[3][0]=sb[3][1]; sb[3][1]=sb[3][2]; sb[3][2]=sb[3][3]; sb[3][3]=t; + for (int cCol = 0; cCol < 4; cCol++) + for (int rRow = 0; rRow < 4; rRow++) + sb[rRow][cCol] = aes_inv_sbox[sb[rRow][cCol]]; + /* AddRoundKey(r) */ + u32 nrk[4] = { rk[r*4+0], rk[r*4+1], rk[r*4+2], rk[r*4+3] }; + { + u32 o[4]; + for (int cCol = 0; cCol < 4; cCol++) + o[cCol] = ((u32)sb[0][cCol] << 24) | ((u32)sb[1][cCol] << 16) | + ((u32)sb[2][cCol] << 8) | (u32)sb[3][cCol]; + s0 = o[0] ^ nrk[0]; s1 = o[1] ^ nrk[1]; s2 = o[2] ^ nrk[2]; s3 = o[3] ^ nrk[3]; + } + /* InvMixColumns(末轮 r=0 跳过):作用在 AddRoundKey 之后的状态上 */ + if (r > 0) { + sv[0]=s0; sv[1]=s1; sv[2]=s2; sv[3]=s3; + for (int cCol = 0; cCol < 4; cCol++) + for (int rRow = 0; rRow < 4; rRow++) + sb[rRow][cCol] = (u8)(sv[cCol] >> (24 - rRow * 8)); + for (int cCol = 0; cCol < 4; cCol++) { + u8 a0=sb[0][cCol], a1=sb[1][cCol], a2=sb[2][cCol], a3=sb[3][cCol]; + sb[0][cCol] = (u8)(aes_gf_mul(a0,0x0e) ^ aes_gf_mul(a1,0x0b) ^ aes_gf_mul(a2,0x0d) ^ aes_gf_mul(a3,0x09)); + sb[1][cCol] = (u8)(aes_gf_mul(a0,0x09) ^ aes_gf_mul(a1,0x0e) ^ aes_gf_mul(a2,0x0b) ^ aes_gf_mul(a3,0x0d)); + sb[2][cCol] = (u8)(aes_gf_mul(a0,0x0d) ^ aes_gf_mul(a1,0x09) ^ aes_gf_mul(a2,0x0e) ^ aes_gf_mul(a3,0x0b)); + sb[3][cCol] = (u8)(aes_gf_mul(a0,0x0b) ^ aes_gf_mul(a1,0x0d) ^ aes_gf_mul(a2,0x09) ^ aes_gf_mul(a3,0x0e)); + } + u32 o[4]; + for (int cCol = 0; cCol < 4; cCol++) + o[cCol] = ((u32)sb[0][cCol] << 24) | ((u32)sb[1][cCol] << 16) | + ((u32)sb[2][cCol] << 8) | (u32)sb[3][cCol]; + s0 = o[0]; s1 = o[1]; s2 = o[2]; s3 = o[3]; + } + } + out[0]=(u8)(s0>>24); out[1]=(u8)(s0>>16); out[2]=(u8)(s0>>8); out[3]=(u8)s0; + out[4]=(u8)(s1>>24); out[5]=(u8)(s1>>16); out[6]=(u8)(s1>>8); out[7]=(u8)s1; + out[8]=(u8)(s2>>24); out[9]=(u8)(s2>>16); out[10]=(u8)(s2>>8); out[11]=(u8)s2; + out[12]=(u8)(s3>>24); out[13]=(u8)(s3>>16); out[14]=(u8)(s3>>8); out[15]=(u8)s3; +} + +/* ================= RFC 3394 AES Key Unwrap ================= */ + +static const u8 wrap_iv[8] = {0xA6,0xA6,0xA6,0xA6,0xA6,0xA6,0xA6,0xA6}; + +int wpa2_key_unwrap(const u8 kek[16], const u8 *in, u32 in_len, u8 *out) { + if (in_len < 24 || (in_len % 8) != 0) return -1; + u32 n = in_len / 8 - 1; + u8 areg[8]; + for (int i = 0; i < 8; i++) areg[i] = in[i]; + /* R 块直接在 out 缓冲中处理(out 容量须 ≥ in_len-8,调用方保证) */ + u8 *r = out; + for (u32 i = 0; i < n * 8; i++) r[i] = in[8 + i]; + u8 blockin[16], b[16]; + for (int j = 5; j >= 0; j--) { + for (u32 i = n; i >= 1; i--) { + /* RFC 3394: B = AES-1(K, (A ^ t) | R[i]),t = n*j + i */ + u64 t = (u64)(n * (u32)j + i); + for (int k = 0; k < 8; k++) + blockin[k] = areg[k] ^ (u8)((t >> (56 - k * 8)) & 0xFF); + for (int k = 0; k < 8; k++) blockin[8+k] = r[(i-1)*8+k]; + wpa2_aes128_dec_block(kek, blockin, b); + for (int k = 0; k < 8; k++) areg[k] = b[k]; + for (int k = 0; k < 8; k++) r[(i-1)*8+k] = b[8+k]; + } + } + for (int i = 0; i < 8; i++) if (areg[i] != wrap_iv[i]) return -1; + return 0; +} + +/* ================= CCMP (RFC 3610 + 802.11i) ================= + * STA 收 AP 数据帧方向:MIC(CBC-MAC) 验证 + CTR 解密。 + * 帧 = MAC 头(24B, 3 地址) || CCMP 头(8B) || 密文 || MIC(8B)。 + */ + +#define CCMP_HDR_LEN 8u +#define CCMP_MIC_LEN 8u + +static void ccmp_nonce16(const u8 *frame, const u8 *chdr, u8 nonce[16]) { + nonce[0] = 0; /* priority = 0 */ + for (int i = 0; i < 6; i++) nonce[1+i] = frame[10+i]; /* A2 = SA */ + /* CCMP 头布局:b0=PN0 b1=PN1 b2=rsvd b3=KeyID b4=PN2 b5=PN3 b6=PN4 b7=PN5 */ + nonce[7] = chdr[0]; /* PN0 */ + nonce[8] = chdr[1]; /* PN1 */ + nonce[9] = chdr[4]; /* PN2 */ + nonce[10] = chdr[5]; /* PN3 */ + nonce[11] = chdr[6]; /* PN4 */ + nonce[12] = chdr[7]; /* PN5 */ + nonce[13] = 0; nonce[14] = 0; nonce[15] = 0; +} + +static void ccmp_ctr_block(const u8 nonce[16], u16 counter, u8 ctr[16]) { + /* RFC 3610 A_i = flags(L-1=1) || 13B nonce || counter(2B) */ + ctr[0] = 0x01; + for (int i = 0; i < 13; i++) ctr[1+i] = nonce[i]; + ctr[14] = (u8)(counter >> 8); + ctr[15] = (u8)(counter); +} + +/* ---- CCMP 头构造:PN 按 802.11i 散布写入 ---- */ +static void ccmp_header_fill(u8 *chdr, u64 pn, u8 key_id) { + chdr[0] = (u8)(pn & 0xFF); /* PN0 */ + chdr[1] = (u8)((pn >> 8) & 0xFF); /* PN1 */ + chdr[2] = 0; /* Reserved */ + chdr[3] = (u8)(0x20 | (key_id & 0x03)); /* ExtIV=1 | KeyID */ + chdr[4] = (u8)((pn >> 16) & 0xFF); /* PN2 */ + chdr[5] = (u8)((pn >> 24) & 0xFF); /* PN3 */ + chdr[6] = (u8)((pn >> 32) & 0xFF); /* PN4 */ + chdr[7] = (u8)((pn >> 40) & 0xFF); /* PN5 */ +} + +/* ---- CBC-MAC:B0 || AAD(24B) || 密文 → MIC(16B)(收发共用) ---- */ +static void ccmp_cbc_mac(const u8 *frame, const u8 *nonce, + const u8 *ct, u32 ct_len, const u8 tk[16], u8 mac[16]) { + u16 fctl = (u16)frame[0] | ((u16)frame[1] << 8); + u16 fc = fctl & 0xC78F; + u16 sc = (u16)frame[22] | ((u16)frame[23] << 8); + sc &= 0x000F; + u8 abuf[24]; + abuf[0] = 0; abuf[1] = 22; + abuf[2] = (u8)(fc & 0xFF); abuf[3] = (u8)(fc >> 8); + for (int i = 0; i < 18; i++) abuf[4+i] = frame[4+i]; + abuf[22] = (u8)(sc & 0xFF); abuf[23] = (u8)(sc >> 8); + + u8 blk[16], b0[16]; + b0[0] = 0x19; /* Adata=0, M=3(8B), L-1=1 */ + for (int i = 0; i < 13; i++) b0[1+i] = nonce[i]; + b0[14] = (u8)(ct_len >> 8); b0[15] = (u8)ct_len; + wpa2_aes128_enc_block(tk, b0, mac); + for (int i = 0; i < 16; i++) blk[i] = abuf[i] ^ mac[i]; + wpa2_aes128_enc_block(tk, blk, mac); + for (int i = 0; i < 8; i++) blk[i] = abuf[16+i] ^ mac[i]; + for (int i = 8; i < 16; i++) blk[i] = mac[i]; + wpa2_aes128_enc_block(tk, blk, mac); + for (u32 off = 0; off < ct_len; off += 16) { + u32 take = ct_len - off; + if (take > 16) take = 16; + for (u32 i = 0; i < 16; i++) + blk[i] = (i < take ? ct[off+i] : 0) ^ mac[i]; + wpa2_aes128_enc_block(tk, blk, mac); + } +} + +int wpa2_ccmp_decrypt(const u8 *frame, u32 len, const u8 tk[16], u8 *out, u32 out_cap) { + u32 hdr = 24; /* 3 地址 data 帧 */ + if (len < hdr + CCMP_HDR_LEN + CCMP_MIC_LEN) return -2; + const u8 *chdr = frame + hdr; + const u8 *ct = frame + hdr + CCMP_HDR_LEN; + u32 ct_len = len - hdr - CCMP_HDR_LEN - CCMP_MIC_LEN; + if (ct_len == 0) return -2; + if (ct_len > out_cap) return -2; + + u8 nonce[16]; /* 13B CCMP 非立即在 [0..12] */ + ccmp_nonce16(frame, chdr, nonce); + + /* ---- MIC 校验(基于密文) ---- */ + u8 mac[16]; + ccmp_cbc_mac(frame, nonce, ct, ct_len, tk, mac); + u8 diff = 0; + for (u32 i = 0; i < CCMP_MIC_LEN; i++) diff |= mac[i] ^ ct[ct_len + i]; + if (diff) return -1; /* MIC 校验失败 */ + + /* ---- CTR 解密 ---- */ + u16 counter = 1; + for (u32 off = 0; off < ct_len; off += 16) { + u8 ctr[16], s[16]; + ccmp_ctr_block(nonce, counter++, ctr); + wpa2_aes128_enc_block(tk, ctr, s); + u32 take = ct_len - off; + if (take > 16) take = 16; + for (u32 i = 0; i < take; i++) + out[off+i] = ct[off+i] ^ s[i]; + } + return (int)ct_len; +} + +int wpa2_ccmp_encrypt(u8 *buf, u32 buf_cap, const u8 *msdu, u32 msdu_len, + const u8 tk[16], u64 pn) { + if (!buf || !msdu || msdu_len == 0) return -1; + if (msdu_len + 24 + CCMP_HDR_LEN + CCMP_MIC_LEN > buf_cap) return -1; + + u8 *chdr = buf + 24; + ccmp_header_fill(chdr, pn, 0); + u8 *ct = chdr + CCMP_HDR_LEN; + + u8 nonce[16]; + ccmp_nonce16(buf, chdr, nonce); + + /* CTR 加密 */ + u16 counter = 1; + for (u32 off = 0; off < msdu_len; off += 16) { + u8 ctr[16], s[16]; + ccmp_ctr_block(nonce, counter++, ctr); + wpa2_aes128_enc_block(tk, ctr, s); + u32 take = msdu_len - off; + if (take > 16) take = 16; + for (u32 i = 0; i < take; i++) ct[off+i] = msdu[off+i] ^ s[i]; + } + + u8 mac[16]; + ccmp_cbc_mac(buf, nonce, ct, msdu_len, tk, mac); + for (u32 i = 0; i < CCMP_MIC_LEN; i++) ct[msdu_len + i] = mac[i]; + return (int)(24 + CCMP_HDR_LEN + msdu_len + CCMP_MIC_LEN); +} + +/* ================= KAT ================= */ + +static int buf_eq(const u8 *a, const u8 *b, u32 n) { + u8 d = 0; + for (u32 i = 0; i < n; i++) d |= a[i] ^ b[i]; + return d == 0; +} + +/* CCMP 自洽往返:用生产 encrypt 构造,再走生产 decrypt。 + * 覆盖 nonce/AAD/B0/CTR 字节布局 + MIC 篡改检测,防索引回归。 */ +static int ccmp_selftest(void) { + static const char payload[] = "Deshab CCMP round-trip payload 0123456789"; + u32 plen = sizeof(payload) - 1; + + u8 tk[16]; + for (int i = 0; i < 16; i++) tk[i] = (u8)(0x30 + i); + + u8 frame[96]; + for (u32 i = 0; i < sizeof(frame); i++) frame[i] = 0; + /* 802.11 data 头:FC=0x0841 (data, toDS),A1/A2/A3,seq ctrl */ + frame[0] = 0x41; frame[1] = 0x08; + for (int i = 0; i < 6; i++) frame[4+i] = (u8)(0xA0 + i); /* A1 = AP */ + for (int i = 0; i < 6; i++) frame[10+i] = (u8)(0x10 + i); /* A2 = STA */ + for (int i = 0; i < 6; i++) frame[16+i] = (u8)(0xB0 + i); /* A3 = DA */ + frame[22] = 0x10; frame[23] = 0x00; + + int flen = wpa2_ccmp_encrypt(frame, sizeof(frame), (const u8 *)payload, plen, + tk, 0x000000000001ULL); + if (flen != (int)(24 + 8 + plen + 8)) return -1; + + u8 out[96]; + int rc = wpa2_ccmp_decrypt(frame, (u32)flen, tk, out, sizeof(out)); + if (rc != (int)plen) return -1; + for (u32 i = 0; i < plen; i++) if (out[i] != (u8)payload[i]) return -1; + + /* 篡改密文 → 必须 MIC 校验失败 */ + frame[24 + 8] ^= 0x01; + if (wpa2_ccmp_decrypt(frame, (u32)flen, tk, out, sizeof(out)) != -1) return -1; + return 0; +} + +int wpa2_kat(void) { + u8 out[64]; + + /* 1. SHA1("abc") = a9993e36...9cd0d89d */ + wpa2_sha1((const u8 *)"abc", 3, out); + { + static const u8 exp[20] = { + 0xa9,0x99,0x3e,0x36,0x47,0x06,0x81,0x6a,0xba,0x3e, + 0x25,0x71,0x78,0x50,0xc2,0x6c,0x9c,0xd0,0xd8,0x9d }; + if (!buf_eq(out, exp, 20)) return 1; + } + + /* 2. HMAC-SHA1 RFC 2202 case 2: key "Jefe" data "what do ya want for nothing?" + * = effcdf6ae5eb2fa2d27416d5f184df9c259a7c79 */ + wpa2_hmac_sha1((const u8 *)"Jefe", 4, + (const u8 *)"what do ya want for nothing?", 28, out); + { + static const u8 exp[20] = { + 0xef,0xfc,0xdf,0x6a,0xe5,0xeb,0x2f,0xa2,0xd2,0x74, + 0x16,0xd5,0xf1,0x84,0xdf,0x9c,0x25,0x9a,0x7c,0x79 }; + if (!buf_eq(out, exp, 20)) return 2; + } + + /* 3. PBKDF2-HMAC-SHA1 RFC 6070: ("password","salt",1,20) + * = 0c60c80f961f0e71f3a9b524af6012062fe037a6 */ + { + u8 dk[32]; + /* 手动 1 iter 版本走 pbkdf2_f 不可见,直接用 4096 向量(与 WPA 一致): + * RFC 6070 case 3: ("password","salt",4096,20) + * = 4b007901b765489abead49d926f721d065a429c1 */ + wpa2_pbkdf2_sha1("password", (const u8 *)"salt", 4, dk); + static const u8 exp[20] = { + 0x4b,0x00,0x79,0x01,0xb7,0x65,0x48,0x9a,0xbe,0xad, + 0x49,0xd9,0x26,0xf7,0x21,0xd0,0x65,0xa4,0x29,0xc1 }; + if (!buf_eq(dk, exp, 20)) return 3; + } + + /* 4. AES-128 FIPS-197 C.1: key 000102...0f, pt 00112233...eeff + * = 69c4e0d86a7b0430d8cdb78070b4c55a */ + { + u8 key[16], pt[16], ct[16]; + for (int i = 0; i < 16; i++) { key[i]=(u8)i; pt[i]=(u8)(i*0x11); } + wpa2_aes128_enc_block(key, pt, ct); + static const u8 exp[16] = { + 0x69,0xc4,0xe0,0xd8,0x6a,0x7b,0x04,0x30, + 0xd8,0xcd,0xb7,0x80,0x70,0xb4,0xc5,0x5a }; + if (!buf_eq(ct, exp, 16)) return 4; + } + + /* 5. AES-128 FIPS-197 C.3 (256bit key 前半忽略,此处用 C.1 变体覆盖 key schedule): + * key 2b7e1516 28aed2a6 abf71588 09cf4f3c + * pt 6bc1bee2 2e409f96 e93d7e11 7393172a + * ct 3ad77bb4 0d7a3660 a89ecaf3 2466ef97 */ + { + static const u8 key[16] = {0x2b,0x7e,0x15,0x16,0x28,0xae,0xd2,0xa6, + 0xab,0xf7,0x15,0x88,0x09,0xcf,0x4f,0x3c}; + static const u8 pt[16] = {0x6b,0xc1,0xbe,0xe2,0x2e,0x40,0x9f,0x96, + 0xe9,0x3d,0x7e,0x11,0x73,0x93,0x17,0x2a}; + static const u8 exp[16] = {0x3a,0xd7,0x7b,0xb4,0x0d,0x7a,0x36,0x60, + 0xa8,0x9e,0xca,0xf3,0x24,0x66,0xef,0x97}; + u8 ct[16]; + wpa2_aes128_enc_block(key, pt, ct); + if (!buf_eq(ct, exp, 16)) return 5; + } + + /* 6. CCMP:构造→解密 往返 + 篡改检测 */ + if (ccmp_selftest() != 0) return 6; + + /* 7. RFC 3394 key unwrap(C.1 128-bit KEK 向量) */ + { + static const u8 kek[16] = {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, + 0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F}; + static const u8 wrapped[24] = {0x1F,0xA6,0x8B,0x0A,0x81,0x12,0xB4,0x47, + 0xAE,0xF3,0x4B,0xD8,0xFB,0x5A,0x7B,0x82, + 0x9D,0x3E,0x86,0x23,0x71,0xD2,0xCF,0xE5}; + static const u8 expect[16] = {0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77, + 0x88,0x99,0xAA,0xBB,0xCC,0xDD,0xEE,0xFF}; + u8 plain[16]; + if (wpa2_key_unwrap(kek, wrapped, 24, plain) != 0) return 7; + if (!buf_eq(plain, expect, 16)) return 7; + } + + return 0; +} diff --git a/CODE/DKM/ath9k/wpa2_crypto.h b/CODE/DKM/ath9k/wpa2_crypto.h new file mode 100644 index 0000000..fc2060e --- /dev/null +++ b/CODE/DKM/ath9k/wpa2_crypto.h @@ -0,0 +1,67 @@ +/* wpa2_crypto.h — WPA2-PSK 握手所需加密底座(DKM ath9k 专用) + * + * 范围(802.11i RSNA,AKM 00-0F-AC:2 PSK): + * SHA1 — RFC 3174 + * HMAC-SHA1 — RFC 2204(EAPOL-Key MIC ver2 = HMAC-SHA1-128) + * PBKDF2-HMAC-SHA1 — RFC 2898(passphrase → PSK,4096 iter) + * PRF-X — 802.11i H.4(PMK → 512bit PTK) + * AES-128 — FIPS-197(仅加密方向;CCMP 的 CTR 与 CBC-MAC 都用 AES-ENC) + * AES Key Unwrap — RFC 3394(KEK 解密 M3 key data 中的 GTK KDE) + * CCMP — RFC 3610(data 帧 MIC 验证 + 计数器解密;加密留 TX 数据路径) + * + * 自检:wpa2_kat() 内置 RFC 2202/6070/FIPS-197 已知答案向量, + * driver_init 时调用,任一失败 panic(ATH-E02)。 + * 约束:无堆(静态/栈缓冲)、无除法热路径、-mno-sse 可编译。 + */ +#ifndef ATH9K_WPA2_CRYPTO_H +#define ATH9K_WPA2_CRYPTO_H + +#include "../dkm_shared.h" + +#define WPA2_PMK_LEN 32 +#define WPA2_PTK_LEN 48 /* KCK(16)+KEK(16)+TK(16)(802.11i CCMP 不取 TKIP MIC 子钥) */ +#define WPA2_KCK_LEN 16 +#define WPA2_KEK_LEN 16 +#define WPA2_TK_LEN 16 + +/* SHA1:out[20] */ +void wpa2_sha1(const u8 *data, u32 len, u8 out[20]); +/* 增量 SHA1(EAPOL MIC 需要对任意长帧做 HMAC,直接给一次性接口) */ +void wpa2_hmac_sha1(const u8 *key, u32 key_len, + const u8 *data, u32 data_len, u8 out[20]); +/* PBKDF2-HMAC-SHA1:passphrase → psk[32](iter 固定 4096,salt=SSID) */ +void wpa2_pbkdf2_sha1(const char *passphrase, const u8 *ssid, u32 ssid_len, + u8 psk[WPA2_PMK_LEN]); +/* PRF-512(802.11i H.4):PMK+label+addr/nonce 串接 → out[64] */ +void wpa2_prf512(const u8 *pmk, const u8 *seed, u32 seed_len, u8 out[64]); + +/* AES-128 单块加密(in/out 16 字节,可同址) */ +void wpa2_aes128_enc_block(const u8 key[16], const u8 in[16], u8 out[16]); +/* AES-128 单块解密(RFC 3394 unwrap 用;CCMP 路径不使用) */ +void wpa2_aes128_dec_block(const u8 key[16], const u8 in[16], u8 out[16]); + +/* RFC 3394 key unwrap:in 为 n*8 字节密文(n>=2),out 得 (n-1)*8 明文; + * 返回 0 成功,-1 integrity check 失败(AIV != 0xA6A6A6A6A6A6A6A6)。 */ +int wpa2_key_unwrap(const u8 kek[16], const u8 *in, u32 in_len, u8 *out); + +/* CCMP 解密(STA 收 AP 数据帧,非 QoS,3 地址): + * frame 指向 802.11 MAC 头起始,len 为整帧长度(含 CCMP 8B 头 + 8B MIC)。 + * 成功时把解密后的数据载荷(去掉 CCMP 头/MIC/FCS 前的明文 MSDU) + * 写入 out 并返回明文长度;MIC 错误返回 -1,参数错返回 -2。 */ +int wpa2_ccmp_decrypt(const u8 *frame, u32 len, const u8 tk[16], u8 *out, u32 out_cap); + +/* CCMP 加密(STA 发 AP 数据帧):在 buf 内就地构造 + * [MAC 头(24B,调用方先填好)][CCMP 头(8B)][密文][MIC(8B)]。 + * buf : 调用方提供的缓冲,前 24 字节须已填 MAC 头 + * msdu : 明文 MSDU + * msdu_len: 明文长度(>0) + * pn : 发包序号(调用方递增维护) + * 返回写入 buf 的总帧长(24+8+msdu_len+8);缓冲不足返回 -1。 */ +int wpa2_ccmp_encrypt(u8 *buf, u32 buf_cap, const u8 *msdu, u32 msdu_len, + const u8 tk[16], u64 pn); + +/* KAT(已知答案自检):返回 0 = 全部通过;非 0 = 第几个用例失败(1 基)。 + * driver_init 必须调用,失败方 panic(ATH-E02)。 */ +int wpa2_kat(void); + +#endif diff --git a/build.ps1 b/build.ps1 index a5cfec5..85d4751 100644 --- a/build.ps1 +++ b/build.ps1 @@ -120,6 +120,22 @@ function Build-DkmDriver([string]$SourcePath, [string]$OutputPath) { Write-Host "[build] DKM driver Output: $OutputPath" } +# 多源 DKM 驱动(如 ath9k + wpa2_crypto):逐文件编译后 ld -r 合并 +function Build-DkmDriverMulti([string[]]$SourcePaths, [string]$OutputPath) { + $outDir = Split-Path -Parent $OutputPath + if (-not (Test-Path $outDir)) { New-Item -ItemType Directory -Force -Path $outDir | Out-Null } + $objs = @() + foreach ($src in $SourcePaths) { + $obj = Join-Path $BuildTmp (([System.IO.Path]::GetFileNameWithoutExtension($src)) + '.o') + & $clang -target x86_64-unknown-none -std=c11 -ffreestanding -fno-builtin -fno-stack-protector -fno-pic -fno-pie -mcmodel=kernel -mno-red-zone -mno-sse -mno-sse2 -mno-mmx -msoft-float -m64 -Wall -Wextra -O2 -c $src -o $obj + if ($LASTEXITCODE -ne 0) { throw "failed to compile DKM driver source: $src" } + $objs += $obj + } + & $lld -r -o $OutputPath @objs + if ($LASTEXITCODE -ne 0) { throw "failed to link DKM driver: $OutputPath" } + Write-Host "[build] DKM driver Output: $OutputPath" +} + function Set-Le16([byte[]]$Buffer, [int]$Offset, [int]$Value) { $Buffer[$Offset] = [byte]($Value -band 0xff) $Buffer[$Offset + 1] = [byte](($Value -shr 8) -band 0xff) @@ -1037,7 +1053,8 @@ Build-DkmDriver (Join-Path $Root 'CODE\DKM\devfs\devfs.c') (Join-Path $SystemD Write-Host '[build] Building DKM network drivers...' Build-DkmDriver (Join-Path $Root 'CODE\DKM\e1000\e1000.c') (Join-Path $SystemDir 'driver\net\e1000.drv') Build-DkmDriver (Join-Path $Root 'CODE\DKM\virtio_net\virtio_net.c') (Join-Path $SystemDir 'driver\net\virtio_net.drv') -Build-DkmDriver (Join-Path $Root 'CODE\DKM\ath9k\ath9k.c') (Join-Path $SystemDir 'driver\net\ath9k.drv') +Build-DkmDriverMulti @((Join-Path $Root 'CODE\DKM\ath9k\ath9k.c'), + (Join-Path $Root 'CODE\DKM\ath9k\wpa2_crypto.c')) (Join-Path $SystemDir 'driver\net\ath9k.drv') Build-DkmDriver (Join-Path $Root 'CODE\DKM\wlan\wlan.c') (Join-Path $SystemDir 'driver\net\wlan.drv') # stage3: input — ps2kbd 注册 IRQ1。