ribble has asked for the wisdom of the Perl Monks concerning the following question:

Hello all. I am after some assistance regarding the creation of a basic authentication header.

I am been asked to code against a restAPI that requires the creation of the authentication header using hmac sha256. I am running into issues getting the hash values to match against the restAPI yet when I check using an online hmac generator my values are correct

This leads me to believe I am doing something wrong when using the app key as part of the hash

The documentation states that the key is comprised of 32 two-character base-16 hexadecimal values. I guess this where my issue is

I don't know how I should be handling the key other than just parsing it as a string.

my simple code so far

#set the strings $method="GET"; $appid="d6468df6c1e8419fb5ec50f62be9a28b"; $appkey="15c7a6e1a5bd73500db29dffd0e19b6c6228b044c64348a6f5d6d470c54fc +208"; $path="/xxxxx/xxxx/api/v1/users/xxxx/xxxxx"; #build the string to hash $step1="$method\\n $datestring\\n $appid\\n $path"; #hmac sha256hash the string $step2=hmac_sha256_hex($step1, $appkey);

I am using hmac_sha256_hex as the app key string is in hex. I am clearly doing something wrong but no idea what?

Do i need to perform some conversion of the app key before using it? I am lost!

thanks for looking

Replies are listed 'Best First'.
Re: HMAC Sha256 Help!
by hippo (Archbishop) on Jul 18, 2017 at 09:21 UTC
    $step1="$method\\n $datestring\\n $appid\\n $path";

    That looks unusual. Why the double backslashes? Why the whitespace? Were you specifically instructed to create $step1 like this?

      Yes, apologies step1 is to be constructed this way.

      a sample string is "GET\n Wed, 08 Apr 2015 21:37:33 GMT \n1b700d2e7b7b4abfa1950c865e23e81a\n /xxxxxxx/api/v1/users/jsmith/factors"

Re: HMAC Sha256 Help! (updated)
by haukex (Archbishop) on Jul 18, 2017 at 09:23 UTC

    Just a guess, since you don't say what you expect to get as a result in $step2: Does hmac_sha256_hex($step1, pack("H*",$appkey)) help?

    Update:

    I am using hmac_sha256_hex as the app key string is in hex.

    I believe the general naming convention in many of the Digest::* modules is that the suffix _hex on the function name refers to their return value, and not their arguments.

      thanks for the reply. Well I don' really know what the expected output should be either, thats my issue really.

      I tried with the pack function to get the hex key into bytes but with no success either.

      as for using hmac_sha256_hex, thanks for the information. I have now changed to hmac_sha256 instead, still no joy but I think thats now the correct hashing mechanism

      I really appreciate the assistance thanks.

      the full instructions to build the authorization header are:

      For GET endpoint:

      1. Build a string based on the request METHOD (GET) DATE/TIME APPLICATION ID PATH (API endpoint, e.g. /xxxxxxxxx/api/v1/users/<userID>/factors)

      2. Create an HMAC SHA256 hash of step 1 using the Application Key This step is executed by calling the HMAC and producing the hash value

      3. Encode the HMAC SHA256 hash from step 2 in Base64

      4. Concatenate the "Application ID", ":", and the "Base64 encoded HMAC SHA256 hash" from step 3 ApplicationID:Base64EncodedHMACSHA256Hash

      5. Encode the value from step 4 in Base64

      6. Concatenate "Basic " and the "Value of Step 5"

      the encoding is all ok, its the creation of the HMAC that seems to be my issue.

      currently I have it as

      #lets check the time $datestring = strftime "%a, %e %b %Y %H:%M:%S GMT", gmtime; #set the strings $method="GET"; $appid="d6468df6c1e8419fb5ec50f62be9a28b"; $appkey="15c7a6e1a5bd73500db29dffd0e19b6c6228b044c64348a6f5d6d470c54fc +208"; $path="/xxxxxxxxxxxx/xxxxxxx/api/v1/users/xxxxx/factors"; #build the hash string $step1="$method\\n$datestring\\n$appid\\n$path"; #hmac sha256hash the string $step2a= encode_base64(hmac_sha256($step1, pack("H*",$appkey))); $step4="$appid:$step2a"; #encode value from step 4 into base 64 $step5 = encode_base64($step4); #now add Basic and the value from step 5 $step6 = ("Basic $step5");
        Well I don' really know what the expected output should be either, thats my issue really.

        This does seem to be the central issue. Is there really no example transaction provided in the API documentation? Perhaps you could ask whomever published the API for one? Is there a reference implementation that you could look at? Even if it's in another programming language, you might be able to just read that, or, you could execute it and run a trace (Wireshark) of a successful request?

Re: HMAC Sha256 Help!
by fishy (Friar) on Jul 18, 2017 at 16:28 UTC
    Hi ribble,

    a couple of years ago (2 or 3 years), I came up with the following code. I just remember that it worked. Now I'm too lazy to study it again... ;-) I think it's self explanatory. The point is writing out the HMAC in correct base64. As you already noted, playing with HMAC's require checking against reference HMAC's calculations and values in order to get it right.

    Have fun!

    #!/usr/bin/env perl use strict; use warnings; use HTTP::Tiny; use Digest::SHA qw( hmac_sha256_base64 ); my $url = shift(@ARGV) || 'http://localhost:8080/saf/CreditWeb?url=htt +p://127.0.0.39:39090/some_files/inotify.pdf&mini=1'; my $digest = hmac_sha256_base64("SaF14202", "manyana"); while (length($digest) % 4) { $digest .= '='; } print "digest: $digest\n"; my %headers = ( SAFHMAC => $digest ); my $response = HTTP::Tiny->new->get($url, { headers => \%headers }); print "$response->{status} $response->{reason}\n"; while (my ($k, $v) = each %{$response->{headers}}) { for (ref $v eq 'ARRAY' ? @$v : $v) { print "$k: $_\n"; } } #print $response->{content} if length $response->{content}; __END__

      Thanks for the reply and the code.

      I am confused as to which digest I should be using and also what I should be outputting.

      the requirement is to create a HMAC sha256 digest using an appkey as the secret

      the app key is a hex value comprised of 32 2 byte values and not 64 1 byte values

      its how to handle that in perl that is causing me the issue as well as which digest to use. I have been using hmac_sha256 as an assumption

      thanks again