2016-09-16 218 views
0

使用Nodejs,我试图生成XML消息的HMAC SHA256,base64编码的签名。我目前有使用PHP的签名生成工作。问题与使用HMAC的数据的base64编码

该过程看起来相当简单,我可以用Nodejs生成base64编码的值,但由于某些原因,该值不匹配,并且比我使用PHP短得多。

下面,我已经包含了一个示例PHP脚本和结果以及Nodejs实现和结果。使用Nodejs,我使用本地加密模块。

// PHP implementation 

$xml = <<<EOD 
<?xml version='1.0' encoding='UTF-8'?> 
<dataset> 
    <record> 
    <id>1</id> 
    <first_name>Carlos</first_name> 
    <last_name>Ruiz</last_name> 
    <email>[email protected]</email> 
    <gender>Male</gender> 
    <ip_address>156.225.191.154</ip_address> 
    </record> 
</dataset> 
EOD; 

$secret = 'secret'; 
$sig = base64_encode(hash_hmac('sha256', $xml, $secret)); 

echo $sig; 

结果: ODhkYTc1YmQzNzc0NWUyNDJlNjY3YTY1NzZhYzFhZGYwOTJlMTIxODdjNzYxOWYyNGQxNGExOGVkYTIyZDQ0ZQ==

// Nodejs implementation 

var crypto = require('crypto'); 

fs.readFile('example.xml', 'utf-8', function(err, data) { 
    function sig(str, key) { 
    return crypto.createHmac('sha256', key) 
     .update(str) 
     .digest('base64'); 
    } 
    console.log(sig(data, 'secret')); 
}); 

结果: iNp1vTd0XiQuZnpldqwa3wkuEhh8dhnyTRShjtoi1E4=

我花了一天时间试图弄清楚这一点,一年使用堆栈溢出+后,这是我的第一次题。

任何援助将不胜感激!

+0

我在你的第一个例子中看到你的XML文件不是一个文件,而是一个字符串。那么....'example.xml'中的实际xml是什么?也就是说,sha256打印是256位或32字节,base64转换大约3/4,因此我们应该期望base64 HMAC打印长度大约为42个字符。因此,Node.js的结果肯定是*看起来正确的长度(43个字符,用'='填充以对齐到4个字节),而PHP字符串绝对不会。它* waaaaay *太长了。 –

+0

感谢您的答复,从mscdex的答案我能弄清楚我需要做什么。正如他解释的,在我的例子中,hash_hmac返回一个十六进制编码的字符串,然后进行base64编码。使用这些信息,我能够通过使用'hex'作为摘要来获取我的nodejs代码,转换为一个字符串并将该字符串编码为base64。 – oudelitonalituridalp

+0

只要你非常清楚**你没有生成base64编码的HMAC值,而是一个两倍的字符串,这是你的软件中优秀的睡眠错误。使消费代码期望base64编码的真正SHA-256 HMAC值是一个无限更好的解决方案。 –

回答

0

的这里的问题是,PHP的hash_hmac()默认返回一个十六进制编码的字符串(见$raw_output参数here),所以你的base64编码的十六进制字符串,而不是实际的原始二进制结果。

所以更改此设置:

$sig = base64_encode(hash_hmac('sha256', $xml, $secret)); 

到:

$sig = base64_encode(hash_hmac('sha256', $xml, $secret, true)); 
+0

感谢您的回复!我曾经想过,PHP是以某种/预期的方式运行的,我没有想到要深入研究这方面的事情。 从你的答案,我能够通过使用'十六进制'作为摘要,转换为字符串和base64编码,得到所需的结果。 – oudelitonalituridalp