使用 c# 的 Amazon ec2 API 版本 2 签名编码

Posted

技术标签:

【中文标题】使用 c# 的 Amazon ec2 API 版本 2 签名编码【英文标题】:Amazon ec2 API version 2 signature encoding with c# 【发布时间】:2010-11-13 06:41:15 【问题描述】:

我在编码 ec2 API 的版本 2 签名的哈希时遇到问题。

请注意,我的第 1 版签名哈希工作正常,但这已被贬值,我需要移至第 2 版。所以首先这里是有效的代码...

parameters 只是一个字典,我要做的就是简单地按键对参数进行排序并附加每个不带分隔符的值对,然后将该字符串与我的键进行哈希处理。 (再次注意,这很好用)

private string GetVersion1Sig()

  string sig = string.Join(string.Empty, parameters.OrderBy(vp => vp.Key).Select(p => string.Format("01", p.Key, p.Value)).ToArray());
  UTF8Encoding encoding = new UTF8Encoding();
  HMACSHA256 signature = new HMACSHA256(encoding.GetBytes(_secretAccessKey));
  byte[] hash = signature.ComputeHash(encoding.GetBytes(sig));
  string result = Convert.ToBase64String(hash);
  return result;

现在,第 2 版有一些变化,这里是 API 开发人员指南中的文档...

    创建稍后在此过程中需要的规范化查询字符串:

一个。使用自然字节顺序按参数名称对 UTF-8 查询字符串组件进行排序。 参数可以来自 GET URI 或 POST 正文(当 Content-Type 是应用程序/x-www-form-urlencoded)。

b. URL 根据以下规则对参数名称和值进行编码:

• 不要对 RFC 3986 定义的任何非保留字符进行 URL 编码。 这些非保留字符是 A-Z、a-z、0-9、连字符 (-)、下划线 (_)、句点 (.)、 和波浪号 ( ~ )。 • 使用 %XY 对所有其他字符进行百分比编码,其中 X 和 Y 是十六进制字符 0-9 和 大写 A-F。 • 百分比编码扩展的 UTF-8 字符,格式为 %XY%ZA.... • 百分比将空格字符编码为 %20(而不是 +,作为常见的编码方案 做)。

注意 目前所有 AWS 服务参数名称都使用非保留字符,因此您不需要 需要对它们进行编码。但是,您可能希望包含处理参数的代码 使用保留字符的名称,以备将来使用。

c。使用等号 ( = ) 将编码参数名称与其编码值分开 (ASCII 字符 61),即使参数值为空。

d。使用与号 ( & ) 分隔名称-值对(ASCII 代码 38)。

    根据以下伪语法创建要签名的字符串(“\n”表示 ASCII 换行符)。 StringToSign = HTTPVerb + "\n" + ValueOfHostHeaderInLowercase + "\n" + HTTPRequestURI + "\n" + 规范化查询字符串 HTTPRequestURI 组件是 URI 的 HTTP 绝对路径组件,但不是 包括,查询字符串。如果 HTTPRequestURI 为空,请使用正斜杠 ( / )。 使用您刚刚创建的字符串、您的秘密访问密钥计算符合 RFC 2104 的 HMAC 作为密钥,SHA256 或 SHA1 作为哈希算法。 欲了解更多信息,请转至http://www.rfc.net/rfc2104.html。 将结果值转换为 base64。 使用结果值作为签名请求参数的值。

所以我所拥有的是......

private string GetSignature()

  StringBuilder sb = new StringBuilder();
  sb.Append("GET\n");
  sb.Append("ec2.amazonaws.com\n");
  sb.Append("/\n");
  sb.Append(string.Join("&", parameters.OrderBy(vp => vp.Key, new CanonicalizedDictCompare()).Select(p => string.Format("0=1", HttpUtility.UrlEncode(p.Key), HttpUtility.UrlEncode(p.Value))).ToArray()));
  UTF8Encoding encoding = new UTF8Encoding();
  HMACSHA256 signature = new HMACSHA256(encoding.GetBytes(_secretAccessKey));
  byte[] hash = signature.ComputeHash(encoding.GetBytes(sb.ToString()));
  string result = Convert.ToBase64String(hash);
  return result;

为了完整起见,这里是 IComparer 实现....

  internal class CanonicalizedDictCompare : IComparer<string>
  
    #region IComparer<string> Members

    public int Compare(string x, string y)
    
      return string.CompareOrdinal(x, y);
    

    #endregion
  

据我所知,我已经为这个哈希做了所有我需要做的事情,但是我不断收到来自服务器的错误,告诉我我的签名不正确。帮助...

【问题讨论】:

上述示例中的类将具有: using System.Security.Cryptography;此外,有关亚马逊对如何执行此操作的描述(减去计算哈希),请参阅docs.amazonwebservices.com/AWSECommerceService/latest/DG/… 【参考方案1】:

好的,我想通了.... HttpUtility 类中的 UrlEncoding 不符合 Amazon 编码方案....grrr (特别是 .NET 实用程序中 % 之后的十六进制值是小写,而不是大写)

b. URL 根据以下规则对参数名称和值进行编码:

不要对任何 RFC 3986 的未保留字符 定义。这些毫无保留的角色 是 A-Z、a-z、0-9、连字符 (-)、 下划线 (_)、句点 (.) 和 波浪号(~)。

百分比编码所有其他字符 使用 %XY,其中 X 和 Y 是十六进制 字符 0-9 和 大写 A-F

百分比编码扩展 UTF-8 %XY%ZA....形式的字符。

百分比编码空间 字符为 %20(而不是 +,如 常见的编码方案)。

所以在编写了一个编码到这个方案的快速方法之后,它工作正常。

【讨论】:

为此干杯。帮助我让它工作。但是我发现我仍然需要(至少)编码连字符。使用连字符进行关键字搜索会导致“无效签名”错误。我还没有测试过其他特殊字符.. 能分享一下这个方法的代码吗?我真的很感激。 @AlirezaNoori 不幸的是,我无法再访问它了。我已经离开了我做这件事的公司。如果我记得,这样做并不难,如果你使用反射器或 IL/Spy,你可以看看它是如何在 HttpUtility 类中完成的,只需将十六进制字符大写。 谢谢。我从 codeproject 中找到了这篇文章,这正是你提到的:codeproject.com/Articles/175025/…

以上是关于使用 c# 的 Amazon ec2 API 版本 2 签名编码的主要内容,如果未能解决你的问题,请参考以下文章

使用 Amazon Web Services (EC2) 和 c# Windows Service/WCF 进行远程调试

从 JAVA API 获取 Amazon EC2 实例的公共 DNS

在 Amazon Elastic Compute Cloud (Amazon EC2) 上托管 twitter 流 api 的优缺点是啥

python 这是来自玩具的日志(来自ipython)和Amazon EC2的定价API。不确定是否仍然支持此功能。我在玩探险

将 PHP 版本 5.3 更新到 7.2 Amazon aws ec2

如何在 .NET 中以编程方式启动 Amazon EC2 实例