I currently have this snippet in Python –
import base64 import hashlib import hmac def hash_hmac(self, key, data): res = hmac.new(base64.b64decode(key), data.encode(), hashlib.sha512).digest() return res
I am trying to replicate it in Node.js, but having difficulty getting the correct hash.
const crypto = require('crypto') const hashHmac = (key, message) => { return crypto.createHmac('sha512', Buffer.from(key, 'base64').toString('utf-8')) .update(message) .digest() .toString('base64') }
Test case: Key: ‘7pgj8Dm6’ Message: ‘TestMessage’
With the python snippet, the hash is
69H45OZkKcmR9LOszbajUUPGkGT8IqasGPAWqW/1stGC2Mex2qhIB6aDbuoy7eGfMsaZiU8Y0lO3mQxlsWNPrw==
With the js snippet, the hash is
OhaJU9IibhhjIjz3R7FmodgOBUPjwhndXX8gn0r2rRzjQvCJl4T40rHXKw3o6Y2JQ5fVHTeStu8K1DRMWxMGBg==
Am I going wrong with the base64 encoding?
Advertisement
Answer
In the NodeJS code, the key is first Base64 decoded and then UTF-8 decoded. Since the key contains byte sequences that are not defined by UTF-8, it is thereby damaged.
Arbitrary binary data, such as ciphertexts, hashes, or keys (at least if randomly generated), must be stored in binary, or a binary-to-text encoding like Base64 must be used (and not a character set encoding like UTF-8) if they are to be converted to a string, see also here.
In the posted example, converting the buffer to a string is not necessary at all. The key can simply be passed directly as a buffer, s. crypto.createHmac()
, i.e. as follows:
var hmac = crypto.createHmac('sha512', Buffer.from(key, 'base64'));
With this, the NodeJS code returns the same result as the Python code.