hmac.New(h func() hash.Hash, key []byte) hash.Hash 在 javascript 中等效

问题描述 投票:0回答:2

我差点就在go lang hmac.New的js实现中卡住好几天了。然而,没有成功。我使用了

crypto
crypto-js
stablelib
模块来实现。问题是,在go lang版本中,
hmac
实例可以通过
hmac
实例创建。例如(代码块是正确且经过测试的):

hmacf := hmac.New(func() hash.Hash {
    return hmac.New(func() hash.Hash {
        return hmac.New(func() hash.Hash {
            return hmac.New(sha256.New, []byte(SALT))
        }, []byte(path[0]))
    }, []byte(path[1]))
}, []byte(path[2]))

其实我也不知道它是怎么运作的!因为在所有与 javascript 相关的模块中,您无法从

hmac
创建
hmac
,并且它们接受确定哈希算法的
string
值。

也许最好询问如何在 javascript 中从

hmac
创建
hmac

解决办法是什么?

当 go 版本的输出与你的实现的输出相同时;您的解决方案是正确的。

javascript go hash hmac
2个回答
2
投票

根据规范(RFC 2104),HMAC 在内部使用摘要函数,例如SHA256。

但是,您的实现应用了(实际上不兼容)内部使用另一个 HMAC 而不是摘要的 HMAC,其中只有最低级别的 HMAC 在内部使用常规摘要。这样就创建了一个嵌套结构。

基于常规 HMAC(带有摘要)的规范,这可以扩展到 Go 代码中使用的带有 HMAC(而不是摘要)的 HMAC:

HMAC(K XOR opad, HMAC(K XOR ipad, text))
s。 RFC2104,第 2 节。HMAC 的定义


由于与规范的差异,找到一个开箱即用的支持此类功能的 JavaScript 库可能不会那么容易。
虽然大多数库当然支持 HMAC,但只允许指定摘要(而不是 HMAC),例如NodeJS 的 crypto 模块的

crypto.createHmac()
,另见其他答案。我不认为这种方法可以用来实现 Go 代码中的逻辑。

如果其他答案的方法不起作用,并且您找不到另一个具有所需功能的 JavaScript 库,您可以自己在 JavaScript 中实现逻辑,因为 HMAC 的规范相对简单(如上所述)。


以下代码是NodeJS的crypto模块的示例实现:

var crypto = require('crypto')

const digest = 'sha256'
const blockSize = 64 // block size of the digest

// define input parameter
var salt = Buffer.from('salt')
var path = [ Buffer.from('alfa'), Buffer.from('beta'), Buffer.from('gamma') ]
var data = Buffer.from('data')

// calculate HMAC
var hmac = hmac(data, salt, path)
console.log(hmac.toString('hex'))

function hmac(data, salt, path) {
    
    // create keyList
    var keyList = []
    keyList.push(salt)
    keyList = keyList.concat(path)

    // determine HMAC recursively
    var result = hmac_rec(data, keyList)
    return result
}

function hmac_rec(data, keyList) {

    // adjust key (according to HMAC specification)
    var key = keyList.pop()
    if (key.length > blockSize) {        
        k = Buffer.allocUnsafe(blockSize).fill('\x00');
        if (keyList.length > 0) {
            hmac_rec(key, [...keyList]).copy(k)
        } else {
            getHash(key).copy(k)
        }
    } else if (key.length < blockSize) {
        k = Buffer.allocUnsafe(blockSize).fill('\x00');
        key.copy(k)
    } else {
        k = key
    }

    // create 'key xor ipad' and 'key xor opad' (according to HMAC specification)  
    var ik = Buffer.allocUnsafe(blockSize)
    var ok = Buffer.allocUnsafe(blockSize)
    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
    if (keyList.length > 0) {
        var innerHMac = hmac_rec(Buffer.concat([ ik, data ]), [...keyList]) 
        var outerHMac = hmac_rec(Buffer.concat([ ok, innerHMac ]), [...keyList])
    } else {
        var innerHMac = getHash(Buffer.concat([ik, data]))
        var outerHMac = getHash(Buffer.concat([ok, innerHMac]))
    }
  
    return outerHMac 
}

// calculate SHA256 hash
function getHash(data){
    var hash = crypto.createHash(digest);
    hash.update(data)
    return hash.digest()
}

结果:

2e631dcb4289f8256861a833ed985fa945cd714ebe7c3bd4ed4b4072b107b073

测试:

以下 Go 代码产生相同的结果:

package main

import (
    "crypto/hmac"
    "crypto/sha256"
    "encoding/hex"
    "fmt"
    "hash"
)

func main() {
    SALT := "salt"
    path := []string{"alfa", "beta", "gamma"}
    hmacf := hmac.New(func() hash.Hash {
        return hmac.New(func() hash.Hash {
            return hmac.New(func() hash.Hash {
                return hmac.New(sha256.New, []byte(SALT))
            }, []byte(path[0]))
        }, []byte(path[1]))
    }, []byte(path[2]))
    hmacf.Write([]byte("data"))
    result := hmacf.Sum(nil)
    fmt.Println(hex.EncodeToString(result)) // 2e631dcb4289f8256861a833ed985fa945cd714ebe7c3bd4ed4b4072b107b073
}

0
投票

也许你需要这样的东西?

const crypto = require('crypto');

const encoding = 'hex';
const SALT = 'your_salt_value';
const path = ['path1', 'path2', 'path3'];

const hmacf = crypto.createHmac('sha256', SALT)
    .update(path[0])
    .digest(encoding);
const hmacf2 = crypto.createHmac('sha256', hmacf)
    .update(path[1])
    .digest(encoding);
const hmacf3 = crypto.createHmac('sha256', hmacf2)
    .update(path[2])
    .digest(encoding);
        
console.log(hmacf3);
© www.soinside.com 2019 - 2024. All rights reserved.