6

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

请注意我的版本 1 签名散列工作正常,但这是贬值,我将需要移动到版本 2。所以首先这里是工作的代码......

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

private string GetVersion1Sig()
{
  string sig = string.Join(string.Empty, parameters.OrderBy(vp => vp.Key).Select(p => string.Format("{0}{1}", 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 开发人员指南中的文档...

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

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

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

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

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

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

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

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

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

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
  }

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

4

1 回答 1

7

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

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

  • 不要对RFC 3986 定义的任何非保留字符进行 URL 编码。这些非保留字符是 AZ、az、0-9、连字符 (-)、下划线 (_)、句点 (.) 和波浪号 (~)。
  • 百分比使用 %XY 对所有其他字符进行编码,其中 X 和 Y 是十六进制字符 0-9 和大写 AF

  • 百分比编码扩展的 UTF-8 字符,格式为 %XY%ZA....

  • 百分比将空格字符编码为 %20(而不是 +,就像常见的编码方案那样)。

因此,在编写了一个对该方案进行编码的快速方法之后,它可以正常工作。

于 2009-07-23T23:25:56.883 回答