拒绝吃鱼的猫 发表于 2023-12-25 16:02:22

关于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, , , , , , , , , , , , , , , , , ))



}


Xelloss0618 发表于 2023-12-25 18:24:39

主要文本编码的问题,火山的文本是Unicode,网页一般用UTF8,你在hash之前,需要用 文本到UTF8(, 假) 转换编码(第二个参数必须用假)
PS. 你拼接文本的那些代码我没细看,如果还不对,你自己检查一下

创世魂 发表于 2023-12-25 18:29:16

肯定是编码问题。一般都是用utf8编码的。

就和楼上说的一样。用文本到UTF8转换。

拒绝吃鱼的猫 发表于 2023-12-25 18:49:40

Xelloss0618 发表于 2023-12-25 18:24
主要文本编码的问题,火山的文本是Unicode,网页一般用UTF8,你在hash之前,需要用 文本到UTF8(, 假) 转换 ...

谢谢 X兄,我给uft8了,貌似计算结果还是不行.

拒绝吃鱼的猫 发表于 2023-12-25 18:54:01

创世魂 发表于 2023-12-25 18:29
肯定是编码问题。一般都是用utf8编码的。

就和楼上说的一样。用文本到UTF8转换。 ...

转换过了,结算结果还是有问题,还在找问题

Xelloss0618 发表于 2023-12-25 19:13:40

拒绝吃鱼的猫 发表于 2023-12-25 18:49
谢谢 X兄,我给uft8了,貌似计算结果还是不行.

那就是字符串拼接得不对,输出 nodejs 里的字符串,跟你自己拼接的对比一下

拒绝吃鱼的猫 发表于 2023-12-25 19:27:53

Xelloss0618 发表于 2023-12-25 19:13
那就是字符串拼接得不对,输出 nodejs 里的字符串,跟你自己拼接的对比一下 ...

我看nodejs里 他把字符串加密后digest('hex'); 也就是十六进制话了
我们的 openssl 加密后的结果是 十六进制化吗?

Xelloss0618 发表于 2023-12-25 20:48:56

拒绝吃鱼的猫 发表于 2023-12-25 19:27
我看nodejs里 他把字符串加密后digest('hex'); 也就是十六进制话了
我们的 openssl 加密后的结果是 十六 ...

取数据HMAC_SHA256 这个命令返回的就是十六进制化的

创世魂 发表于 2023-12-25 21:21:59

拒绝吃鱼的猫 发表于 2023-12-25 19:27
我看nodejs里 他把字符串加密后digest('hex'); 也就是十六进制话了
我们的 openssl 加密后的结果是 十六 ...

加解密类.取数据HMAC_字节集_SHA256 (文本到UTF8 ("111", 假), 文本到UTF8 ("111", 假))   

直接这样。让密码也用utf8编码的。

拒绝吃鱼的猫 发表于 2023-12-25 22:02:40

创世魂 发表于 2023-12-25 21:21
加解密类.取数据HMAC_字节集_SHA256 (文本到UTF8 ("111", 假), 文本到UTF8 ("111", 假))   

直接这样。 ...

用了 计算的结果还是不对,我拼接的看起来也没啥问题,我都头儿大了
页: [1] 2
查看完整版本: 关于hmac sha256 我的计算结果和人家的有出入