node.js — Выходные данные Node Crypto createHmac () отличаются от выходных данных PHP hash_hmac () с теми же входными данными?

Я пытаюсь повторить функцию генерации хеша PHP в Node. Этот хеш используется как часть 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

6

Решение

Я могу получить правильный результат в 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,

Для полноты, еще одна опция, поддерживаемая модулем Crypto:

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

2

Другие решения

Других решений пока нет …

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector