0

Recently needed to translate a code snippet of hashing from Java to Nodejs and I can't get the same result as Java. Sample from Java;

SecretKeySpec signingKey = new SecretKeySpec(client_secret.getBytes(UTF_8), HMAC_SHA256_ALGORITHM);
Mac mac = Mac.getInstance(HMAC_SHA256_ALGORITHM);
mac.init(signingKey);


byte[] rawBodyHash = mac.doFinal(payload.getBytes(UTF_8));
String bodyHash=new String(Base64.encodeBase64(rawBodyHash)).replace("\r\n", "");

in this snippet client_secret is a string but payload is a JSON object. This is my javascript snippet -

if (!_.isString(body)) {
    bodyString = JSON.stringify(body);
}

return createHmac("sha256", this.secret)
 .update(bodyString, "utf8")
 .digest("base64")
 .replace("\r\n", "");

I'm getting very different outputs for the hash.

I suspect that the hashing of a byte array of JSON on java's side is very different compared to the hashing of a JSON.stringify-ed JSON on javascript's side. What would be a good translation of java to javascript, to get the same output?

Edit

when client_secret = 'secret', and payload = {"foo": "bar"};

both of this code snippet gives me the same output. PzqzmGtlarsXrz6xRD7WwI74//n+qDkVkJ0bQhrsib4=

However when another field is added into the payload, payload = {"foo":"bar", "bar":"foo"} , the output would be different.

Java: 3SsGheXe/TUxVxefwiQGFygrXtx/IkqDzXR9/8ZWPNo=

Javascript: H391/AGzJP3P+ID8AOeq2nsRPmivH+Kc+hXxBf+832Q=

Here is the updated Java snippet

import org.json.JSONObject;
...
JSONObject payload = new JSONObject();
      payload.put("foo", "bar");
      payload.put("bar", "foo");
...
byte[] rawBodyHash = mac.doFinal(payload.toString().getBytes("UTF-8"));
String bodyHash = new String bodyHash=new String(Base64.encodeBase64(rawBodyHash)).replace("\r\n", "");

I have compared the two payload string values in both languages and they are the same. So why are their output values different?

Edit v2

Thanks @Topaco for pointing out that the order of Java JSON requires an explicit order to be set, otherwise the keys will be sorted in ascending order, making the hash different than the JS's output.

Glad to know that the translation of Java to Javascript works fine, thanks!

claireckc
  • 395
  • 2
  • 11
  • Did you try comparing the two JSON strings whether they give the same input for your hashing methods? There might be subtle differences (like new line characters, indentation etc.) that affect the hashes. – Gergely Kőrössy Jan 20 '21 at 02:40
  • @GergelyKőrössy Thanks for commenting so quickly! Are you saying that contents aside, this javascript code should have the same output as the java snippet? – claireckc Jan 20 '21 at 02:53
  • If you won't put the different outputs into your question, you are handicapping the people who want to help you. – NomadMaker Jan 20 '21 at 03:04
  • @NomadMaker thanks for the heads up. I've added the sample values and outputs – claireckc Jan 20 '21 at 04:59
  • The different results are caused by different order of the name/value pairs. In the JS code, the order _after serialization_ is (`{"foo": "bar", "bar": "foo"}` -> `H391/AGzJP3P+ID8AOeq2nsRPmivH+Kc+hXxBf+832Q=`) and in the Java code (`{"bar": "foo", "foo": "bar"}` -> `3SsGheXe/TUxVxefwiQGFygrXtx/IkqDzXR9/8ZWPNo=)`. Which is correct? Both, since JSON defines no special order, see [here](https://stackoverflow.com/a/4920304). If you need a special order, you have to implement it yourself, for Java e.g. [here](https://towardsdatascience.com/create-an-ordered-jsonobject-in-java-fb9629247d76). – Topaco Jan 20 '21 at 11:06

0 Answers0