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');
Другие вопросы по тегам