php - Node Crypto createHmac() 输出与具有相同输入的 PHP hash_hmac() 输出不同吗?

标签 php node.js

我正在尝试在 Node.js 中复制一个 PHP 哈希生成函数。此哈希用作 API 的一部分。 PHP 版本创建系统接受的正确输出。尽管我认为函数的输入相同,但 Node 版本会创建不同的输出。

这是因为 PHP 和 Node HMAC 函数的工作方式有一些根本不同吗?还是因为我只是缺少字符编码的一些怪癖?还是我只是搞砸了其他事情?


PHP代码

$url = 'https://example.com/api/endpoint';
$user = 'apiuser';

// Example key
$key = '+raC8YR2F+fZypNJ5q+CAlqLFqNN1AlAfWwkwJLcI7jrAvppjRPikWp523G/u0BLSpN9+2LusJvpSwrfU9X2uA==';

$timestamp = gmdate('D, d M Y H:i:s T', 1543554184); // gmdate('D, d M Y H:i:s T');

$hashdata = "GET\n$url\n$user\n$timestamp\n";

print_r($hashdata);
/*
GET
https://example.com/api/endpoint
apiuser
Fri, 30 Nov 2018 05:03:04 GMT
*/

$decoded_key = base64_decode($key);

print_r(unpack('H*', $decoded_key));
// Array ( [1] => fab682f1847617e7d9ca9349e6af82025a8b16a34dd409407d6c24c092dc23b8eb02fa698d13e2916a79db71bfbb404b4a937dfb62eeb09be94b0adf53d5f6b8 )

$generated_hash = hash_hmac('sha256', $hashdata, $decoded_key, true);

$encoded_hash = base64_encode($generated_hash);

print_r($encoded_hash);
// vwdT8XhtSA1q+JvAfsRpJumfI4pemoaNFbjjc5JFsvw=

Node.js 代码

crypto = require('crypto');
moment = require('moment-timezone');

let url = 'https://example.com/api/endpoint';
let api_user = 'apiuser';

// Example key
let api_key = '+raC8YR2F+fZypNJ5q+CAlqLFqNN1AlAfWwkwJLcI7jrAvppjRPikWp523G/u0BLSpN9+2LusJvpSwrfU9X2uA==';

let timestamp = moment.tz(1543554184 * 1000, 'GMT').format('ddd, DD MMM YYYY HH:mm:ss z'); // moment.tz(new Date(), 'GMT').format('ddd, DD MMM YYYY HH:mm:ss z');

let hash_data = 'GET\n' + url + '\n' + api_user + '\n' + timestamp + '\n';

console.log($hashdata);
/*
GET
https://example.com/api/endpoint
apiuser
Fri, 30 Nov 2018 05:03:04 GMT
*/

let decoded_key = Buffer.from(api_key, 'base64').toString('utf8');

console.log(Buffer.from(api_key, 'base64'));
// <Buffer fa b6 82 f1 84 76 17 e7 d9 ca 93 49 e6 af 82 02 5a 8b 16 a3 4d d4 09 40 7d 6c 24 c0 92 dc 23 b8 eb 02 fa 69 8d 13 e2 91 6a 79 db 71 bf bb 40 4b 4a 93 ... >

const hmac = crypto.createHmac('sha256', decoded_key);
hmac.update(hash_data);

// Not sure which should be closest to PHP
// Or if there is a difference
let encoded_hash = hmac.digest('base64');
// let encoded_hash = Buffer(hmac.digest('binary')).toString('base64');

console.log(encoded_hash);
// hmac.digest('base64') == eLLVC9cUvq6Ber6t9TBTihSoq+2VWIMUJKiL4/fIj3s=
// Buffer(hmac.digest('binary')).toString('base64') == eLLVC9cUvq6Ber6t9TBTihSoq+2VWIMUJKiL4/fIj3s=

除了 HMAC 函数输出之外的所有内容似乎都是一样的。

操作系统:Windows 10 - 64 位

Node.js 版本:v10.13.0

PHP 版本:7.2.7

最佳答案

我可以在 Node.js 中通过将 decoded_key 保留为 Buffer 并将其作为 Buffer 直接发送到 来获得正确的结果>crypto.createHmac:

let decoded_key = Buffer.from(api_key, 'base64');
const hmac = crypto.createHmac('sha256', decoded_key);

这是受支持的,请参阅 crypto.createHmac :

key <string> | <Buffer> | <TypedArray> | <DataView>

结果是 vwdT8XhtSA1q+JvAfsRpJumfI4pemoaNFbjjc5JFsvw= - 与 PHP 相同。
工作示例:https://repl.it/repls/DisguisedBlankTechnologies

问题一定出在 .toString('utf8') 上。我没有找到另一种将其作为字符串进行编码的方法,但它与 Buffer 一样有效。

为了完整起见,加密模块支持的另一个选项:

const hmac = crypto.createHmac('sha256', decoded_key);
hmac.write(hash_data);
hmac.end();
let encoded_hash = hmac.read().toString('base64');

工作示例:https://repl.it/repls/LightcoralUnwelcomeProfessionals

关于php - Node Crypto createHmac() 输出与具有相同输入的 PHP hash_hmac() 输出不同吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53699898/

相关文章:

php - 在 PHP 中显示自定义 404 错误页面而不重定向

php - 如何修复 XML "Opening and ending tag mismatch error"?

php - jQuery UI Datepicker - 能够选择日期或月份

javascript - Buffer + writeUInt32LE 从 NodeJS 到 Javascript

node.js - 带项目和过滤器的 Mongoose 查询

javascript - HTML/JS 表单被提交两次

php - 在html表格中打印数据库数据

javascript - 在这种情况下,javascript 将 undefined 分配给未声明的变量,并且在访问变量时抛出引用错误

javascript - 无法安装js-bson

php - 如何将我的 PHP 网站设置为多语言网站?