aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--AUTHORS4
-rw-r--r--epan/crypt/airpdcap.c447
-rw-r--r--epan/crypt/airpdcap_debug.h4
-rw-r--r--epan/crypt/airpdcap_int.h2
-rw-r--r--epan/crypt/airpdcap_rijndael.c314
-rw-r--r--epan/crypt/airpdcap_rijndael.h4
-rw-r--r--epan/crypt/airpdcap_tkip.c10
7 files changed, 761 insertions, 24 deletions
diff --git a/AUTHORS b/AUTHORS
index 7e02f80a50..daad675f3d 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -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);