关于hmac sha256 我的计算结果和人家的有出入
本帖最后由 拒绝吃鱼的猫 于 2023-12-25 16:06 编辑import got, { Method } from 'got';
import { createHash, createHmac } from 'crypto';
const endpoint = 'https://xxx.com';
const accessKey = '<your key>';
const accessSecret = '<your secret>';
const signatureVersion = '2.0';
async function call(method: Method, body?: Record<string, any>) {
const pathname = '/xxx';
const contentType = 'application/json';
const requestTime = Date.now();
const headers: Record<string, string | number> = {
'x-ty-timestamp': requestTime,
'x-ty-accesskey': accessKey,
'x-ty-signature-version': signatureVersion,
'content-type': contentType,
};
const customHeaders: Record<string, string | number> = {};
for (const headerKey of Object.keys(headers)) {
if (headerKey.startsWith('x-ty-')) {
customHeaders = headers;
}
}
const query = {};
const orderedCustomHeaderString = keyPairsToOrderedString(customHeaders);
const orderedQueryString = keyPairsToOrderedString(query);
let body_hash = '';
if (contentType === 'application/json') {
if (Object.keys(body ?? {}).length) {
// 这里直接使用 JSON.stringify 是因为 got 在发送 json 时采用同样的参数
body_hash = createHash('sha256')
.update(JSON.stringify(body ?? {}))
.digest('hex');
}
}
const signaturedString = [
fixedEncodeURIComponent(pathname),
fixedEncodeURIComponent(method.toUpperCase()),
fixedEncodeURIComponent(contentType),
orderedCustomHeaderString,
orderedQueryString,
body_hash,
requestTime,
accessKey,
signatureVersion,
].join('\n');
const targetSignature = createHmac('sha256', accessSecret).update(signaturedString).digest('hex');
console.log(signaturedString);
const ret = await got(`${endpoint}${pathname}`, {
method,
headers: {
...headers,
Authorization: targetSignature,
},
throwHttpErrors: false,
});
console.log(ret.body);
}
function keyPairsToOrderedString(keyPairs: Record<string, any>) {
return Object.keys(keyPairs)
.sort()
.map((key) => `${fixedEncodeURIComponent(key)}=${fixedEncodeURIComponent(String(keyPairs || ''))}`)
.join('&');
}
function fixedEncodeURIComponent(str: string) {
return encodeURIComponent(str).replace(/[!'()*]/g, function (c) {
return '%' + c.charCodeAt(0).toString(16);
});
}
void call('post', {
foo: 'bar',
});上面是nodejs代码
我改为下面的火山代码,发现遇到问题了,
不知道哪里的问题 计算结果不一致
<火山程序 类型 = "通常" 版本 = 1 />
方法 请求 <公开 静态>
{
变量 apiUrl <类型 = 文本型>
apiUrl = "https://xxxx.com"
变量 accessKey <类型 = 文本型>
accessKey = "123123123"
变量 accessSecret <类型 = 文本型>
accessSecret = "123123123"
变量 signatureVersion <类型 = 文本型>
signatureVersion = "2.0"
变量 pathname <类型 = 文本型>
pathname = "/xxxxx"
变量 contentType <类型 = 文本型>
contentType = "application/json"
变量 requestTime <类型 = 长整数>
requestTime = 取毫秒时间戳 (取现行时间 ())
变量 headers <类型 = Headers类Ex>
headers.添加 ("x-ty-timestamp", 到文本 (requestTime))
headers.添加 ("x-ty-accesskey", accessKey)
headers.添加 ("x-ty-signature-version", signatureVersion)
headers.添加 ("content-type", contentType)
变量 orderedCustomHeaderString <类型 = 文本型>
// orderedCustomHeaderString = URL编码Ex ("x-ty-accesskey=" + accessKey + "&" + "x-ty-signature-version=" + signatureVersion + "&" + "x-ty-timestamp=" + 到文本 (requestTime))
orderedCustomHeaderString = URL编解码类.编码文本 ("x-ty-accesskey=" + accessKey + "&" + "x-ty-signature-version=" + signatureVersion + "&" + "x-ty-timestamp=" + 到文本 (requestTime))
变量 orderedQueryString <类型 = JSON对象类Ex>
变量 signatured <类型 = JSON数组类Ex>
signatured.置入文本值 (URL编码Ex (pathname), 0)
signatured.置入文本值 (URL编码Ex ("GET"), 1)
signatured.置入文本值 (URL编码Ex (contentType), 2)
signatured.置入文本值 (orderedCustomHeaderString, 3)
signatured.置入对象值 (orderedQueryString, 4)
signatured.置入长整数值 (requestTime, 5)
signatured.置入文本值 (accessKey, 6)
signatured.置入文本值 (signatureVersion, 7)
// 调试输出 (signatured.到可读文本 ())
变量 signaturedString <类型 = 文本型>
计次循环 (signatured.取成员数 ())
{
signaturedString = signaturedString + signatured.取文本值 (取循环索引 ()) + "\n"
}
// 调试输出 (signaturedString)
变量 targetSignature <类型 = 文本型>
targetSignature = 加解密类.取数据HMAC_SHA256 (到字节集 (signaturedString), accessSecret)
headers.添加 ("Authorization", targetSignature)
// 网页访问Ex_T (apiUrl + pathname, E_请求类型.GET, , , headers, , , , , , , , , , , , , , , , , )
调试输出 (网页访问Ex_T (apiUrl + pathname, E_请求类型.GET, , , headers, , , , , , , , , , , , , , , , , ))
}
主要文本编码的问题,火山的文本是Unicode,网页一般用UTF8,你在hash之前,需要用 文本到UTF8(, 假) 转换编码(第二个参数必须用假)
PS. 你拼接文本的那些代码我没细看,如果还不对,你自己检查一下 肯定是编码问题。一般都是用utf8编码的。
就和楼上说的一样。用文本到UTF8转换。 Xelloss0618 发表于 2023-12-25 18:24
主要文本编码的问题,火山的文本是Unicode,网页一般用UTF8,你在hash之前,需要用 文本到UTF8(, 假) 转换 ...
谢谢 X兄,我给uft8了,貌似计算结果还是不行. 创世魂 发表于 2023-12-25 18:29
肯定是编码问题。一般都是用utf8编码的。
就和楼上说的一样。用文本到UTF8转换。 ...
转换过了,结算结果还是有问题,还在找问题 拒绝吃鱼的猫 发表于 2023-12-25 18:49
谢谢 X兄,我给uft8了,貌似计算结果还是不行.
那就是字符串拼接得不对,输出 nodejs 里的字符串,跟你自己拼接的对比一下 Xelloss0618 发表于 2023-12-25 19:13
那就是字符串拼接得不对,输出 nodejs 里的字符串,跟你自己拼接的对比一下 ...
我看nodejs里 他把字符串加密后digest('hex'); 也就是十六进制话了
我们的 openssl 加密后的结果是 十六进制化吗? 拒绝吃鱼的猫 发表于 2023-12-25 19:27
我看nodejs里 他把字符串加密后digest('hex'); 也就是十六进制话了
我们的 openssl 加密后的结果是 十六 ...
取数据HMAC_SHA256 这个命令返回的就是十六进制化的 拒绝吃鱼的猫 发表于 2023-12-25 19:27
我看nodejs里 他把字符串加密后digest('hex'); 也就是十六进制话了
我们的 openssl 加密后的结果是 十六 ...
加解密类.取数据HMAC_字节集_SHA256 (文本到UTF8 ("111", 假), 文本到UTF8 ("111", 假))
直接这样。让密码也用utf8编码的。 创世魂 发表于 2023-12-25 21:21
加解密类.取数据HMAC_字节集_SHA256 (文本到UTF8 ("111", 假), 文本到UTF8 ("111", 假))
直接这样。 ...
用了 计算的结果还是不对,我拼接的看起来也没啥问题,我都头儿大了
页:
[1]
2