1

This is the java function that does the job.

 static byte[] HmacSHA384(String data, byte[] key) {
    try {
        mac.init(new SecretKeySpec(key, HMAC_ALGORITHM));
    } catch (InvalidKeyException e) {
        //throw new PWAINUnRecoverableException("Invalid key exception while mac init", e);
        throw new RuntimeException("Invalid key exception while mac init", e);
    }
    return mac.doFinal(data.getBytes(StandardCharsets.UTF_8));
}

I've already tried this answer with no luck.

Used crypto-js module also as:

const result = crypto_js.HmacSHA384(key, data).toString();
console.log(result.split('').map(getBytes)); // used this to match byte array from java output. No luck!
function getBytes(x) {return x.charCodeAt(0);}

Note that I'm using key as a String in JavaScript code as crypto_js.HmacSHA384 accepts String only and not a byte[]. But I've compared my string's byte[] with java code's byte[].

Output from JS code:

[97,104,69,80,106,49,121,83,100,87,120,56,76,65,101,71,54,52,81,110,104,108,72,55,54,56,112,104,56,109,72,101,68,43,83,70,73,89,54,81,71,53,49,98,48,119,115,117,72,83,112,117,99,110,107,76,113,78,105,73,76,107,120,82]

Output from Java code:

[-29, 76, -16, -110, -35, -87, 18, -53, -1, -105, -77, -96, -49, -110, 102, -74, -110, 31, -87, 115, 102, -43, 101, -89, -82, -8, 96, -99, -89, 103, -128, 104, -121, -107, -98, 18, -18, 85, 97, -121, 30, 91, -42, -11, -6, -58, -7, 113]

Both takes same input.

Any help will be appreciated. Thanks!

  • Input data are same? Please double check the input data. – Mostafa Nov 21 '19 at 08:03
  • And even better, post a complete example, i.e. including corresponding `data` and (test-) `key` (otherwise the output data won't help much). `result` on the CryptoJS-side contains the return value as _hexadecimal string_. For a comparison with the Java-side simply use e.g. [`bytesToHex`](https://stackoverflow.com/a/9855338). – Topaco Nov 21 '19 at 09:48

1 Answers1

3

In JavaScript it's not so easy to output raw bytes. See the answer https://stackoverflow.com/a/29433028/7873775 for the details.

But the byte arrays will still be different in Java and JavaScript because in JavaScript the Uint8Array represents an array of 8-bit unsigned integers while in Java byte range is from -128 to 127.

So Uint8Array [132, 179] in Java byte[] is [-124, -77].

To output the HMAC value in JavaScript you need to encode it in either Hex or Base64.

Here is Java code using commons-codec library:

byte[] key = "Secret Passphrase".getBytes(StandardCharsets.UTF_8);
String valueToDigest = "Message";
byte[] hmac = new HmacUtils(HMAC_SHA_384, key).hmac(valueToDigest);
System.out.println(asList(hmac));
System.out.println(Hex.encodeHexString(hmac));
System.out.println(Base64.encodeBase64String(hmac));

The result:

  • Hex: 84b318cc0232a370c1f8b8746afcb575fc2debc680122c7422fd425638896d0dcf9e905b8cd9c1d7aed8d5439a2a2328
  • Base64: hLMYzAIyo3DB+Lh0avy1dfwt68aAEix0Iv1CVjiJbQ3PnpBbjNnB167Y1UOaKiMo

Here is code with CryptoJS library:

const CryptoJS = require("crypto-js");
const hash = CryptoJS.HmacSHA384("Message", "Secret Passphrase");
console.log(hash.toString(CryptoJS.enc.Hex));
console.log(hash.toString(CryptoJS.enc.Base64));

And the result is identical:

  • Hex: 84b318cc0232a370c1f8b8746afcb575fc2debc680122c7422fd425638896d0dcf9e905b8cd9c1d7aed8d5439a2a2328
  • Base64: hLMYzAIyo3DB+Lh0avy1dfwt68aAEix0Iv1CVjiJbQ3PnpBbjNnB167Y1UOaKiMo
Eugene Khyst
  • 9,236
  • 7
  • 38
  • 65
  • However, all my outputs are not correct. Suppose I've to encrypt "x" with "y" as key then the result of java and javascript's encryption will differ in case of special characters such as '+' is replaced with '-', '/' is replaced with '_', etc. Rest all the alphabets remains same. e.g. In JS - `MPz+nWPmqSXoNENkMTtw38I3Qwnxf5gZzDLQAFr80mkCz9F2vdStf44ySzlk/+Wf` In Java - `MPz-nWPmqSXoNENkMTtw38I3Qwnxf5gZzDLQAFr80mkCz9F2vdStf44ySzlk_-Wf` I don't know what is causing this exactly. Is this an encoding issue? – Aryan Arora Nov 22 '19 at 05:50
  • The Java lib uses "Base 64 Encoding with URL and Filename Safe Alphabet'" in RFC 4648. The alphabet uses '-' instead of '+' and '_' instead of '/'. The JS lib uses RFC 2045. The hex values must be exactly the same. To use in Java RFC 2045 do `Base64.getEncoder().encodeToString(bytes)`. See https://docs.oracle.com/javase/8/docs/api/java/util/Base64.html – Eugene Khyst Nov 22 '19 at 07:15
  • Thanks a lot! I was banging my head over this. This was very helpful. :) – Aryan Arora Nov 22 '19 at 10:20