2

I need to sign some JSON data in Java and then send the data and sign to NodeJS.

Take a look at this example.

import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import java.security.MessageDigest;
public class SomeClass {
 private double n1 = 0.0;
 private double n2 = 3.2544572232515347E-4;
 private static String bytesToHex(byte[] bytes) {
 StringBuffer result = new StringBuffer();
 for (byte b : bytes) result.append(Integer.toString((b & 0xff) + 0x100, 16).substring(1));
 return result.toString();
 }
 private static String getSha256(String value) {
 try{
 MessageDigest md = MessageDigest.getInstance("SHA-256");
 md.update(value.getBytes());
 return bytesToHex(md.digest());
 } catch(Exception ex){
 throw new RuntimeException(ex);
 }
 }
 public static void main(String[] args) {
 SomeClass SC = new SomeClass();
 Gson gson = new Gson();
 String jsonString = gson.toJson(SC);
 JsonParser parser = new JsonParser();
 JsonElement jsonElement = parser.parse(jsonString);
 JsonObject data = jsonElement.getAsJsonObject();
 JsonObject rootObject = new JsonObject();
 rootObject.addProperty("sign", getSha256(jsonString));
 rootObject.add("data", data);
 System.out.println(gson.toJson(rootObject));
 }
}

After all I get this String {"sign":"c196a32af925e19897b00f430d9043854ccd5c109d2aee10ec15dfa2bbc060b9","data":{"n1":0.0,"n2":3.2544572232515347E-4}}

The problem happens when I try to parse JSON in JS and check sign.

function checkHash(data){
 return data.key === sha(config.server_key + JSON.stringify(data.data) + config.server_key);
}

This function return false because the sign of data in JS is f5bcb176b734f6a38eae9f0a332a00ae3b798c918ec505bc50baac84b3b1a43a

And I if I look at JSON in JS it looks like {"n1":0,"n2":0.00032544572232515347} So, there is a problem with double in parsing JSON in JS.

And there are some questions:

1) Maybe there is a way to parse JSON by levels(like GSON, dataObject.get("data").getAsString())? I searched a library but I coudn't find anything.

2) Maybe there is another way to sign JSON data in JAVA and check sign in JS?

I found that I can use custom JSONWriter in GSON, but I think there must be more simple way.

Update for people who may search this question

I used java.security.MessageDigest to make sha256, and it worked fine until I sent some long data. When I package program with Maven it starts making wrong hashes. Using org.apache.commons.codec.digest.DigestUtils.sha256Hex solved my problem.

asked Feb 8, 2018 at 8:31
5
  • "So, there is a problem with double in parsing JSON in JS." Yea, you can't "Double parse" JSON. Commented Feb 8, 2018 at 8:38
  • This has nothing to do with parsing JSON. Open a console and copy/paste console.log(3.2544572232515347E-4); It's resolves the value of 3.2544572232515347 / 10^4 and shows 0.00032544572232515347. If you want to keep the value in its original state then pass it as a string, not a double. Commented Feb 8, 2018 at 8:44
  • That said, if the precision is fixed (always 16) then you can use data.data.n2.toExponential(16) Commented Feb 8, 2018 at 8:47
  • @Archer Thank you, but data structure can be different, Commented Feb 8, 2018 at 9:17
  • Just stop using numbers for keys then. Commented Feb 8, 2018 at 9:25

1 Answer 1

2

The issue here is that data.data is a structure of variables in memory, not a simple stream of bytes you can hash. Depending on whitespace and ordering, there are many, many valid string representations of this data, one of which (presumably) hashes to c196a32af925e19897b00f430d9043854ccd5c109d2aee10ec15dfa2bbc060b9, and there is no way for JSON.stringify to know which you want. (I can't actually see any salting happening in your Java code though?)

if you want to check the signature, you'll need to either pass the object as

{ "data": "{\"value\": 1234}", "sig": "abcd" }

then parse it to get a string and a signature, verify they match, and then parse the string to get the data; or else move the signature to a header and check it against the entire JSON payload before you parse it. The latter is rather more elegant but may be harder to implement.

Equally of course you can do this out-of-the-box simply by using a TLS connection, but of course that might be tricky depending on your server &c.

answered Feb 8, 2018 at 8:48
Sign up to request clarification or add additional context in comments.

1 Comment

Thank you! I thought about it but it will be a bit strange to send JSON in JSON. But I will use it if there are no any other ways.

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.