递归火山软件开发平台

 找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
热搜: 火山 源码 类库
查看: 3683|回复: 11
打印 上一主题 下一主题

[视窗] 关于hmac sha256 我的计算结果和人家的有出入

[复制链接]

32

主题

293

帖子

1184

积分

核心用户

Rank: 9Rank: 9Rank: 9

积分
1184
跳转到指定楼层
楼主
发表于 2023-12-25 16:02:22 | 只看该作者 回帖奖励 |正序浏览 |阅读模式
本帖最后由 拒绝吃鱼的猫 于 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. }
复制代码


回复

使用道具 举报

26

主题

1900

帖子

6926

积分

核心用户

Rank: 9Rank: 9Rank: 9

积分
6926
来自 2#
发表于 2023-12-25 18:24:39 | 只看该作者
主要文本编码的问题,火山的文本是Unicode,网页一般用UTF8,你在hash之前,需要用 文本到UTF8(, 假) 转换编码(第二个参数必须用假)
PS. 你拼接文本的那些代码我没细看,如果还不对,你自己检查一下
回复

使用道具 举报

32

主题

293

帖子

1184

积分

核心用户

Rank: 9Rank: 9Rank: 9

积分
1184
12#
 楼主| 发表于 2023-12-25 23:19:16 | 只看该作者
创世魂 发表于 2023-12-25 23:00
逐个调试了。

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

thx 谢谢了
回复

使用道具 举报

444

主题

1万

帖子

4万

积分

超级版主

Rank: 8Rank: 8

积分
40529
11#
发表于 2023-12-25 23:00:37 | 只看该作者
拒绝吃鱼的猫 发表于 2023-12-25 22:02
用了 计算的结果还是不对,我拼接的看起来也没啥问题,我都头儿大了

逐个调试了。

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

看看是哪一个步骤数据不对。
安卓无障碍实战课:点击查看
交流群:641526939
回复

使用道具 举报

32

主题

293

帖子

1184

积分

核心用户

Rank: 9Rank: 9Rank: 9

积分
1184
10#
 楼主| 发表于 2023-12-25 22:02:40 | 只看该作者
创世魂 发表于 2023-12-25 21:21
加解密类.取数据HMAC_字节集_SHA256 (文本到UTF8 ("111", 假), 文本到UTF8 ("111", 假))   

直接这样。 ...

用了 计算的结果还是不对,我拼接的看起来也没啥问题,我都头儿大了
回复

使用道具 举报

444

主题

1万

帖子

4万

积分

超级版主

Rank: 8Rank: 8

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

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

直接这样。让密码也用utf8编码的。
安卓无障碍实战课:点击查看
交流群:641526939
回复

使用道具 举报

26

主题

1900

帖子

6926

积分

核心用户

Rank: 9Rank: 9Rank: 9

积分
6926
8#
发表于 2023-12-25 20:48:56 | 只看该作者
拒绝吃鱼的猫 发表于 2023-12-25 19:27
我看nodejs里 他把字符串加密后digest('hex'); 也就是十六进制话了
我们的 openssl 加密后的结果是 十六 ...

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

使用道具 举报

32

主题

293

帖子

1184

积分

核心用户

Rank: 9Rank: 9Rank: 9

积分
1184
7#
 楼主| 发表于 2023-12-25 19:27:53 | 只看该作者
Xelloss0618 发表于 2023-12-25 19:13
那就是字符串拼接得不对,输出 nodejs 里的字符串,跟你自己拼接的对比一下 ...

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

使用道具 举报

26

主题

1900

帖子

6926

积分

核心用户

Rank: 9Rank: 9Rank: 9

积分
6926
6#
发表于 2023-12-25 19:13:40 | 只看该作者
拒绝吃鱼的猫 发表于 2023-12-25 18:49
谢谢 X兄,我给uft8了,貌似计算结果还是不行.

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

使用道具 举报

32

主题

293

帖子

1184

积分

核心用户

Rank: 9Rank: 9Rank: 9

积分
1184
5#
 楼主| 发表于 2023-12-25 18:54:01 | 只看该作者
创世魂 发表于 2023-12-25 18:29
肯定是编码问题。  一般都是用utf8编码的。

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

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

使用道具 举报

32

主题

293

帖子

1184

积分

核心用户

Rank: 9Rank: 9Rank: 9

积分
1184
地板
 楼主| 发表于 2023-12-25 18:49:40 | 只看该作者
Xelloss0618 发表于 2023-12-25 18:24
主要文本编码的问题,火山的文本是Unicode,网页一般用UTF8,你在hash之前,需要用 文本到UTF8(, 假) 转换 ...

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

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|小黑屋|递归火山软件开发平台 ( 鄂ICP备18029190号 )

GMT+8, 2024-11-24 04:12 , Processed in 0.099613 second(s), 20 queries .

Powered by Discuz! X3.4

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表