Node Crypto createHmac()输出与PHP hash_hmac()输出的输出是否相同?

Ver*_*pos 6 php node.js

我试图在Node中复制PHP哈希生成函数.此哈希用作API的一部分.PHP版本创建系统接受的正确输出.节点版本创建了不同的输出,尽管我认为它们是函数上的相同输入.

这是因为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=
Run Code Online (Sandbox Code Playgroud)

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=
Run Code Online (Sandbox Code Playgroud)

除了HMAC功能输出之外的所有内容似乎都是相同的.

操作系统:Windows 10 - 64位

Node.js版本:v10.13.0

PHP版本:7.2.7

Kob*_*obi 3

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

let decoded_key = Buffer.from(api_key, 'base64');
const hmac = crypto.createHmac('sha256', decoded_key);
Run Code Online (Sandbox Code Playgroud)

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

key <string> | <Buffer> | <TypedArray> | <DataView>
Run Code Online (Sandbox Code Playgroud)

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

问题一定出在.toString('utf8'). 我没有找到另一种可以作为字符串的编码,但它的效果与Buffer.

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

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

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