Heim  >  Artikel  >  Backend-Entwicklung  >  hmac.New(h func() hash.Hash, Schlüsselbyte) hash.Hash-Äquivalent in JavaScript

hmac.New(h func() hash.Hash, Schlüsselbyte) hash.Hash-Äquivalent in JavaScript

WBOY
WBOYnach vorne
2024-02-09 08:12:18456Durchsuche

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

In PHP müssen wir häufig Verschlüsselungsalgorithmen verwenden, um die Datensicherheit zu gewährleisten. HMAC (Hash-based Message Authentication Code) ist ein häufig verwendeter Verschlüsselungsalgorithmus zur Überprüfung der Datenintegrität und Identitätsauthentifizierung. In PHP können wir eine HMAC-Instanz mit der Funktion hmac.New() erstellen, die die Angabe einer Hash-Funktion und eines Schlüssels erfordert. Ebenso können wir in JavaScript äquivalente Methoden verwenden, um die gleiche Funktionalität zu erreichen. In diesem Artikel zeige ich Ihnen, wie Sie mit entsprechenden Methoden in JavaScript eine HMAC-Instanz erstellen und wie Sie Daten zwischen PHP und JavaScript ver- und entschlüsseln.

Frageninhalt

Ich steckte mehrere Tage lang fast in der js-Implementierung von go lang hmac.new fest. Es gab jedoch keinen Erfolg. Ich verwende cryptocrypto-jsstablelib 模块进行实现。问题是,在go lang版本中,hmac实例可以通过hmac Instanzerstellung. Zum Beispiel (Codeblock ist korrekt und getestet):

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]))

Eigentlich weiß ich auch nicht, wie es funktioniert! Denn in allen Javascript-bezogenen Modulen können Sie keine Werte von hmac 创建 hmac,并且它们接受确定哈希算法的 string erhalten.

Vielleicht wäre es besser, in Javascript zu fragen, wie man von hmac创建hmac kommt.

Was ist die Lösung?

Wenn die Ausgabe der Go-Version mit der Ausgabe Ihrer Implementierung übereinstimmt, ist Ihre Lösung korrekt.

Workaround

Gemäß der Spezifikation (rfc 2104) verwendet hmac intern Digest-Funktionen, wie z. B. sha256.

Ihre Implementierung wendet jedoch einen HMac an (und ist damit tatsächlich nicht kompatibel), der intern einen anderen HMac anstelle des Digests verwendet, wobei nur der HMac der niedrigsten Ebene intern den regulären Digest verwendet. Dadurch entsteht eine verschachtelte Struktur.

Basierend auf der Spezifikation von regulärem hmac (mit Digest) kann dies auf hmac mit hmac (anstelle von Digest) erweitert werden, das im Go-Code verwendet wird:

hmac(k xor opad, hmac(k xor ipad, text))s. rfc2104, Abschnitt 2. Definition von hmac

Aufgrund der Unterschiede zur Spezifikation ist es möglicherweise nicht so einfach, eine Javascript-Bibliothek zu finden, die diese Funktionalität sofort unterstützt.
Während die meisten Bibliotheken sicherlich hmac unterstützen, erlauben Sie nur die Angabe von Digests (nicht von hmac), wie z. B. dem Kryptomodul von nodejs crypto.createhmac(), siehe auch Andere Antworten. Ich glaube nicht, dass dieser Ansatz zur Implementierung von Logik in Go-Code verwendet werden kann.

Wenn die Ansätze der anderen Antworten nicht funktionieren und Sie keine andere Javascript-Bibliothek mit der gewünschten Funktionalität finden, können Sie die Logik selbst in Javascript implementieren, da die Spezifikation von hmac relativ einfach ist (siehe oben).

Der folgende Code ist eine Beispielimplementierung des Kryptomoduls von nodejs:

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()
}

Ergebnis:

2e631dcb4289f8256861a833ed985fa945cd714ebe7c3bd4ed4b4072b107b073

Test:

Der folgende Go-Code führt zum gleichen Ergebnis:

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
}

Herausgeber:

Inspiriert von diesem Artikel ist Folgendes hmac_rec() 的更紧凑/高效的实现,它使用常规最后一个迭代步骤的 hmac(这也使得 gethash() veraltet):

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 
}

Das obige ist der detaillierte Inhalt vonhmac.New(h func() hash.Hash, Schlüsselbyte) hash.Hash-Äquivalent in JavaScript. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:stackoverflow.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen