Skip to content

Commit 841c985

Browse files
committed
document hccapx serializer
1 parent de5e27f commit 841c985

File tree

3 files changed

+152
-8
lines changed

3 files changed

+152
-8
lines changed

components/hccapx_serializer/hccapx_serializer.c

Lines changed: 114 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
1+
/**
2+
* @file hccapx_serializer.c
3+
* @author risinek ([email protected])
4+
* @date 2021-04-05
5+
* @copyright Copyright (c) 2021
6+
*
7+
* @brief Implements HCCAPX serializer
8+
*/
19
#include "hccapx_serializer.h"
210

311
#include <stdint.h>
@@ -9,25 +17,53 @@
917
#include "frame_analyzer_types.h"
1018
#include "frame_analyzer_parser.h"
1119

20+
/**
21+
* @brief Constants based on reference
22+
*
23+
* @see Ref: https://hashcat.net/wiki/doku.php?id=hccapx
24+
*/
25+
//@{
1226
#define HCCAPX_SIGNATURE 0x58504348
1327
#define HCCAPX_VERSION 4
1428
#define HCCAPX_KEYVER_WPA 1
1529
#define HCCAPX_KEYVER_WPA2 2
1630
#define HCCAPX_MAX_EAPOL_SIZE 256
17-
31+
//@}
1832

1933
static char *TAG = "hccapx_serializer";
34+
35+
/**
36+
* @brief Default values for hccapx buffer
37+
*/
2038
static hccapx_t hccapx = {
2139
.signature = HCCAPX_SIGNATURE,
2240
.version = 4,
2341
.message_pair = 255,
2442
.keyver = HCCAPX_KEYVER_WPA2
25-
};
43+
};
44+
45+
/**
46+
* @brief Stores last processed message
47+
*/
48+
//@{
2649
static unsigned message_ap = 0;
2750
static unsigned message_sta = 0;
51+
//@}
52+
53+
/**
54+
* @brief Stores number of message from which was the EAPoL packet saved.
55+
*/
2856
static unsigned eapol_source = 0;
2957

30-
bool is_array_zero(uint8_t *array, unsigned size){
58+
/**
59+
* @brief Says whether array contains only zero values or not
60+
*
61+
* @param array array pointer
62+
* @param size size of given array
63+
* @return true all values are zero
64+
* @return false some value is different from zero
65+
*/
66+
static bool is_array_zero(uint8_t *array, unsigned size){
3167
for(unsigned i = 0; i < size; i++){
3268
if(array[i] != 0){
3369
return false;
@@ -50,6 +86,17 @@ hccapx_t *hccapx_serializer_get(){
5086
return &hccapx;
5187
}
5288

89+
/**
90+
* @brief Saves EAPoL-Key frame into HCCAPX buffer
91+
*
92+
* Also sets Key MIC value to the one present in the given EAPoL-Key packet
93+
*
94+
* @param eapol_packet EAPoL packet to be saved that includes also EAPoL header
95+
* @param eapol_key_packet EAPoL-Key parsed to get key MIC from it
96+
* @return unsigned
97+
* @return 1 if error occured
98+
* @return 0 if successfully saved
99+
*/
53100
static unsigned save_eapol(eapol_packet_t *eapol_packet, eapol_key_packet_t *eapol_key_packet){
54101
unsigned eapol_len = 0;
55102
eapol_len = sizeof(eapol_packet_header_t) + ntohs(eapol_packet->header.packet_body_length);
@@ -63,22 +110,37 @@ static unsigned save_eapol(eapol_packet_t *eapol_packet, eapol_key_packet_t *eap
63110
return 0;
64111
}
65112

113+
/**
114+
* @brief Handles first message of WPA handshake - from AP to STA
115+
*
116+
* This message is from AP. It always contains ANonce.
117+
*
118+
* @param eapol_key_packet parsed EAPoL-Key packet
119+
*/
66120
static void ap_message_m1(eapol_key_packet_t *eapol_key_packet){
67121
ESP_LOGD(TAG, "From AP M1");
68122
message_ap = 1;
69123
memcpy(hccapx.nonce_ap, eapol_key_packet->key_nonce, 32);
70124
}
71125

126+
/**
127+
* @brief Handles third message of WPA handshake - from AP to STA
128+
*
129+
* @param eapol_packet
130+
* @param eapol_key_packet
131+
*/
72132
static void ap_message_m3(eapol_packet_t* eapol_packet, eapol_key_packet_t *eapol_key_packet){
73133
ESP_LOGD(TAG, "From AP M3");
74134
message_ap = 3;
75135
if(message_ap == 0){
136+
// No AP message was processed yet. ANonce has to be copied into HCCAPX buffer.
76137
memcpy(hccapx.nonce_ap, eapol_key_packet->key_nonce, 32);
77138
}
78139
if(message_sta == 2){
79140
hccapx.message_pair = 2;
80141
}
81142
if(eapol_source == 2){
143+
// EAPoL packet was already saved from message #2. No need to resave it.
82144
return;
83145
}
84146
if(save_eapol(eapol_packet, eapol_key_packet) != 0){
@@ -90,6 +152,13 @@ static void ap_message_m3(eapol_packet_t* eapol_packet, eapol_key_packet_t *eapo
90152
}
91153
}
92154

155+
/**
156+
* @brief Handles messages from AP - handshake M1 and M3.
157+
*
158+
* @param frame
159+
* @param eapol_packet
160+
* @param eapol_key_packet
161+
*/
93162
static void ap_message(data_frame_t *frame, eapol_packet_t* eapol_packet, eapol_key_packet_t *eapol_key_packet){
94163
if((!is_array_zero(hccapx.mac_sta, 6)) && (memcmp(frame->mac_header.addr1, hccapx.mac_sta, 6) != 0)){
95164
ESP_LOGE(TAG, "Different STA");
@@ -100,6 +169,7 @@ static void ap_message(data_frame_t *frame, eapol_packet_t* eapol_packet, eapol_
100169
}
101170
// Determine which message this is by Key MIC
102171
// Key MIC is always empty in M1 and always present in M3
172+
// Ref: 802.11i-2004 [8.5.3]
103173
if(is_array_zero(eapol_key_packet->key_mic, 16)){
104174
ap_message_m1(eapol_key_packet);
105175
}
@@ -110,6 +180,15 @@ static void ap_message(data_frame_t *frame, eapol_packet_t* eapol_packet, eapol_
110180
memcpy(hccapx.keymic, eapol_key_packet->key_mic, 16);
111181
}
112182

183+
/**
184+
* @brief Handles second message of handshake - from STA to AP.
185+
*
186+
* Saves EAPoL packet as this is the first time key MIC is present.
187+
* Saves SNonce.
188+
*
189+
* @param eapol_packet
190+
* @param eapol_key_packet
191+
*/
113192
static void sta_message_m2(eapol_packet_t* eapol_packet, eapol_key_packet_t *eapol_key_packet){
114193
ESP_LOGD(TAG, "From STA M2");
115194
message_sta = 2;
@@ -124,13 +203,22 @@ static void sta_message_m2(eapol_packet_t* eapol_packet, eapol_key_packet_t *eap
124203
}
125204
}
126205

206+
/**
207+
* @brief Handles fourth message of the handshake. From STA to AP.
208+
*
209+
*
210+
* @param eapol_packet
211+
* @param eapol_key_packet
212+
*/
127213
static void sta_message_m4(eapol_packet_t* eapol_packet, eapol_key_packet_t *eapol_key_packet){
128214
ESP_LOGD(TAG, "From STA M4");
129-
if(message_sta == 2){
215+
if((message_sta == 2) && (eapol_source != 0)){
216+
// If message 2 was already fully processed, there is no need to process M4 again
130217
ESP_LOGD(TAG, "Already have M2, not worth");
131218
return;
132219
}
133220
if(message_ap == 0){
221+
// If there was no AP message processed yet, ANonce will be always missing.
134222
ESP_LOGE(TAG, "Not enought handshake messages received.");
135223
return;
136224
}
@@ -150,6 +238,13 @@ static void sta_message_m4(eapol_packet_t* eapol_packet, eapol_key_packet_t *eap
150238
}
151239
}
152240

241+
/**
242+
* @brief Handles messages from STA - M2 and M4
243+
*
244+
* @param frame
245+
* @param eapol_packet
246+
* @param eapol_key_packet
247+
*/
153248
static void sta_message(data_frame_t *frame, eapol_packet_t* eapol_packet, eapol_key_packet_t *eapol_key_packet){
154249
if(is_array_zero(hccapx.mac_sta, 6)){
155250
memcpy(hccapx.mac_sta, frame->mac_header.addr2, 6);
@@ -160,6 +255,7 @@ static void sta_message(data_frame_t *frame, eapol_packet_t* eapol_packet, eapol
160255
}
161256
// Determine which message this is by SNonce
162257
// SNonce is present in M2, empty in M4
258+
// Ref: 802.11i-2004 [8.5.3]
163259
if(!is_array_zero(eapol_key_packet->key_nonce, 16)){
164260
sta_message_m2(eapol_packet, eapol_key_packet);
165261
}
@@ -168,9 +264,23 @@ static void sta_message(data_frame_t *frame, eapol_packet_t* eapol_packet, eapol
168264
}
169265
}
170266

267+
/**
268+
* @detail This component is a state machine, so this function can be used without knowing current state from outside.
269+
* WPA handshake pseudo-diagram:
270+
* @code{.unparsed}
271+
* AP STA
272+
* M1 ---------> |
273+
* | <--------- M2
274+
* M3 ---------> |
275+
* | <--------- M4
276+
* @endcode
277+
*
278+
* @param frame
279+
*/
171280
void hccapx_serializer_add_frame(data_frame_t *frame){
172281
eapol_packet_t *eapol_packet = parse_eapol_packet(frame);
173282
eapol_key_packet_t *eapol_key_packet = parse_eapol_key_packet(eapol_packet);
283+
// Determine direction of the frame by comparing BSSID (addr3) with source address (addr2)
174284
if(memcmp(frame->mac_header.addr2, frame->mac_header.addr3, 6) == 0){
175285
ap_message(frame, eapol_packet, eapol_key_packet);
176286
}

components/hccapx_serializer/interface/hccapx_serializer.h

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,23 @@
1+
/**
2+
* @file hccapx_serializer.h
3+
* @author risinek ([email protected])
4+
* @date 2021-04-05
5+
* @copyright Copyright (c) 2021
6+
*
7+
* @brief Provides interface to generate HCCAPX formatted binary from raw frame bytes
8+
*/
19
#ifndef HCCAPX_SERIALIZER_H
210
#define HCCAPX_SERIALIZER_H
311

412
#include <stdint.h>
513

614
#include "frame_analyzer_types.h"
715

8-
// Ref: https://hashcat.net/wiki/doku.php?id=hccapx
16+
/**
17+
* @brief HCCAPX structure according to reference
18+
*
19+
* @see Ref: https://hashcat.net/wiki/doku.php?id=hccapx
20+
*/
921
typedef struct __attribute__((__packed__)){
1022
uint32_t signature;
1123
uint32_t version;
@@ -22,8 +34,31 @@ typedef struct __attribute__((__packed__)){
2234
uint8_t eapol[256];
2335
} hccapx_t;
2436

37+
/**
38+
* @brief Creates new HCCAPX buffer for given SSID.
39+
*
40+
* This will clear any previous HCCAPX. If you want to save it, first call hccapx_serializer_get() and copy buffer somewhere else.
41+
* @param ssid SSID of AP from which the handshake frames will be comming.
42+
* @param size length of SSID string (including \0)
43+
*/
2544
void hccapx_serializer_init(const uint8_t *ssid, unsigned size);
45+
46+
/**
47+
* @brief Returns pointer to buffer with HCCAPX formatted binary data
48+
*
49+
* @return hccapx_t*
50+
*/
2651
hccapx_t *hccapx_serializer_get();
52+
53+
/**
54+
* @brief Adds new handshake frames into current HCCAPX.
55+
*
56+
* This function will process given frames and extract data that are relevant.
57+
* If frame contains handshake from another STA than the one that was already added before,
58+
* frame will be skipped and error message will be printed.
59+
*
60+
* @param frame data frame with EAPoL-Key packet
61+
*/
2762
void hccapx_serializer_add_frame(data_frame_t *frame);
2863

2964
#endif

components/pcap_serializer/interface/pcap_serializer.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,8 @@ typedef struct {
4242
* @brief Prepares new empty buffer for PCAP formatted binary data.
4343
*
4444
* Has always to be called before pcap_serializer_append_frame()
45-
* @return
46-
* - uint8_t* pointer to newly allocated PCAP buffer.
47-
* - NULL initialisation failed
45+
* @return uint8_t* pointer to newly allocated PCAP buffer.
46+
* @return \c NULL initialisation failed
4847
*/
4948
uint8_t *pcap_serializer_init();
5049

0 commit comments

Comments
 (0)