HMAC хеширование с кодировкой Base64 с использованием Javascript
Я работаю с Payeezy API для обработки платежей через веб-приложение, для их API для покупки требуется HMAC с полезной нагрузкой, подписанной с использованием API-секрета. Выдержка из документов:
Создайте параметр данных, добавив параметры ниже в том же порядке, как показано. а. apikey - API-ключ разработчика. б. nonce - безопасное случайное число. с. отметка времени - отметка времени в миллисекундах. д. токен - Торговый токен. е. Полезная нагрузка - фактическое содержание тела, переданное в виде почтового запроса. Вычислите хэш HMAC SHA256 для вышеуказанного параметра данных, используя ключ ниже f. apiSecret - токен Consumer Secret для данного ключа API. Вычислите base64 хэша, который будет нашим требуемым значением заголовка авторизации.
Я нашел библиотеку с именем jshashes в NPM и попытался использовать их библиотеку для хэширования параметров заголовка, мой код выглядит так:
const payload = {
"merchant_ref": "1-Sale",
"transaction_type": "purchase",
"method": "credit_card",
"amount": amount * 100,
"partial_redemption": "false",
"currency_code": "USD",
"credit_card": {
"type": type,
"cardholder_name": cardholder_name,
"card_number": card_number,
"exp_date": exp_date,
"cvv": cvv
}
}
const data = apikey + nounce + timestamp + token + JSON.stringify(payload)
const sha256 = new Hashes.SHA256()
const shaData = sha256.b64_hmac(apiSecret, data)
Результат по сравнению с хэшированным значением выборки выглядит так:
//mine
beWtpCGDv/iBoAUDAThGFXIge9eli/Xtl7JIBuR1bd4=
//payeezy sample
NmUzMTNmYWU0YjExM2UxMmM0NjllZGI1NThjY2M5MmUzMzE3NTFlZmQ1NDQxYzAzMTgwMmIwNDQ0MWVmYTdhMw==
Судя по количеству символов, я могу сказать, что мой процесс хэширования не является правильным, но я не могу понять, где произошла ошибка.
Я видел подобные вопросы здесь, но никто не ответил, любая помощь приветствуется.
ДОПОЛНИТЕЛЬНО, я пробовал криптобиблиотеку на Node.js:
const data = apikey + nounce + timestamp + token + JSON.stringify(payload)
const hmac = crypto.createHmac('sha512', apiSecret)
hmac.on('readable', () => {
const data = hmac.read()
if (data) {
console.log(data.toString('base64'));
}
})
hmac.write(data)
hmac.end()
Тот же результат, только с половиной длины символа по сравнению с хэшированным значением выборки.
ОБНОВЛЕНИЕ: После того, как я использовал SHA512 для данных, он, наконец, возвратил строку, которая выглядит так же, как длина образца, но проверка все еще не проходит...
1 ответ
Если вы конвертируете пример base64 с этого сайта в строку
console.log(atob('NmUzMTNmYWU0YjExM2UxMmM0NjllZGI1NThjY2M5MmUzMzE3NTFlZmQ1NDQxYzAzMTgwMmIwNDQ0MWVmYTdhMw=='))
Ты получаешь
6e313fae4b113e12c469edb558ccc92e331751efd5441c031802b04441efa7a3
Это 64-символьная (256-битная) шестнадцатеричная строка
Поэтому я предполагаю, что они получают шестнадцатеричную строку HMAC, а base64 кодирует это - что выглядит ужасно глупо, ведь шестнадцатеричное безопасно отправлять как есть, зачем увеличивать его на 4/3rds!!
если бы они просто использовали base64 HMAC, это было бы только 45 символов!
Вместо этого они получают 64-символьную шестнадцатеричную строку и base64 кодируют это, чтобы получить 88 символов!! странное дизайнерское решение!!
Итак, ваш код должен сделать то же самое
лайк
Data = Buffer.from(sha256.hex_hmac(apiSecret, data), 'utf-8').toString('base64');
не уверен, что в узле есть лучший способ конвертировать шестнадцатеричную строку в base64, но это работает
И наконец (на самом деле этот бит просто "соответствует" тому, как рассчитывается авторизация на странице примера, на которую ссылается OP https://developer.payeezy.com/payeezy-api/apis/post/transactions-3
) Таким образом, нет необходимости увеличивать полезную нагрузку без причины)
Еще один момент, который вам нужно знать, JSON должен быть в определенном формате, кажется... 2 пробела с отступом... опять же, это чертовски глупая трата пропускной способности... {"key":1234}
занимает 12 символов
{
"key": 1234
}
занимает 17
Так или иначе, вам нужно сделать это:
JSON.stringify(payload,null, 2)
Эта последняя часть головоломки должна сделать ваш код следующим
const data = apikey + nonce + timestamp + token + JSON.stringify(payload,null, 2)
const sha256 = new Hashes.SHA256()
const shaData = Buffer.from(sha256.hex_hmac(secret, data), 'utf-8').toString('base64');