Politician 1.0.0
WiFi Auditing Library for ESP32
Loading...
Searching...
No Matches
PoliticianFormat.cpp
Go to the documentation of this file.
1#include "PoliticianFormat.h"
2#include "politician_compat.h"
3
4namespace politician {
5namespace format {
6
7static void appendHex(std::string& str, const uint8_t* data, size_t len) {
8 char buf[3];
9 for (size_t i = 0; i < len; i++) {
10 sprintf(buf, "%02x", data[i]);
11 str += buf;
12 }
13}
14
15std::string toHC22000(const HandshakeRecord& rec) {
16#ifndef POLITICIAN_NO_HC22000
17 if (rec.type == CAP_EAPOL_HALF) return std::string(); // No anonce — not crackable
18
19 // Hashcat 22000 Format:
20 // WPA*TYPE*MIC*BSSID*STA*SSID*ANONCE*EAPOL*KEYVER*KEYDATA
21
22 std::string out = "WPA*";
23
24 // 1. TYPE
25 if (rec.type == CAP_PMKID) out += "01*";
26 else if (rec.type == CAP_SAE) out += "06*";
27 else out += "02*";
28
29 // 2. MIC (Field 3)
30 if (rec.type == CAP_PMKID || rec.type == CAP_SAE) {
31 out += "*"; // Empty for PMKID/SAE
32 } else {
33 appendHex(out, rec.mic, 16);
34 out += "*";
35 }
36
37 // 3. BSSID (Field 4)
38 appendHex(out, rec.bssid, 6);
39 out += "*";
40
41 // 4. STA (Field 5)
42 appendHex(out, rec.sta, 6);
43 out += "*";
44
45 // 5. SSID (Field 6)
46 appendHex(out, (const uint8_t*)rec.ssid, rec.ssid_len);
47 out += "*";
48
49 // 6. ANONCE (Field 7)
50 if (rec.type == CAP_EAPOL || rec.type == CAP_EAPOL_CSA) {
51 appendHex(out, rec.anonce, 32);
52 }
53 out += "*";
54
55 // 7. EAPOL/M2 (Field 8)
56 if (rec.type == CAP_EAPOL || rec.type == CAP_EAPOL_CSA) {
57 appendHex(out, rec.eapol_m2, rec.eapol_m2_len);
58 }
59 out += "*";
60
61 // 8. KEYVER (Field 9)
62 out += "02*"; // Default to WPA2/AES
63
64 // 9. KEYDATA (Field 10) - Used for PMKID or SAE elements
65 if (rec.type == CAP_PMKID) {
66 appendHex(out, rec.pmkid, 16);
67 } else if (rec.type == CAP_SAE) {
68 appendHex(out, rec.sae_data, rec.sae_len);
69 }
70
71 return out;
72#else
73 (void)rec;
74 return std::string();
75#endif
76}
77
78size_t writePcapngGlobalHeader(uint8_t* buffer) {
79#ifndef POLITICIAN_NO_PCAPNG
80 size_t offset = 0;
81
82 // 1. Section Header Block (SHB)
83 uint32_t shb_type = 0x0A0D0D0A;
84 uint32_t shb_len = 28;
85 uint32_t magic = 0x1A2B3C4D;
86 uint16_t v_major = 1;
87 uint16_t v_minor = 0;
88 int64_t section_len = -1;
89
90 memcpy(buffer + offset, &shb_type, 4); offset += 4;
91 memcpy(buffer + offset, &shb_len, 4); offset += 4;
92 memcpy(buffer + offset, &magic, 4); offset += 4;
93 memcpy(buffer + offset, &v_major, 2); offset += 2;
94 memcpy(buffer + offset, &v_minor, 2); offset += 2;
95 memcpy(buffer + offset, &section_len, 8); offset += 8;
96 memcpy(buffer + offset, &shb_len, 4); offset += 4;
97
98 // 2. Interface Description Block (IDB)
99 uint32_t idb_type = 0x00000001;
100 uint32_t idb_len = 20;
101 uint16_t link_type = 127; // IEEE 802.11 radiotap
102 uint16_t reserved = 0;
103 uint32_t snaplen = 65535;
104
105 memcpy(buffer + offset, &idb_type, 4); offset += 4;
106 memcpy(buffer + offset, &idb_len, 4); offset += 4;
107 memcpy(buffer + offset, &link_type, 2); offset += 2;
108 memcpy(buffer + offset, &reserved, 2); offset += 2;
109 memcpy(buffer + offset, &snaplen, 4); offset += 4;
110 memcpy(buffer + offset, &idb_len, 4); offset += 4;
111
112 return offset;
113#else
114 (void)buffer;
115 return 0;
116#endif
117}
118
119size_t writePcapngPacket(const uint8_t* payload, size_t payload_len, int8_t rssi, uint8_t channel, uint64_t ts_usec, uint8_t* buffer, size_t max_len) {
120#ifndef POLITICIAN_NO_PCAPNG
121 uint16_t freq = 0;
122 uint16_t chan_flags = 0;
123 if (channel <= 14) {
124 freq = 2407 + (channel * 5);
125 if (channel == 14) freq = 2484;
126 chan_flags = 0x00A0; // 2GHz + Dynamic CCK/OFDM
127 } else {
128 freq = 5000 + (channel * 5);
129 chan_flags = 0x0140; // 5GHz + OFDM
130 }
131
132 uint8_t radiotap[14] = {
133 0x00, 0x00, // Version 0, Pad 0
134 0x0E, 0x00, // Header length 14
135 0x28, 0x00, 0x00, 0x00, // Present mask: Channel + RSSI
136 (uint8_t)(freq & 0xFF), (uint8_t)(freq >> 8),
137 (uint8_t)(chan_flags & 0xFF), (uint8_t)(chan_flags >> 8),
138 (uint8_t)rssi,
139 0x00 // Pad
140 };
141
142 uint32_t rt_len = 14;
143 uint32_t cap_len = (uint32_t)payload_len + rt_len;
144 uint32_t pkt_len = (uint32_t)payload_len + rt_len;
145 uint32_t aligned_pkt_len = (cap_len + 3) & ~3;
146 uint32_t pkt_padding = aligned_pkt_len - cap_len;
147
148 // Options: RSSI (8), Channel (8), End (4) = 20 bytes
149 uint32_t opt_len = 20;
150 uint32_t block_len = 32 + aligned_pkt_len + opt_len;
151
152 if (block_len > max_len) return 0;
153
154 size_t offset = 0;
155 uint32_t epb_type = 0x00000006;
156 uint32_t interface_id = 0;
157 uint32_t ts_high = (uint32_t)(ts_usec >> 32);
158 uint32_t ts_low = (uint32_t)(ts_usec & 0xFFFFFFFF);
159
160 memcpy(buffer + offset, &epb_type, 4); offset += 4;
161 memcpy(buffer + offset, &block_len, 4); offset += 4;
162 memcpy(buffer + offset, &interface_id, 4); offset += 4;
163 memcpy(buffer + offset, &ts_high, 4); offset += 4;
164 memcpy(buffer + offset, &ts_low, 4); offset += 4;
165 memcpy(buffer + offset, &cap_len, 4); offset += 4;
166 memcpy(buffer + offset, &pkt_len, 4); offset += 4;
167
168 memcpy(buffer + offset, radiotap, rt_len); offset += rt_len;
169 memcpy(buffer + offset, payload, payload_len); offset += payload_len;
170
171 if (pkt_padding > 0) {
172 memset(buffer + offset, 0, pkt_padding); offset += pkt_padding;
173 }
174
175 // Option TLVs
176 uint16_t opt_code; uint16_t opt_vlen;
177
178 // RSSI (0x8001)
179 opt_code = 0x8001; opt_vlen = 1;
180 memcpy(buffer + offset, &opt_code, 2); offset += 2;
181 memcpy(buffer + offset, &opt_vlen, 2); offset += 2;
182 buffer[offset++] = (uint8_t)rssi;
183 memset(buffer + offset, 0, 3); offset += 3;
184
185 // Channel (0x8002)
186 opt_code = 0x8002; opt_vlen = 1;
187 memcpy(buffer + offset, &opt_code, 2); offset += 2;
188 memcpy(buffer + offset, &opt_vlen, 2); offset += 2;
189 buffer[offset++] = channel;
190 memset(buffer + offset, 0, 3); offset += 3;
191
192 // End of Options
193 opt_code = 0x0000; opt_vlen = 0;
194 memcpy(buffer + offset, &opt_code, 2); offset += 2;
195 memcpy(buffer + offset, &opt_vlen, 2); offset += 2;
196
197 memcpy(buffer + offset, &block_len, 4); offset += 4;
198
199 return offset;
200#else
201 (void)payload; (void)payload_len; (void)rssi; (void)channel; (void)ts_usec; (void)buffer; (void)max_len;
202 return 0;
203#endif
204}
205
206size_t writePcapngRecord(const HandshakeRecord& rec, uint8_t* buffer, size_t max_len) {
207#ifndef POLITICIAN_NO_PCAPNG
208 size_t offset = 0;
209 uint8_t pkt[512];
210 uint64_t ts = (uint64_t)millis() * 1000;
211
212 // Packet 1: Beacon
213 {
214 size_t p = 0;
215 // MAC Header (24 bytes): Frame Control(2), Dur(2), DA(6), SA(6), BSSID(6), Seq(2)
216 pkt[p++] = 0x80; pkt[p++] = 0x00; pkt[p++] = 0x00; pkt[p++] = 0x00; // Type Mgmt / Subtype Beacon
217 for (int i=0; i<6; i++) pkt[p++] = 0xFF; // Broadcast DA
218 memcpy(pkt + p, rec.bssid, 6); p += 6; // SA
219 memcpy(pkt + p, rec.bssid, 6); p += 6; // BSSID
220 pkt[p++] = 0x00; pkt[p++] = 0x00; // Seq
221 // Fixed params (12 bytes)
222 memset(pkt + p, 0, 8); p += 8; // Timestamp
223 pkt[p++] = 0x64; pkt[p++] = 0x00; // Beacon Interval (100)
224 pkt[p++] = 0x11; pkt[p++] = 0x04; // Capabilities
225 // Tagged params
226 pkt[p++] = 0x00; pkt[p++] = rec.ssid_len; // SSID Tag
227 memcpy(pkt + p, rec.ssid, rec.ssid_len); p += rec.ssid_len;
228 pkt[p++] = 0x03; pkt[p++] = 0x01; pkt[p++] = rec.channel; // Channel Tag
229
230 size_t w = writePcapngPacket(pkt, p, rec.rssi, rec.channel, ts++, buffer + offset, max_len - offset);
231 if (w == 0) return offset;
232 offset += w;
233 }
234
235 if (rec.type == CAP_PMKID) {
236 // Packet 2: EAPOL M1 containing PMKID in Key Data
237 size_t p = 0;
238 pkt[p++] = 0x08; pkt[p++] = 0x02; pkt[p++] = 0x00; pkt[p++] = 0x00; // Data / QoS Data, FromDS=1
239 memcpy(pkt + p, rec.sta, 6); p += 6; // DA
240 memcpy(pkt + p, rec.bssid, 6); p += 6; // SA
241 memcpy(pkt + p, rec.bssid, 6); p += 6; // BSSID
242 pkt[p++] = 0x00; pkt[p++] = 0x00; // Seq
243 pkt[p++] = 0x00; pkt[p++] = 0x00; // QoS Control
244
245 // LLC SNAP
246 uint8_t snap[8] = { 0xAA, 0xAA, 0x03, 0x00, 0x00, 0x00, 0x88, 0x8E };
247 memcpy(pkt + p, snap, 8); p += 8;
248
249 // EAPOL Version 1, Type 3 (Key)
250 pkt[p++] = 0x01; pkt[p++] = 0x03;
251
252 uint16_t eapol_len = 95 + 22; // Key Frame + 22 bytes Key Data (PMKID)
253 pkt[p++] = (eapol_len >> 8); pkt[p++] = (eapol_len & 0xFF);
254
255 // EAPOL Key Frame (95 bytes without Key Data)
256 uint8_t eapolPayload[95] = {0};
257 eapolPayload[0] = 0x02; // Descriptor Type
258 eapolPayload[1] = 0x00; eapolPayload[2] = 0x8A; // Key Info (Pairwise, Ack)
259 eapolPayload[5] = 0x00; eapolPayload[6] = 0x00; eapolPayload[7] = 0x00; eapolPayload[8] = 0x00;
260 eapolPayload[9] = 0x00; eapolPayload[10] = 0x00; eapolPayload[11] = 0x00; eapolPayload[12] = 0x01; // Replay Counter
261 // Remaining is zeros
262 eapolPayload[93] = 0x00; eapolPayload[94] = 0x16; // Key Data Len = 22
263
264 memcpy(pkt + p, eapolPayload, 95); p += 95;
265
266 // Key Data: PMKID = DD 14 00 0F AC 04 <16 bytes>
267 pkt[p++] = 0xDD; pkt[p++] = 0x14; pkt[p++] = 0x00; pkt[p++] = 0x0F; pkt[p++] = 0xAC; pkt[p++] = 0x04;
268 memcpy(pkt + p, rec.pmkid, 16); p += 16;
269
270 size_t w = writePcapngPacket(pkt, p, rec.rssi, rec.channel, ts++, buffer + offset, max_len - offset);
271 if (w == 0) return offset;
272 offset += w;
273
274 } else if (rec.type == CAP_SAE) {
275 // Packet 2: SAE Authentication (Commit or Confirm)
276 size_t p = 0;
277 // MAC Header: Type Mgmt / Subtype Auth (0xB0)
278 pkt[p++] = 0xB0; pkt[p++] = 0x00; pkt[p++] = 0x00; pkt[p++] = 0x00;
279 memcpy(pkt + p, rec.bssid, 6); p += 6; // DA (APs BSSID)
280 memcpy(pkt + p, rec.sta, 6); p += 6; // SA (Client MAC)
281 memcpy(pkt + p, rec.bssid, 6); p += 6; // BSSID
282 pkt[p++] = 0x00; pkt[p++] = 0x00; // Seq
283
284 // SAE Fixed Header (6 bytes)
285 pkt[p++] = 0x03; pkt[p++] = 0x00; // Algorithm: SAE (3)
286 pkt[p++] = rec.sae_seq; pkt[p++] = 0x00; // Sequence
287 pkt[p++] = 0x00; pkt[p++] = 0x00; // Status: Success (0)
288
289 // SAE Body
290 if (rec.sae_len > 0) {
291 memcpy(pkt + p, rec.sae_data, rec.sae_len);
292 p += rec.sae_len;
293 }
294
295 size_t w = writePcapngPacket(pkt, p, rec.rssi, rec.channel, ts++, buffer + offset, max_len - offset);
296 if (w == 0) return offset;
297 offset += w;
298
299 } else {
300 // CAP_EAPOL / EAPOL_CSA / EAPOL_HALF
301 // Packet 2: EAPOL M1 (AP -> STA)
302 if (rec.has_anonce) {
303 size_t p = 0;
304 pkt[p++] = 0x08; pkt[p++] = 0x02; pkt[p++] = 0x00; pkt[p++] = 0x00; // Data / QoS Data, FromDS=1
305 memcpy(pkt + p, rec.sta, 6); p += 6; // DA
306 memcpy(pkt + p, rec.bssid, 6); p += 6; // SA
307 memcpy(pkt + p, rec.bssid, 6); p += 6; // BSSID
308 pkt[p++] = 0x00; pkt[p++] = 0x00; // Seq
309 pkt[p++] = 0x00; pkt[p++] = 0x00; // QoS Control
310
311 uint8_t snap[8] = { 0xAA, 0xAA, 0x03, 0x00, 0x00, 0x00, 0x88, 0x8E };
312 memcpy(pkt + p, snap, 8); p += 8;
313
314 pkt[p++] = 0x01; pkt[p++] = 0x03;
315 uint16_t eapol_len = 95;
316 pkt[p++] = (eapol_len >> 8); pkt[p++] = (eapol_len & 0xFF);
317
318 uint8_t eapolPayload[95] = {0};
319 eapolPayload[0] = 0x02;
320 eapolPayload[1] = 0x00; eapolPayload[2] = 0x8A; // Key Info
321 eapolPayload[12] = 0x01; // Replay Counter
322 memcpy(&eapolPayload[13], rec.anonce, 32); // Anonce
323
324 memcpy(pkt + p, eapolPayload, 95); p += 95;
325
326 size_t w = writePcapngPacket(pkt, p, rec.rssi, rec.channel, ts++, buffer + offset, max_len - offset);
327 if (w == 0) return offset;
328 offset += w;
329 }
330
331 // Packet 3: EAPOL M2 (STA -> AP)
332 if (rec.eapol_m2_len > 0) {
333 size_t p = 0;
334 pkt[p++] = 0x08; pkt[p++] = 0x01; pkt[p++] = 0x00; pkt[p++] = 0x00; // Data / QoS Data, ToDS=1
335 memcpy(pkt + p, rec.bssid, 6); p += 6; // DA
336 memcpy(pkt + p, rec.sta, 6); p += 6; // SA
337 memcpy(pkt + p, rec.bssid, 6); p += 6; // BSSID
338 pkt[p++] = 0x00; pkt[p++] = 0x00; // Seq
339 pkt[p++] = 0x00; pkt[p++] = 0x00; // QoS Control
340
341 uint8_t snap[8] = { 0xAA, 0xAA, 0x03, 0x00, 0x00, 0x00, 0x88, 0x8E };
342 memcpy(pkt + p, snap, 8); p += 8;
343
344 memcpy(pkt + p, rec.eapol_m2, rec.eapol_m2_len); p += rec.eapol_m2_len;
345
346 size_t w = writePcapngPacket(pkt, p, rec.rssi, rec.channel, ts++, buffer + offset, max_len - offset);
347 if (w == 0) return offset;
348 offset += w;
349 }
350
351 // Packet 4: EAPOL M3 (AP -> STA)
352 if (rec.has_m3) {
353 size_t p = 0;
354 pkt[p++] = 0x08; pkt[p++] = 0x02; pkt[p++] = 0x00; pkt[p++] = 0x00; // FromDS=1
355 memcpy(pkt + p, rec.sta, 6); p += 6;
356 memcpy(pkt + p, rec.bssid, 6); p += 6;
357 memcpy(pkt + p, rec.bssid, 6); p += 6;
358 pkt[p++] = 0x00; pkt[p++] = 0x00;
359 pkt[p++] = 0x00; pkt[p++] = 0x00;
360
361 uint8_t snap[8] = { 0xAA, 0xAA, 0x03, 0x00, 0x00, 0x00, 0x88, 0x8E };
362 memcpy(pkt + p, snap, 8); p += 8;
363
364 memcpy(pkt + p, rec.eapol_m3, rec.eapol_m3_len); p += rec.eapol_m3_len;
365
366 size_t w = writePcapngPacket(pkt, p, rec.rssi, rec.channel, ts++, buffer + offset, max_len - offset);
367 if (w == 0) return offset;
368 offset += w;
369 }
370
371 // Packet 5: EAPOL M4 (STA -> AP)
372 if (rec.has_m4) {
373 size_t p = 0;
374 pkt[p++] = 0x08; pkt[p++] = 0x01; pkt[p++] = 0x00; pkt[p++] = 0x00; // ToDS=1
375 memcpy(pkt + p, rec.bssid, 6); p += 6;
376 memcpy(pkt + p, rec.sta, 6); p += 6;
377 memcpy(pkt + p, rec.bssid, 6); p += 6;
378 pkt[p++] = 0x00; pkt[p++] = 0x00;
379 pkt[p++] = 0x00; pkt[p++] = 0x00;
380
381 uint8_t snap[8] = { 0xAA, 0xAA, 0x03, 0x00, 0x00, 0x00, 0x88, 0x8E };
382 memcpy(pkt + p, snap, 8); p += 8;
383
384 memcpy(pkt + p, rec.eapol_m4, rec.eapol_m4_len); p += rec.eapol_m4_len;
385
386 size_t w = writePcapngPacket(pkt, p, rec.rssi, rec.channel, ts++, buffer + offset, max_len - offset);
387 if (w == 0) return offset;
388 offset += w;
389 }
390 }
391
392 return offset;
393#else
394 (void)rec; (void)buffer; (void)max_len;
395 return 0;
396#endif
397}
398
399} // namespace format
400} // namespace politician
#define CAP_EAPOL_HALF
#define CAP_SAE
#define CAP_EAPOL_CSA
#define CAP_EAPOL
#define CAP_PMKID
size_t writePcapngPacket(const uint8_t *payload, size_t payload_len, int8_t rssi, uint8_t channel, uint64_t ts_usec, uint8_t *buffer, size_t max_len)
Serializes a Raw 802.11 Frame into a PCAPNG Enhanced Packet Block.
std::string toHC22000(const HandshakeRecord &rec)
Converts a captured HandshakeRecord into the Hashcat 22000 (hc22000) text format.
static void appendHex(std::string &str, const uint8_t *data, size_t len)
size_t writePcapngRecord(const HandshakeRecord &rec, uint8_t *buffer, size_t max_len)
Serializes a HandshakeRecord into PCAPNG Enhanced Packet Blocks.
size_t writePcapngGlobalHeader(uint8_t *buffer)
Writes a PCAPNG Global Header (SHB + IDB).
A captured handshake or PMKID record delivered to the EapolCb callback.
uint32_t millis()