- Remove GLIB1 code
[obnox/wireshark/wip.git] / epan / crypt / airpdcap.c
1 /* airpdcap.c
2  *
3  * $Id$
4  * Copyright (c) 2006 CACE Technologies, Davis (California)
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. Neither the name of the project nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * Alternatively, this software may be distributed under the terms of the
20  * GNU General Public License ("GPL") version 2 as published by the Free
21  * Software Foundation.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  */
35
36 /****************************************************************************/
37 /*      File includes                                                           */
38
39 #ifdef HAVE_CONFIG_H
40 # include "config.h"
41 #endif
42
43 #include <epan/tvbuff.h>
44 #include <epan/crc32.h>
45 #include <epan/strutil.h>
46 #include <epan/emem.h>
47 #include <epan/pint.h>
48
49 #include "airpdcap_system.h"
50 #include "airpdcap_int.h"
51
52 #include "crypt-sha1.h"
53 #include "crypt-md5.h"
54
55 #include "airpdcap_debug.h"
56
57 #include "wep-wpadefs.h"
58
59 #ifdef NEED_G_ASCII_STRCASECMP_H
60 #include "../g_ascii_strcasecmp.h"
61 #endif
62
63 /****************************************************************************/
64
65 /****************************************************************************/
66 /*      Constant definitions                                                    */
67
68 #define AIRPDCAP_SHA_DIGEST_LEN 20
69
70 /*      EAPOL definitions                                                       */
71 /**
72  * Length of the EAPOL-Key key confirmation key (KCK) used to calculate
73  * MIC over EAPOL frame and validate an EAPOL packet (128 bits)
74  */
75 #define AIRPDCAP_WPA_KCK_LEN    16
76 /**
77  *Offset of the Key MIC in the EAPOL packet body
78  */
79 #define AIRPDCAP_WPA_MICKEY_OFFSET      77
80 /**
81  * Maximum length of the EAPOL packet (it depends on the maximum MAC
82  * frame size)
83  */
84 #define AIRPDCAP_WPA_MAX_EAPOL_LEN      4095
85 /**
86  * EAPOL Key Descriptor Version 1, used for all EAPOL-Key frames to and
87  * from a STA when neither the group nor pairwise ciphers are CCMP for
88  * Key Descriptor 1.
89  * @note
90  * Defined in 802.11i-2004, page 78
91  */
92 #define AIRPDCAP_WPA_KEY_VER_CCMP       1
93 /**
94  * EAPOL Key Descriptor Version 2, used for all EAPOL-Key frames to and
95  * from a STA when either the pairwise or the group cipher is AES-CCMP
96  * for Key Descriptor 2.
97  * /note
98  * Defined in 802.11i-2004, page 78
99  */
100 #define AIRPDCAP_WPA_KEY_VER_AES_CCMP   2
101
102 /****************************************************************************/
103
104 /****************************************************************************/
105 /*      Macro definitions                                                       */
106
107 extern const UINT32 crc32_table[256];
108 #define CRC(crc, ch)     (crc = (crc >> 8) ^ crc32_table[(crc ^ (ch)) & 0xff])
109
110 #define AIRPDCAP_GET_TK(ptk)    (ptk + 32)
111
112 /****************************************************************************/
113
114 /****************************************************************************/
115 /*      Type definitions                                                        */
116
117 /*      Internal function prototype declarations                                */
118
119 #ifdef  __cplusplus
120 extern "C" {
121 #endif
122
123 /**
124  * It is a step of the PBKDF2 (specifically the PKCS #5 v2.0) defined in
125  * the RFC 2898 to derive a key (used as PMK in WPA)
126  * @param password [IN] pointer to a password (sequence of between 8 and
127  * 63 ASCII encoded characters)
128  * @param ssid [IN] pointer to the SSID string encoded in max 32 ASCII
129  * encoded characters
130  * @param iterations [IN] times to hash the password (4096 for WPA)
131  * @param count [IN] ???
132  * @param output [OUT] pointer to a preallocated buffer of
133  * AIRPDCAP_SHA_DIGEST_LEN characters that will contain a part of the key
134  */
135 static INT AirPDcapRsnaPwd2PskStep(
136     const guint8 *ppbytes,
137     const guint passLength,
138     const CHAR *ssid,
139     const size_t ssidLength,
140     const INT iterations,
141     const INT count,
142     UCHAR *output)
143     ;
144
145 /**
146  * It calculates the passphrase-to-PSK mapping reccomanded for use with
147  * RSNAs. This implementation uses the PBKDF2 method defined in the RFC
148  * 2898.
149  * @param password [IN] pointer to a password (sequence of between 8 and
150  * 63 ASCII encoded characters)
151  * @param ssid [IN] pointer to the SSID string encoded in max 32 ASCII
152  * encoded characters
153  * @param output [OUT] calculated PSK (to use as PMK in WPA)
154  * @note
155  * Described in 802.11i-2004, page 165
156  */
157 static INT AirPDcapRsnaPwd2Psk(
158     const CHAR *passphrase,
159     const CHAR *ssid,
160     const size_t ssidLength,
161     UCHAR *output)
162     ;
163
164 static INT AirPDcapRsnaMng(
165     UCHAR *decrypt_data,
166     guint mac_header_len,
167     guint *decrypt_len,
168     PAIRPDCAP_KEY_ITEM key,
169     AIRPDCAP_SEC_ASSOCIATION *sa,
170     INT offset)
171     ;
172
173 static INT AirPDcapWepMng(
174     PAIRPDCAP_CONTEXT ctx,
175     UCHAR *decrypt_data,
176     guint mac_header_len,
177     guint *decrypt_len,
178     PAIRPDCAP_KEY_ITEM key,
179     AIRPDCAP_SEC_ASSOCIATION *sa,
180     INT offset)
181     ;
182
183 static INT AirPDcapRsna4WHandshake(
184     PAIRPDCAP_CONTEXT ctx,
185     const UCHAR *data,
186     AIRPDCAP_SEC_ASSOCIATION *sa,
187     PAIRPDCAP_KEY_ITEM key,
188     INT offset)
189     ;
190 /**
191  * It checks whether the specified key is corrected or not.
192  * @note
193  * For a standard WEP key the length will be changed to the standard
194  * length, and the type changed in a generic WEP key.
195  * @param key [IN] pointer to the key to validate
196  * @return
197  * - TRUE: the key contains valid fields and values
198  * - FALSE: the key has some invalid field or value
199  */
200 static INT AirPDcapValidateKey(
201     PAIRPDCAP_KEY_ITEM key)
202     ;
203
204 static INT AirPDcapRsnaMicCheck(
205     UCHAR *eapol,
206     USHORT eapol_len,
207     UCHAR KCK[AIRPDCAP_WPA_KCK_LEN],
208     USHORT key_ver)
209     ;
210
211 /**
212  * @param ctx [IN] pointer to the current context
213  * @param id [IN] id of the association (composed by BSSID and MAC of
214  * the station)
215  * @return
216  * - index of the Security Association structure if found
217  * - -1, if the specified addresses pair BSSID-STA MAC has not been found
218  */
219 static INT AirPDcapGetSa(
220     PAIRPDCAP_CONTEXT ctx,
221     AIRPDCAP_SEC_ASSOCIATION_ID *id)
222     ;
223
224 static INT AirPDcapStoreSa(
225     PAIRPDCAP_CONTEXT ctx,
226     AIRPDCAP_SEC_ASSOCIATION_ID *id)
227     ;
228
229 static const UCHAR * AirPDcapGetStaAddress(
230     const AIRPDCAP_MAC_FRAME_ADDR4 *frame)
231     ;
232
233 static const UCHAR * AirPDcapGetBssidAddress(
234     const AIRPDCAP_MAC_FRAME_ADDR4 *frame)
235     ;
236
237 static void AirPDcapRsnaPrfX(
238     AIRPDCAP_SEC_ASSOCIATION *sa,
239     const UCHAR pmk[32],
240     const UCHAR snonce[32],
241     const INT x,        /*      for TKIP 512, for CCMP 384      */
242     UCHAR *ptk)
243     ;
244
245 #ifdef  __cplusplus
246 }
247 #endif
248
249 /****************************************************************************/
250
251 /****************************************************************************/
252 /* Exported function definitions                                                */
253
254 #ifdef  __cplusplus
255 extern "C" {
256 #endif
257
258 INT AirPDcapPacketProcess(
259     PAIRPDCAP_CONTEXT ctx,
260     const guint8 *data,
261     const guint mac_header_len,
262     const guint tot_len,
263     UCHAR *decrypt_data,
264     guint *decrypt_len,
265     PAIRPDCAP_KEY_ITEM key,
266     gboolean mngHandshake,
267     gboolean mngDecrypt)
268 {
269     const UCHAR *address;
270     AIRPDCAP_SEC_ASSOCIATION_ID id;
271     int index;
272     PAIRPDCAP_SEC_ASSOCIATION sa;
273     int offset = 0;
274     guint bodyLength;
275     const guint8 dot1x_header[] = {
276         0xAA,             /* DSAP=SNAP */
277         0xAA,             /* SSAP=SNAP */
278         0x03,             /* Control field=Unnumbered frame */
279         0x00, 0x00, 0x00, /* Org. code=encaps. Ethernet */
280         0x88, 0x8E        /* Type: 802.1X authentication */
281     };
282
283 #ifdef _DEBUG
284     CHAR msgbuf[255];
285 #endif
286
287     AIRPDCAP_DEBUG_TRACE_START("AirPDcapPacketProcess");
288
289     if (ctx==NULL) {
290         AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapPacketProcess", "NULL context", AIRPDCAP_DEBUG_LEVEL_5);
291         AIRPDCAP_DEBUG_TRACE_END("AirPDcapPacketProcess");
292         return AIRPDCAP_RET_UNSUCCESS;
293     }
294     if (data==NULL || tot_len==0) {
295         AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapPacketProcess", "NULL data or length=0", AIRPDCAP_DEBUG_LEVEL_5);
296         AIRPDCAP_DEBUG_TRACE_END("AirPDcapPacketProcess");
297         return AIRPDCAP_RET_UNSUCCESS;
298     }
299
300     /* check if the packet is of data type      */
301     if (AIRPDCAP_TYPE(data[0])!=AIRPDCAP_TYPE_DATA) {
302         AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapPacketProcess", "not data packet", AIRPDCAP_DEBUG_LEVEL_5);
303         return AIRPDCAP_RET_NO_DATA;
304     }
305
306     /* check correct packet size, to avoid wrong elaboration of encryption algorithms   */
307     if (tot_len < (UINT)(mac_header_len+AIRPDCAP_CRYPTED_DATA_MINLEN)) {
308         AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapPacketProcess", "minimum length violated", AIRPDCAP_DEBUG_LEVEL_5);
309         return AIRPDCAP_RET_WRONG_DATA_SIZE;
310     }
311
312     /* get BSSID */
313     if ( (address=AirPDcapGetBssidAddress((const AIRPDCAP_MAC_FRAME_ADDR4 *)(data))) != NULL) {
314         memcpy(id.bssid, address, AIRPDCAP_MAC_LEN);
315 #ifdef _DEBUG
316         sprintf(msgbuf, "BSSID: %2X.%2X.%2X.%2X.%2X.%2X\t", id.bssid[0],id.bssid[1],id.bssid[2],id.bssid[3],id.bssid[4],id.bssid[5]);
317 #endif
318         AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapPacketProcess", msgbuf, AIRPDCAP_DEBUG_LEVEL_3);
319     } else {
320         AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapPacketProcess", "BSSID not found", AIRPDCAP_DEBUG_LEVEL_5);
321         return AIRPDCAP_RET_REQ_DATA;
322     }
323
324     /* get STA address  */
325     if ( (address=AirPDcapGetStaAddress((const AIRPDCAP_MAC_FRAME_ADDR4 *)(data))) != NULL) {
326         memcpy(id.sta, address, AIRPDCAP_MAC_LEN);
327 #ifdef _DEBUG
328         sprintf(msgbuf, "ST_MAC: %2X.%2X.%2X.%2X.%2X.%2X\t", id.sta[0],id.sta[1],id.sta[2],id.sta[3],id.sta[4],id.sta[5]);
329 #endif
330         AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapPacketProcess", msgbuf, AIRPDCAP_DEBUG_LEVEL_3);
331     } else {
332         AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapPacketProcess", "SA not found", AIRPDCAP_DEBUG_LEVEL_5);
333         return AIRPDCAP_RET_REQ_DATA;
334     }
335
336     /* search for a cached Security Association for current BSSID and station MAC       */
337     if ((index=AirPDcapGetSa(ctx, &id))==-1) {
338         /* create a new Security Association    */
339         if ((index=AirPDcapStoreSa(ctx, &id))==-1) {
340             return AIRPDCAP_RET_UNSUCCESS;
341         }
342     }
343
344     /* get the Security Association structure   */
345     sa=&ctx->sa[index];
346
347     /* cache offset in the packet data (to scan encryption data)        */
348     offset = mac_header_len;
349
350     /*  check if data is encrypted (use the WEP bit in the Frame Control field) */
351     if (AIRPDCAP_WEP(data[1])==0)
352     {
353         if (mngHandshake) {
354             /* data is sent in cleartext, check if is an authentication message or end the process      */
355             AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapPacketProcess", "Unencrypted data", AIRPDCAP_DEBUG_LEVEL_3);
356
357             /* check if the packet as an LLC header and the packet is 802.1X authentication (IEEE 802.1X-2004, pg. 24)  */
358             if (memcmp(data+offset, dot1x_header, 8) == 0) {
359                 AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapPacketProcess", "Authentication: EAPOL packet", AIRPDCAP_DEBUG_LEVEL_3);
360
361                 /* skip LLC header      */
362                 offset+=8;
363
364                 /* check the version of the EAPOL protocol used (IEEE 802.1X-2004, pg. 24)      */
365                 /* TODO EAPOL protocol version to check?        */
366                 /*if (data[offset]!=2) {
367                     AIRPDCAP_DEBUG_PRINT_LINE("EAPOL protocol version not recognized", AIRPDCAP_DEBUG_LEVEL_5);
368                     return AIRPDCAP_RET_NO_VALID_HANDSHAKE;
369                 }*/
370
371                 /*      check if the packet is a EAPOL-Key (0x03) (IEEE 802.1X-2004, pg. 25)    */
372                 if (data[offset+1]!=3) {
373                     AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapPacketProcess", "Not EAPOL-Key", AIRPDCAP_DEBUG_LEVEL_5);
374                     return AIRPDCAP_RET_NO_VALID_HANDSHAKE;
375                 }
376
377                 /* get and check the body length (IEEE 802.1X-2004, pg. 25)     */
378                 bodyLength=pntohs(data+offset+2);
379                 if ((tot_len-offset-4) < bodyLength) {
380                     AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapPacketProcess", "EAPOL body too short", AIRPDCAP_DEBUG_LEVEL_5);
381                     return AIRPDCAP_RET_NO_VALID_HANDSHAKE;
382                 }
383
384                 /* skip EAPOL MPDU and go to the first byte of the body */
385                 offset+=4;
386
387                 /* check if the key descriptor type is valid (IEEE 802.1X-2004, pg. 27) */
388                 if (/*data[offset]!=0x1 &&*/    /* RC4 Key Descriptor Type (deprecated) */
389                     data[offset]!=0x2 &&                /* IEEE 802.11 Key Descriptor Type                      */
390                     data[offset]!=0xFE)         /* TODO what's this value???                                    */
391                 {
392                     AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapPacketProcess", "Not valid key descriptor type", AIRPDCAP_DEBUG_LEVEL_5);
393                     return AIRPDCAP_RET_NO_VALID_HANDSHAKE;
394                 }
395
396                 /* start with descriptor body   */
397                 offset+=1;
398
399                 /* manage the 4-way handshake to define the key */
400                 return AirPDcapRsna4WHandshake(ctx, data, sa, key, offset);
401             } else {
402                 /* cleartext message, not authentication */
403                 AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapPacketProcess", "No authentication data", AIRPDCAP_DEBUG_LEVEL_5);
404                 return AIRPDCAP_RET_NO_DATA_ENCRYPTED;
405             }
406         }
407     } else {
408         if (mngDecrypt) {
409
410             if (decrypt_data==NULL)
411                 return AIRPDCAP_RET_UNSUCCESS;
412
413             /*  create new header and data to modify    */
414             *decrypt_len = tot_len;
415             memcpy(decrypt_data, data, *decrypt_len);
416
417             /* encrypted data   */
418             AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapPacketProcess", "Encrypted data", AIRPDCAP_DEBUG_LEVEL_3);
419
420             /* check the Extension IV to distinguish between WEP encryption and WPA encryption  */
421             /* refer to IEEE 802.11i-2004, 8.2.1.2, pag.35 for WEP,     */
422             /*          IEEE 802.11i-2004, 8.3.2.2, pag. 45 for TKIP,           */
423             /*          IEEE 802.11i-2004, 8.3.3.2, pag. 57 for CCMP                    */
424             if (AIRPDCAP_EXTIV(data[offset+3])==0) {
425                 AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapPacketProcess", "WEP encryption", AIRPDCAP_DEBUG_LEVEL_3);
426                 return AirPDcapWepMng(ctx, decrypt_data, mac_header_len, decrypt_len, key, sa, offset);
427             } else {
428                 AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapPacketProcess", "TKIP or CCMP encryption", AIRPDCAP_DEBUG_LEVEL_3);
429                 return AirPDcapRsnaMng(decrypt_data, mac_header_len, decrypt_len, key, sa, offset);
430             }
431         }
432     }
433
434     return AIRPDCAP_RET_UNSUCCESS;
435 }
436
437 INT AirPDcapSetKeys(
438     PAIRPDCAP_CONTEXT ctx,
439     AIRPDCAP_KEY_ITEM keys[],
440     const size_t keys_nr)
441 {
442     INT i;
443     INT success;
444     AIRPDCAP_DEBUG_TRACE_START("AirPDcapSetKeys");
445
446     if (ctx==NULL || keys==NULL) {
447         AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapSetKeys", "NULL context or NULL keys array", AIRPDCAP_DEBUG_LEVEL_3);
448         AIRPDCAP_DEBUG_TRACE_END("AirPDcapSetKeys");
449         return 0;
450     }
451
452     if (keys_nr>AIRPDCAP_MAX_KEYS_NR) {
453         AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapSetKeys", "Keys number greater than maximum", AIRPDCAP_DEBUG_LEVEL_3);
454         AIRPDCAP_DEBUG_TRACE_END("AirPDcapSetKeys");
455         return 0;
456     }
457
458     /* clean key and SA collections before setting new ones     */
459     AirPDcapInitContext(ctx);
460
461     /* check and insert keys    */
462     for (i=0, success=0; i<(INT)keys_nr; i++) {
463         if (AirPDcapValidateKey(keys+i)==TRUE) {
464             if (keys[i].KeyType==AIRPDCAP_KEY_TYPE_WPA_PWD) {
465                 AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapSetKeys", "Set a WPA-PWD key", AIRPDCAP_DEBUG_LEVEL_4);
466                 AirPDcapRsnaPwd2Psk(keys[i].UserPwd.Passphrase, keys[i].UserPwd.Ssid, keys[i].UserPwd.SsidLen, keys[i].KeyData.Wpa.Psk);
467             }
468 #ifdef  _DEBUG
469             else if (keys[i].KeyType==AIRPDCAP_KEY_TYPE_WPA_PMK) {
470                 AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapSetKeys", "Set a WPA-PMK key", AIRPDCAP_DEBUG_LEVEL_4);
471             } else if (keys[i].KeyType==AIRPDCAP_KEY_TYPE_WEP) {
472                 AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapSetKeys", "Set a WEP key", AIRPDCAP_DEBUG_LEVEL_4);
473             } else {
474                 AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapSetKeys", "Set a key", AIRPDCAP_DEBUG_LEVEL_4);
475             }
476 #endif
477             memcpy(&ctx->keys[success], &keys[i], sizeof(keys[i]));
478             success++;
479         }
480     }
481
482     ctx->keys_nr=success;
483
484     AIRPDCAP_DEBUG_TRACE_END("AirPDcapSetKeys");
485     return success;
486 }
487
488
489 INT AirPDcapGetKeys(
490     const PAIRPDCAP_CONTEXT ctx,
491     AIRPDCAP_KEY_ITEM keys[],
492     const size_t keys_nr)
493 {
494     UINT i;
495     UINT j;
496     AIRPDCAP_DEBUG_TRACE_START("AirPDcapGetKeys");
497
498     if (ctx==NULL) {
499         AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapGetKeys", "NULL context", AIRPDCAP_DEBUG_LEVEL_5);
500         AIRPDCAP_DEBUG_TRACE_END("AirPDcapGetKeys");
501         return 0;
502     } else if (keys==NULL) {
503         AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapGetKeys", "NULL keys array", AIRPDCAP_DEBUG_LEVEL_5);
504         AIRPDCAP_DEBUG_TRACE_END("AirPDcapGetKeys");
505         return (INT)ctx->keys_nr;
506     } else {
507         for (i=0, j=0; i<ctx->keys_nr && i<keys_nr && i<AIRPDCAP_MAX_KEYS_NR; i++) {
508             memcpy(&keys[j], &ctx->keys[i], sizeof(keys[j]));
509             j++;
510             AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapGetKeys", "Got a key", AIRPDCAP_DEBUG_LEVEL_5);
511         }
512
513         AIRPDCAP_DEBUG_TRACE_END("AirPDcapGetKeys");
514         return j;
515     }
516 }
517
518 /*
519  * XXX - This won't be reliable if a packet containing SSID "B" shows
520  * up in the middle of a 4-way handshake for SSID "A".
521  * We should probably use a small array or hash table to keep multiple
522  * SSIDs.
523  */
524 INT AirPDcapSetLastSSID(
525     PAIRPDCAP_CONTEXT ctx,
526     CHAR *pkt_ssid,
527     size_t pkt_ssid_len)
528 {
529     if (!ctx || !pkt_ssid || pkt_ssid_len < 1 || pkt_ssid_len > WPA_SSID_MAX_SIZE)
530         return AIRPDCAP_RET_UNSUCCESS;
531
532     memcpy(ctx->pkt_ssid, pkt_ssid, pkt_ssid_len);
533     ctx->pkt_ssid_len = pkt_ssid_len;
534
535     return AIRPDCAP_RET_SUCCESS;
536 }
537
538 INT AirPDcapInitContext(
539     PAIRPDCAP_CONTEXT ctx)
540 {
541     AIRPDCAP_DEBUG_TRACE_START("AirPDcapInitContext");
542
543     if (ctx==NULL) {
544         AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapInitContext", "NULL context", AIRPDCAP_DEBUG_LEVEL_5);
545         AIRPDCAP_DEBUG_TRACE_END("AirPDcapInitContext");
546         return AIRPDCAP_RET_UNSUCCESS;
547     }
548
549     memset(ctx->keys, 0, sizeof(AIRPDCAP_KEY_ITEM) * AIRPDCAP_MAX_KEYS_NR);
550     ctx->keys_nr=0;
551     memset(ctx->sa, 0, AIRPDCAP_MAX_SEC_ASSOCIATIONS_NR * sizeof(AIRPDCAP_SEC_ASSOCIATION));
552
553     ctx->first_free_index=0;
554     ctx->index=-1;
555     ctx->sa_index=-1;
556     ctx->pkt_ssid_len = 0;
557
558     AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapInitContext", "Context initialized!", AIRPDCAP_DEBUG_LEVEL_5);
559     AIRPDCAP_DEBUG_TRACE_END("AirPDcapInitContext");
560     return AIRPDCAP_RET_SUCCESS;
561 }
562
563 INT AirPDcapDestroyContext(
564     PAIRPDCAP_CONTEXT ctx)
565 {
566     AIRPDCAP_DEBUG_TRACE_START("AirPDcapDestroyContext");
567
568     if (ctx==NULL) {
569         AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapDestroyContext", "NULL context", AIRPDCAP_DEBUG_LEVEL_5);
570         AIRPDCAP_DEBUG_TRACE_END("AirPDcapDestroyContext");
571         return AIRPDCAP_RET_UNSUCCESS;
572     }
573
574     ctx->first_free_index=0;
575     ctx->index=-1;
576     ctx->sa_index=-1;
577
578     AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapDestroyContext", "Context destroyed!", AIRPDCAP_DEBUG_LEVEL_5);
579     AIRPDCAP_DEBUG_TRACE_END("AirPDcapDestroyContext");
580     return AIRPDCAP_RET_SUCCESS;
581 }
582
583 #ifdef  __cplusplus
584 }
585 #endif
586
587 /****************************************************************************/
588
589 /****************************************************************************/
590 /* Internal function definitions                                                */
591
592 #ifdef  __cplusplus
593 extern "C" {
594 #endif
595
596 static INT
597 AirPDcapRsnaMng(
598     UCHAR *decrypt_data,
599     guint mac_header_len,
600     guint *decrypt_len,
601     PAIRPDCAP_KEY_ITEM key,
602     AIRPDCAP_SEC_ASSOCIATION *sa,
603     INT offset)
604 {
605     INT ret_value;
606
607     if (sa->key==NULL) {
608         AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapRsnaMng", "No key associated", AIRPDCAP_DEBUG_LEVEL_3);
609         return AIRPDCAP_RET_REQ_DATA;
610     }
611     if (sa->validKey==FALSE) {
612         AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapRsnaMng", "Key not yet valid", AIRPDCAP_DEBUG_LEVEL_3);
613         return AIRPDCAP_RET_UNSUCCESS;
614     }
615     if (sa->wpa.key_ver==1) {
616         /*      CCMP -> HMAC-MD5 is the EAPOL-Key MIC, RC4 is the EAPOL-Key encryption algorithm        */
617         AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapRsnaMng", "TKIP", AIRPDCAP_DEBUG_LEVEL_3);
618
619         ret_value=AirPDcapTkipDecrypt(decrypt_data+offset, *decrypt_len-offset, decrypt_data+AIRPDCAP_TA_OFFSET, AIRPDCAP_GET_TK(sa->wpa.ptk));
620         if (ret_value)
621             return ret_value;
622
623         AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapRsnaMng", "TKIP DECRYPTED!!!", AIRPDCAP_DEBUG_LEVEL_3);
624         /* remove MIC (8bytes) and ICV (4bytes) from the end of packet  */
625         *decrypt_len-=12;
626     } else {
627         /*      AES-CCMP -> HMAC-SHA1-128 is the EAPOL-Key MIC, AES wep_key wrap is the EAPOL-Key encryption algorithm  */
628         AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapRsnaMng", "CCMP", AIRPDCAP_DEBUG_LEVEL_3);
629
630         ret_value=AirPDcapCcmpDecrypt(decrypt_data, mac_header_len, (INT)*decrypt_len, AIRPDCAP_GET_TK(sa->wpa.ptk));
631         if (ret_value)
632             return ret_value;
633
634         AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapRsnaMng", "CCMP DECRYPTED!!!", AIRPDCAP_DEBUG_LEVEL_3);
635         /* remove MIC (8bytes) from the end of packet   */
636         *decrypt_len-=8;
637     }
638
639     /* remove protection bit    */
640     decrypt_data[1]&=0xBF;
641
642     /* remove TKIP/CCMP header  */
643     offset = mac_header_len;
644     *decrypt_len-=8;
645     memcpy(decrypt_data+offset, decrypt_data+offset+8, *decrypt_len-offset);
646
647     if (key!=NULL) {
648         memcpy(key, sa->key, sizeof(AIRPDCAP_KEY_ITEM));
649
650         if (sa->wpa.key_ver==AIRPDCAP_WPA_KEY_VER_CCMP)
651             key->KeyType=AIRPDCAP_KEY_TYPE_TKIP;
652         else if (sa->wpa.key_ver==AIRPDCAP_WPA_KEY_VER_AES_CCMP)
653             key->KeyType=AIRPDCAP_KEY_TYPE_CCMP;
654     }
655
656     return AIRPDCAP_RET_SUCCESS;
657 }
658
659 static INT
660 AirPDcapWepMng(
661     PAIRPDCAP_CONTEXT ctx,
662     UCHAR *decrypt_data,
663     guint mac_header_len,
664     guint *decrypt_len,
665     PAIRPDCAP_KEY_ITEM key,
666     AIRPDCAP_SEC_ASSOCIATION *sa,
667     INT offset)
668 {
669     UCHAR wep_key[AIRPDCAP_WEP_KEY_MAXLEN+AIRPDCAP_WEP_IVLEN];
670     size_t keylen;
671     INT ret_value=1;
672     INT key_index;
673     AIRPDCAP_KEY_ITEM *tmp_key;
674     UINT8 useCache=FALSE;
675     UCHAR *try_data = ep_alloc(*decrypt_len);
676
677     if (sa->key!=NULL)
678         useCache=TRUE;
679
680     for (key_index=0; key_index<(INT)ctx->keys_nr; key_index++) {
681         /* use the cached one, or try all keys  */
682         if (!useCache) {
683             tmp_key=&ctx->keys[key_index];
684         } else {
685             if (sa->key!=NULL && sa->key->KeyType==AIRPDCAP_KEY_TYPE_WEP) {
686                 AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapWepMng", "Try cached WEP key...", AIRPDCAP_DEBUG_LEVEL_3);
687                 tmp_key=sa->key;
688             } else {
689                 AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapWepMng", "Cached key is not valid, try another WEP key...", AIRPDCAP_DEBUG_LEVEL_3);
690                 tmp_key=&ctx->keys[key_index];
691             }
692         }
693
694         /* obviously, try only WEP keys...      */
695         if (tmp_key->KeyType==AIRPDCAP_KEY_TYPE_WEP)
696         {
697             AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapWepMng", "Try WEP key...", AIRPDCAP_DEBUG_LEVEL_3);
698
699             memset(wep_key, 0, sizeof(wep_key));
700             memcpy(try_data, decrypt_data, *decrypt_len);
701
702             /* Costruct the WEP seed: copy the IV in first 3 bytes and then the WEP key (refer to 802-11i-2004, 8.2.1.4.3, pag. 36)     */
703             memcpy(wep_key, try_data+mac_header_len, AIRPDCAP_WEP_IVLEN);
704             keylen=tmp_key->KeyData.Wep.WepKeyLen;
705             memcpy(wep_key+AIRPDCAP_WEP_IVLEN, tmp_key->KeyData.Wep.WepKey, keylen);
706
707             ret_value=AirPDcapWepDecrypt(wep_key,
708                 keylen+AIRPDCAP_WEP_IVLEN,
709                 try_data + (mac_header_len+AIRPDCAP_WEP_IVLEN+AIRPDCAP_WEP_KIDLEN),
710                 *decrypt_len-(mac_header_len+AIRPDCAP_WEP_IVLEN+AIRPDCAP_WEP_KIDLEN+AIRPDCAP_CRC_LEN));
711
712             if (ret_value == AIRPDCAP_RET_SUCCESS)
713                 memcpy(decrypt_data, try_data, *decrypt_len);
714         }
715
716         if (!ret_value && tmp_key->KeyType==AIRPDCAP_KEY_TYPE_WEP) {
717             /* the tried key is the correct one, cached in the Security Association     */
718
719             sa->key=tmp_key;
720
721             if (key!=NULL) {
722                 memcpy(key, &sa->key, sizeof(AIRPDCAP_KEY_ITEM));
723                 key->KeyType=AIRPDCAP_KEY_TYPE_WEP;
724             }
725
726             break;
727         } else {
728             /* the cached key was not valid, try other keys     */
729
730             if (useCache==TRUE) {
731                 useCache=FALSE;
732                 key_index--;
733             }
734         }
735     }
736
737     if (ret_value)
738         return ret_value;
739
740     AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapWepMng", "WEP DECRYPTED!!!", AIRPDCAP_DEBUG_LEVEL_3);
741
742     /* remove ICV (4bytes) from the end of packet       */
743     *decrypt_len-=4;
744
745     /* remove protection bit    */
746     decrypt_data[1]&=0xBF;
747
748     /* remove IC header */
749     offset = mac_header_len;
750     *decrypt_len-=4;
751     memcpy(decrypt_data+offset, decrypt_data+offset+AIRPDCAP_WEP_IVLEN+AIRPDCAP_WEP_KIDLEN, *decrypt_len-offset);
752
753     return AIRPDCAP_RET_SUCCESS;
754 }
755
756 /* Refer to IEEE 802.11i-2004, 8.5.3, pag. 85   */
757 static INT
758 AirPDcapRsna4WHandshake(
759     PAIRPDCAP_CONTEXT ctx,
760     const UCHAR *data,
761     AIRPDCAP_SEC_ASSOCIATION *sa,
762     PAIRPDCAP_KEY_ITEM key,
763     INT offset)
764 {
765     AIRPDCAP_KEY_ITEM *tmp_key, pkt_key;
766     INT key_index;
767     INT ret_value=1;
768     UCHAR useCache=FALSE;
769     UCHAR eapol[AIRPDCAP_EAPOL_MAX_LEN];
770     USHORT eapol_len;
771
772     if (sa->key!=NULL)
773         useCache=TRUE;
774
775     /* a 4-way handshake packet use a Pairwise key type (IEEE 802.11i-2004, pg. 79)     */
776     if (AIRPDCAP_EAP_KEY(data[offset+1])!=1) {
777         AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapRsna4WHandshake", "Group/STAKey message (not used)", AIRPDCAP_DEBUG_LEVEL_5);
778         return AIRPDCAP_RET_NO_VALID_HANDSHAKE;
779     }
780
781     /* TODO timeouts? reauthentication? */
782
783     /* TODO consider key-index  */
784
785     /* TODO considera Deauthentications */
786
787     AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapRsna4WHandshake", "4-way handshake...", AIRPDCAP_DEBUG_LEVEL_5);
788
789     /* manage 4-way handshake packets; this step completes the 802.1X authentication process (IEEE 802.11i-2004, pag. 85)       */
790
791     /* message 1: Authenticator->Supplicant (Sec=0, Mic=0, Ack=1, Inst=0, Key=1(pairwise), KeyRSC=0, Nonce=ANonce, MIC=0)       */
792     if (AIRPDCAP_EAP_INST(data[offset+1])==0 &&
793         AIRPDCAP_EAP_ACK(data[offset+1])==1 &&
794         AIRPDCAP_EAP_MIC(data[offset])==0)
795     {
796         AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapRsna4WHandshake", "4-way handshake message 1", AIRPDCAP_DEBUG_LEVEL_3);
797
798         /* On reception of Message 1, the Supplicant determines whether the Key Replay Counter field value has been                     */
799         /* used before with the current PMKSA. If the Key Replay Counter field value is less than or equal to the current       */
800         /* local value, the Supplicant discards the message.                                                                                                                                                                    */
801         /* -> not checked, the Authenticator will be send another Message 1 (hopefully!)                                                                                                */
802
803         /* save ANonce (from authenticator)     to derive the PTK with the SNonce (from the 2 message)  */
804         memcpy(sa->wpa.nonce, data+offset+12, 32);
805
806         /* get the Key Descriptor Version (to select algorithm used in decryption -CCMP or TKIP-)       */
807         sa->wpa.key_ver=AIRPDCAP_EAP_KEY_DESCR_VER(data[offset+1]);
808
809         sa->handshake=1;
810
811         return AIRPDCAP_RET_SUCCESS_HANDSHAKE;
812     }
813
814     /* message 2|4: Supplicant->Authenticator (Sec=0|1, Mic=1, Ack=0, Inst=0, Key=1(pairwise), KeyRSC=0, Nonce=SNonce|0, MIC=MIC(KCK,EAPOL))    */
815     if (AIRPDCAP_EAP_INST(data[offset+1])==0 &&
816         AIRPDCAP_EAP_ACK(data[offset+1])==0 &&
817         AIRPDCAP_EAP_MIC(data[offset])==1)
818     {
819         if (AIRPDCAP_EAP_SEC(data[offset])==0) {
820
821             /* PATCH:   some implementations set secure bit to 0 also in the 4th message                */
822             /*          to recognize which message is this check if wep_key data length is 0            */
823             /*          in the 4th message                                                              */
824             if (data[offset+92]!=0 || data[offset+93]!=0) {
825                 /* message 2    */
826                 AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapRsna4WHandshake", "4-way handshake message 2", AIRPDCAP_DEBUG_LEVEL_3);
827
828                 /* On reception of Message 2, the Authenticator checks that the key replay counter corresponds to the   */
829                 /* outstanding Message 1. If not, it silently discards the message.                                                                                             */
830                 /* If the calculated MIC does not match the MIC that the Supplicant included in the EAPOL-Key frame,    */
831                 /* the Authenticator silently discards Message 2.                                                                                                                                               */
832                 /* -> not checked; the Supplicant will send another message 2 (hopefully!)                                                                              */
833
834                 /* now you can derive the PTK   */
835                 for (key_index=0; key_index<(INT)ctx->keys_nr || useCache; key_index++) {
836                     /* use the cached one, or try all keys      */
837                     if (!useCache) {
838                         AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapRsna4WHandshake", "Try WPA key...", AIRPDCAP_DEBUG_LEVEL_3);
839                         tmp_key=&ctx->keys[key_index];
840                     } else {
841                         /* there is a cached key in the security association, if it's a WPA key try it...       */
842                         if (sa->key!=NULL &&
843                             (sa->key->KeyType==AIRPDCAP_KEY_TYPE_WPA_PWD ||
844                              sa->key->KeyType==AIRPDCAP_KEY_TYPE_WPA_PSK ||
845                              sa->key->KeyType==AIRPDCAP_KEY_TYPE_WPA_PMK)) {
846                                 AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapRsna4WHandshake", "Try cached WPA key...", AIRPDCAP_DEBUG_LEVEL_3);
847                                 tmp_key=sa->key;
848                         } else {
849                             AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapRsna4WHandshake", "Cached key is of a wrong type, try WPA key...", AIRPDCAP_DEBUG_LEVEL_3);
850                             tmp_key=&ctx->keys[key_index];
851                         }
852                     }
853
854                     /* obviously, try only WPA keys...  */
855                     if (tmp_key->KeyType==AIRPDCAP_KEY_TYPE_WPA_PWD ||
856                         tmp_key->KeyType==AIRPDCAP_KEY_TYPE_WPA_PSK ||
857                         tmp_key->KeyType==AIRPDCAP_KEY_TYPE_WPA_PMK)
858                     {
859                         if (tmp_key->KeyType == AIRPDCAP_KEY_TYPE_WPA_PWD && tmp_key->UserPwd.SsidLen == 0 && ctx->pkt_ssid_len > 0 && ctx->pkt_ssid_len <= AIRPDCAP_WPA_SSID_MAX_LEN) {
860                             /* We have a "wildcard" SSID.  Use the one from the packet. */
861                             memcpy(&pkt_key, tmp_key, sizeof(pkt_key));
862                             memcpy(&pkt_key.UserPwd.Ssid, ctx->pkt_ssid, ctx->pkt_ssid_len);
863                              pkt_key.UserPwd.SsidLen = ctx->pkt_ssid_len;
864                             AirPDcapRsnaPwd2Psk(pkt_key.UserPwd.Passphrase, pkt_key.UserPwd.Ssid,
865                                 pkt_key.UserPwd.SsidLen, pkt_key.KeyData.Wpa.Psk);
866                             tmp_key = &pkt_key;
867                         }
868
869                         /* derive the PTK from the BSSID, STA MAC, PMK, SNonce, ANonce  */
870                         AirPDcapRsnaPrfX(sa,                    /* authenticator nonce, bssid, station mac      */
871                             tmp_key->KeyData.Wpa.Pmk,   /* PMK  */
872                             data+offset+12,             /* supplicant nonce     */
873                             512,
874                             sa->wpa.ptk);
875
876                         /* verify the MIC (compare the MIC in the packet included in this message with a MIC calculated with the PTK)   */
877                         eapol_len=pntohs(data+offset-3)+4;
878                         memcpy(eapol, &data[offset-5], (eapol_len<AIRPDCAP_EAPOL_MAX_LEN?eapol_len:AIRPDCAP_EAPOL_MAX_LEN));
879                         ret_value=AirPDcapRsnaMicCheck(eapol,                                           /*      eapol frame (header also)               */
880                             eapol_len,                                                                                                  /*      eapol frame length                              */
881                             sa->wpa.ptk,                                                                                                /*      Key Confirmation Key                            */
882                             AIRPDCAP_EAP_KEY_DESCR_VER(data[offset+1]));                /*      EAPOL-Key description version   */
883
884                         /* If the MIC is valid, the Authenticator checks that the RSN information element bit-wise matches              */
885                         /* that from the (Re)Association Request message.                                                                                                                                               */
886                         /*              i) TODO If these are not exactly the same, the Authenticator uses MLME-DEAUTHENTICATE.request   */
887                         /* primitive to terminate the association.                                                                                                                                                              */
888                         /*              ii) If they do match bit-wise, the Authenticator constructs Message 3.                                                                  */
889                     }
890
891                     if (!ret_value &&
892                         (tmp_key->KeyType==AIRPDCAP_KEY_TYPE_WPA_PWD ||
893                         tmp_key->KeyType==AIRPDCAP_KEY_TYPE_WPA_PSK ||
894                         tmp_key->KeyType==AIRPDCAP_KEY_TYPE_WPA_PMK))
895                     {
896                         /* the temporary key is the correct one, cached in the Security Association     */
897
898                         sa->key=tmp_key;
899
900                         if (key!=NULL) {
901                             memcpy(key, &tmp_key, sizeof(AIRPDCAP_KEY_ITEM));
902                             if (AIRPDCAP_EAP_KEY_DESCR_VER(data[offset+1])==AIRPDCAP_WPA_KEY_VER_CCMP)
903                                 key->KeyType=AIRPDCAP_KEY_TYPE_TKIP;
904                             else if (AIRPDCAP_EAP_KEY_DESCR_VER(data[offset+1])==AIRPDCAP_WPA_KEY_VER_AES_CCMP)
905                                 key->KeyType=AIRPDCAP_KEY_TYPE_CCMP;
906                         }
907
908                         break;
909                     } else {
910                         /* the cached key was not valid, try other keys */
911
912                         if (useCache==TRUE) {
913                             useCache=FALSE;
914                             key_index--;
915                         }
916                     }
917                 }
918
919                 if (ret_value) {
920                     AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapRsna4WHandshake", "handshake step failed", AIRPDCAP_DEBUG_LEVEL_3);
921                     return AIRPDCAP_RET_NO_VALID_HANDSHAKE;
922                 }
923
924                 sa->handshake=2;
925
926                 return AIRPDCAP_RET_SUCCESS_HANDSHAKE;
927             } else {
928                 /* message 4    */
929
930                 /* TODO "Note that when the 4-Way Handshake is first used Message 4 is sent in the clear."      */
931
932                 /* TODO check MIC and Replay Counter                                                                                                                                                                                    */
933                 /* On reception of Message 4, the Authenticator verifies that the Key Replay Counter field value is one */
934                 /* that it used on this 4-Way Handshake; if it is not, it silently discards the message.                                                */
935                 /* If the calculated MIC does not match the MIC that the Supplicant included in the EAPOL-Key frame, the        */
936                 /* Authenticator silently discards Message 4.                                                                                                                                                           */
937
938                 AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapRsna4WHandshake", "4-way handshake message 4 (patched)", AIRPDCAP_DEBUG_LEVEL_3);
939
940                 sa->handshake=4;
941
942                 sa->validKey=TRUE;
943
944                 return AIRPDCAP_RET_SUCCESS_HANDSHAKE;
945             }
946             /* END OF PATCH                                                                                                                                                                     */
947             /*                                                                                                                                                                                                          */
948         } else {
949             /* message 4        */
950
951             /* TODO "Note that when the 4-Way Handshake is first used Message 4 is sent in the clear."  */
952
953             /* TODO check MIC and Replay Counter                                                                                                                                                                                        */
954             /* On reception of Message 4, the Authenticator verifies that the Key Replay Counter field value is one     */
955             /* that it used on this 4-Way Handshake; if it is not, it silently discards the message.                                            */
956             /* If the calculated MIC does not match the MIC that the Supplicant included in the EAPOL-Key frame, the    */
957             /* Authenticator silently discards Message 4.                                                                                                                                                               */
958
959             AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapRsna4WHandshake", "4-way handshake message 4", AIRPDCAP_DEBUG_LEVEL_3);
960
961             sa->handshake=4;
962
963             sa->validKey=TRUE;
964
965             return AIRPDCAP_RET_SUCCESS_HANDSHAKE;
966         }
967     }
968
969     /* message 3: Authenticator->Supplicant (Sec=1, Mic=1, Ack=1, Inst=0/1, Key=1(pairwise), KeyRSC=???, Nonce=ANonce, MIC=1)   */
970     if (AIRPDCAP_EAP_ACK(data[offset+1])==1 &&
971         AIRPDCAP_EAP_MIC(data[offset])==1)
972     {
973         AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapRsna4WHandshake", "4-way handshake message 3", AIRPDCAP_DEBUG_LEVEL_3);
974
975         /* On reception of Message 3, the Supplicant silently discards the message if the Key Replay Counter field              */
976         /* value has already been used or if the ANonce value in Message 3 differs from the ANonce value in Message 1.  */
977         /* -> not checked, the Authenticator will send another message 3 (hopefully!)                                                                                           */
978
979         /*      TODO check page 88 (RNS)        */
980
981         return AIRPDCAP_RET_SUCCESS_HANDSHAKE;
982     }
983
984     return AIRPDCAP_RET_UNSUCCESS;
985 }
986
987 static INT
988 AirPDcapRsnaMicCheck(
989     UCHAR *eapol,
990     USHORT eapol_len,
991     UCHAR KCK[AIRPDCAP_WPA_KCK_LEN],
992     USHORT key_ver)
993 {
994     UCHAR mic[AIRPDCAP_WPA_MICKEY_LEN];
995     UCHAR c_mic[20];    /* MIC 16 byte, the HMAC-SHA1 use a buffer of 20 bytes */
996
997     /* copy the MIC from the EAPOL packet       */
998     memcpy(mic, eapol+AIRPDCAP_WPA_MICKEY_OFFSET+4, AIRPDCAP_WPA_MICKEY_LEN);
999
1000     /* set to 0 the MIC in the EAPOL packet (to calculate the MIC) */
1001     memset(eapol+AIRPDCAP_WPA_MICKEY_OFFSET+4, 0, AIRPDCAP_WPA_MICKEY_LEN);
1002
1003     if (key_ver==AIRPDCAP_WPA_KEY_VER_CCMP) {
1004         /* use HMAC-MD5 for the EAPOL-Key MIC   */
1005         md5_hmac(eapol, eapol_len, KCK, AIRPDCAP_WPA_KCK_LEN, c_mic);
1006     } else if (key_ver==AIRPDCAP_WPA_KEY_VER_AES_CCMP) {
1007         /* use HMAC-SHA1-128 for the EAPOL-Key MIC */
1008         sha1_hmac(KCK, AIRPDCAP_WPA_KCK_LEN, eapol, eapol_len, c_mic);
1009     } else
1010         /* key descriptor version not recognized */
1011         return AIRPDCAP_RET_UNSUCCESS;
1012
1013     /* compare calculated MIC with the Key MIC and return result (0 means success) */
1014     return memcmp(mic, c_mic, AIRPDCAP_WPA_MICKEY_LEN);
1015 }
1016
1017 static INT
1018 AirPDcapValidateKey(
1019     PAIRPDCAP_KEY_ITEM key)
1020 {
1021     size_t len;
1022     UCHAR ret=TRUE;
1023     AIRPDCAP_DEBUG_TRACE_START("AirPDcapValidateKey");
1024
1025     if (key==NULL) {
1026         AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapValidateKey", "NULL key", AIRPDCAP_DEBUG_LEVEL_5);
1027         AIRPDCAP_DEBUG_TRACE_START("AirPDcapValidateKey");
1028         return FALSE;
1029     }
1030
1031     switch (key->KeyType) {
1032         case AIRPDCAP_KEY_TYPE_WEP:
1033             /* check key size limits    */
1034             len=key->KeyData.Wep.WepKeyLen;
1035             if (len<AIRPDCAP_WEP_KEY_MINLEN || len>AIRPDCAP_WEP_KEY_MAXLEN) {
1036                 AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapValidateKey", "WEP key: key length not accepted", AIRPDCAP_DEBUG_LEVEL_5);
1037                 ret=FALSE;
1038             }
1039             break;
1040
1041         case AIRPDCAP_KEY_TYPE_WEP_40:
1042             /* set the standard length  and use a generic WEP key type  */
1043             key->KeyData.Wep.WepKeyLen=AIRPDCAP_WEP_40_KEY_LEN;
1044             key->KeyType=AIRPDCAP_KEY_TYPE_WEP;
1045             break;
1046
1047         case AIRPDCAP_KEY_TYPE_WEP_104:
1048             /* set the standard length  and use a generic WEP key type  */
1049             key->KeyData.Wep.WepKeyLen=AIRPDCAP_WEP_104_KEY_LEN;
1050             key->KeyType=AIRPDCAP_KEY_TYPE_WEP;
1051             break;
1052
1053         case AIRPDCAP_KEY_TYPE_WPA_PWD:
1054             /* check passphrase and SSID size limits    */
1055             len=strlen(key->UserPwd.Passphrase);
1056             if (len<AIRPDCAP_WPA_PASSPHRASE_MIN_LEN || len>AIRPDCAP_WPA_PASSPHRASE_MAX_LEN) {
1057                 AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapValidateKey", "WPA-PWD key: passphrase length not accepted", AIRPDCAP_DEBUG_LEVEL_5);
1058                 ret=FALSE;
1059             }
1060
1061             len=key->UserPwd.SsidLen;
1062             if (len>AIRPDCAP_WPA_SSID_MAX_LEN) {
1063                 AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapValidateKey", "WPA-PWD key: ssid length not accepted", AIRPDCAP_DEBUG_LEVEL_5);
1064                 ret=FALSE;
1065             }
1066
1067             break;
1068
1069         case AIRPDCAP_KEY_TYPE_WPA_PSK:
1070             break;
1071
1072         case AIRPDCAP_KEY_TYPE_WPA_PMK:
1073             break;
1074
1075         default:
1076             ret=FALSE;
1077     }
1078
1079     AIRPDCAP_DEBUG_TRACE_END("AirPDcapValidateKey");
1080     return ret;
1081 }
1082
1083 static INT
1084 AirPDcapGetSa(
1085     PAIRPDCAP_CONTEXT ctx,
1086     AIRPDCAP_SEC_ASSOCIATION_ID *id)
1087 {
1088     INT index;
1089
1090     if (ctx->sa_index!=-1) {
1091         /* at least one association was stored                                                                                                          */
1092         /* search for the association from sa_index to 0 (most recent added)    */
1093         for (index=ctx->sa_index; index>=0; index--) {
1094             if (ctx->sa[index].used) {
1095                 if (memcmp(id, &(ctx->sa[index].saId), sizeof(AIRPDCAP_SEC_ASSOCIATION_ID))==0) {
1096                     ctx->index=index;
1097                     return index;
1098                 }
1099             }
1100         }
1101     }
1102
1103     return -1;
1104 }
1105
1106 static INT
1107 AirPDcapStoreSa(
1108     PAIRPDCAP_CONTEXT ctx,
1109     AIRPDCAP_SEC_ASSOCIATION_ID *id)
1110 {
1111     INT last_free;
1112
1113     if (ctx->sa[ctx->first_free_index].used) {
1114         /* last addition was in the middle of the array (and the first_free_index was just incremented by 1)    */
1115         /* search for a free space from the first_free_index to AIRPDCAP_STA_INFOS_NR (to avoid free blocks in  */
1116         /*              the middle)                                                                                                                                                                                                                                     */
1117         for (last_free=ctx->first_free_index; last_free<AIRPDCAP_MAX_SEC_ASSOCIATIONS_NR; last_free++)
1118             if (!ctx->sa[last_free].used)
1119                 break;
1120
1121         if (last_free>=AIRPDCAP_MAX_SEC_ASSOCIATIONS_NR) {
1122             /* there is no empty space available. FAILURE       */
1123             return -1;
1124         }
1125
1126         /* store first free space index */
1127         ctx->first_free_index=last_free;
1128     }
1129
1130     /* use this info    */
1131     ctx->index=ctx->first_free_index;
1132
1133     /* reset the info structure */
1134     memset(ctx->sa+ctx->index, 0, sizeof(AIRPDCAP_SEC_ASSOCIATION));
1135
1136     ctx->sa[ctx->index].used=1;
1137
1138     /* set the info structure   */
1139     memcpy(&(ctx->sa[ctx->index].saId), id, sizeof(AIRPDCAP_SEC_ASSOCIATION_ID));
1140
1141     /* increment by 1 the first_free_index (heuristic)  */
1142     ctx->first_free_index++;
1143
1144     /* set the sa_index if the added index is greater the the sa_index  */
1145     if (ctx->index > ctx->sa_index)
1146         ctx->sa_index=ctx->index;
1147
1148     return ctx->index;
1149 }
1150
1151 /*
1152  * AirPDcapGetBssidAddress() and AirPDcapGetBssidAddress() are used for
1153  * key caching.  In each case, it's more important to return a value than
1154  * to return a _correct_ value, so we fudge addresses in some cases, e.g.
1155  * the BSSID in bridged connections.
1156  * FromDS    ToDS    Sta    BSSID
1157  * 0         0       addr2  addr3
1158  * 0         1       addr2  addr1
1159  * 1         0       addr1  addr2
1160  * 1         1       addr2  addr1
1161  */
1162
1163 static const UCHAR *
1164 AirPDcapGetStaAddress(
1165     const AIRPDCAP_MAC_FRAME_ADDR4 *frame)
1166 {
1167     switch(AIRPDCAP_DS_BITS(frame->fc[1])) { /* Bit 1 = FromDS, bit 0 = ToDS */
1168         case 0:
1169         case 1:
1170         case 3:
1171             return frame->addr2;
1172         case 2:
1173             return frame->addr1;
1174         default:
1175             return NULL;
1176     }
1177 }
1178
1179 static const UCHAR *
1180 AirPDcapGetBssidAddress(
1181     const AIRPDCAP_MAC_FRAME_ADDR4 *frame)
1182 {
1183     switch(AIRPDCAP_DS_BITS(frame->fc[1])) { /* Bit 1 = FromDS, bit 0 = ToDS */
1184         case 0:
1185             return frame->addr3;
1186         case 1:
1187         case 3:
1188             return frame->addr1;
1189         case 2:
1190             return frame->addr2;
1191         default:
1192             return NULL;
1193     }
1194 }
1195
1196 /* Function used to derive the PTK. Refer to IEEE 802.11I-2004, pag. 74 */
1197 static void
1198 AirPDcapRsnaPrfX(
1199     AIRPDCAP_SEC_ASSOCIATION *sa,
1200     const UCHAR pmk[32],
1201     const UCHAR snonce[32],
1202     const INT x,        /*      for TKIP 512, for CCMP 384      */
1203     UCHAR *ptk)
1204 {
1205     UINT8 i;
1206     UCHAR R[100];
1207     INT offset=sizeof("Pairwise key expansion");
1208
1209     memset(R, 0, 100);
1210
1211     memcpy(R, "Pairwise key expansion", offset);
1212
1213     /*  Min(AA, SPA) || Max(AA, SPA)    */
1214     if (memcmp(sa->saId.sta, sa->saId.bssid, AIRPDCAP_MAC_LEN) < 0)
1215     {
1216         memcpy(R + offset, sa->saId.sta, AIRPDCAP_MAC_LEN);
1217         memcpy(R + offset+AIRPDCAP_MAC_LEN, sa->saId.bssid, AIRPDCAP_MAC_LEN);
1218     }
1219     else
1220     {
1221         memcpy(R + offset, sa->saId.bssid, AIRPDCAP_MAC_LEN);
1222         memcpy(R + offset+AIRPDCAP_MAC_LEN, sa->saId.sta, AIRPDCAP_MAC_LEN);
1223     }
1224
1225     offset+=AIRPDCAP_MAC_LEN*2;
1226
1227     /*  Min(ANonce,SNonce) || Max(ANonce,SNonce)        */
1228     if( memcmp(snonce, sa->wpa.nonce, 32) < 0 )
1229     {
1230         memcpy(R + offset, snonce, 32);
1231         memcpy(R + offset + 32, sa->wpa.nonce, 32);
1232     }
1233     else
1234     {
1235         memcpy(R + offset, sa->wpa.nonce, 32);
1236         memcpy(R + offset + 32, snonce, 32);
1237     }
1238
1239     offset+=32*2;
1240
1241     for(i = 0; i < (x+159)/160; i++)
1242     {
1243         R[offset] = i;
1244         sha1_hmac(pmk, 32, R, 100, ptk + i * 20);
1245     }
1246 }
1247
1248 static INT
1249 AirPDcapRsnaPwd2PskStep(
1250     const guint8 *ppBytes,
1251     const guint ppLength,
1252     const CHAR *ssid,
1253     const size_t ssidLength,
1254     const INT iterations,
1255     const INT count,
1256     UCHAR *output)
1257 {
1258     UCHAR digest[36], digest1[AIRPDCAP_SHA_DIGEST_LEN];
1259     INT i, j;
1260
1261     /* U1 = PRF(P, S || INT(i)) */
1262     memcpy(digest, ssid, ssidLength);
1263     digest[ssidLength] = (UCHAR)((count>>24) & 0xff);
1264     digest[ssidLength+1] = (UCHAR)((count>>16) & 0xff);
1265     digest[ssidLength+2] = (UCHAR)((count>>8) & 0xff);
1266     digest[ssidLength+3] = (UCHAR)(count & 0xff);
1267     sha1_hmac(ppBytes, ppLength, digest, ssidLength+4, digest1);
1268
1269     /* output = U1 */
1270     memcpy(output, digest1, AIRPDCAP_SHA_DIGEST_LEN);
1271     for (i = 1; i < iterations; i++) {
1272         /* Un = PRF(P, Un-1) */
1273         sha1_hmac(ppBytes, ppLength, digest1, AIRPDCAP_SHA_DIGEST_LEN, digest);
1274
1275         memcpy(digest1, digest, AIRPDCAP_SHA_DIGEST_LEN);
1276         /* output = output xor Un */
1277         for (j = 0; j < AIRPDCAP_SHA_DIGEST_LEN; j++) {
1278             output[j] ^= digest[j];
1279         }
1280     }
1281
1282     return AIRPDCAP_RET_SUCCESS;
1283 }
1284
1285 static INT
1286 AirPDcapRsnaPwd2Psk(
1287     const CHAR *passphrase,
1288     const CHAR *ssid,
1289     const size_t ssidLength,
1290     UCHAR *output)
1291 {
1292     UCHAR m_output[AIRPDCAP_WPA_PSK_LEN];
1293     GByteArray *pp_ba = g_byte_array_new();
1294
1295     memset(m_output, 0, AIRPDCAP_WPA_PSK_LEN);
1296
1297     if (!uri_str_to_bytes(passphrase, pp_ba)) {
1298         g_byte_array_free(pp_ba, TRUE);
1299         return 0;
1300     }
1301
1302     AirPDcapRsnaPwd2PskStep(pp_ba->data, pp_ba->len, ssid, ssidLength, 4096, 1, m_output);
1303     AirPDcapRsnaPwd2PskStep(pp_ba->data, pp_ba->len, ssid, ssidLength, 4096, 2, &m_output[AIRPDCAP_SHA_DIGEST_LEN]);
1304
1305     memcpy(output, m_output, AIRPDCAP_WPA_PSK_LEN);
1306     g_byte_array_free(pp_ba, TRUE);
1307
1308     return 0;
1309 }
1310
1311 /*
1312  * Returns the decryption_key_t struct given a string describing the key.
1313  * Returns NULL if the key_string cannot be parsed.
1314  */
1315 decryption_key_t*
1316 parse_key_string(gchar* input_string)
1317 {
1318     gchar *type;
1319     gchar *key;
1320     gchar *ssid;
1321
1322     GString    *key_string = NULL;
1323     GByteArray *ssid_ba = NULL, *key_ba;
1324     gboolean    res;
1325
1326     gchar **tokens;
1327     guint n = 0;
1328     decryption_key_t *dk;
1329     gchar *first_nibble = input_string;
1330
1331     if(input_string == NULL)
1332         return NULL;
1333
1334     /*
1335      * Parse the input_string. It should be in the form
1336      * <key type>:<key data>[:<ssid>]
1337      * XXX - For backward compatibility, the a WEP key can be just a string
1338      * of hexadecimal characters (if WEP key is wrong, null will be
1339      * returned...).
1340      */
1341
1342     /* First, check for a WEP string */
1343     /* XXX - This duplicates code in packet-ieee80211.c */
1344     if (g_ascii_strncasecmp(input_string, STRING_KEY_TYPE_WEP ":", 4) == 0) {
1345         first_nibble += 4;
1346     }
1347
1348     key_ba = g_byte_array_new();
1349     res = hex_str_to_bytes(first_nibble, key_ba, FALSE);
1350
1351     if (res && key_ba->len > 0) {
1352         /* Key is correct! It was probably an 'old style' WEP key */
1353         /* Create the decryption_key_t structure, fill it and return it*/
1354         dk = g_malloc(sizeof(decryption_key_t));
1355
1356         dk->type = AIRPDCAP_KEY_TYPE_WEP;
1357         /* XXX - The current key handling code in the GUI requires
1358          * no separators and lower case */
1359         dk->key  = g_string_new(bytes_to_str(key_ba->data, key_ba->len));
1360         g_string_down(dk->key);
1361         dk->bits = key_ba->len * 8;
1362         dk->ssid = NULL;
1363
1364         g_byte_array_free(key_ba, TRUE);
1365         return dk;
1366     }
1367     g_byte_array_free(key_ba, TRUE);
1368
1369
1370     tokens = g_strsplit(input_string,":",0);
1371
1372     /* Tokens is a null termiated array of strings ... */
1373     while(tokens[n] != NULL)
1374         n++;
1375
1376     if(n < 2)
1377     {
1378         /* Free the array of strings */
1379         g_strfreev(tokens);
1380         return NULL;
1381     }
1382
1383     type = g_strdup(tokens[0]);
1384
1385     /*
1386      * The second token is the key (right now it doesn't matter
1387      * if it is a passphrase[+ssid] or an hexadecimal one)
1388      */
1389     key = g_strdup(tokens[1]);
1390
1391     ssid = NULL;
1392     /* Maybe there is a third token (an ssid, if everything else is ok) */
1393     if(n >= 3)
1394     {
1395         ssid = g_strdup(tokens[2]);
1396     }
1397
1398     if (g_ascii_strcasecmp(type,STRING_KEY_TYPE_WPA_PSK) == 0) /* WPA key */
1399     {
1400         /* Create a new string */
1401         key_string = g_string_new(key);
1402
1403         key_ba = g_byte_array_new();
1404         res = hex_str_to_bytes(key, key_ba, FALSE);
1405
1406         /* Two tokens means that the user should have entered a WPA-BIN key ... */
1407         if(!res || ((key_string->len) != WPA_PSK_KEY_CHAR_SIZE))
1408         {
1409             g_string_free(key_string, TRUE);
1410             g_byte_array_free(key_ba, TRUE);
1411
1412             g_free(type);
1413             g_free(key);
1414             /* No ssid has been created ... */
1415             /* Free the array of strings */
1416             g_strfreev(tokens);
1417             return NULL;
1418         }
1419
1420         /* Key was correct!!! Create the new decryption_key_t ... */
1421         dk = (decryption_key_t*)g_malloc(sizeof(decryption_key_t));
1422
1423         dk->type = AIRPDCAP_KEY_TYPE_WPA_PMK;
1424         dk->key  = g_string_new(key);
1425         dk->bits = dk->key->len * 4;
1426         dk->ssid = NULL;
1427
1428         g_string_free(key_string, TRUE);
1429         g_byte_array_free(key_ba, TRUE);
1430         g_free(key);
1431         g_free(type);
1432
1433         /* Free the array of strings */
1434         g_strfreev(tokens);
1435         return dk;
1436     }
1437     else if(g_ascii_strcasecmp(type,STRING_KEY_TYPE_WPA_PWD) == 0) /* WPA key *//* If the number of tokens is more than three, we accept the string... if the first three tokens are correct... */
1438     {
1439         /* Create a new string */
1440         key_string = g_string_new(key);
1441         ssid_ba = NULL;
1442
1443         /* Three (or more) tokens mean that the user entered a WPA-PWD key ... */
1444         if( ((key_string->len) > WPA_KEY_MAX_CHAR_SIZE) || ((key_string->len) < WPA_KEY_MIN_CHAR_SIZE))
1445         {
1446             g_string_free(key_string, TRUE);
1447
1448             g_free(type);
1449             g_free(key);
1450             g_free(ssid);
1451
1452             /* Free the array of strings */
1453             g_strfreev(tokens);
1454             return NULL;
1455         }
1456
1457         if(ssid != NULL) /* more than three tokens found, means that the user specified the ssid */
1458         {
1459             ssid_ba = g_byte_array_new();
1460             if (! uri_str_to_bytes(ssid, ssid_ba)) {
1461                 g_string_free(key_string, TRUE);
1462                 g_byte_array_free(ssid_ba, TRUE);
1463                 g_free(type);
1464                 g_free(key);
1465                 g_free(ssid);
1466                 /* Free the array of strings */
1467                 g_strfreev(tokens);
1468                 return NULL;
1469             }
1470
1471             if(ssid_ba->len > WPA_SSID_MAX_CHAR_SIZE)
1472             {
1473                 g_string_free(key_string, TRUE);
1474                 g_byte_array_free(ssid_ba, TRUE);
1475
1476                 g_free(type);
1477                 g_free(key);
1478                 g_free(ssid);
1479
1480                 /* Free the array of strings */
1481                 g_strfreev(tokens);
1482                 return NULL;
1483             }
1484         }
1485
1486         /* Key was correct!!! Create the new decryption_key_t ... */
1487         dk = (decryption_key_t*)g_malloc(sizeof(decryption_key_t));
1488
1489         dk->type = AIRPDCAP_KEY_TYPE_WPA_PWD;
1490         dk->key  = g_string_new(key);
1491         dk->bits = 256; /* This is the length of the array pf bytes that will be generated using key+ssid ...*/
1492         dk->ssid = byte_array_dup(ssid_ba); /* NULL if ssid_ba is NULL */
1493
1494         g_string_free(key_string, TRUE);
1495         if (ssid_ba != NULL)
1496             g_byte_array_free(ssid_ba, TRUE);
1497
1498         g_free(type);
1499         g_free(key);
1500         if(ssid != NULL)
1501             g_free(ssid);
1502
1503         /* Free the array of strings */
1504         g_strfreev(tokens);
1505         return dk;
1506     }
1507
1508     /* Something was wrong ... free everything */
1509
1510     g_free(type);
1511     g_free(key);
1512     if(ssid != NULL)
1513         g_free(ssid); /* It is not always present */
1514     if (ssid_ba != NULL)
1515         g_byte_array_free(ssid_ba, TRUE);
1516
1517     /* Free the array of strings */
1518     g_strfreev(tokens);
1519
1520     return NULL;
1521 }
1522
1523 /*
1524  * Returns a newly allocated string representing the given decryption_key_t
1525  * struct, or NULL if something is wrong...
1526  */
1527 gchar*
1528 get_key_string(decryption_key_t* dk)
1529 {
1530     gchar* output_string = NULL;
1531
1532     if(dk == NULL || dk->key == NULL)
1533         return NULL;
1534
1535     switch(dk->type) {
1536         case AIRPDCAP_KEY_TYPE_WEP:
1537             output_string = g_strdup_printf("%s:%s",STRING_KEY_TYPE_WEP,dk->key->str);
1538             break;
1539         case AIRPDCAP_KEY_TYPE_WPA_PWD:
1540             if(dk->ssid == NULL)
1541                 output_string = g_strdup_printf("%s:%s",STRING_KEY_TYPE_WPA_PWD,dk->key->str);
1542             else
1543                 output_string = g_strdup_printf("%s:%s:%s",
1544                     STRING_KEY_TYPE_WPA_PWD, dk->key->str,
1545                     format_uri(dk->ssid, ":"));
1546             break;
1547         case AIRPDCAP_KEY_TYPE_WPA_PMK:
1548             output_string = g_strdup_printf("%s:%s",STRING_KEY_TYPE_WPA_PSK,dk->key->str);
1549             break;
1550         default:
1551             return NULL;
1552             break;
1553     }
1554
1555     return output_string;
1556 }
1557
1558 #ifdef  __cplusplus
1559 }
1560 #endif
1561
1562 /****************************************************************************/
1563
1564 /*
1565  * Editor modelines
1566  *
1567  * Local Variables:
1568  * c-basic-offset: 4
1569  * tab-width: 8
1570  * set-tabs-mode: nil
1571  * End:
1572  *
1573  * ex: set shiftwidth=4 tabstop=8 expandtab
1574  * :indentSize=4:tabSize=8:noTabs=true:
1575  */