首頁 >後端開發 >Golang >hmac.New(h func() hash.Hash, key byte) hash.Hash 在 JavaScript 中等效

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

WBOY
WBOY轉載
2024-02-09 08:12:18566瀏覽

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

在PHP中,我們經常需要使用加密演算法來保護資料的安全性。 HMAC(Hash-based Message Authentication Code)是一種常用的加密演算法,用於驗證資料完整性和身份認證。在PHP中,我們可以使用hmac.New()函數來建立HMAC實例,該函數需要指定一個雜湊函數和一個金鑰。與此類似,在JavaScript中,我們可以使用等效的方法來實現相同的功能。在本文中,我將為您介紹如何在JavaScript中使用等效的方法來建立HMAC實例,以及如何在PHP和JavaScript之間進行資料的加密和解密。

問題內容

差點在go lang hmac.new的js實作中卡住好幾天了。然而,沒有成功。我使用 cryptocrypto-jsstablelib 模組進行實作。問題是,在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 版本的輸出與您的實作的輸出相同時;您的解決方案是正確的。

解決方法

根據規格 (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
}

編輯:

這篇文章的啟發,以下是hmac_rec() 的更緊湊/高效的實現,它使用常規最後一個迭代步驟的hmac(這也使得gethash() 過時):

function hmac_rec(data, keyList) {
    var key = keyList.pop()
    if (keyList.length > 0) {
        
        // adjust key (according to HMAC specification)
        if (key.length > blockSize) {        
            k = Buffer.allocUnsafe(blockSize).fill('\x00');
            hmac_rec(key, [...keyList]).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
        var innerHMac = hmac_rec(Buffer.concat([ ik, data ]), [...keyList]) 
        var outerHMac = hmac_rec(Buffer.concat([ ok, innerHMac ]), [...keyList])
    } else {
        var outerHMac = crypto.createHmac(digest, key).update(data).digest();
    }  
    return outerHMac 
}

以上是hmac.New(h func() hash.Hash, key byte) hash.Hash 在 JavaScript 中等效的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:stackoverflow.com。如有侵權,請聯絡admin@php.cn刪除