I'm trying to generate SHA256 and HmacSHA512 hashes on a device which unfortunately has no support for the standard Node crypto
library. So I am adjusting the code to use CryptoJS instead. However, CryptoJS cannot encode the Hash as in binary (only Hex, Base64 and Latin1 are available encoders).
Below is the function I'm trying to migrate. Previous (unusable) code is commented out.
const getMessageSignature = (path, request, secret, nonce) => {
// Expected outcome:
// API-Sign = Message signature using HMAC-SHA512 of (URI path + SHA256(nonce + POST data)) and base64 decoded secret API key
const message = JSON.stringify(request);
const secret_buffer = btoa(secret);
const hash = CryptoJS.algo.SHA256.create();
const hmac = CryptoJS.algo.HMAC.create(CryptoJS.algo.SHA256, secret_buffer);
const hash_digest = hash.update(nonce + message).finalize().toString(CryptoJS.enc.Base64);
const hmac_digest = hmac.update(path + hash_digest).finalize().toString(CryptoJS.enc.Base64);
// CANNOT USE BELOW (Buffer and crypto not supported)
// const secret_buffer = new Buffer(secret, 'base64');
// const hash = new crypto.createHash('sha256');
// const hmac = new crypto.createHmac('sha512', secret_buffer);
// const hash_digest = hash.update(nonce + message).digest('binary');
// const hmac_digest = hmac.update(path + hash_digest, 'binary').digest('base64');
return hmac_digest;
};
I found the answer. First of all: btoa()
is not necessary, as CryptoJS has its own functionality to turn Base64 into its own format (WordLists): CryptoJS.enc.Base64.parse
. Next up is that path
and hash_digest
cannot be merged properly as there's a Type Mismatch (string and binary), so JS uses the string representation. The solution is to first create a SHA512 HMAC using CryptoJS.algo.HMAC.create(CryptoJS.algo.SHA512, secret)
and then update it step-by-step for each value with hmac.update(value, secret)
. Finally, you'll also have to use CryptoJS' built-in Base64 decoder to finally produce the signature string.
const getMessageSignature = (path, request, secret, nonce) => {
// API-Sign = Message signature using HMAC-SHA512 of (URI path + SHA256(nonce + POST data)) and base64 decoded secret API key
const message = JSON.stringify(request);
const hash = CryptoJS.SHA256(nonce + message);
const secret_buffer = CryptoJS.enc.Base64.parse(secret);
const hmac = CryptoJS.algo.HMAC.create(CryptoJS.algo.SHA512, secret_buffer);
hmac.update(path, secret_buffer);
hmac.update(hash, secret_buffer);
return hmac.finalize().toString(CryptoJS.enc.Base64);
};