如何使用 google 应用脚本使用双数组键或十六进制字符串键对字符串进行 HMAC SHA256 签名?

How to HMAC SHA256 sign a string with a double array key or an hex string key using google apps script?

AWS example on Signature Version 4, I am trying to reproduce the example using a Google Sheets with Google apps scripting. I face an issue with the kregion signature in the example. While I can confirm that the AWS example is valid using an online signature tool 之后,我再也无法使用任何 Google 应用程序脚本重现示例输出。由于 HMAC SHA256 签名适用于示例的较早部分 (kdate),问题似乎出在数据的存储或使用方式上。

适用于 kDate 的部分来自 another Whosebug entry to convert byte array to hex string and with the help of Google apps script documentation for computeHmacSha256Signature:

var input="20120215";
var key="AWS4"+"wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY";//Do not worry, this is an example key, not my actual key
var signature=Utilities.computeHmacSha256Signature(input,key);
signature=signature.map(function(chr){return (chr+256).toString(16).slice(-2)}).join('');//convert byte array to hex string
Logger.log(signature);//valid 969fbb94feb542b71ede6f87fe4d5fa29c789342b0f407474670f0c2489e0a0d

kRegion 也是这样:

var input="us-east-1";
var key="969fbb94feb542b71ede6f87fe4d5fa29c789342b0f407474670f0c2489e0a0d";
var signature=Utilities.computeHmacSha256Signature(input,key);
signature=signature.map(function(chr){return (chr+256).toString(16).slice(-2)}).join('');
Logger.log(signature);//non-valid a59e30f9d899c47b3dd68ea1c0ab3bb529e03a8f4ed2f54cb64af547330a22a0

我对它没有产生有效的示例 kRegion 输出并不感到惊讶 69daa0209cd9c5ff5c8ced464a696fd4252e981430b10e3d3fd8e2f197d7a70c 因为密钥存储为十六进制字符串,这没有多大意义。尝试将十六进制字符串解码为受此 github entry:

启发的字节数组也是同样的事情
var input="us-east-1";
var key="969fbb94feb542b71ede6f87fe4d5fa29c789342b0f407474670f0c2489e0a0d";
var a=[];
for(var i=0, len=key.length; i<len; i+=2) {
  a.push(parseInt(key.substr(i,2),16));
}
key=a;
Logger.log(key);//[150.0, 159.0, 187.0, 148.0, 254.0, 181.0, 66.0, 183.0, 30.0, 222.0, 111.0, 135.0, 254.0, 77.0, 95.0, 162.0, 156.0, 120.0, 147.0, 66.0, 176.0, 244.0, 7.0, 71.0, 70.0, 112.0, 240.0, 194.0, 72.0, 158.0, 10.0, 13.0]
var signature=Utilities.computeHmacSha256Signature(input,key);
signature=signature.map(function(chr){return (chr+256).toString(16).slice(-2)}).join('');
Logger.log(signature);//non-valid ac7a5b21190d18b323886d48cd3c4c7486a0f1dd4edb80d245a221a95f5e689b

使用 online converter,我可以确认密钥已正确转换。然而,输出签名仍然是错误的。 我想知道这是否可能是因为关键字节存储为双精度。所以,我尝试了以下输出签名没有区别:

var input="us-east-1";
var key=[0x96, 0x9f, 0xbb, 0x94, 0xfe, 0xb5, 0x42, 0xb7, 0x1e, 0xde, 0x6f, 0x87, 0xfe, 0x4d, 0x5f, 0xa2, 0x9c, 0x78, 0x93, 0x42, 0xb0, 0xf4, 0x07, 0x47, 0x46, 0x70, 0xf0, 0xc2, 0x48, 0x9e, 0x0a, 0x0d];
var signature=Utilities.computeHmacSha256Signature(input,key);
signature=signature.map(function(chr){return (chr+256).toString(16).slice(-2)}).join('');
Logger.log(signature);//non-valid ac7a5b21190d18b323886d48cd3c4c7486a0f1dd4edb80d245a221a95f5e689b

然后我想也许 computeHmacSha256Signature 函数的两个参数都需要是字节数组:

var input=[0x75, 0x73, 0x2d, 0x65, 0x61, 0x73, 0x74, 0x2d, 0x31];
var key=[0x96, 0x9f, 0xbb, 0x94, 0xfe, 0xb5, 0x42, 0xb7, 0x1e, 0xde, 0x6f, 0x87, 0xfe, 0x4d, 0x5f, 0xa2, 0x9c, 0x78, 0x93, 0x42, 0xb0, 0xf4, 0x07, 0x47, 0x46, 0x70, 0xf0, 0xc2, 0x48, 0x9e, 0x0a, 0x0d];
var signature=Utilities.computeHmacSha256Signature(input,key);//leads to error "Cannot convert Array to (class)[]."
signature=signature.map(function(chr){return (chr+256).toString(16).slice(-2)}).join('');
Logger.log(signature);

以上导致错误"Cannot convert Array to (class)[]."。这似乎表明 computeHmacSha256Signature 函数更适合字符串输入。

我通过使用 kDate 的输出签名而不将其转换为字符串,得到了另一个无效的 kRegion 输出签名:

var input="20120215";
var key="AWS4"+"wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY";
var signature=Utilities.computeHmacSha256Signature(input,key);
input="us-east-1";
key=signature;
signature = Utilities.computeHmacSha256Signature(input,key);
signature=signature.map(function(chr){return (chr+256).toString(16).slice(-2)}).join('');
Logger.log(signature);//non-valid c3b37a4dc2e085fcd35411493526592a33ef1d7d38454a25e574a34fe190d7be

我尝试了很多其他转换都没有成功。

  • 您想使用 Google Apps 脚本实现 "Examples of How to Derive a Signing Key for Signature Version 4" 示例脚本的结果。

    • 在您的情况下,您希望从以下样本值中检索 f4780e2d9f65fa895f9c67b32ce1baf0b0d8a43505a000a1a9e090d414db404d 的值,如 kSigning.

      key = 'wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY'
      dateStamp = '20120215'
      regionName = 'us-east-1'
      serviceName = 'iam'
      

如果我的理解是正确的,这个示例脚本怎么样?

要点:

  • 在GoogleApps Script中,Utilities.computeHmacSha256Signature()加密的数据是带符号的十六进制字节数组。在 the sample scripts 中,字节数组被转换为无符号十六进制。所以需要转换。
    • 但是,当Utilities.computeHmacSha256Signature()创建字节数组时,创建的字节数组无需转换即可用于Utilities.computeHmacSha256Signature()

根据上述情况,Google Apps Script 的示例脚本可以制作如下。

示例脚本:

在这个示例脚本中,为了检查脚本是否正确,我使用https://docs.aws.amazon.com/general/latest/gr/signature-v4-examples.html处的示例值测试了脚本。

function myFunction() {
  // These are the sample values of https://docs.aws.amazon.com/general/latest/gr/signature-v4-examples.html
  var key = 'wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY';
  var dateStamp = '20120215';
  var regionName = 'us-east-1';
  var serviceName = 'iam';

  // I prepared the following script.
  var kDate = Utilities.computeHmacSha256Signature(dateStamp, "AWS4" + key);
  var kRegion = Utilities.computeHmacSha256Signature(Utilities.newBlob(regionName).getBytes(), kDate);
  var kService = Utilities.computeHmacSha256Signature(Utilities.newBlob(serviceName).getBytes(), kRegion);
  var kSigning = Utilities.computeHmacSha256Signature(Utilities.newBlob("aws4_request").getBytes(), kService);
  kSigning = kSigning.map(function(e) {return ("0" + (e < 0 ? e + 256 : e).toString(16)).slice(-2)}).join("");

  Logger.log(kSigning) // Result
}
  • 以上脚本为例,kDate是字节数组。所以需要将regionName转为byte数组。请注意这一点。

结果:

f4780e2d9f65fa895f9c67b32ce1baf0b0d8a43505a000a1a9e090d414db404d

此值与the sample value相同。至此,发现编写的脚本returns值正确。

参考文献:

如果我误解了你的问题,这不是你想要的结果,我深表歉意。