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

标签 go cryptography hmac

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

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

我为每种语言开发了一个示例测试:Go , PHPJavaScript .

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


开始

package main

import (
    "crypto/hmac"
    "crypto/sha256"
    "encoding/base64"
    "fmt"
)

func main() {
    data := "My name is Danniel"

    mac := hmac.New(sha256.New, []byte("secret"))
    mac.Write([]byte(data))

    macSum := mac.Sum(nil)
    data64 := base64.StdEncoding.EncodeToString(macSum)
    fmt.Println(fmt.Sprintf("mac: %s | b64: %s", macSum, data64))

    data64 = base64.StdEncoding.EncodeToString([]byte("My name is Danniel"))
    fmt.Println(fmt.Sprintf("b64: %s", data64))
}

输出

mac: 6��q��0��5й��|��G�#0��ih | b64: NqzRcf/FMLPvo678NdC58JB8lgOFR+wjMNQDDwSkaWg=
b64: TXkgbmFtZSBpcyBEYW5uaWVs

PHP

$data = 'My name is Danniel';

$macSum = hash_hmac('sha256', $data, 'secret');
$data64 = base64_encode($macSum);
echo sprintf('mac: %s | b64: %s', $macSum, $data64) . "\n";

$data64 = base64_encode('My name is Danniel');
echo sprintf('b64: %s', $data64) . "\n";

输出

mac: 36acd171ffc530b3efa3aefc35d0b9f0907c96038547ec2330d4030f04a46968 | b64: MzZhY2QxNzFmZmM1MzBiM2VmYTNhZWZjMzVkMGI5ZjA5MDdjOTYwMzg1NDdlYzIzMzBkNDAzMGYwNGE0Njk2OA==
b64: TXkgbmFtZSBpcyBEYW5uaWVs

JavaScript

var data = 'My name is Danniel';

var mac = CryptoJS.HmacSHA256(data, 'secret');
var macSum = mac.toString();
var data64 = btoa(macSum)
console.log('mac: ' + macSum + ' | b64: ' + data64);

var data64 = btoa('My name is Danniel')
console.log('b64: ' + data64);

输出

"mac: 36acd171ffc530b3efa3aefc35d0b9f0907c96038547ec2330d4030f04a46968 | b64: MzZhY2QxNzFmZmM1MzBiM2VmYTNhZWZjMzVkMGI5ZjA5MDdjOTYwMzg1NDdlYzIzMzBkNDAzMGYwNGE0Njk2OA=="
"b64: TXkgbmFtZSBpcyBEYW5uaWVs"

最佳答案

问题是您的 PHP 和 JavaScript 代码都这样做:Base64(Hex(Hmac(key, msg)))。你真的不需要双重编码。

在 PHP 中,您可以简单地请求 raw_encoding 而不是 hex:

$macSum = hash_hmac('sha256', $data, 'secret'<b>, true</b>);

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

var data64 = mac.toString(CryptoJS.enc.Base64);

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

var data = 'My name is Danniel';
  
var mac = CryptoJS.HmacSHA256(data, 'secret');
var macSum = mac.toString();
var data64 = mac.toString(CryptoJS.enc.Base64)
document.write('mac: ' + macSum + ' | b64: ' + data64);

var data64 = btoa('My name is Danniel')
document.write('<br>b64: ' + data64);
<script src="https://cdn.rawgit.com/CryptoStore/crypto-js/3.1.2/build/rollups/hmac-sha256.js"></script>
  <script src="https://cdn.rawgit.com/CryptoStore/crypto-js/3.1.2/build/components/enc-base64.js"></script>

关于go - 为什么 Go 生成的 hmac 哈希与 PHP 和 JavaScript 不同?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35584879/

相关文章:

pointers - golang 和指针接收器中的自定义错误

c# - 如何验证 PayPal Webhook 签名?

c# - 如何从 C# 应用程序发送签名的电子邮件?

javascript - 是否有任何接受十六进制输入的 JavaScript 加密 HMAC 库?

postgresql - 在 GoLang 中将图像转换为 Base64

shell - ssh 在 golang 中使用交互式 shell 执行 nsenter 作为远程命令来调试 docker 容器

java - AES 256-CBC 上的 key 和 iv 问题

node.js - AWS4 S3 POST 签名计算失败示例

javascript - 将 HMAC-SHA384 函数从 Java 转换为 JavaScript

go - 为什么 golang sched 在变量为奇数或偶数时运行不同?是巧合还是命中注定?