Anexon
Anexon

Reputation: 133

CryptoJS and Crypto (nodejs) won't generate the same HMAC SHA256 hash

A third party API provider requires a signature to be sent in the headers. They have have shared They gave us a working example in Postman. In the example they do a Hmac SHA256 encoded in base64 + UTF8. For that they use CryptoJS. However, I need to use crypto (nodejs library) due to some environment limitations.

Nevertheless, I'm not able to generate the same signature using both libraries, at least without adding the UTF-8 encoding.

Am I missing a step here?

import CryptoJS from 'crypto-js';
import crypto from 'crypto';

const _method = "GET";
const _host = "mycustom.domain.com";
const _resourceUri = "/api/resource/11058723";
const _requestBody = "";
const _apiVersion = "1.5";
const _timeStamp = "2023-02-21T13:54:10Z";

let stringToSign = _method +
    "\n" +
    _host +
    "\n" +
    _resourceUri +
    "\n" +
    _requestBody +
    "\n" +
    _apiVersion +
    "\n" +
    _timeStamp +
    "\n";

const _secretKey = "this_is_a_secret_key"

// -- BEGIN -- POSTMAN EXSAMPLE
// CRYPTO-JS SIG
const sig = CryptoJS.HmacSHA256(stringToSign, _secretKey);
const sigBase64_utf8_encoding = CryptoJS.enc.Base64.stringify(CryptoJS.enc.Utf8.parse(sig));
const sigBase64 = CryptoJS.enc.Base64.stringify(sig);

console.log("SIG - HMAC (CryptoJS) + UTF8 enc.: ", sigBase64_utf8_encoding);
// HMAC (CryptoJS) + UTF8 enc.:  YmVhZWZlMTQ3MzQxODRjYWViY2I1MWVhMDUxMDk3OTlkODgyZTEyNjQ0OGFiNTM3NTgwM2ExOTg0OGEwZDRjOQ==
console.log("SIG - HMAC (CryptoJS): ", sigBase64);
// HMAC (CryptoJS):  vq7+FHNBhMrry1HqBRCXmdiC4SZEirU3WAOhmEig1Mk=
// -- END -- POSTMAN EXAMPLE

// CRYPTO SIG
const hmac = crypto.createHmac('sha256', _secretKey);
const sig_2 = hmac.update(stringToSign);
const sigBase64_2 = sig_2.digest('base64');
const sig_utf8_2 = Buffer.from(sigBase64_2).toString('utf8');
console.log("SIG - HMAC (Crypto): ", sigBase64_2);
// SIG - HMAC (Crypto): vq7+FHNBhMrry1HqBRCXmdiC4SZEirU3WAOhmEig1Mk=
console.log("SIG - HMAC - UTF8 (Crypto): ", sig_utf8_2);
// SIG - HMAC - UTF8 (Crypto): vq7+FHNBhMrry1HqBRCXmdiC4SZEirU3WAOhmEig1Mk=

This is the expected signature I should get with the example from above: YmVhZWZlMTQ3MzQxODRjYWViY2I1MWVhMDUxMDk3OTlkODgyZTEyNjQ0OGFiNTM3NTgwM2ExOTg0OGEwZDRjOQ==

I would need to get the same signature using crypto library instead of CryptoJs

Upvotes: 3

Views: 1814

Answers (1)

jps
jps

Reputation: 22465

This is the expected signature I should get with the example from above: YmVhZWZlMTQ3MzQxODRjYWViY2I1MWVhMDUxMDk3OTlkODgyZTEyNjQ0OGFiNTM3NTgwM2ExOTg0OGEwZDRjOQ==

When you decode it, you'll find a HEX String inside:

beaefe14734184caebcb51ea05109799d882e126448ab5375803a19848a0d4c9

The following code use "hex" output of the digest function and Base64 encodes it, the results are shown in the code comments:

const hmac = crypto.createHmac('sha256', _secretKey);
const sig_2 = hmac.update(stringToSign);
const sigHex = sig_2.digest('hex');
const sigBase64 = Buffer.from(sigHex).toString('base64');
console.log("SIG - HMAC (Crypto HEX): ", sigHex);
// SIG - HMAC (Crypto): beaefe14734184caebcb51ea05109799d882e126448ab5375803a19848a0d4c9
console.log("SIG - HMAC - Base64 (Crypto): ", sigBase64);
// SIG - HMAC - UTF8 (Crypto): YmVhZWZlMTQ3MzQxODRjYWViY2I1MWVhMDUxMDk3OTlkODgyZTEyNjQ0OGFiNTM3NTgwM2ExOTg0OGEwZDRjOQ==

Note: actually it seems to be quite unusual that a Base64 encoded Hex string is required. Usually, either a Hex string or a Base64 string of the original binary data is required, i.e. like this: vq7+FHNBhMrry1HqBRCXmdiC4SZEirU3WAOhmEig1Mk=.

Upvotes: 4

Related Questions