Javascript: Equivalent of PHP's hash_hmac() with RAW BINARY output?
Asked Answered
V

6

18

I am connecting to the Amazon Product Advertising API, and to sign my request I need to base64-encode the raw binary output of an HMAC-SHA256 hash.

In the PHP documentation for hash_hmac, the fourth parameter bool $raw_output controls whether the output is raw binary data (true) or lowercase hexits (false). My program works in PHP by simply setting that parameter to true.

However, I am now trying to port this over to Javascript. I tried using the CryptoJS.HmacSHA256() function, but it seems to be returning the lowercase hexits. How can I convert this to binary?

I have tried the following according to the CryptoJS documentation, but both outputs are identical:

var hash = CryptoJS.HmacSHA256("hello", "key");
console.log(hash.toString());
console.log(hash.toString(CryptoJS.enc.Base64));
Venomous answered 23/8, 2012 at 19:59 Comment(0)
D
22

This is explained in their documentation. Try this:

var hash = CryptoJS.HmacSHA256("Message", "Secret Passphrase");

var base64 = hash.toString(CryptoJS.enc.Base64);

You need to include http://crypto-js.googlecode.com/svn/tags/3.0.2/build/components/enc-base64-min.js for this. If you didn't include this, CryptoJS.enc.Base64 will be undefined and fallback to the default.

Working demo: http://jsfiddle.net/ak5Qm/

Dungdungan answered 23/8, 2012 at 20:4 Comment(10)
I have already tried that, it doesn't seem to work. Please see my revised question for a better explanation.Venomous
@Kevin did you include the base64-min.js? Since it works fine here: jsfiddle.net/ak5QmDungdungan
Yes, I have included enc-base64.js from the "components" folder. Even without it there are no errors; is there a way for me to know whether it actually found it or not?Venomous
@Kevin if you use google chrome, press ctrl+shift+j when your page loads and see if there are errors. You can also simply write CryptoJS.enc.Base64 in your console to see if it's undefinedDungdungan
Like I said, there are no errors. However, the result of writing that IS undefined. Thank you, I'll look into what is causing the issue.Venomous
Yeah I meant, in my chrome at least, the console is populated with error messages for resources (such as scripts) that were not found. Like this: i.imgur.com/j6NQI.pngDungdungan
It turns out I had my scripts included in the wrong order: enc-base64 THEN hmac-sha256, rather than vice versa. Switching this order solved the problem. Thanks again!Venomous
<script src="crypto-js.googlecode.com/svn/tags/3.0.2/build/rollups/…> <script src="crypto-js.googlecode.com/svn/tags/3.0.2/build/components/…>Dennett
@Dungdungan I think the fiddle on longer works. Looks like Google moved those scriptsBleeder
Note : the CryptoJS HmacSHA256 function supports binary mode by default,Elinorelinore
S
10

PHP:

base64_encode(hash_hmac('sha256', $value, $key, true));

Nodejs equivalent:

const crypto = require('crypto');
let token = crypto.createHmac("sha256", key).update(value).digest().toString('base64');
Steinke answered 27/11, 2018 at 6:6 Comment(0)
O
4

php code

echo base64_encode(hash_hmac('SHA1', 'shanghai', '0', true).'beijing');

php output

xvBv49PpaYvXAIfy3iOSDWNQj89iZWlqaW5n

node code

var crypto = require('crypto');
var buf1 = crypto.createHmac("sha1", "0").update("shanghai").digest();
var buf2 = Buffer.from('beijing');
console.log(Buffer.concat([buf1, buf2]).toString('base64'));    

node output

xvBv49PpaYvXAIfy3iOSDWNQj89iZWlqaW5n
Oakland answered 22/9, 2017 at 12:48 Comment(1)
Your code is not clear, what is the key and what is the value?Elagabalus
N
1

For the web browser:

async hmac_sha1 (str, secret) {
  let enc = new TextEncoder("utf-8");
  let key = await window.crypto.subtle.importKey(
    "raw",
    enc.encode(secret),
    {
      name: "HMAC",
      hash: {name: "SHA-1"}
    },
    false,
    ["sign", "verify"]
  );
  let signature = await window.crypto.subtle.sign(
    "HMAC",
    key,
    enc.encode(str)
  );
  let b = new Uint8Array(signature);
  return Array.prototype.map.call(b, x => x.toString(16).padStart(2, '0')).join("");
}
Naturalism answered 16/4, 2023 at 17:26 Comment(0)
A
0

You can also use this npm package to do the same in Javascript.

var jsSHA = require('jssha');

hmac_sha1(string, key){
    let shaObj = new jsSHA("SHA-1", "TEXT");
    shaObj.setHMACKey(key, "TEXT");
    shaObj.update(string);
    let hmac = shaObj.getHMAC("B64");
    return hmac;
};
Abran answered 15/9, 2019 at 9:16 Comment(1)
You can put your private key's also into my public library !Dodiedodo
H
0

This worked for me :

var CryptoJS = require("crypto-js");
const raw_signature = hmacSHA1(baseString, signingKey);
const signature = raw_signature.toString(CryptoJS.enc.Base64);

It's giving the exact same result as, in PHP, :

$rawSignature = hash_hmac("sha1", $baseString, $signingKey, true);
$signature    = base64_encode($rawSignature);
Hightension answered 5/4, 2020 at 9:30 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.