1

I have a problem to verify a string create by crypto.createHmac with Node.js.

I made some test, first in PHP - everything is OK but I can't find the correct way todo this in Node.js:

PHP CODE:

$jsonData = '"face_url":"https:\/\/"';
echo($jsonData);
echo("\n");
$client_secret = 'kqm6FksaIT';
echo hash_hmac("sha256", $jsonData, $client_secret);

Result:

"face_url":"https:\/\/"
34a4eb09a639c9b80713158ae89e7e8311586e6e6d76e09967f4e42a24759b3e

With Node.js, I have a problem with the interpretation of the string:

var crypto = require('crypto');
var str = '"face_url":"https:\/\/"';
console.log(str);
//OK
var buf1 = crypto.createHmac('sha256','kqm6FksaIT').update(str);
var v = buf1.digest('hex');
console.log(v);
//END

RESULT:

"face_url":"https://"
eb502c4711a6d926eeec7830ff34e021ed62c91e574f383f6534fdd30857a907
=> FAIL.

As you can see, the interpretation of the string is different "face_url":"https:\/\/"** VS **"face_url":"https://"**

I have tried a lot of things, Buffer.From base64, utf8, JSON.stringify, JSON.parse but I can't find a solution.

If you try with another string like: '"face_url":"https"' it's OK Result is the same.

I try to validate the key received in a Netatmo POST packet who contain: "face_url":"https:\/\/netatmocameraimage.blob.core

You can find an implementation of netatmo webhook in PHP here: https://github.com/Netatmo/Netatmo-API-PHP/blob/master/Examples/Webhook_Server_Example.php

Dharman
  • 30,962
  • 25
  • 85
  • 135

2 Answers2

1

After reflexion, the only difference between codes was the interpretation of request.body.

In PHP, it seems to be in plain text. Nodejs parses the request in JSON format ...

After that supposition, i made some test with NodeJS this morning, i configured the expres server with the following option:

var express = require('express');
var crypto = require('crypto');
var app = express();
var bodyParser = require('body-parser');
app.use(bodyParser.text({type:"*/*"}));

After that, the string appears correctly with these famous "/" :

console.log RESULT : ,"face_url":"https://netatmocameraimage.blob.core.windows.net/production/

And voila! The HMAC is now CORRECT!

The HMAC from NETATMO is calculated on brut text and not from JSON!

Dharman
  • 30,962
  • 25
  • 85
  • 135
0

In the PHP code, only the escape sequences \\ and \' are recognized in a single quoted expression, in all other cases the backslash is interpreted as a literal backslash, i.e. \/ is interpreted as a literal backslash followed by a literal slash (see here, sec. Single quoted). This explains the output of the PHP code:

$jsonData = '"face_url":"https:\/\/"';
...
Output:
"face_url":"https:\/\/"
34a4eb09a639c9b80713158ae89e7e8311586e6e6d76e09967f4e42a24759b3e

In JavaScript, the backslash is ignored for characters that do not represent an escape sequence, (see here, last passage), i.e. an \/ is equivalent to a literal slash. This explains the output of the JavaScript code:

var str = '"face_url":"https:\/\/"';
...
Output:
"face_url":"https://"
eb502c4711a6d926eeec7830ff34e021ed62c91e574f383f6534fdd30857a907

So in order for the JavaScript code to give the same result as the PHP, the backslash must be masked:

var str = '"face_url":"https:\\/\\/"'; 
...
Output:
"face_url":"https:\/\/"
34a4eb09a639c9b80713158ae89e7e8311586e6e6d76e09967f4e42a24759b3e 

Presumably the string with the \/ is the result of a JSON serialization in PHP with json_encode(), which escapes the / by default, i.e. converts it to \/, see also here. In JavaScript, / is simply serialized as /. Note that in PHP the escaping of / can be disabled with JSON_UNESCAPED_SLASHES, see also here.

Topaco
  • 40,594
  • 4
  • 35
  • 62