HMAC 哈希与 Base64 编码与 Javascript



我正在使用Payeezy API来处理Web应用程序的付款,他们的购买API需要使用API密钥签名的有效负载HMAC。文档摘录:

通过按如下所示的相同顺序附加以下参数来构造数据参数。 a. apikey - 开发者的 API 密钥。 b. 随机数 - 安全随机数。 c. 时间戳 - 以毫秒为单位的纪元时间戳。 d. 令牌 - 商家令牌。 e. 有效负载 - 作为后请求传递的实际正文内容。使用以下键在上述数据参数上计算 HMAC SHA256 哈希 f. apiSecret - 给定 api 密钥的使用者密钥令牌 计算哈希的 base64,这将是我们所需的授权标头值。

我在 NPM 上找到了一个名为 jshashes 的库,我尝试使用他们的库来散列我的标头参数,我的代码如下所示:

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 后,它最终返回了一个字符串,该字符串看起来与示例具有相同的字符长度,但验证仍然没有通过......

如果将base64 示例从该站点转换为字符串

console.log(atob('NmUzMTNmYWU0YjExM2UxMmM0NjllZGI1NThjY2M5MmUzMzE3NTFlZmQ1NDQxYzAzMTgwMmIwNDQ0MWVmYTdhMw=='))

你得到

6e313fae4b113e12c469edb558ccc92e331751efd5441c031802b04441efa7a3

这是一个 64 个字符(256 位(的十六进制字符串

所以我的猜测是他们得到了十六进制字符串 HMAC,并对其进行了 base64 编码 - 这似乎非常愚蠢,十六进制可以按原样安全发送,为什么要让它大 4/3rds!!

如果他们只是使用 HMAC 的 base64,它只有 45 个字符长!!

相反,他们得到 64 个字符的十六进制字符串和 base64 编码以获得 88 个字符!! 奇怪的设计决定!!

因此,您的代码也应该这样做

喜欢

Data = Buffer.from(sha256.hex_hmac(apiSecret, data), 'utf-8').toString('base64');

不确定 node 中是否有更好的方法将十六进制编码的字符串转换为 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');

最新更新