为什么 Go 生成的 hmac 哈希值与 PHP 和 JavaScript 不同?

Dan*_*gno 1 cryptography go hmac

我开始用 Go 编写代码,并尝试通过检查客户端发送的签名来进行简单的请求验证。乍一看一切都很好,但经过几次验证真实请求的测试后,我发现 Go 生成了一个尴尬的哈希值。

\n\n

为了证明Go后端和JavaScript签名之间的不一致,我开发了相同签名方法的PHP版本,它给了我与JavaScript版本相同的结果,所以我的期望是正确的。

\n\n

我为每种语言开发了一个示例测试:GoPHPJavaScript

\n\n

那么,要在 Go 中达到 PHP 和 JavaScript 相同的结果,我应该怎么做呢?

\n\n
\n\n

\n\n
package main\n\nimport (\n    "crypto/hmac"\n    "crypto/sha256"\n    "encoding/base64"\n    "fmt"\n)\n\nfunc main() {\n    data := "My name is Danniel"\n\n    mac := hmac.New(sha256.New, []byte("secret"))\n    mac.Write([]byte(data))\n\n    macSum := mac.Sum(nil)\n    data64 := base64.StdEncoding.EncodeToString(macSum)\n    fmt.Println(fmt.Sprintf("mac: %s | b64: %s", macSum, data64))\n\n    data64 = base64.StdEncoding.EncodeToString([]byte("My name is Danniel"))\n    fmt.Println(fmt.Sprintf("b64: %s", data64))\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

输出

\n\n
mac: 6\xef\xbf\xbd\xef\xbf\xbdq\xef\xbf\xbd\xef\xbf\xbd0\xef\xbf\xbd\xef\xa3\xae\xef\xbf\xbd5\xd0\xb9\xef\xbf\xbd\xef\xbf\xbd|\xef\xbf\xbd\xef\xbf\xbdG\xef\xbf\xbd#0\xef\xbf\xbd\xef\xbf\xbdih | b64: NqzRcf/FMLPvo678NdC58JB8lgOFR+wjMNQDDwSkaWg=\nb64: TXkgbmFtZSBpcyBEYW5uaWVs\n
Run Code Online (Sandbox Code Playgroud)\n\n
\n\n

PHP

\n\n
$data = \'My name is Danniel\';\n\n$macSum = hash_hmac(\'sha256\', $data, \'secret\');\n$data64 = base64_encode($macSum);\necho sprintf(\'mac: %s | b64: %s\', $macSum, $data64) . "\\n";\n\n$data64 = base64_encode(\'My name is Danniel\');\necho sprintf(\'b64: %s\', $data64) . "\\n";\n
Run Code Online (Sandbox Code Playgroud)\n\n

输出

\n\n
mac: 36acd171ffc530b3efa3aefc35d0b9f0907c96038547ec2330d4030f04a46968 | b64: MzZhY2QxNzFmZmM1MzBiM2VmYTNhZWZjMzVkMGI5ZjA5MDdjOTYwMzg1NDdlYzIzMzBkNDAzMGYwNGE0Njk2OA==\nb64: TXkgbmFtZSBpcyBEYW5uaWVs\n
Run Code Online (Sandbox Code Playgroud)\n\n
\n\n

JavaScript

\n\n
var data = \'My name is Danniel\';\n\nvar mac = CryptoJS.HmacSHA256(data, \'secret\');\nvar macSum = mac.toString();\nvar data64 = btoa(macSum)\nconsole.log(\'mac: \' + macSum + \' | b64: \' + data64);\n\nvar data64 = btoa(\'My name is Danniel\')\nconsole.log(\'b64: \' + data64);\n
Run Code Online (Sandbox Code Playgroud)\n\n

输出

\n\n
"mac: 36acd171ffc530b3efa3aefc35d0b9f0907c96038547ec2330d4030f04a46968 | b64: MzZhY2QxNzFmZmM1MzBiM2VmYTNhZWZjMzVkMGI5ZjA5MDdjOTYwMzg1NDdlYzIzMzBkNDAzMGYwNGE0Njk2OA=="\n"b64: TXkgbmFtZSBpcyBEYW5uaWVs"\n
Run Code Online (Sandbox Code Playgroud)\n

Art*_* B. 5

问题是您的 PHP 和 JavaScript 代码都执行以下操作:Base64(Hex(Hmac(key, msg)))。你真的不需要双重编码。

在 PHP 中,您可以简单地请求raw_encoding而不是十六进制:

$macSum = hash_hmac('sha256', $data, 'secret', true);
Run Code Online (Sandbox Code Playgroud)

在 CryptoJS 中,您必须直接编码为 Base64,而不是编码为十六进制,然后使用btoa()

var data64 = mac.toString(CryptoJS.enc.Base64);
Run Code Online (Sandbox Code Playgroud)

为此,您需要包含 enc-base64.js 组件。

$macSum = hash_hmac('sha256', $data, 'secret', true);
Run Code Online (Sandbox Code Playgroud)
var data64 = mac.toString(CryptoJS.enc.Base64);
Run Code Online (Sandbox Code Playgroud)