# Handshake Capture - ESP32-C6 1.47" LCD Production-oriented WiFi 4-way handshake capture for Waveshare ESP32-C6-LCD-1.47. **Firmware version:** `HANDSHAKE_FIRMWARE_VERSION` in `HandshakeCapture.h` (also printed on serial at boot). **Review backlog:** prioritized fixes from a full firmware pass → **`MUST_DO_IMPROVEMENTS.md`**. ## Features - **SD required for capture:** No card, or open/write failure → pending PCAP is **discarded** and the slot freed (no infinite pending). Hot-insert: sketch retries `SD_Init()` before each capture round. - **SD storage:** Saves **only complete 4-way handshakes** as `.pcap` (LINKTYPE_IEEE802_11): `4way___s.pcap`. Filenames are **FAT-sanitized**. No PMKID-only or partial EAPOL dumps. - **Auto-deauth:** Bursts toward mapped clients to provoke a full 4-way. - **Display:** **Green** = targetable 2.4 GHz WPA/WPA2/WPA3 AP, **gray** = shown but skipped, **red** = 4-way saved to SD. - **No web UI:** Capture-only device. - **WPA / WPA2 / WPA3 PSK / mixed** (when the core reports them). Skips Open, WEP, WPA2-Enterprise. - **2.4 GHz only capture sweep:** channels `1-14` are targeted. Secure APs seen on `5/6 GHz` stay visible in the list but are marked `5G+` and skipped. - **BSSID cache:** Captured BSSIDs stay red across rescans **and across reboots**: each successful save appends that AP’s BSSID to **`/cap_bssids.txt`** (one line `AA:BB:…:FF`). On boot (after SD mounts), that file is merged into RAM so the device **does not re-target** APs already marked good. - **Pre-save PCAP check:** Before writing a `.pcap`, the firmware **walks the in-memory PCAP** and counts **EAPOL-Key** frames (type 3, same LLC/SNAP rules as live capture). If the count is below four, the buffer is discarded (no file, no BSSID append). This does **not** verify MIC, nonces, or distinct M1–M4 — that still requires offline tools / knowing the passphrase. - **Shared SPI protection:** LCD flushes and SD filesystem calls now serialize on one bus lock; SD writes also pause LVGL updates for the duration of the transaction. **Convert:** `hcxpcapngtool` / Wireshark / aircrack-ng expect PCAP with EAPOL-Key frames; a full 4-way is included in each saved file (plus one target beacon when available). ### “Partial” captures — what’s actually possible - **Not mergeable across random reconnects:** EAPOL messages from *different* 4-way runs (different nonces / MIC context) usually **cannot** be stitched into one crackable handshake. Tools need a **coherent** set for that AP↔STA association attempt. - **Within one visit, frames can trickle in:** While tuned to a channel, the device keeps **one PCAP buffer per target AP**. If the client reconnects several times during the same session, **all EAPOL frames append** until either four are seen (then SD save) or the channel round ends without four (buffer dropped — no file). - **EAPOL counting is still heuristic:** Live path stops after **four** matching frames; the **PCAP recount** before SD write catches obvious buffer/counter mismatch. It still does **not** cryptographically validate the 4-way (MIC / replay / message order) — use Wireshark or `hcxpcapngtool` on a PC for that. - **Fewer than four frames:** Some attacks (e.g. **PMKID in message 1**, or classic **M1+M2** with beacon) need fewer frames, but this firmware **only saves on four** so every file aims to be a clean full 4-way for your earlier requirement. ## Hardware - Waveshare ESP32-C6-LCD-1.47 (non-touch, ST7789) - TF card in onboard slot ## Build & Flash Requires LVGL and lv_conf from the ESP32-C6-LCD-1.47-Demo: ```bash cd "/path/to/4 way handshake" arduino-cli compile \ -b 'esp32:esp32:esp32c6:PartitionScheme=huge_app' \ --build-path /tmp/arduino-build-handshake-c6 \ --libraries "ESP32-C6-LCD-1.47-Demo/Arduino/libraries" \ handshake-capture-c6 ``` ```bash arduino-cli upload \ -p /dev/cu.usbmodem* \ -b 'esp32:esp32:esp32c6:PartitionScheme=huge_app' \ --input-dir /tmp/arduino-build-handshake-c6 ``` Use `arduino-cli board list` to find the correct port. For bench builds, set `HANDSHAKE_DEBUG 1` in `HandshakeCapture.h` to restore verbose serial logs. `USE_SOFTAP` defaults to `0`; only turn it on for lab experiments where you explicitly want `WIFI_AP_STA`. ## Flow 1. Boot → scan → display networks (`green` targetable, `gray` skipped) 2. Channel sweep + **up to 2 WPA APs at a time** on that channel; **map clients → deauth burst → listen** (several rounds per visit) 3. PCAP grows in RAM; **SD write only when 4 EAPOL-Key frames** are seen for that AP 4. On save → mark red; **refill slots** with other networks on the same channel, then **next channel** until everyone captured or timed out 5. If a visit ends without 4 EAPOL for an AP, that buffer is discarded (no partial PCAP); the next sweep can try again 6. Mid-capture rescans are intentionally not exposed in the UI; if you add one later, stop capture first and clear active slots before rebuilding `networks[]` ## Production checklist | Item | Notes | |------|--------| | **Flash layout** | Prefer `PartitionScheme=huge_app` (~40% of that partition at v1.0.0); default `default` partition is too small (~96% full). | | **SD** | FAT-formatted microSD; capture is gated on `SD_IsReady()` (successful `SD_Init`), not raw `cardType()` (unreliable after WiFi on shared SPI). | | **Serial** | `115200` — boot line shows `handshake-capture-c6 vX.Y.Z`. | | **Legal / authorization** | Only deploy on networks you own or have **explicit written permission** to test. Unauthorized interception or disruption is illegal in many jurisdictions. | ## Release discipline 1. Bump `HANDSHAKE_FIRMWARE_VERSION` in `HandshakeCapture.h` for any field release. 2. Rebuild with the same `arduino-cli` FQBN and partition scheme you ship. 3. Run a short on-bench test: scan → capture → confirm `.pcap` opens in Wireshark and shows four EAPOL-Key exchanges for the target BSSID.