diff options
author | Gerald Combs <gerald@wireshark.org> | 2008-07-30 22:32:21 +0000 |
---|---|---|
committer | Gerald Combs <gerald@wireshark.org> | 2008-07-30 22:32:21 +0000 |
commit | b5a8677250457bf9bab44eba58d4e8ccc9a8ce29 (patch) | |
tree | 26d0d2af8e6deb28e8476b095ab0aa0e015a625b | |
parent | 476c61472a9b684ec86ba508b5b20e89a8816708 (diff) |
Add WPA group key decryption from Brian Stormont, via bug 1420:
Although this patch successfully recognizes group keys and decrypts packets
properly using the group key, there is a limitation. If an AP is using key
rotation, clicking on individual packets in a trace may not properly decrypt a
packet encrypted with a group key. This is because the current structure used
in Wireshark only supports one active unicast and one active group key. If a
new key has been seen, but you are looking at a packet encrypted with an older
key, it will not decrypt. The summary lines, however, do show the packets
properly decrypted.
I've written up a much longer and more detailed explanation in a comment in the
code, along with a proposed idea for a solution, plus a clunky work-around in
the GUI when using the current code.
I also suspect there might still be a problem with decrypting TKIP groups keys
that are sent using WPA2 authentication. In the most common operation, if you
are using WPA2, you'll also be using AES keys. It's not a common AP
configuration to use WPA2 with TKIP. In fact, most APs don't seem to support
it. Since it is an uncommon setup, I haven't put aside the time to test this
patch against such an AP. I do have access to an AP that supports this, so
when I have the time I'll test it and if needed, will submit another patch to
handle that odd-ball condition.
From me:
Remove the decrypt element of s_rijndael_ctx (which was unused, as indicated
in the comments).
Preserve the GPL licensing text in several files (which the patch shouldn't
have removed).
Remove changes that added whitespace.
Convert C++-style comments to C-style.
Update to include recent SVN changes (e.g. renaming variables named "index").
Remove extraneous printf's.
Define DEBUG_DUMP in airpdcap_debug.h.
Comment out some instances of DEBUG_DUMP.
Change malloc/free to g_malloc/g_free.
Use g_memdup instead of allocating and copying.
Use gint16 instead of INT16 in airpdcap_rijndael.c.
Add Brian to AUTHORS.
svn path=/trunk/; revision=25879
-rw-r--r-- | AUTHORS | 4 | ||||
-rw-r--r-- | epan/crypt/airpdcap.c | 447 | ||||
-rw-r--r-- | epan/crypt/airpdcap_debug.h | 4 | ||||
-rw-r--r-- | epan/crypt/airpdcap_int.h | 2 | ||||
-rw-r--r-- | epan/crypt/airpdcap_rijndael.c | 314 | ||||
-rw-r--r-- | epan/crypt/airpdcap_rijndael.h | 4 | ||||
-rw-r--r-- | epan/crypt/airpdcap_tkip.c | 10 |
7 files changed, 761 insertions, 24 deletions
@@ -2760,6 +2760,10 @@ Edward J. Paradise <pdice [AT] cisco.com> { RFC4938bis enhancements to PPPoE } +Brian Stormont <nospam [AT] stormyprods.com> { + WPA group key decryption +} + and by: Pavel Roskin <proski [AT] gnu.org> diff --git a/epan/crypt/airpdcap.c b/epan/crypt/airpdcap.c index 3214ed5edb..150210b634 100644 --- a/epan/crypt/airpdcap.c +++ b/epan/crypt/airpdcap.c @@ -45,6 +45,8 @@ #include <epan/strutil.h> #include <epan/emem.h> #include <epan/pint.h> +#include <epan/crypt/crypt-rc4.h> +#include <epan/crypt/airpdcap_rijndael.h> #include "airpdcap_system.h" #include "airpdcap_int.h" @@ -86,7 +88,7 @@ * @note * Defined in 802.11i-2004, page 78 */ -#define AIRPDCAP_WPA_KEY_VER_CCMP 1 +#define AIRPDCAP_WPA_KEY_VER_NOT_CCMP 1 /** * EAPOL Key Descriptor Version 2, used for all EAPOL-Key frames to and * from a STA when either the pairwise or the group cipher is AES-CCMP @@ -96,8 +98,14 @@ */ #define AIRPDCAP_WPA_KEY_VER_AES_CCMP 2 +/** Define EAPOL Key Descriptor type values: use 254 for WPA and 2 for WPA2 **/ +#define AIRPDCAP_RSN_WPA_KEY_DESCRIPTOR 254 +#define AIRPDCAP_RSN_WPA2_KEY_DESCRIPTOR 2 + /****************************************************************************/ + + /****************************************************************************/ /* Macro definitions */ @@ -252,6 +260,334 @@ static void AirPDcapRsnaPrfX( extern "C" { #endif +const guint8 broadcast_mac[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; + + +/* NOTE : this assumes the WPA RSN IE format. If it were to be a generic RSN IE, then + we would need to change the structure since it could be variable length depending on the number + of unicast OUI and auth OUI. */ +typedef struct { + guint8 bElementID; + guint8 bLength; + guint8 OUI[4]; + guint16 iVersion; + guint8 multicastOUI[4]; + guint16 iUnicastCount; /* this should always be 1 for WPA client */ + guint8 unicastOUI[4]; + guint16 iAuthCount; /* this should always be 1 for WPA client */ + guint8 authOUI[4]; + guint16 iWPAcap; +} RSN_IE; + +#define EAPKEY_MIC_LEN 16 /* length of the MIC key for EAPoL_Key packet's MIC using MD5 */ +#define NONCE_LEN 32 + +typedef struct { + guint8 type; + guint8 key_information[2]; /* Make this an array to avoid alignment issues */ + guint8 key_length[2]; /* Make this an array to avoid alignment issues */ + guint8 replay_counter[8]; + guint8 key_nonce[NONCE_LEN]; + guint8 key_iv[16]; + guint8 key_sequence_counter[8]; /* also called the RSC */ + guint8 key_id[8]; + guint8 key_mic[EAPKEY_MIC_LEN]; + guint8 key_data_len[2]; /* Make this an array rather than a U16 to avoid alignment shifting */ + guint8 ie[sizeof(RSN_IE)]; /* Make this an array to avoid alignment issues */ +} EAPOL_RSN_KEY, * P_EAPOL_RSN_KEY; + + + +/* A note about some limitations with the WPA decryption: + +Unless someone takes the time to restructure the current method used for maintaining decryption keys, there +will be some anomalies observed when using the decryption feature. + +Currently, there is only one pairwise (unicast) key and one group (broadcast) key saved for each security association +(SA). As a result, if a wireless sniffer session captures the traffic of a station (STA) associating with an AP +more than once, or captures a STA roaming, then you will not be able to arbitrarilly click on different encrypted +packets in the trace and observe their internal decrypted structure. This is because when you click on a packet, +Wireshark immediately performs the decryption routine with whatever the last key used was. It does not maintain a +cache of all the keys that were used by this STA/AP pairing. + +However, if you are just looking at the summary lines of a capture, it will appear that everything was decrypted properly. +This is because when first performing a capture or initially reading a capture file, Wireshark will first +process the packets in order. As it encounters new EAPOL packets, it will update its internal key list with the +newfound key. Then it will use that key for decrypting subsequent packets. Each time a new key is found, the old key +is overwritten. So, if you then click on a packet that was previously decrypted properly, it might suddenly no longer +be decrypted because a later EAPOL key had caused the internal decryption key to be updated. + +For broadcast packets, there is a clunky work-around. If the AP is using group-key rotation, you simply have to find the appropriate +EAPOL group key packet (usually size is 211 bytes and will have a protocol type of EAPOL and Info field of Key). If you click on it +and then click on the broadcast packet you are trying to decrypt, the packet will be decrypted properly. By first +clicking on the EAPOL packet for the group-key, you will force Wireshark to parse that packet and load the group-key it +contains. That group key will then be used for decrypting all subsequent broadcast packets you click on. + +Ideally, it would be best to maintain an expanding list of SA keys. Perhaps we could associate packet number ranges +that they apply to. Then, whenever we need to decrypt a packet, we can determine which key to use based on whether +it is broadcast or unicast and within what packet number range it falls. + +Either that, or store two versions of encrypted packets - the orginal packet and it's successfully +decrypted version. Then Wireshark wouldn't have to decrypt packets on the fly if they were already successfully decrypted. + +*/ + + +static void +AirPDcapDecryptWPABroadcastKey(P_EAPOL_RSN_KEY pEAPKey, guint8 *decryption_key, PAIRPDCAP_SEC_ASSOCIATION sa) +{ + guint8 new_key[32]; + guint8 key_version; + guint8 *szEncryptedKey; + guint16 key_len; + static AIRPDCAP_KEY_ITEM dummy_key; /* needed in case AirPDcapRsnaMng() wants the key structure */ + + /* We skip verifying the MIC of the key. If we were implementing a WPA supplicant we'd want to verify, but for a sniffer it's not needed. */ + + /* Preparation for decrypting the group key - determine group key data length */ + /* depending on whether it's a TKIP or AES encryption key */ + key_version = AIRPDCAP_EAP_KEY_DESCR_VER(pEAPKey->key_information[1]); + if (key_version == AIRPDCAP_WPA_KEY_VER_NOT_CCMP){ + /* TKIP */ + memcpy(&key_len, pEAPKey->key_length, 2); /* get the key length as a UINT16 */ + }else if (key_version == AIRPDCAP_WPA_KEY_VER_AES_CCMP){ + /* AES */ + memcpy(&key_len, pEAPKey->key_data_len, 2); /* get the key length as a UINT16 */ + } + key_len = ntohs(key_len); /* Convert to proper endianess */ + + /* Encrypted key is in the information element field of the EAPOL key packet */ + szEncryptedKey = g_memdup(pEAPKey->ie, key_len); + + DEBUG_DUMP("Encrypted Broadcast key:", szEncryptedKey, key_len); + DEBUG_DUMP("KeyIV:", pEAPKey->key_iv, 16); + DEBUG_DUMP("decryption_key:", decryption_key, 16); + + /* Build the full decryption key based on the IV and part of the pairwise key */ + memcpy(new_key, pEAPKey->key_iv, 16); + memcpy(new_key+16, decryption_key, 16); + DEBUG_DUMP("FullDecrKey:", new_key, 32); + + if (key_version == AIRPDCAP_WPA_KEY_VER_NOT_CCMP){ + guint8 dummy[256]; + /* TKIP key */ + /* Per 802.11i, Draft 3.0 spec, section 8.5.2, p. 97, line 4-8, */ + /* group key is decrypted using RC4. Concatenate the IV with the 16 byte EK (PTK+16) to get the decryption key */ + + rc4_state_struct rc4_state; + crypt_rc4_init(&rc4_state, new_key, sizeof(new_key)); + + /* Do dummy 256 iterations of the RC4 algorithm (per 802.11i, Draft 3.0, p. 97 line 6) */ + crypt_rc4(&rc4_state, dummy, 256); + crypt_rc4(&rc4_state, szEncryptedKey, key_len); + + } else if (key_version == AIRPDCAP_WPA_KEY_VER_AES_CCMP){ + /* AES CCMP key */ + + guint8 key_found; + guint16 key_index; + guint8 *decrypted_data; + + /* This storage is needed for the AES_unwrap function */ + decrypted_data = (guint8 *) g_malloc(key_len); + + AES_unwrap(decryption_key, 16, szEncryptedKey, key_len, decrypted_data); + + /* With WPA2 what we get after Broadcast Key decryption is an actual RSN structure. + The key itself is stored as a GTK KDE + WPA2 IE (1 byte) id = 0xdd, length (1 byte), GTK OUI (4 bytes), key index (1 byte) and 1 reserved byte. Thus we have to + pass pointer to the actual key with 8 bytes offset */ + + key_found = FALSE; + key_index = 0; + while(key_index < key_len && !key_found){ + guint8 rsn_id; + + /* Get RSN ID */ + rsn_id = decrypted_data[key_index]; + + if (rsn_id != 0xdd){ + key_index += decrypted_data[key_index+1]+2; + }else{ + key_found = TRUE; + } + } + + if (key_found){ + /* Skip over the GTK header info, and don't copy past the end of the encrypted data */ + memcpy(szEncryptedKey, decrypted_data+key_index+8, key_len-key_index-8); + } + + g_free(decrypted_data); + } + + /* Decrypted key is now in szEncryptedKey with len of key_len */ + DEBUG_DUMP("Broadcast key:", szEncryptedKey, key_len); + + /* Load the proper key material info into the SA */ + sa->key = &dummy_key; /* we just need key to be not null because it is checked in AirPDcapRsnaMng(). The WPA key materials are actually in the .wpa structure */ + sa->validKey = TRUE; + sa->wpa.key_ver = key_version; + + /* Since this is a GTK and it's size is only 32 bytes (vs. the 64 byte size of a PTK), we fake it and put it in at a 32-byte offset so the */ + /* AirPDcapRsnaMng() function will extract the right piece of the GTK for decryption. (The first 16 bytes of the GTK are used for decryption.) */ + memset(sa->wpa.ptk, 0, sizeof(sa->wpa.ptk)); + memcpy(sa->wpa.ptk+32, szEncryptedKey, key_len); + g_free(szEncryptedKey); +} + + +/* Return a pointer the the requested SA. If it doesn't exist create it. */ +PAIRPDCAP_SEC_ASSOCIATION +AirPDcapGetSaPtr( + PAIRPDCAP_CONTEXT ctx, + AIRPDCAP_SEC_ASSOCIATION_ID *id) +{ + int sa_index; + + /* search for a cached Security Association for supplied BSSID and STA MAC */ + if ((sa_index=AirPDcapGetSa(ctx, id))==-1) { + /* create a new Security Association if it doesn't currently exist */ + if ((sa_index=AirPDcapStoreSa(ctx, id))==-1) { + return NULL; + } + } + /* get the Security Association structure */ + return &ctx->sa[sa_index]; +} + +INT AirPDcapScanForGroupKey( + PAIRPDCAP_CONTEXT ctx, + const guint8 *data, + const guint mac_header_len, + const guint tot_len +) +{ + const UCHAR *address; + AIRPDCAP_SEC_ASSOCIATION_ID id; + guint bodyLength; + PAIRPDCAP_SEC_ASSOCIATION sta_sa; + PAIRPDCAP_SEC_ASSOCIATION sa; + int offset = 0; + const guint8 dot1x_header[] = { + 0xAA, /* DSAP=SNAP */ + 0xAA, /* SSAP=SNAP */ + 0x03, /* Control field=Unnumbered frame */ + 0x00, 0x00, 0x00, /* Org. code=encaps. Ethernet */ + 0x88, 0x8E /* Type: 802.1X authentication */ + }; + + P_EAPOL_RSN_KEY pEAPKey; +#ifdef _DEBUG + CHAR msgbuf[255]; +#endif + + AIRPDCAP_DEBUG_TRACE_START("AirPDcapScanForGroupKey"); + + /* cache offset in the packet data */ + offset = mac_header_len; + + /* check if the packet has an LLC header and the packet is 802.1X authentication (IEEE 802.1X-2004, pg. 24) */ + if (memcmp(data+offset, dot1x_header, 8) == 0) { + + AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapScanForGroupKey", "Authentication: EAPOL packet", AIRPDCAP_DEBUG_LEVEL_3); + + /* skip LLC header */ + offset+=8; + + + /* check if the packet is a EAPOL-Key (0x03) (IEEE 802.1X-2004, pg. 25) */ + if (data[offset+1]!=3) { + AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapScanForGroupKey", "Not EAPOL-Key", AIRPDCAP_DEBUG_LEVEL_3); + return AIRPDCAP_RET_NO_VALID_HANDSHAKE; + } + + /* get and check the body length (IEEE 802.1X-2004, pg. 25) */ + bodyLength=pntohs(data+offset+2); + if ((tot_len-offset-4) < bodyLength) { + AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapScanForGroupKey", "EAPOL body too short", AIRPDCAP_DEBUG_LEVEL_3); + return AIRPDCAP_RET_NO_VALID_HANDSHAKE; + } + + /* skip EAPOL MPDU and go to the first byte of the body */ + offset+=4; + + pEAPKey = (P_EAPOL_RSN_KEY) (data+offset); + + /* check if the key descriptor type is valid (IEEE 802.1X-2004, pg. 27) */ + if (/*pEAPKey->type!=0x1 &&*/ /* RC4 Key Descriptor Type (deprecated) */ + pEAPKey->type != AIRPDCAP_RSN_WPA2_KEY_DESCRIPTOR && /* IEEE 802.11 Key Descriptor Type (WPA2) */ + pEAPKey->type != AIRPDCAP_RSN_WPA_KEY_DESCRIPTOR) /* 254 = RSN_KEY_DESCRIPTOR - WPA, */ + { + AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapScanForGroupKey", "Not valid key descriptor type", AIRPDCAP_DEBUG_LEVEL_3); + return AIRPDCAP_RET_NO_VALID_HANDSHAKE; + } + + /* start with descriptor body */ + offset+=1; + + /* Verify the bitfields: Key = 0(groupwise) Mic = 1 Ack = 1 Secure = 1 */ + if (AIRPDCAP_EAP_KEY(data[offset+1])!=0 || + AIRPDCAP_EAP_ACK(data[offset+1])!=1 || + AIRPDCAP_EAP_MIC(data[offset]) != 1 || + AIRPDCAP_EAP_SEC(data[offset]) != 1){ + + AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapScanForGroupKey", "Key bitfields not correct", AIRPDCAP_DEBUG_LEVEL_3); + return AIRPDCAP_RET_NO_VALID_HANDSHAKE; + } + + /* get BSSID */ + if ( (address=AirPDcapGetBssidAddress((const AIRPDCAP_MAC_FRAME_ADDR4 *)(data))) != NULL) { + memcpy(id.bssid, address, AIRPDCAP_MAC_LEN); +#ifdef _DEBUG + 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]); +#endif + AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapScanForGroupKey", msgbuf, AIRPDCAP_DEBUG_LEVEL_3); + } else { + AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapScanForGroupKey", "BSSID not found", AIRPDCAP_DEBUG_LEVEL_5); + return AIRPDCAP_RET_REQ_DATA; + } + + /* force STA address to be the broadcast MAC so we create an SA for the groupkey */ + memcpy(id.sta, broadcast_mac, AIRPDCAP_MAC_LEN); + + /* get the Security Association structure for the broadcast MAC and AP */ + sa = AirPDcapGetSaPtr(ctx, &id); + if (sa == NULL){ + return AIRPDCAP_RET_UNSUCCESS; + } + + /* Get the SA for the STA, since we need its pairwise key to decrpyt the group key */ + + /* get STA address */ + if ( (address=AirPDcapGetStaAddress((const AIRPDCAP_MAC_FRAME_ADDR4 *)(data))) != NULL) { + memcpy(id.sta, address, AIRPDCAP_MAC_LEN); +#ifdef _DEBUG + 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]); +#endif + AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapScanForGroupKey", msgbuf, AIRPDCAP_DEBUG_LEVEL_3); + } else { + AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapScanForGroupKey", "SA not found", AIRPDCAP_DEBUG_LEVEL_5); + return AIRPDCAP_RET_REQ_DATA; + } + + sta_sa = AirPDcapGetSaPtr(ctx, &id); + if (sta_sa == NULL){ + return AIRPDCAP_RET_UNSUCCESS; + } + + /* Extract the group key and install it in the SA */ + AirPDcapDecryptWPABroadcastKey(pEAPKey, sta_sa->wpa.ptk+16, sa); + + }else{ + AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapScanForGroupKey", "Skipping: not an EAPOL packet", AIRPDCAP_DEBUG_LEVEL_3); + } + + AIRPDCAP_DEBUG_TRACE_END("AirPDcapScanForGroupKey"); + return 0; +} + + INT AirPDcapPacketProcess( PAIRPDCAP_CONTEXT ctx, const guint8 *data, @@ -265,7 +601,6 @@ INT AirPDcapPacketProcess( { const UCHAR *address; AIRPDCAP_SEC_ASSOCIATION_ID id; - int sa_index; PAIRPDCAP_SEC_ASSOCIATION sa; int offset = 0; guint bodyLength; @@ -330,16 +665,11 @@ INT AirPDcapPacketProcess( return AIRPDCAP_RET_REQ_DATA; } - /* search for a cached Security Association for current BSSID and station MAC */ - if ((sa_index=AirPDcapGetSa(ctx, &id))==-1) { - /* create a new Security Association */ - if ((sa_index=AirPDcapStoreSa(ctx, &id))==-1) { - return AIRPDCAP_RET_UNSUCCESS; - } - } - - /* get the Security Association structure */ - sa=&ctx->sa[sa_index]; + /* get the Security Association structure for the STA and AP */ + sa = AirPDcapGetSaPtr(ctx, &id); + if (sa == NULL){ + return AIRPDCAP_RET_UNSUCCESS; + } /* cache offset in the packet data (to scan encryption data) */ offset = mac_header_len; @@ -422,8 +752,40 @@ INT AirPDcapPacketProcess( AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapPacketProcess", "WEP encryption", AIRPDCAP_DEBUG_LEVEL_3); return AirPDcapWepMng(ctx, decrypt_data, mac_header_len, decrypt_len, key, sa, offset); } else { + INT status; AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapPacketProcess", "TKIP or CCMP encryption", AIRPDCAP_DEBUG_LEVEL_3); - return AirPDcapRsnaMng(decrypt_data, mac_header_len, decrypt_len, key, sa, offset); + + /* If index >= 1, then use the group key. This will not work if the AP is using + more than one group key simultaneously. I've not seen this in practice, however. Usually an AP + will rotate between the two key index values of 1 and 2 whenever it needs to change the group key to be used. */ + if (AIRPDCAP_KEY_INDEX(data[offset+3])>=1){ + + AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapPacketProcess", "The key index = 1. This is encrypted with a group key.", AIRPDCAP_DEBUG_LEVEL_3); + + /* force STA address to broadcast MAC so we load the SA for the groupkey */ + memcpy(id.sta, broadcast_mac, AIRPDCAP_MAC_LEN); + +#ifdef _DEBUG + 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]); + AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapPacketProcess", msgbuf, AIRPDCAP_DEBUG_LEVEL_3); +#endif + + /* search for a cached Security Association for current BSSID and broadcast MAC */ + sa = AirPDcapGetSaPtr(ctx, &id); + if (sa == NULL){ + return AIRPDCAP_RET_UNSUCCESS; + } + } + + /* Decrypt the packet using the appropriate SA */ + status = AirPDcapRsnaMng(decrypt_data, mac_header_len, decrypt_len, key, sa, offset); + + /* If we successfully decrypted a packet, scan it to see if it contains a group key handshake. + The group key handshake could be sent at any time the AP wants to change the key (such as when + it is using key rotation) so we must scan every packet. */ + if (status == AIRPDCAP_RET_SUCCESS) + AirPDcapScanForGroupKey(ctx, decrypt_data, mac_header_len, *decrypt_len); + return status; } } } @@ -482,6 +844,25 @@ INT AirPDcapSetKeys( return success; } +static void +AirPDcapCleanKeys( + PAIRPDCAP_CONTEXT ctx) +{ + AIRPDCAP_DEBUG_TRACE_START("AirPDcapCleanKeys"); + + if (ctx==NULL) { + AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapCleanKeys", "NULL context", AIRPDCAP_DEBUG_LEVEL_5); + AIRPDCAP_DEBUG_TRACE_END("AirPDcapCleanKeys"); + return; + } + + memset(ctx->keys, 0, sizeof(AIRPDCAP_KEY_ITEM) * AIRPDCAP_MAX_KEYS_NR); + + ctx->keys_nr=0; + + AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapCleanKeys", "Keys collection cleaned!", AIRPDCAP_DEBUG_LEVEL_5); + AIRPDCAP_DEBUG_TRACE_END("AirPDcapCleanKeys"); +} INT AirPDcapGetKeys( const PAIRPDCAP_CONTEXT ctx, @@ -543,15 +924,15 @@ INT AirPDcapInitContext( return AIRPDCAP_RET_UNSUCCESS; } - memset(ctx->keys, 0, sizeof(AIRPDCAP_KEY_ITEM) * AIRPDCAP_MAX_KEYS_NR); - ctx->keys_nr=0; - memset(ctx->sa, 0, AIRPDCAP_MAX_SEC_ASSOCIATIONS_NR * sizeof(AIRPDCAP_SEC_ASSOCIATION)); + AirPDcapCleanKeys(ctx); ctx->first_free_index=0; ctx->index=-1; ctx->sa_index=-1; ctx->pkt_ssid_len = 0; + memset(ctx->sa, 0, AIRPDCAP_MAX_SEC_ASSOCIATIONS_NR * sizeof(AIRPDCAP_SEC_ASSOCIATION)); + AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapInitContext", "Context initialized!", AIRPDCAP_DEBUG_LEVEL_5); AIRPDCAP_DEBUG_TRACE_END("AirPDcapInitContext"); return AIRPDCAP_RET_SUCCESS; @@ -568,6 +949,8 @@ INT AirPDcapDestroyContext( return AIRPDCAP_RET_UNSUCCESS; } + AirPDcapCleanKeys(ctx); + ctx->first_free_index=0; ctx->index=-1; ctx->sa_index=-1; @@ -613,9 +996,14 @@ AirPDcapRsnaMng( /* CCMP -> HMAC-MD5 is the EAPOL-Key MIC, RC4 is the EAPOL-Key encryption algorithm */ AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapRsnaMng", "TKIP", AIRPDCAP_DEBUG_LEVEL_3); + DEBUG_DUMP("ptk", sa->wpa.ptk, 64); + DEBUG_DUMP("ptk portion used", AIRPDCAP_GET_TK(sa->wpa.ptk), 16); + ret_value=AirPDcapTkipDecrypt(decrypt_data+offset, *decrypt_len-offset, decrypt_data+AIRPDCAP_TA_OFFSET, AIRPDCAP_GET_TK(sa->wpa.ptk)); - if (ret_value) + if (ret_value){ + AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapRsnaMng", "TKIP failed!", AIRPDCAP_DEBUG_LEVEL_3); return ret_value; + } AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapRsnaMng", "TKIP DECRYPTED!!!", AIRPDCAP_DEBUG_LEVEL_3); /* remove MIC (8bytes) and ICV (4bytes) from the end of packet */ @@ -644,7 +1032,7 @@ AirPDcapRsnaMng( if (key!=NULL) { memcpy(key, sa->key, sizeof(AIRPDCAP_KEY_ITEM)); - if (sa->wpa.key_ver==AIRPDCAP_WPA_KEY_VER_CCMP) + if (sa->wpa.key_ver==AIRPDCAP_WPA_KEY_VER_NOT_CCMP) key->KeyType=AIRPDCAP_KEY_TYPE_TKIP; else if (sa->wpa.key_ver==AIRPDCAP_WPA_KEY_VER_AES_CCMP) key->KeyType=AIRPDCAP_KEY_TYPE_CCMP; @@ -896,7 +1284,7 @@ AirPDcapRsna4WHandshake( if (key!=NULL) { memcpy(key, &tmp_key, sizeof(AIRPDCAP_KEY_ITEM)); - if (AIRPDCAP_EAP_KEY_DESCR_VER(data[offset+1])==AIRPDCAP_WPA_KEY_VER_CCMP) + if (AIRPDCAP_EAP_KEY_DESCR_VER(data[offset+1])==AIRPDCAP_WPA_KEY_VER_NOT_CCMP) key->KeyType=AIRPDCAP_KEY_TYPE_TKIP; else if (AIRPDCAP_EAP_KEY_DESCR_VER(data[offset+1])==AIRPDCAP_WPA_KEY_VER_AES_CCMP) key->KeyType=AIRPDCAP_KEY_TYPE_CCMP; @@ -967,6 +1355,7 @@ AirPDcapRsna4WHandshake( if (AIRPDCAP_EAP_ACK(data[offset+1])==1 && AIRPDCAP_EAP_MIC(data[offset])==1) { + P_EAPOL_RSN_KEY pEAPKey; AIRPDCAP_DEBUG_PRINT_LINE("AirPDcapRsna4WHandshake", "4-way handshake message 3", AIRPDCAP_DEBUG_LEVEL_3); /* On reception of Message 3, the Supplicant silently discards the message if the Key Replay Counter field */ @@ -975,6 +1364,24 @@ AirPDcapRsna4WHandshake( /* TODO check page 88 (RNS) */ + /* If using WPA2 PSK, message 3 will contain an RSN for the group key (GTK KDE). + In order to properly support decrypting WPA2-PSK packets, we need to parse this to get the group key.*/ + pEAPKey = (P_EAPOL_RSN_KEY)(&(data[offset-1])); + if (pEAPKey->type == AIRPDCAP_RSN_WPA2_KEY_DESCRIPTOR){ + PAIRPDCAP_SEC_ASSOCIATION broadcast_sa; + AIRPDCAP_SEC_ASSOCIATION_ID id; + + /* Get broadcacst SA for the current BSSID */ + memcpy(id.sta, broadcast_mac, AIRPDCAP_MAC_LEN); + memcpy(id.bssid, sa->saId.bssid, AIRPDCAP_MAC_LEN); + broadcast_sa = AirPDcapGetSaPtr(ctx, &id); + + if (broadcast_sa == NULL){ + return AIRPDCAP_RET_UNSUCCESS; + } + AirPDcapDecryptWPABroadcastKey(pEAPKey, sa->wpa.ptk+16, broadcast_sa); + } + return AIRPDCAP_RET_SUCCESS_HANDSHAKE; } @@ -997,7 +1404,7 @@ AirPDcapRsnaMicCheck( /* set to 0 the MIC in the EAPOL packet (to calculate the MIC) */ memset(eapol+AIRPDCAP_WPA_MICKEY_OFFSET+4, 0, AIRPDCAP_WPA_MICKEY_LEN); - if (key_ver==AIRPDCAP_WPA_KEY_VER_CCMP) { + if (key_ver==AIRPDCAP_WPA_KEY_VER_NOT_CCMP) { /* use HMAC-MD5 for the EAPOL-Key MIC */ md5_hmac(eapol, eapol_len, KCK, AIRPDCAP_WPA_KCK_LEN, c_mic); } else if (key_ver==AIRPDCAP_WPA_KEY_VER_AES_CCMP) { diff --git a/epan/crypt/airpdcap_debug.h b/epan/crypt/airpdcap_debug.h index ff48a0b7cc..224bf54d7e 100644 --- a/epan/crypt/airpdcap_debug.h +++ b/epan/crypt/airpdcap_debug.h @@ -89,6 +89,8 @@ void print_debug_line(CHAR *function, CHAR *msg, INT level); #endif #endif +#define DEBUG_DUMP(x,y,z) g_warning("%s: %s", x, bytes_to_str(y, (z))) + #else /* !defined _DEBUG */ #define AIRPDCAP_DEBUG_LEVEL_1 @@ -100,6 +102,8 @@ void print_debug_line(CHAR *function, CHAR *msg, INT level); #define AIRPDCAP_DEBUG_TRACE_START(function) #define AIRPDCAP_DEBUG_TRACE_END(function) +#define DEBUG_DUMP(x,y,z) + #endif /* ?defined _DEBUG */ diff --git a/epan/crypt/airpdcap_int.h b/epan/crypt/airpdcap_int.h index d4576ddfdf..cc219fc3ca 100644 --- a/epan/crypt/airpdcap_int.h +++ b/epan/crypt/airpdcap_int.h @@ -78,6 +78,8 @@ */ #define AIRPDCAP_EXTIV(KeyID) ((KeyID >> 5) & 0x1) +#define AIRPDCAP_KEY_INDEX(KeyID) ((KeyID >> 6) & 0x3) /* Used to determine TKIP group key from unicast (group = 1, unicast = 0) */ + /* Macros to get various bits of an EAPOL frame */ #define AIRPDCAP_EAP_KEY_DESCR_VER(KeyInfo_1) ((UCHAR)(KeyInfo_1 & 0x3)) #define AIRPDCAP_EAP_KEY(KeyInfo_1) ((KeyInfo_1 >> 3) & 0x1) diff --git a/epan/crypt/airpdcap_rijndael.c b/epan/crypt/airpdcap_rijndael.c index 8e3922938c..4f0d866c5e 100644 --- a/epan/crypt/airpdcap_rijndael.c +++ b/epan/crypt/airpdcap_rijndael.c @@ -689,6 +689,73 @@ static const UINT32 Td3[256] = { 0xcb84617bU, 0x32b670d5U, 0x6c5c7448U, 0xb85742d0U, }; +static const UINT32 Td4[256] = { + 0x52525252U, 0x09090909U, 0x6a6a6a6aU, 0xd5d5d5d5U, + 0x30303030U, 0x36363636U, 0xa5a5a5a5U, 0x38383838U, + 0xbfbfbfbfU, 0x40404040U, 0xa3a3a3a3U, 0x9e9e9e9eU, + 0x81818181U, 0xf3f3f3f3U, 0xd7d7d7d7U, 0xfbfbfbfbU, + 0x7c7c7c7cU, 0xe3e3e3e3U, 0x39393939U, 0x82828282U, + 0x9b9b9b9bU, 0x2f2f2f2fU, 0xffffffffU, 0x87878787U, + 0x34343434U, 0x8e8e8e8eU, 0x43434343U, 0x44444444U, + 0xc4c4c4c4U, 0xdedededeU, 0xe9e9e9e9U, 0xcbcbcbcbU, + 0x54545454U, 0x7b7b7b7bU, 0x94949494U, 0x32323232U, + 0xa6a6a6a6U, 0xc2c2c2c2U, 0x23232323U, 0x3d3d3d3dU, + 0xeeeeeeeeU, 0x4c4c4c4cU, 0x95959595U, 0x0b0b0b0bU, + 0x42424242U, 0xfafafafaU, 0xc3c3c3c3U, 0x4e4e4e4eU, + 0x08080808U, 0x2e2e2e2eU, 0xa1a1a1a1U, 0x66666666U, + 0x28282828U, 0xd9d9d9d9U, 0x24242424U, 0xb2b2b2b2U, + 0x76767676U, 0x5b5b5b5bU, 0xa2a2a2a2U, 0x49494949U, + 0x6d6d6d6dU, 0x8b8b8b8bU, 0xd1d1d1d1U, 0x25252525U, + 0x72727272U, 0xf8f8f8f8U, 0xf6f6f6f6U, 0x64646464U, + 0x86868686U, 0x68686868U, 0x98989898U, 0x16161616U, + 0xd4d4d4d4U, 0xa4a4a4a4U, 0x5c5c5c5cU, 0xccccccccU, + 0x5d5d5d5dU, 0x65656565U, 0xb6b6b6b6U, 0x92929292U, + 0x6c6c6c6cU, 0x70707070U, 0x48484848U, 0x50505050U, + 0xfdfdfdfdU, 0xededededU, 0xb9b9b9b9U, 0xdadadadaU, + 0x5e5e5e5eU, 0x15151515U, 0x46464646U, 0x57575757U, + 0xa7a7a7a7U, 0x8d8d8d8dU, 0x9d9d9d9dU, 0x84848484U, + 0x90909090U, 0xd8d8d8d8U, 0xababababU, 0x00000000U, + 0x8c8c8c8cU, 0xbcbcbcbcU, 0xd3d3d3d3U, 0x0a0a0a0aU, + 0xf7f7f7f7U, 0xe4e4e4e4U, 0x58585858U, 0x05050505U, + 0xb8b8b8b8U, 0xb3b3b3b3U, 0x45454545U, 0x06060606U, + 0xd0d0d0d0U, 0x2c2c2c2cU, 0x1e1e1e1eU, 0x8f8f8f8fU, + 0xcacacacaU, 0x3f3f3f3fU, 0x0f0f0f0fU, 0x02020202U, + 0xc1c1c1c1U, 0xafafafafU, 0xbdbdbdbdU, 0x03030303U, + 0x01010101U, 0x13131313U, 0x8a8a8a8aU, 0x6b6b6b6bU, + 0x3a3a3a3aU, 0x91919191U, 0x11111111U, 0x41414141U, + 0x4f4f4f4fU, 0x67676767U, 0xdcdcdcdcU, 0xeaeaeaeaU, + 0x97979797U, 0xf2f2f2f2U, 0xcfcfcfcfU, 0xcecececeU, + 0xf0f0f0f0U, 0xb4b4b4b4U, 0xe6e6e6e6U, 0x73737373U, + 0x96969696U, 0xacacacacU, 0x74747474U, 0x22222222U, + 0xe7e7e7e7U, 0xadadadadU, 0x35353535U, 0x85858585U, + 0xe2e2e2e2U, 0xf9f9f9f9U, 0x37373737U, 0xe8e8e8e8U, + 0x1c1c1c1cU, 0x75757575U, 0xdfdfdfdfU, 0x6e6e6e6eU, + 0x47474747U, 0xf1f1f1f1U, 0x1a1a1a1aU, 0x71717171U, + 0x1d1d1d1dU, 0x29292929U, 0xc5c5c5c5U, 0x89898989U, + 0x6f6f6f6fU, 0xb7b7b7b7U, 0x62626262U, 0x0e0e0e0eU, + 0xaaaaaaaaU, 0x18181818U, 0xbebebebeU, 0x1b1b1b1bU, + 0xfcfcfcfcU, 0x56565656U, 0x3e3e3e3eU, 0x4b4b4b4bU, + 0xc6c6c6c6U, 0xd2d2d2d2U, 0x79797979U, 0x20202020U, + 0x9a9a9a9aU, 0xdbdbdbdbU, 0xc0c0c0c0U, 0xfefefefeU, + 0x78787878U, 0xcdcdcdcdU, 0x5a5a5a5aU, 0xf4f4f4f4U, + 0x1f1f1f1fU, 0xddddddddU, 0xa8a8a8a8U, 0x33333333U, + 0x88888888U, 0x07070707U, 0xc7c7c7c7U, 0x31313131U, + 0xb1b1b1b1U, 0x12121212U, 0x10101010U, 0x59595959U, + 0x27272727U, 0x80808080U, 0xececececU, 0x5f5f5f5fU, + 0x60606060U, 0x51515151U, 0x7f7f7f7fU, 0xa9a9a9a9U, + 0x19191919U, 0xb5b5b5b5U, 0x4a4a4a4aU, 0x0d0d0d0dU, + 0x2d2d2d2dU, 0xe5e5e5e5U, 0x7a7a7a7aU, 0x9f9f9f9fU, + 0x93939393U, 0xc9c9c9c9U, 0x9c9c9c9cU, 0xefefefefU, + 0xa0a0a0a0U, 0xe0e0e0e0U, 0x3b3b3b3bU, 0x4d4d4d4dU, + 0xaeaeaeaeU, 0x2a2a2a2aU, 0xf5f5f5f5U, 0xb0b0b0b0U, + 0xc8c8c8c8U, 0xebebebebU, 0xbbbbbbbbU, 0x3c3c3c3cU, + 0x83838383U, 0x53535353U, 0x99999999U, 0x61616161U, + 0x17171717U, 0x2b2b2b2bU, 0x04040404U, 0x7e7e7e7eU, + 0xbabababaU, 0x77777777U, 0xd6d6d6d6U, 0x26262626U, + 0xe1e1e1e1U, 0x69696969U, 0x14141414U, 0x63636363U, + 0x55555555U, 0x21212121U, 0x0c0c0c0cU, 0x7d7d7d7dU, +}; + static const UINT32 rcon[] = { 0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000, 0x20000000, 0x40000000, 0x80000000, @@ -833,12 +900,14 @@ INT rijndaelKeySetupDec( return Nr; } +/* TODO: this is inefficient. We are building both the encryption and decryption key + regardless of how we want to use the key. Would be faster to build the one + key we need. */ void rijndael_set_key( rijndael_ctx *ctx, const UCHAR *key, INT bits) { - ctx->Nr = rijndaelKeySetupEnc(ctx->ek, key, bits); rijndaelKeySetupDec(ctx->dk, key, bits); } @@ -1037,5 +1106,248 @@ void rijndael_encrypt( rijndaelEncrypt(ctx->ek, ctx->Nr, src, dst); } + + +void rijndaelDecrypt(const UINT32 rk[/*4*(Nr + 1)*/], INT Nr, const UINT8 ct[16], UINT8 pt[16]) { + UINT32 s0, s1, s2, s3, t0, t1, t2, t3; +#ifndef FULL_UNROLL + INT r; +#endif /* ?FULL_UNROLL */ + + /* + * map byte array block to cipher state + * and add initial round key: + */ + s0 = GETU32(ct ) ^ rk[0]; + s1 = GETU32(ct + 4) ^ rk[1]; + s2 = GETU32(ct + 8) ^ rk[2]; + s3 = GETU32(ct + 12) ^ rk[3]; +#ifdef FULL_UNROLL + /* round 1: */ + t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[ 4]; + t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[ 5]; + t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[ 6]; + t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[ 7]; + /* round 2: */ + s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[ 8]; + s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[ 9]; + s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[10]; + s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[11]; + /* round 3: */ + t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[12]; + t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[13]; + t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[14]; + t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[15]; + /* round 4: */ + s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[16]; + s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[17]; + s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[18]; + s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[19]; + /* round 5: */ + t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[20]; + t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[21]; + t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[22]; + t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[23]; + /* round 6: */ + s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[24]; + s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[25]; + s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[26]; + s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[27]; + /* round 7: */ + t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[28]; + t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[29]; + t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[30]; + t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[31]; + /* round 8: */ + s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[32]; + s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[33]; + s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[34]; + s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[35]; + /* round 9: */ + t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[36]; + t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[37]; + t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[38]; + t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[39]; + if (Nr > 10) { + /* round 10: */ + s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[40]; + s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[41]; + s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[42]; + s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[43]; + /* round 11: */ + t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[44]; + t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[45]; + t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[46]; + t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[47]; + if (Nr > 12) { + /* round 12: */ + s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[48]; + s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[49]; + s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[50]; + s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[51]; + /* round 13: */ + t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[52]; + t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[53]; + t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[54]; + t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[55]; + } + } + rk += Nr << 2; +#else /* !FULL_UNROLL */ + /* + * Nr - 1 full rounds: + */ + r = Nr >> 1; + for (;;) { + t0 = + Td0[(s0 >> 24) ] ^ + Td1[(s3 >> 16) & 0xff] ^ + Td2[(s2 >> 8) & 0xff] ^ + Td3[(s1 ) & 0xff] ^ + rk[4]; + t1 = + Td0[(s1 >> 24) ] ^ + Td1[(s0 >> 16) & 0xff] ^ + Td2[(s3 >> 8) & 0xff] ^ + Td3[(s2 ) & 0xff] ^ + rk[5]; + t2 = + Td0[(s2 >> 24) ] ^ + Td1[(s1 >> 16) & 0xff] ^ + Td2[(s0 >> 8) & 0xff] ^ + Td3[(s3 ) & 0xff] ^ + rk[6]; + t3 = + Td0[(s3 >> 24) ] ^ + Td1[(s2 >> 16) & 0xff] ^ + Td2[(s1 >> 8) & 0xff] ^ + Td3[(s0 ) & 0xff] ^ + rk[7]; + + rk += 8; + if (--r == 0) { + break; + } + + s0 = + Td0[(t0 >> 24) ] ^ + Td1[(t3 >> 16) & 0xff] ^ + Td2[(t2 >> 8) & 0xff] ^ + Td3[(t1 ) & 0xff] ^ + rk[0]; + s1 = + Td0[(t1 >> 24) ] ^ + Td1[(t0 >> 16) & 0xff] ^ + Td2[(t3 >> 8) & 0xff] ^ + Td3[(t2 ) & 0xff] ^ + rk[1]; + s2 = + Td0[(t2 >> 24) ] ^ + Td1[(t1 >> 16) & 0xff] ^ + Td2[(t0 >> 8) & 0xff] ^ + Td3[(t3 ) & 0xff] ^ + rk[2]; + s3 = + Td0[(t3 >> 24) ] ^ + Td1[(t2 >> 16) & 0xff] ^ + Td2[(t1 >> 8) & 0xff] ^ + Td3[(t0 ) & 0xff] ^ + rk[3]; + } +#endif /* ?FULL_UNROLL */ + /* + * apply last round and + * map cipher state to byte array block: + */ + s0 = + (Td4[(t0 >> 24) ] & 0xff000000) ^ + (Td4[(t3 >> 16) & 0xff] & 0x00ff0000) ^ + (Td4[(t2 >> 8) & 0xff] & 0x0000ff00) ^ + (Td4[(t1 ) & 0xff] & 0x000000ff) ^ + rk[0]; + PUTU32(pt , s0); + s1 = + (Td4[(t1 >> 24) ] & 0xff000000) ^ + (Td4[(t0 >> 16) & 0xff] & 0x00ff0000) ^ + (Td4[(t3 >> 8) & 0xff] & 0x0000ff00) ^ + (Td4[(t2 ) & 0xff] & 0x000000ff) ^ + rk[1]; + PUTU32(pt + 4, s1); + s2 = + (Td4[(t2 >> 24) ] & 0xff000000) ^ + (Td4[(t1 >> 16) & 0xff] & 0x00ff0000) ^ + (Td4[(t0 >> 8) & 0xff] & 0x0000ff00) ^ + (Td4[(t3 ) & 0xff] & 0x000000ff) ^ + rk[2]; + PUTU32(pt + 8, s2); + s3 = + (Td4[(t3 >> 24) ] & 0xff000000) ^ + (Td4[(t2 >> 16) & 0xff] & 0x00ff0000) ^ + (Td4[(t1 >> 8) & 0xff] & 0x0000ff00) ^ + (Td4[(t0 ) & 0xff] & 0x000000ff) ^ + rk[3]; + PUTU32(pt + 12, s3); +} + + +void rijndael_decrypt( + const rijndael_ctx *ctx, + const UCHAR *src, + UCHAR *dst) +{ + rijndaelDecrypt(ctx->dk, ctx->Nr, src, dst); +} + + +/* Based on RFC 3394 and NIST AES Key Wrap Specification pseudo-code. + +This function is used to unwrap an encrypted AES key. One example of its use is +in the WPA-2 protocol to get the group key. +*/ +UCHAR +AES_unwrap(UCHAR *kek, UINT16 key_len, UCHAR *cipher_text, UINT16 cipher_len, UCHAR *output) +{ + UCHAR a[8], b[16]; + UCHAR *r; + UCHAR *c; + gint16 i, j, n; + rijndael_ctx ctx; + + /* Initialize variables */ + + n = (cipher_len/8)-1; /* the algorithm works on 64-bits at a time */ + memcpy(a, cipher_text, 8); + r = output; + c = cipher_text; + memcpy(r, c+8, cipher_len - 8); + + /* Compute intermediate values */ + + for (j=5; j >= 0; --j){ + r = output + (n - 1) * 8; + /* DEBUG_DUMP("r1", (r-8), 8); */ + /* DEBUG_DUMP("r2", r, 8); */ + for (i = n; i >= 1; --i){ + UINT16 t = (n*j) + i; + /* DEBUG_DUMP("a", a, 8); */ + memcpy(b, a, 8); + b[7] ^= t; + /* DEBUG_DUMP("a plus t", b, 8); */ + memcpy(b+8, r, 8); + rijndael_set_key(&ctx, kek, key_len*8 /*bits*/); + rijndael_decrypt(&ctx, b, b); /* NOTE: we are using the same src and dst buffer. It's ok. */ + /* DEBUG_DUMP("aes decrypt", b, 16) */ + memcpy(a,b,8); + memcpy(r, b+8, 8); + r -= 8; + } + } + + /* DEBUG_DUMP("a", a, 8); */ + /* DEBUG_DUMP("output", output, cipher_len - 8); */ + + return 0; +} + /* */ /******************************************************************************/ diff --git a/epan/crypt/airpdcap_rijndael.h b/epan/crypt/airpdcap_rijndael.h index 48d6116a1a..e88b301087 100644 --- a/epan/crypt/airpdcap_rijndael.h +++ b/epan/crypt/airpdcap_rijndael.h @@ -52,7 +52,6 @@ /* */ /* Note: copied AirPDcap/rijndael/rijndael.h */ typedef struct s_rijndael_ctx { - INT decrypt; INT Nr; /* key-length-dependent number of rounds */ UINT32 ek[4 * (RIJNDAEL_MAXNR + 1)]; /* encrypt key schedule */ UINT32 dk[4 * (RIJNDAEL_MAXNR + 1)]; /* decrypt key schedule */ @@ -75,6 +74,9 @@ void rijndael_set_key( const UCHAR *key, INT bits) ; + +UCHAR AES_unwrap(UCHAR *kek, UINT16 key_len, UCHAR *cipher_text, UINT16 cipher_len, UCHAR *output); + /* */ /******************************************************************************/ diff --git a/epan/crypt/airpdcap_tkip.c b/epan/crypt/airpdcap_tkip.c index e64b303445..819a0c6dce 100644 --- a/epan/crypt/airpdcap_tkip.c +++ b/epan/crypt/airpdcap_tkip.c @@ -216,17 +216,23 @@ INT AirPDcapTkipDecrypt( UCHAR TA[AIRPDCAP_MAC_LEN], UCHAR TK[AIRPDCAP_TK_LEN]) { + UINT64 TSC64; UINT32 TSC; UINT16 TSC16; UINT8 *IV; UINT16 TTAK[AIRPDCAP_TTAK_LEN]; UINT8 wep_seed[AIRPDCAP_WEP_128_KEY_LEN]; + /* DEBUG_DUMP("TA", TA, 6); */ + IV = tkip_mpdu; - TSC16 = (UINT16)READ_6(IV[2], IV[0], IV[4], IV[5], IV[6], IV[7]); + TSC64 = READ_6(IV[2], IV[0], IV[4], IV[5], IV[6], IV[7]); + TSC16 = (UINT16)TSC64; - TSC = (UINT32)TSC16 >> 16; + /* The original code made no sense!! We were shifting a 16-bit number 16 bits to the right. */ + /* We instead have to have READ_6() be returned to a UINT64 and shift *that* value. */ + TSC = (UINT32)(TSC64 >> 16); AirPDcapTkipMixingPhase1(TTAK, TK, TA, TSC); |