pythonencryptionwirelesswiresharkwpa

Creating WPA Message Integrity Code (MIC) with Python


I tried to calculate the MIC for a WPA Handshake packet, but unfortunatelly it fails. To be more precise, I took the 802.1x packet (like the specification says).

MIC = HMAC_MD5(MIC Key, 16, 802.1x data)

This is the relevant Code:

mic = hmac.new(ptk[0:16],data)
print "mic: " + mic.hexdigest()  + "\n"

Where hmac.new is taken from the hmac lib:

import hmac,hashlib,binascii

The key for the encryption consists obviously of the first 16 bytes of the Pairwise Transcient Key (the so called Key Confirmation Key). The PTK is confirmed by a program called cowPatty. So I can exclude these two factors to be wrong. This is my 802.1x data, which is introduced by the hex values 0103:

01030077fe010a001000000000000000
01ae11df37f5fb100665ce0c849f5950
c0e7901da3224ddfc9e9434babad5512
73000000000000000000000000000000
00000000000000000000000000000000
00e8b4b90bfc3fd97b657afeb66262ae
940018dd160050f20101000050f20201
000050f20401000050f202

The MIC that Wireshark calculates is:

e8b4b90bfc3fd97b657afeb66262ae94

The MIC that I calculate is:

5492624bb538b52d6aa6261c692bd595

Unfortunatelly it doesn't matter what I do, I am never be able to compute the same MIC. Maybe some expert has valuable input, that really would be appreciated!

Best regards!


Solution

  • Here is the EAPOL data (starting right after the Logical-Link Control) from the second message in a 4 way handshake:

    unsigned char eapol[] =
    {
        '\x01',        // Version
        '\x03',        // Type
        '\x00','\x77', // Length
        '\xfe',        // Key Descriptor Type
        '\x01','\x0a', // Key information
        '\x00','\x10', // Key length
        // Replay counter
        '\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x01',
        // WPA Key Nounce
        '\x77','\xd6','\x54','\xad','\x0c','\x1f','\xea','\x2f',
        '\x20','\x99','\xf1','\xdd','\x1c','\xae','\xdb','\xd8',
        '\xf7','\xe8','\x86','\xb0','\x81','\x60','\xed','\x7f',
        '\x70','\xdd','\xbb','\x33','\xb6','\xf1','\xd9','\x98',
        // Key IV
        '\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
        '\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
        // Key RSC
        '\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
        // Key ID
        '\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
        // MIC **************** CHANGE HERE ********************
    //  '\x0a','\x62','\x24','\x07','\x11','\x36','\xd5','\x67',
    //  '\x87','\xc0','\x7b','\x82','\x6b','\x06','\xf7','\xff',
        '\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
        '\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00',
        // Key Data Length
        '\x00','\x18',
        // Key Data
        '\xdd','\x16','\x00','\x50','\xf2','\x01','\x01','\x00',
        '\x00','\x50','\xf2','\x04','\x01','\x00','\x00','\x50',
        '\xf2','\x04','\x01','\x00','\x00','\x50','\xf2','\x02'
    };
    

    Make sure you replace the 16 bytes of MIC field by '\x00' and you'll have a valid EAPOL data ready to be calculated against Michael algorithm.

    Also, make sure you're using the right algorithm based on WPA version. WPA1 uses HMAC with MD5 hash function, WPA2 uses HMAC with SHA1 hash, as you can see in aircrack-ng source:

    if (ap->wpa.keyver == 1)
        HMAC(EVP_md5(), ptk[j], 16, ap->wpa.eapol, ap->wpa.eapol_size, mic[j], NULL);
    else
        HMAC(EVP_sha1(), ptk[j], 16, ap->wpa.eapol, ap->wpa.eapol_size, mic[j], NULL);
    

    I think python uses MD5 by default in HMAC object.