I try to convert one go hmac usecase into nodejs, for normal hmac I know how to convert it into nodejs. But I have the below go code.
Note: go
hmac.New
first arg is a custom hash which is HMAC. But I didn't find any alternative in nodejs version.
Nodejs [createHmac][1] only support string hash algorithm, and can't support custom hash algorithm. Does anyone know how to implement the same feature in nodejs?
package main
import (
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"fmt"
"hash"
)
func main() {
hmacf := hmac.New(func() hash.Hash {
return hmac.New(sha256.New, []byte("inner-key1"))
}, []byte("inner-key2"));
hmacf.Write([]byte("message"))
fmt.Println(hex.EncodeToString(hmacf.Sum(nil)))
}
| [1]: https://nodejs.org/api/crypto.html#cryptocreatehmacalgorithm-key-options
HMAC by definition uses a digest internally and not an HMAC. Therefore, the Go implementation is actually a generalization of the HMAC definition and it is not surprising that most libraries do not support this, just as it is not supported out-of-the-box by NodeJS.
However, because of the comparatively simple definition of HMAC, it is easy to implement the required functionality.
The following is a recursive implementation that uses the crypto library:
const crypto = require('crypto')
function hmac_rec(data, keyList) {
const digest = 'sha256', blockSizeOfDigest = 64
var key = keyList.pop()
if (keyList.length > 0) {
// adjust key (according to HMAC specification)
if (key.length > blockSizeOfDigest) {k = Buffer.allocUnsafe(blockSizeOfDigest).fill('\x00'); hmac_rec(key, [...keyList]).copy(k)}
else if (key.length < blockSizeOfDigest) {k = Buffer.allocUnsafe(blockSizeOfDigest).fill('\x00'); key.copy(k)}
else k = key
// create 'key xor ipad' and 'key xor opad' (according to HMAC specification)
var ik = Buffer.allocUnsafe(blockSizeOfDigest), ok = Buffer.allocUnsafe(blockSizeOfDigest)
k.copy(ik); k.copy(ok)
for (var i = 0; i < ik.length; i++) {ik[i] = 0x36 ^ ik[i]; ok[i] = 0x5c ^ ok[i]}
// calculate HMac(HMac)
var innerHMac = hmac_rec(Buffer.concat([ ik, data ]), [...keyList])
var hMac = hmac_rec(Buffer.concat([ ok, innerHMac ]), [...keyList])
} else {
// calculate regular HMac(Hash)
var hMac = crypto.createHmac(digest, key).update(data).digest();
}
return hMac
}
Test:
var keyList = [ Buffer.from('inner-key1'), Buffer.from('inner-key2') ]
var data = Buffer.from('message', 'utf8')
var result = hmac_rec(data, keyList)
console.log(result.toString('hex')) // 48d2fcee3d16024d053db80f3e7140b853159f69d15a66d4cd6fad907b44e0cf
in accordance with the result of the posted Go Code.