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
+ */
1
9
#include "hccapx_serializer.h"
2
10
3
11
#include <stdint.h>
9
17
#include "frame_analyzer_types.h"
10
18
#include "frame_analyzer_parser.h"
11
19
20
+ /**
21
+ * @brief Constants based on reference
22
+ *
23
+ * @see Ref: https://hashcat.net/wiki/doku.php?id=hccapx
24
+ */
25
+ //@{
12
26
#define HCCAPX_SIGNATURE 0x58504348
13
27
#define HCCAPX_VERSION 4
14
28
#define HCCAPX_KEYVER_WPA 1
15
29
#define HCCAPX_KEYVER_WPA2 2
16
30
#define HCCAPX_MAX_EAPOL_SIZE 256
17
-
31
+ //@}
18
32
19
33
static char * TAG = "hccapx_serializer" ;
34
+
35
+ /**
36
+ * @brief Default values for hccapx buffer
37
+ */
20
38
static hccapx_t hccapx = {
21
39
.signature = HCCAPX_SIGNATURE ,
22
40
.version = 4 ,
23
41
.message_pair = 255 ,
24
42
.keyver = HCCAPX_KEYVER_WPA2
25
- };
43
+ };
44
+
45
+ /**
46
+ * @brief Stores last processed message
47
+ */
48
+ //@{
26
49
static unsigned message_ap = 0 ;
27
50
static unsigned message_sta = 0 ;
51
+ //@}
52
+
53
+ /**
54
+ * @brief Stores number of message from which was the EAPoL packet saved.
55
+ */
28
56
static unsigned eapol_source = 0 ;
29
57
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 ){
31
67
for (unsigned i = 0 ; i < size ; i ++ ){
32
68
if (array [i ] != 0 ){
33
69
return false;
@@ -50,6 +86,17 @@ hccapx_t *hccapx_serializer_get(){
50
86
return & hccapx ;
51
87
}
52
88
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
+ */
53
100
static unsigned save_eapol (eapol_packet_t * eapol_packet , eapol_key_packet_t * eapol_key_packet ){
54
101
unsigned eapol_len = 0 ;
55
102
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
63
110
return 0 ;
64
111
}
65
112
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
+ */
66
120
static void ap_message_m1 (eapol_key_packet_t * eapol_key_packet ){
67
121
ESP_LOGD (TAG , "From AP M1" );
68
122
message_ap = 1 ;
69
123
memcpy (hccapx .nonce_ap , eapol_key_packet -> key_nonce , 32 );
70
124
}
71
125
126
+ /**
127
+ * @brief Handles third message of WPA handshake - from AP to STA
128
+ *
129
+ * @param eapol_packet
130
+ * @param eapol_key_packet
131
+ */
72
132
static void ap_message_m3 (eapol_packet_t * eapol_packet , eapol_key_packet_t * eapol_key_packet ){
73
133
ESP_LOGD (TAG , "From AP M3" );
74
134
message_ap = 3 ;
75
135
if (message_ap == 0 ){
136
+ // No AP message was processed yet. ANonce has to be copied into HCCAPX buffer.
76
137
memcpy (hccapx .nonce_ap , eapol_key_packet -> key_nonce , 32 );
77
138
}
78
139
if (message_sta == 2 ){
79
140
hccapx .message_pair = 2 ;
80
141
}
81
142
if (eapol_source == 2 ){
143
+ // EAPoL packet was already saved from message #2. No need to resave it.
82
144
return ;
83
145
}
84
146
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
90
152
}
91
153
}
92
154
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
+ */
93
162
static void ap_message (data_frame_t * frame , eapol_packet_t * eapol_packet , eapol_key_packet_t * eapol_key_packet ){
94
163
if ((!is_array_zero (hccapx .mac_sta , 6 )) && (memcmp (frame -> mac_header .addr1 , hccapx .mac_sta , 6 ) != 0 )){
95
164
ESP_LOGE (TAG , "Different STA" );
@@ -100,6 +169,7 @@ static void ap_message(data_frame_t *frame, eapol_packet_t* eapol_packet, eapol_
100
169
}
101
170
// Determine which message this is by Key MIC
102
171
// Key MIC is always empty in M1 and always present in M3
172
+ // Ref: 802.11i-2004 [8.5.3]
103
173
if (is_array_zero (eapol_key_packet -> key_mic , 16 )){
104
174
ap_message_m1 (eapol_key_packet );
105
175
}
@@ -110,6 +180,15 @@ static void ap_message(data_frame_t *frame, eapol_packet_t* eapol_packet, eapol_
110
180
memcpy (hccapx .keymic , eapol_key_packet -> key_mic , 16 );
111
181
}
112
182
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
+ */
113
192
static void sta_message_m2 (eapol_packet_t * eapol_packet , eapol_key_packet_t * eapol_key_packet ){
114
193
ESP_LOGD (TAG , "From STA M2" );
115
194
message_sta = 2 ;
@@ -124,13 +203,22 @@ static void sta_message_m2(eapol_packet_t* eapol_packet, eapol_key_packet_t *eap
124
203
}
125
204
}
126
205
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
+ */
127
213
static void sta_message_m4 (eapol_packet_t * eapol_packet , eapol_key_packet_t * eapol_key_packet ){
128
214
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
130
217
ESP_LOGD (TAG , "Already have M2, not worth" );
131
218
return ;
132
219
}
133
220
if (message_ap == 0 ){
221
+ // If there was no AP message processed yet, ANonce will be always missing.
134
222
ESP_LOGE (TAG , "Not enought handshake messages received." );
135
223
return ;
136
224
}
@@ -150,6 +238,13 @@ static void sta_message_m4(eapol_packet_t* eapol_packet, eapol_key_packet_t *eap
150
238
}
151
239
}
152
240
241
+ /**
242
+ * @brief Handles messages from STA - M2 and M4
243
+ *
244
+ * @param frame
245
+ * @param eapol_packet
246
+ * @param eapol_key_packet
247
+ */
153
248
static void sta_message (data_frame_t * frame , eapol_packet_t * eapol_packet , eapol_key_packet_t * eapol_key_packet ){
154
249
if (is_array_zero (hccapx .mac_sta , 6 )){
155
250
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
160
255
}
161
256
// Determine which message this is by SNonce
162
257
// SNonce is present in M2, empty in M4
258
+ // Ref: 802.11i-2004 [8.5.3]
163
259
if (!is_array_zero (eapol_key_packet -> key_nonce , 16 )){
164
260
sta_message_m2 (eapol_packet , eapol_key_packet );
165
261
}
@@ -168,9 +264,23 @@ static void sta_message(data_frame_t *frame, eapol_packet_t* eapol_packet, eapol
168
264
}
169
265
}
170
266
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
+ */
171
280
void hccapx_serializer_add_frame (data_frame_t * frame ){
172
281
eapol_packet_t * eapol_packet = parse_eapol_packet (frame );
173
282
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)
174
284
if (memcmp (frame -> mac_header .addr2 , frame -> mac_header .addr3 , 6 ) == 0 ){
175
285
ap_message (frame , eapol_packet , eapol_key_packet );
176
286
}
0 commit comments