How to calculate PMKID for WPA*01?
#1
I am trying to calculate PMKID 4d4fe7aac3a2cecab195321ceb99a7d0 for WPA*01 hash 22000 but can't get the correct result. See Example hashes

I think I have the correct equations in my code to calculate PSK, PMK and PMKID according to WPA/WPA2-PSK PMKID Bruteforce Attack description mentioned at the end of article here and there

I verified my calculation of PSK is correct see online calculator

My program below will give me the results:

PSK  = 88f43854ae7b1624fc2ab7724859e795130f4843c7535729e819cf92f39535dc
PMK  = 29033d570e2f52259f03135c935239053c7d0e0c3bb9ab06e97d92e3c3da3e4e
PMKID = 1e3216791e82bbc72da6590c4fae759a

Code:
#include <iostream>

#include <openssl/evp.h>
#include <openssl/sha.h>
#include <openssl/hmac.h>
// crypto.h used for the version
#include <openssl/crypto.h>
#include <cstdio>                             
#include <string>

int32_t iterations = 4096;
const char* password = "hashcat!";
const char* salttext = "hashcat-essid";

unsigned char salt_PMKID[20] = { 'P', 'M', 'K', ' ', 'n', 'a', 'm', 'e', 0xfc, 0x69, 0x0c, 0x15, 0x82, 0x64, 0xf4,0x74, 0x7f, 0x87, 0xf9, 0xf4 };  //Test

unsigned char PSK[0x20];
unsigned char PMK[0x20];
unsigned char PMKID[0x10];

uint32_t outputBytes = 32;

void PBKDF2_HMAC_SHA_1_PSK_PMK_PMKID(const char* pass, const char* salt, int32_t iterations, uint32_t outputBytes, char* hexResult)
{
    unsigned int i;
    unsigned int digest_PMKID_len = 16;
    unsigned int* PMKID_len = &digest_PMKID_len;
    unsigned char digest[0x20];

    //In WPA2 PSK, the Pre-Shared Key is the same as the Pairwise Master Key (PMK).
    //Calculate PSK = PBKDF2(Passphrase, SSID, 4096)
    PKCS5_PBKDF2_HMAC(pass, (int)strlen(pass), (const unsigned char*)salt,(int)strlen(salt), iterations, EVP_sha1(), outputBytes, digest);
    for (i = 0; i < sizeof(digest); i++)
sprintf(hexResult + (i * 2), "%02x", 255 & digest[i]);
printf_s("PSK  = %s\n", hexResult);

//Calculate PMK = PBKDF2(HMAC−SHA1, PSK, SSID, 4096, 256)
PKCS5_PBKDF2_HMAC((const char*)digest, 32, (const unsigned char*)salt, (int)strlen(salt), iterations, EVP_sha1(), outputBytes, digest);
    for (i = 0; i < sizeof(digest); i++)
        sprintf(hexResult + (i * 2), "%02x", 255 & digest[i]);
printf_s("PMK  = %s\n", hexResult);

    //Calculate PMKID = HMAC-SHA1-128(PMK,"PMK Name" | MAC_AP | MAC_STA)
    HMAC(EVP_sha1(), (const char*)digest, 32, (const unsigned char*)salt_PMKID, (size_t)20, digest, PMKID_len);
    /*memcpy(test, (const unsigned char*)salt_PMKID, 20);*/
    for (i = 0; i < 16; i++)
        sprintf(hexResult + (i * 2), "%02x", 255 & digest[i]);
    printf_s("PMKID = %s\n", hexResult); 
}


int main()
{
    // 2*outputBytes+1 is 2 hex bytes per binary byte,
    // and one character at the end for the string-terminating \0
    char hexResult[2 * 32 + 1];
    memset(hexResult, 0, sizeof(hexResult));

    PBKDF2_HMAC_SHA_1_PSK_PMK_PMKID(password, salttext, iterations, outputBytes, hexResult);
}
Reply
#2
Just compare my solution (PKCS5_PBKDF2_HMAC -> HMAC(EVP_sha1)
Code:
PMK is calculated by:
PKCS5_PBKDF2_HMAC((const char*)psk, psklen, (unsigned char*)essid,  essidlen, 4096, EVP_sha1(), 32, pmk)
PMKID is calculated by:
HMAC(EVP_sha1(), pmk, 32, salt, 20, pmkid, NULL);
$ wlangenpmk -e "hashcat-essid" -p "hashcat!"

essid (networkname)....: hashcat-essid
password...............: hashcat!
plainmasterkey (SHA1)..: 88f43854ae7b1624fc2ab7724859e795130f4843c7535729e819cf92f39535dc



with your code ( (PKCS5_PBKDF2_HMAC -> PKCS5_PBKDF2_HMAC -> HMAC(EVP_sha1):
Code:
//Calculate PSK = PBKDF2(Passphrase, SSID, 4096)
    PKCS5_PBKDF2_HMAC(pass, (int)strlen(pass), (const unsigned char*)salt,(int)strlen(salt), iterations, EVP_sha1(), outputBytes, digest);

//Calculate PMK = PBKDF2(HMAC−SHA1, PSK, SSID, 4096, 256)
PKCS5_PBKDF2_HMAC((const char*)digest, 32, (const unsigned char*)salt, (int)strlen(salt), iterations, EVP_sha1(), outputBytes, digest);

    //Calculate PMKID = HMAC-SHA1-128(PMK,"PMK Name" | MAC_AP | MAC_STA)
    HMAC(EVP_sha1(), (const char*)digest, 32, (const unsigned char*)salt_PMKID, (size_t)20, digest, PMKID_len);
    /*memcpy(test, (const unsigned char*)salt_PMKID, 20);*/
you run PKCS5_PBKDF2_HMAC twice. That result in a wrong PMK
your PMK = 29033d570e2f52259f03135c935239053c7d0e0c3bb9ab06e97d92e3c3da3e4e

There is absolutely no need to calculate the PSK (by your first function), because it is given:
const char* password = "hashcat!";
as well as the ESSID:
const char* salttext = "hashcat-essid";
Reply
#3
Attached (quick and dirty) sample code (hash is taken from hashcat example hashes (22000).

Code:
$ ./evp
PMKID expected:   4d4fe7aac3a2cecab195321ceb99a7d0
PMKID calculated: 4d4fe7aac3a2cecab195321ceb99a7d0

Please notice that we are using the new EVP API:
https://wiki.openssl.org/index.php/OpenSSL_3.0


Code:
//essid (networkname)....: hashcat-essid
//password...............: hashcat!
//plainmasterkey (SHA1)..: 88f43854ae7b1624fc2ab7724859e795130f4843c7535729e819cf92f39535dc

//4d4fe7aac3a2cecab195321ceb99a7d0:fc690c158264:f4747f87f9f4:hashcat-essid:hashcat!

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <unistd.h>
#include <stdbool.h>

#include <openssl/evp.h>
#include <openssl/err.h>
#include <openssl/params.h>


/*===========================================================================*/
// global EVP var
static EVP_MAC *hmac;
static EVP_MAC *cmac;
static EVP_MAC_CTX *ctxhmac = NULL;
static EVP_MAC_CTX *ctxcmac = NULL;
static OSSL_PARAM paramsmd5[3];
static OSSL_PARAM paramssha1[3];
static OSSL_PARAM paramsaes128[3];
/*===========================================================================*/

/*===========================================================================*/
static bool evpinitwpa()
{
hmac = EVP_MAC_fetch(NULL, "hmac", NULL);
if(hmac == NULL) return false;
cmac = EVP_MAC_fetch(NULL, "cmac", NULL);
if(cmac == NULL) return false;

paramsmd5[0] = OSSL_PARAM_construct_utf8_string("digest", "md5", 0);
paramsmd5[1] = OSSL_PARAM_construct_end();

paramssha1[0] = OSSL_PARAM_construct_utf8_string("digest", "sha1", 0);
paramssha1[1] = OSSL_PARAM_construct_end();

paramsaes128[0] = OSSL_PARAM_construct_utf8_string("cipher", "aes-128-cbc", 0);
paramsaes128[1] = OSSL_PARAM_construct_end();

ctxhmac = EVP_MAC_CTX_new(hmac);
if(ctxhmac == NULL) return false;
ctxcmac = EVP_MAC_CTX_new(cmac);
if(ctxcmac == NULL) return false;
return true;
}
/*===========================================================================*/
static bool genpmkid(const unsigned char *pmk, uint8_t *macap, uint8_t *macclient, uint8_t *pmkid)
{
static char *pmkname = "PMK Name";

memcpy(pmkid, pmkname, 8);
memcpy(pmkid +8, macap, 6);
memcpy(pmkid +14, macclient, 6);
if(!EVP_MAC_init(ctxhmac, pmk, 32, paramssha1)) return false;
if(!EVP_MAC_update(ctxhmac, pmkid, 20)) return false;
if(!EVP_MAC_final(ctxhmac, pmkid, NULL, 20)) return false;
return true;
}
/*===========================================================================*/

int main()
{
static uint8_t macap[] = {0xfc, 0x69, 0x0c, 0x15, 0x82, 0x64};
static uint8_t macclient[] = {0xf4, 0x74, 0x7f, 0x87, 0xf9, 0xf4};
static uint8_t pmk[] =
{
0x88, 0xf4, 0x38, 0x54, 0xae, 0x7b, 0x16, 0x24, 0xfc, 0x2a, 0xb7, 0x72, 0x48, 0x59, 0xe7, 0x95,
0x13, 0x0f, 0x48, 0x43, 0xc7, 0x53, 0x57, 0x29, 0xe8, 0x19, 0xcf, 0x92, 0xf3, 0x95, 0x35, 0xdc
};

static uint8_t pmkid[20];

if(evpinitwpa() == false) goto err;
size_t i;

if(genpmkid(pmk, macap, macclient, pmkid) == false) goto err;

printf("PMKID expected:   4d4fe7aac3a2cecab195321ceb99a7d0\nPMKID calculated: ");
for (i = 0; i < 16; i++) printf("%02x", pmkid[i]);
printf("\n");

EVP_MAC_CTX_free(ctxhmac);
EVP_MAC_free(hmac);
exit(0);

err:
EVP_MAC_CTX_free(ctxhmac);
EVP_MAC_free(hmac);
fprintf(stderr, "Something went wrong\n");
ERR_print_errors_fp(stderr);
exit (1);
}

Please notice:
The code include EVP init code of WPA1, WPA2 and WPA2 key version 3 while the PTK and MIC calculation is still missing. But this is simple to add (when using the new EVP API).

From my point of view it is worth to move from OpenSSL 1.1 to 3.0 (for many reasons), but I have to rewrite the entire crypto stuff of hcxdumptool, hcxtools and hcxkeys to get benefit of the new EVP API.
Reply