简体   繁体   中英

How to replicate Node's Crypto.createHmac( 'sha256', buffer) in the browser?

How to get to "feature parity" between Node's Crypto.createHmac( 'sha256', buffer) and CryptoJS.HmacSHA256(..., secret) ?

I have a 3rd party code that does what you can see here as the method node1 . I would need to achieve the same result in the browser. Seemingly, the difference is in the that the secret is base64 decoded on the node side. But I still can't get the same output.

const CryptoJS = require('crypto-js')
const Crypto = require('crypto')

const message = "Message"
const secret = "Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw=="

function node1() {
  return Crypto.createHmac("sha256", Buffer.from(secret, 'base64'))
      .update(message, "utf8")
      .digest("base64");
}

function node2() {
  return Crypto.createHmac("sha256", Buffer.from(secret, 'base64').toString('base64'))
      .update(message, "utf8")
      .digest("base64");
}

function browser() {
  const crypted = CryptoJS.HmacSHA256(message, secret)
  return CryptoJS.enc.Base64.stringify(crypted)
}

console.log('node1', node1())
console.log('node2', node2())
console.log('browser-like', browser())

// node1 agitai8frSJpJuXwd4HMJC/t2tluUJPMZy8CeYsEHTE=
// node2 fxJQFWs5W3A4otaAlnlV0kh4yfQPb4Y1ChSVZsUAAXA=
// browser-like fxJQFWs5W3A4otaAlnlV0kh4yfQPb4Y1ChSVZsUAAXA=

So, I can reproduce a naive browser-like behaviour in node. This gave me the idea to use atob in the browser, to reproduce node's behaviour. The following sign method is my best guess on the browser side.

function sign(message) {
  const crypted = CryptoJS.HmacSHA256(message, atob(secret));
  return CryptoJS.enc.Base64.stringify(crypted)
}

function signNotDecoded(message) {
  const crypted = CryptoJS.HmacSHA256(message, secret);
  return CryptoJS.enc.Base64.stringify(crypted)
}

console.log('browser', sign('Message'))
console.log('browser-like', signNotDecoded('Message'))

// browser dnVm5jBgIBNV6pFd4J9BJTjx3BFsm7K32SCcEQX7RHA= 
// browser-like fxJQFWs5W3A4otaAlnlV0kh4yfQPb4Y1ChSVZsUAAXA=

So, running signDecoded() in the browser, and running browser() in node gives the same output. Running both node2() and browser() in node again provide the same output, but still sign() differs from node1() .

Based on the above, I'm quite sure that the problem is with my usage of atob, but what do I miss there?

Change

atob(secret)

To

CryptoJS.enc.Base64.parse(secret)

Because if you pass a raw string as key to the function it will be re-parsed as UTF-8.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM