如何使用谷歌应用脚本对带有双数组键或十六进制字符串键的 HMAC SHA256 签名?



按照签名版本 4 上的 AWS 示例,我尝试使用带有 Google 应用程序脚本的 Google 表格重现该示例。我在示例中遇到了 kregion 签名的问题。虽然我可以使用在线签名工具确认 AWS 示例有效,但我永远无法使用任何 Google 应用程序脚本重现示例输出。由于HMAC SHA256签名适用于示例的早期部分(kdate(,因此问题似乎来自数据的存储或使用方式。

适用于kDate的是以下内容,其中包含来自另一个stackoverflow条目的部分,以将字节数组转换为十六进制字符串,并借助Google应用程序脚本文档进行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 条目启发的字节数组是相同的:

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

使用在线转换器,我可以确认密钥转换良好。然而,输出签名仍然是错误的。 我想知道是否可能是因为密钥字节存储为双精度。因此,我尝试了以下内容,对输出签名没有区别:

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);

上述导致错误"无法将数组转换为(类([]"。这似乎表明 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 脚本获得"如何派生签名版本 4 的签名密钥的示例"示例脚本的结果。

    • 在您的情况下,您希望从以下示例值中检索f4780e2d9f65fa895f9c67b32ce1baf0b0d8a43505a000a1a9e090d414db404d的值,作为kSigning

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

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

要点:

  • 在Google Apps Script中,由Utilities.computeHmacSha256Signature()加密的数据是有符号十六进制的字节数组。在示例脚本中,字节数组将转换为无符号十六进制。所以需要转换。
    • 但是,当字节数组由Utilities.computeHmacSha256Signature()创建时,创建的字节数组可用于Utilities.computeHmacSha256Signature()而无需转换。

从上述情况来看,Google Apps 脚本的示例脚本可以按如下方式制作。

示例脚本:

在此示例脚本中,为了检查脚本是否正确,我使用 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需要转换为字节数组。请小心这一点。

结果:

f4780e2d9f65fa895f9c67b32ce1baf0b0d8a43505a000a1a9e090d414db404d

此值与示例值相同。由此,发现准备好的脚本返回正确的值。

引用:

  • computeHmacSha256签名(值,键(
  • 地图((

如果我误解了你的问题,这不是你想要的结果,我很抱歉。

最新更新