Beefy Boxes and Bandwidth Generously Provided by pair Networks
go ahead... be a heretic

Re: HMAC_SHA1 Implementation for WPA

by cord-bin (Friar)
on Jun 23, 2014 at 09:43 UTC ( #1090900=note: print w/replies, xml ) Need Help??

in reply to [SOLVED] HMAC_SHA1 Implementation for WPA

Hi, The IEEE 802.11i-2004 says:
The PTK is generated by concatenating the following attributes: PMK, A +P nonce (ANonce), STA nonce (SNonce), AP MAC address, and STA MAC add +ress. You should better check this as the order is important.
This isn't exactly what you are doing here :
my $a = "Pairwise key expansion"; # application-specific data my $b = $amac.$smac.$snonce.$anonce; my $r = ""; for(my $i=0;$i<4;$i++){ my $data = $a."\x00".$b.$i;
The product is then put through PBKDF2-SHA1 as the cryptographic hash function. The PBKDF2 key derivation function has five input parameters:
DK = PBKDF2(PRF, Password, Salt, c, dkLen)
  • PRF is a pseudorandom function of two parameters with output length hLen (e.g. a keyed HMAC)
  • Password is the master password from which a derived key is generated
  • Salt is a cryptographic salt
  • c is the number of iterations desired
  • dkLen is the desired length of the derived key
  • DK is the generated derived key

  • For more on pbkdf2 used in perl check this link PBKDF2 crypt
    Here's some code used to do this

    Replies are listed 'Best First'.
    Re^2: HMAC_SHA1 Implementation for WPA
    by return0 (Acolyte) on Jun 23, 2014 at 23:11 UTC
      Hi, there actually have been quite a few amendments since 2004, thankfully. You may want to look into a more updated document. As far as "five input parameters" goes, can you not see my 5 parameters? Also, I know that the order is important, as all documentation on building the string data to send to the HMAC-SHA1 uses min() max() functions in its concatentation syntax. This is why I have them hard-coded at the moment.
      In a similar way, the computation of the pairwise temporal keys is wri +tten: PRF-512(PMK, "Pairwise key expansion", MAC1||MAC2||Nonce1||Nonce2) Here MAC1 and MAC2 are the MAC addresses of the two devices where MAC1 + is the smaller (numerically) and MAC2 is the larger of the two addre +sses. Similarly, Nonce1 is the smallest value between ANonce and SNon +ce, while Nonce2 is the largest of the two values.

      During my more recent research however, I did find a Python implementation which shows similar difficulties, and might shed some insight on your documentation problem - as he did successfully calculate the PTK in Python in a *very* similar way.
      Maybe this is a key, but I do use the pack() function, which seems to be the same. I am going to read the .cap file directly using Net::Pcap now and check if the "string" is somehow causing the issue.

    Re^2: HMAC_SHA1 Implementation for WPA
    by return0 (Acolyte) on Jun 24, 2014 at 03:12 UTC
      I have added code into aircrack-ng.c from the latest sauce which writes the pke[] array to a file as so:
      FILE *pkef; pkef=fopen("pke.txt", "a"); for(j=0; j<nparallel; ++j) { /* compute the pairwise transient key and the +frame MIC */ for (i = 0; i < 4; i++) { pke[99] = i; HMAC(EVP_sha1(), pmk[j], 32, pke, 100, + ptk[j] + i * 20, NULL); int kk = 0; fprintf(pkef,"==> "); for(kk = 0;kk<=99;kk++){ fprintf(pkef, "%i ",pke[kk]); } fprintf(pkef,"\n---------------------\ +n"); }
      After which I converted it to hex, and the output was exactly that which it should be: "Pairwise key expansion" . 0x00 . $mac1 . $mac2 . $nonce1 . $nonce2 . 0x00; # where $mac1 < $mac2 && $nonce1 < $nonce2. Now, I used this hex in Perl and tried hmac_sha1 and even PBKDF2 again, to no avail (using the pre-computed PMK as the key just like Aircrack-ng). I have tried 1 and 4096 passes, I know I am using CCMP-WPA2, I know what cowpatty and aircrack-ng produce, i have also tried reading the raw bytes directly from Net::Pcap but I cannot seem to get the correct first 128 bits of the PTK.. I bet it has to do with not being able to replicate that danged HMAC() C function properly. There's a description of it in the openSSL documentation as:
      unsigned char *HMAC(const EVP_MD *evp_md, const void *key, int key_len, const unsigned char *d, int n, unsigned char *md, unsigned int *md_len);
      Could it simply not be possible? Thanks monks! :)
    Re^2: HMAC_SHA1 Implementation for WPA
    by return0 (Acolyte) on Jun 28, 2014 at 03:44 UTC
      Okay, so I feel like I am getting a bit closer. I got the Python program from the link ( to work, even though I don't know python, and watched exactly what it was doing.
      import hmac import hashlib from hashlib import sha1 import binascii import sys A = "Pairwise key expansion" APmac = binascii.a2b_hex("001dd0f694b0") Clientmac = binascii.a2b_hex("489d2477179a") ANonce = binascii.a2b_hex("87f2718bad169e4987c94255395e054bcaf77c +8d791698bf03dc85ed3c90832a") SNonce = binascii.a2b_hex("143fbb4333341f36e17667f88aa02c5230ab82 +c508cc4bd5947dd7e50475ad36") B = min(APmac,Clientmac)+max(APmac,Clientmac)+min(ANonce,SNo +nce)+max(ANonce,SNonce) def customPRF512(key,A,B): blen = 64 i = 0 R = '' while i<=((blen*8+159)/160): hmacsha1 =,A+chr(0x00)+B+chr(i),sha1) i+=1 R = R+hmacsha1.digest() print "R: ",binascii.b2a_hex(hmacsha1.digest()),"\n" return R[:blen] pmk = binascii.a2b_hex("9051ba43660caec7a909fbbe6b91e4685f1457b5a2e236 +60d728afbd2c7abfba") ptk = customPRF512(pmk,A,B) print "pmk:\t\t",binascii.b2a_hex(pmk),"\n" print "ptk:\t\t",binascii.b2a_hex(ptk[0:16]),"\n" print "A: ",binascii.b2a_hex(A),"\n" print "CHR(0x00): ",chr(0x00),"\n" print "B: ",binascii.b2a_hex(B),"\n" print "key: ",binascii.b2a_hex(pmk),"\n" print "CHR(0): ",chr(0),"\n" i = 0 string = A+chr(0x00)+B+chr(i) print "STRING: ",binascii.b2a_hex(string);

      It produced the correct PTK from my PMK using the hmac_sha1 class. You can see it from "directly from python loop" in the code.
      #!/usr/bin/perl -w use strict; use Digest::HMAC_SHA1 qw(hmac_sha1 hmac_sha1_hex); my $pmk = pack("H*","9051ba43660caec7a909fbbe6b91e4685f1457b5a2e23660d +728afbd2c7abfba"); my $a; foreach(split("","Pairwise key expansion")){ $a .= sprintf("%x",ord($_)); } # 5061697277697365206b657920657870616e73696f6e OK my $i = 0x00; # 00 in hex my $smac = pack("H*","489d2477179a"); my $amac = pack("H*","001dd0f694b0"); my $snonce = pack("H*","143fbb4333341f36e17667f88aa02c5230ab82c508cc4b +d5947dd7e50475ad36"); my $anonce = pack("H*","87f2718bad169e4987c94255395e054bcaf77c8d791698 +bf03dc85ed3c90832a"); my $b = $amac.$smac.$snonce.$anonce; # Directly from Python code in for loop (without spaces): # 5061697277697365206b657920657870616e73696f6e 00 001dd0f694b0 + 489d2477179a1 # 43fbb4333341f36e17667f88aa02c5230ab82c508cc4bd5947dd7e50475a +d36 # 87f2718bad169e4987c94255395e054bcaf77c8d791698bf03dc85ed3c90 +832a 00 my $hd = $a.$i.$b.$i; my $digest = hmac_sha1($hd,$pmk); print unpack("H*",$digest)."\n"; # according to docs: $digest = hmac_s +ha1($data, $key); # does not come out as 9287f887faade9257f5a806309a2bac8956fcbec like +hmac_sha1 from Python ?
      I am almost sure that the pack() fucntion in Perl is similar to his a2b_hex() method as I have altered his Python code to print it for each iteration. As you can see the "Pairwise key expansion" is turned into hex via each character's ascii code, which I did with sprintf and ord. That comes out to:


      which is correct. Is the pack() function argument wrong? is the hmacsha1 not the same as in Python? I am so lost right now. :( Thanks monks!

    Log In?

    What's my password?
    Create A New User
    Node Status?
    node history
    Node Type: note [id://1090900]
    and all is quiet...

    How do I use this? | Other CB clients
    Other Users?
    Others making s'mores by the fire in the courtyard of the Monastery: (6)
    As of 2018-01-16 17:28 GMT
    Find Nodes?
      Voting Booth?
      How did you see in the new year?

      Results (186 votes). Check out past polls.