递归火山软件开发平台

标题: 关于hmac sha256 我的计算结果和人家的有出入 [打印本页]

作者: 拒绝吃鱼的猫    时间: 2023-12-25 16:02
标题: 关于hmac sha256 我的计算结果和人家的有出入
本帖最后由 拒绝吃鱼的猫 于 2023-12-25 16:06 编辑
  1. import got, { Method } from 'got';
  2. import { createHash, createHmac } from 'crypto';

  3. const endpoint = 'https://xxx.com';
  4. const accessKey = '<your key>';
  5. const accessSecret = '<your secret>';
  6. const signatureVersion = '2.0';

  7. async function call(method: Method, body?: Record<string, any>) {
  8.   const pathname = '/xxx';
  9.   const contentType = 'application/json';
  10.   const requestTime = Date.now();

  11.   const headers: Record<string, string | number> = {
  12.     'x-ty-timestamp': requestTime,
  13.     'x-ty-accesskey': accessKey,
  14.     'x-ty-signature-version': signatureVersion,
  15.     'content-type': contentType,
  16.   };

  17.   const customHeaders: Record<string, string | number> = {};
  18.   for (const headerKey of Object.keys(headers)) {
  19.     if (headerKey.startsWith('x-ty-')) {
  20.       customHeaders[headerKey] = headers[headerKey];
  21.     }
  22.   }

  23.   const query = {};

  24.   const orderedCustomHeaderString = keyPairsToOrderedString(customHeaders);
  25.   const orderedQueryString = keyPairsToOrderedString(query);

  26.   let body_hash = '';

  27.   if (contentType === 'application/json') {
  28.     if (Object.keys(body ?? {}).length) {
  29.       // 这里直接使用 JSON.stringify 是因为 got 在发送 json 时采用同样的参数
  30.       body_hash = createHash('sha256')
  31.         .update(JSON.stringify(body ?? {}))
  32.         .digest('hex');
  33.     }
  34.   }

  35.   const signaturedString = [
  36.     fixedEncodeURIComponent(pathname),
  37.     fixedEncodeURIComponent(method.toUpperCase()),
  38.     fixedEncodeURIComponent(contentType),
  39.     orderedCustomHeaderString,
  40.     orderedQueryString,
  41.     body_hash,
  42.     requestTime,
  43.     accessKey,
  44.     signatureVersion,
  45.   ].join('\n');

  46.   const targetSignature = createHmac('sha256', accessSecret).update(signaturedString).digest('hex');

  47.   console.log(signaturedString);

  48.   const ret = await got(`${endpoint}${pathname}`, {
  49.     method,
  50.     headers: {
  51.       ...headers,
  52.       Authorization: targetSignature,
  53.     },
  54.     throwHttpErrors: false,
  55.   });

  56.   console.log(ret.body);
  57. }

  58. function keyPairsToOrderedString(keyPairs: Record<string, any>) {
  59.   return Object.keys(keyPairs)
  60.     .sort()
  61.     .map((key) => `${fixedEncodeURIComponent(key)}=${fixedEncodeURIComponent(String(keyPairs[key] || ''))}`)
  62.     .join('&');
  63. }

  64. function fixedEncodeURIComponent(str: string) {
  65.   return encodeURIComponent(str).replace(/[!'()*]/g, function (c) {
  66.     return '%' + c.charCodeAt(0).toString(16);
  67.   });
  68. }

  69. void call('post', {
  70.   foo: 'bar',
  71. });
复制代码
上面是nodejs代码
我改为下面的火山代码,发现遇到问题了,
不知道哪里的问题 计算结果不一致

  1. <火山程序 类型 = "通常" 版本 = 1 />

  2. 方法 请求 <公开 静态>
  3. {
  4.     变量 apiUrl <类型 = 文本型>
  5.     apiUrl = "https://xxxx.com"
  6.     变量 accessKey <类型 = 文本型>
  7.     accessKey = "123123123"
  8.     变量 accessSecret <类型 = 文本型>
  9.     accessSecret = "123123123"
  10.     变量 signatureVersion <类型 = 文本型>
  11.     signatureVersion = "2.0"
  12.     变量 pathname <类型 = 文本型>
  13.     pathname = "/xxxxx"
  14.     变量 contentType <类型 = 文本型>
  15.     contentType = "application/json"
  16.     变量 requestTime <类型 = 长整数>
  17.     requestTime = 取毫秒时间戳 (取现行时间 ())
  18.     变量 headers <类型 = Headers类Ex>
  19.     headers.添加 ("x-ty-timestamp", 到文本 (requestTime))
  20.     headers.添加 ("x-ty-accesskey", accessKey)
  21.     headers.添加 ("x-ty-signature-version", signatureVersion)
  22.     headers.添加 ("content-type", contentType)
  23.     变量 orderedCustomHeaderString <类型 = 文本型>
  24.     // orderedCustomHeaderString = URL编码Ex ("x-ty-accesskey=" + accessKey + "&" + "x-ty-signature-version=" + signatureVersion + "&" + "x-ty-timestamp=" + 到文本 (requestTime))
  25.     orderedCustomHeaderString = URL编解码类.编码文本 ("x-ty-accesskey=" + accessKey + "&" + "x-ty-signature-version=" + signatureVersion + "&" + "x-ty-timestamp=" + 到文本 (requestTime))

  26.     变量 orderedQueryString <类型 = JSON对象类Ex>

  27.     变量 signatured <类型 = JSON数组类Ex>
  28.     signatured.置入文本值 (URL编码Ex (pathname), 0)
  29.     signatured.置入文本值 (URL编码Ex ("GET"), 1)
  30.     signatured.置入文本值 (URL编码Ex (contentType), 2)
  31.     signatured.置入文本值 (orderedCustomHeaderString, 3)
  32.     signatured.置入对象值 (orderedQueryString, 4)
  33.     signatured.置入长整数值 (requestTime, 5)
  34.     signatured.置入文本值 (accessKey, 6)
  35.     signatured.置入文本值 (signatureVersion, 7)
  36.     // 调试输出 (signatured.到可读文本 ())
  37.     变量 signaturedString <类型 = 文本型>

  38.     计次循环 (signatured.取成员数 ())
  39.     {
  40.         signaturedString = signaturedString + signatured.取文本值 (取循环索引 ()) + "\n"
  41.     }


  42.     // 调试输出 (signaturedString)
  43.     变量 targetSignature <类型 = 文本型>
  44.     targetSignature = 加解密类.取数据HMAC_SHA256 (到字节集 (signaturedString), accessSecret)



  45.     headers.添加 ("Authorization", targetSignature)


  46.     // 网页访问Ex_T (apiUrl + pathname, E_请求类型.GET, , , headers, , , , , , , , , , , , , , , , , )

  47.     调试输出 (网页访问Ex_T (apiUrl + pathname, E_请求类型.GET, , , headers, , , , , , , , , , , , , , , , , ))



  48. }
复制代码



作者: Xelloss0618    时间: 2023-12-25 18:24
主要文本编码的问题,火山的文本是Unicode,网页一般用UTF8,你在hash之前,需要用 文本到UTF8(, 假) 转换编码(第二个参数必须用假)
PS. 你拼接文本的那些代码我没细看,如果还不对,你自己检查一下
作者: 创世魂    时间: 2023-12-25 18:29
肯定是编码问题。  一般都是用utf8编码的。

就和楼上说的一样。用  文本到UTF8  转换。
作者: 拒绝吃鱼的猫    时间: 2023-12-25 18:49
Xelloss0618 发表于 2023-12-25 18:24
主要文本编码的问题,火山的文本是Unicode,网页一般用UTF8,你在hash之前,需要用 文本到UTF8(, 假) 转换 ...

谢谢 X兄,我给uft8了,貌似计算结果还是不行.
作者: 拒绝吃鱼的猫    时间: 2023-12-25 18:54
创世魂 发表于 2023-12-25 18:29
肯定是编码问题。  一般都是用utf8编码的。

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

转换过了,结算结果还是有问题,还在找问题
作者: Xelloss0618    时间: 2023-12-25 19:13
拒绝吃鱼的猫 发表于 2023-12-25 18:49
谢谢 X兄,我给uft8了,貌似计算结果还是不行.

那就是字符串拼接得不对,输出 nodejs 里的字符串,跟你自己拼接的对比一下
作者: 拒绝吃鱼的猫    时间: 2023-12-25 19:27
Xelloss0618 发表于 2023-12-25 19:13
那就是字符串拼接得不对,输出 nodejs 里的字符串,跟你自己拼接的对比一下 ...

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

取数据HMAC_SHA256 这个命令返回的就是十六进制化的
作者: 创世魂    时间: 2023-12-25 21:21
拒绝吃鱼的猫 发表于 2023-12-25 19:27
我看nodejs里 他把字符串加密后digest('hex'); 也就是十六进制话了
我们的 openssl 加密后的结果是 十六 ...

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

直接这样。让密码也用utf8编码的。
作者: 拒绝吃鱼的猫    时间: 2023-12-25 22:02
创世魂 发表于 2023-12-25 21:21
加解密类.取数据HMAC_字节集_SHA256 (文本到UTF8 ("111", 假), 文本到UTF8 ("111", 假))   

直接这样。 ...

用了 计算的结果还是不对,我拼接的看起来也没啥问题,我都头儿大了
作者: 创世魂    时间: 2023-12-25 23:00
拒绝吃鱼的猫 发表于 2023-12-25 22:02
用了 计算的结果还是不对,我拼接的看起来也没啥问题,我都头儿大了

逐个调试了。

把nodejs里面的所有信息都输出一下,和火山里面的对比一下。

看看是哪一个步骤数据不对。
作者: 拒绝吃鱼的猫    时间: 2023-12-25 23:19
创世魂 发表于 2023-12-25 23:00
逐个调试了。

把nodejs里面的所有信息都输出一下,和火山里面的对比一下。

thx 谢谢了




欢迎光临 递归火山软件开发平台 (https://bbs.voldp.com/) Powered by Discuz! X3.4