0

I am trying to convert my node js POST call to Java. In doing so, i want to change the logic of HMAC signature generation to a java method. But the signature seems not matching in node js vs in java. I will paste my node js and java code below for your reference:

const crypto = require('crypto');
const CONTENT_TYPE = 'Content-Type';
const APPLICATION_JSON_UTF8 = 'application/json; charset=utf-8';
const SIGNATURE = 'X-Hub-Signature';


const botConfig = {
    webhookURL: 'WEBHOOK_URL',
    secretKey: 'hP6pFhyqazD3vCuw5wjzGwicqF3nPq1H'
};


function buildSignatureHeader(buf, secret) {
    return 'sha256=' + buildSignature(buf, secret);
}

function buildSignature(buf, secret) {
    const hmac = crypto.createHmac('sha256', Buffer.from(secret, 'utf8'));
    hmac.update(buf);
    return hmac.digest('hex');
}

app.get('/', function (req, res) {
    const recvMessage =  {
                        "userId":"USERID",
                        "messagePayload": {
                            "type":"agent",
                            "text": "hi",
                            "channelName":"ENDPOINT"
                        },
                        "profile": {"firstName": 'SOMEUSER'}
                      };




console.log("Going to Call");
 const data = Buffer.from(JSON.stringify(recvMessage), 'utf8');
 const headers = {};
    headers[CONTENT_TYPE] = APPLICATION_JSON_UTF8;
    headers[SIGNATURE]    = buildSignatureHeader(data, botConfig.secretKey);
    var interactive = false;
    var oauth=false;
    console.log('signature:'+  buildSignatureHeader(JSON.stringify(recvMessage), botConfig.secretKey));

In Java my Code for certificate generation looks like :

public class HmacSha1Signature {
  /*  public HmacSha1Signature() {
        super();
    }
*/
  private static final String HMAC_SHA1_ALGORITHM = "HmacSHA1";

          private static String toHexString(byte[] bytes) {
                  Formatter formatter = new Formatter();

                  for (byte b : bytes) {
                          formatter.format("%02x", b);
                  }

                  return formatter.toString();
          }

          public static String calculateRFC2104HMAC(String data, String key)
                  throws SignatureException, NoSuchAlgorithmException, InvalidKeyException
          {
               SecretKeySpec signingKey = new SecretKeySpec(key.getBytes(), "HmacSHA256");
              Mac mac = Mac.getInstance("HmacSHA256");
              mac.init(signingKey);

              return toHexString(mac.doFinal(data.getBytes()));
          }

          public static void main(String[] args) throws Exception {

                  String data= "{\n" + 
                  "                        \"userId\":\"USERID\",\n" + 
                  "                        \"messagePayload\": {\n" + 
                  "                            \"type\":\"agent\",\n" + 
                  "                            \"text\": \"hi\",\n" + 
                  "                            \"channelName\":\"CHANNEL\"\n" + 
                  "                        },\n" + 
                  "                        \"profile\": {\"firstName\": 'SOMEUSER'}\n" + 
                  "                      }";
                  String hmac = calculateRFC2104HMAC(data, "hP6pFhyqazD3vCuw5wjzGwicqF3nPq1H");

                  System.out.println(hmac);

          }
} 

In NODE JS my signature looks like:

2176fd6b050b536f65ac146fb8471f1472098a7cc5e17bc61f85cf82e06e45d7

While in java it is :

2a899031182deda92c4cf97dd84c246ff65371acb9c41c04c360e1ab512e6038

Can you guys help me pointing out the mistake i am making here. Why doesnt the signatures match ?

Bibin Mathew
  • 203
  • 3
  • 15

1 Answers1

0

For me the only way to compute HMAC signature that worked in Java is :

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;
import org.apache.commons.codec.binary.Hex;

final String HMAC_SHA512 = "HmacSHA512";
final String CHARSET = "ISO-8859-1";
final String HMAC_KEY = "0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF01...";

String hmacFootprint = null;
Mac mac = Mac.getInstance(HMAC_SHA512);
mac.init(new SecretKeySpec(DatatypeConverter.parseHexBinary(HMAC_KEY), mac.getAlgorithm()));
final byte[] macData = mac.doFinal(requestParameters.toString().getBytes());
byte[] hex = new Hex().encode(macData);
hmacFootprint = new String(hex, CHARSET).toUpperCase();

Hope it helps.

Thanks to this answer : java hmac/sha512 generation

Paul
  • 1,410
  • 1
  • 14
  • 30