5

I'm building a HMAC API and I have issues testing the hashing with Paw.

On Paw I have this payload:

GET:/hello/world:"":9a6e30f2016370b6f2dcfb6880501d7f2305d69bout

and a custom HMAC-SHA256 variable (actually function like this that sets it in the X-Hash header.

X-Hash: 4Cq2yehWumDcUk1dYyfhm6qWjJVBkOCB8o12f5l0WGE=

In my PHP API I have the same thing:

GET:/hello/world:"":9a6e30f2016370b6f2dcfb6880501d7f2305d69bout

and used:

hash_hmac('sha256', $this->getPayload(), '9a6e30f2016370b6f2dcfb6880501d7f2305d69bout', false);

So when comparing the hashes:

Paw: 4Cq2yehWumDcUk1dYyfhm6qWjJVBkOCB8o12f5l0WGE=
PHP: 6961b9d1f6e986c49d963cbebd691fa68dfa59b4ce3b7f05320c2d43eae3c7c3

They are very different. Any idea why is that?

Update

Paw Code:

function evaluate(context){
  var loc = getLocation(context.getCurrentRequest().url);

  var payload = "";
  payload += context.getCurrentRequest().method + ':';
  payload += loc.pathname + ':';
  payload += JSON.stringify(context.getCurrentRequest().body) + ':';
    payload += "9a6e30f2016370b6f2dcfb6880501d7f2305d69bout"; // Private key
  return payload;
};

function getLocation(href) {
    var match = href.match(/^(https?\:)\/\/(([^:\/?#]*)(?:\:([0-9]+))?)(\/[^?#]*)(\?[^#]*|)(#.*|)$/);
    return match && {
        protocol: match[1],
        host: match[2],
        hostname: match[3],
        port: match[4],
        pathname: match[5],
        search: match[6],
        hash: match[7]
    }
}

PHP Code (with lots of comments):

if (strpos(strtoupper($authHeader), 'HMAC') !== 0) {
    echo 'out';
    throw new HttpForbiddenException();
}
else {
    $hmacSignature = $app->request->headers()->get('X-Hash');
    $publicKey = $app->request->headers()->get('X-Public');

    if ( empty($hmacSignature) || empty($publicKey) ) {
        echo 'out2';
        throw new HttpForbiddenException();
    }
    else {

        $this->hmacManager->setPublicKey($publicKey);
        print '$publickey = ' . $publicKey . '<br>';

        // Validate if base64_encoded or not
        if( base64_decode($hmacSignature, true) !== FALSE ) {
            $binaryString = base64_decode($hmacSignature);
            $hmacSignature = bin2hex($binaryString);
            print 'decoding ' . '<br>';
        }
        $this->hmacManager->setHmacSignature($hmacSignature);
        print '$hmacSignature = ' . $hmacSignature . '<br>';

        $this->hmacManager->setRequestMethod($app->request->getMethod());
        print 'method = ' . $app->request->getMethod() . '<br>';
        $this->hmacManager->setRequestResourceUri($app->request->getResourceUri());
        print 'uri = ' . $app->request->getResourceUri() . '<br>';

        $requestBody = $app->request()->getBody();
        if (Utils::isJson($requestBody)) {
            $requestBody = json_decode($requestBody);
        }
        $this->hmacManager->setRequestBody(json_encode($requestBody));
        print 'body = ' . json_encode($requestBody) . '<br>';

        print 'private key = ' . $this->hmacManager->getPrivateKey() . '<br>';

        $payload = '';
        $payload .= $this->hmacManager->getRequestMethod() . ":";
        $payload .= $this->hmacManager->getRequestResourceUri() . ":";
        $payload .= $this->hmacManager->getRequestBody() . ":";
        $payload .= $this->hmacManager->getPrivateKey();
        print 'PHP payload [' . $payload . ']';
        $this->hmacManager->setPayload($payload);

        $hmacValue = $this->hmacManager->generateHmac();
        $isValid = $this->hmacManager->isValid($this->hmacManager->generateHmac(), $hmacSignature);

        if ($isValid !== true) {
            echo 'out3';
            throw new HttpForbiddenException();
        }
    }
}

generateHmac from another class:

public function generateHmac()
{
    print 'Generating HMAC' . '<br>';
    $algorithm = $this->getAlgorithm();
    print 'algo ' . $algorithm . '<br>';
    $privateKey = $this->getPrivateKey();
    print 'privk ' . $privateKey . '<br>';

    if (empty($algorithm)) {
        throw new \RuntimeException('Algorithm must be set and not empty');
    } elseif (empty($privateKey)) {
        throw new \RuntimeException('Private key must be set and not empty');
    }

    print 'payload ' . $this->getPayload() . '<br>';
    $hash = hash_hmac($this->getAlgorithm(), $this->getPayload(), $this->getPrivateKey(), false);
    print 'php hasj: ' . $hash . '<br>';

    return $hash;
}

Finally, here's the output statements:

$publickey = 95f97b93560f951b4cae46c86d03d9b1a81d4ae8
decoding 
$hmacSignature = e02ab6c9e856ba60dc524d5d6327e19baa968c954190e081f28d767f99745861

method = GET
uri = /hello/world
body = ""
private key = 9a6e30f2016370b6f2dcfb6880501d7f2305d69bout
PHP payload [GET:/hello/world:"":9a6e30f2016370b6f2dcfb6880501d7f2305d69bout]

Generating HMAC
algo sha256
privk 9a6e30f2016370b6f2dcfb6880501d7f2305d69bout
payload GET:/hello/world:"":9a6e30f2016370b6f2dcfb6880501d7f2305d69bout
php hash: 6961b9d1f6e986c49d963cbebd691fa68dfa59b4ce3b7f05320c2d43eae3c7c3

Hope it helps!

Community
  • 1
  • 1
Vallieres
  • 859
  • 7
  • 19

2 Answers2

4

The paw hash is base64 encoded while the PHP one is in hexadecimal. So decode the paw hash first:

$binary = base64_decode($pawHash);
$hex = bin2hex($binary);

And then compare this to your own hash.

laurent
  • 88,262
  • 77
  • 290
  • 428
  • Can't I do the opposite? Decode the generated hash in Paw before sending it so my API is as it is? Or perhaps detect if it's base64-encoded? – Vallieres Apr 30 '15 at 19:34
  • Still not working. I did like you said (and check if base64_decode (str, true) !== FALSE) to be sure it's a base64 string but it now give me this hash: e02ab6c9e856ba60dc524d5d6327e19baa968c954190e081f28d767f99745861 still very different from what I have in PHP. – Vallieres Apr 30 '15 at 19:45
  • It's hard to tell what could be the issue without seeing the rest of the code. It could be something wrong with the payload for example. Even a tiny difference and the hashes will look totally different. – laurent Apr 30 '15 at 19:49
  • Color me dumb, I forgot to give Paw the private key in the 'Key' field...AAAARG! @this.lau_ you still helped me greatly so I will accept your answer! Thanks again! – Vallieres May 01 '15 at 15:12
2

We've just added new Base 64 to Hex conversion dynamic values, this should solve your problem.

Wrap your HMAC signature dynamic value inside the new Base 64 to Hex one, and you'll get a valid hexadecimal signature:

Hexadecimal HMAC signature with Paw

You can install this new dynamic value here: Base 64 to Hex Dynamic Value

Micha Mazaheri
  • 3,481
  • 1
  • 21
  • 26