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

时间:2009-07-23 05:45:49

标签: c# amazon-ec2 hash amazon

我遇到了为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开发人员指南的doco ......

  1. 创建稍后在此过程中需要的规范化查询字符串:
  2. 一个。使用自然字节顺序按参数名称对UTF-8查询字符串组件进行排序。 参数可以来自GET URI或POST主体(当Content-Type时 是application / x-www-form-urlencoded)。

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

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

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

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

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

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

      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
        }
      

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

1 个答案:

答案 0 :(得分:7)

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

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

  • 不要对任何网址进行网址编码 RFC 3986的无保留字符 定义。这些无保留的字符 是A-Z,a-z,0-9,连字符( - ), 下划线(_),句号(。)和 tilde(〜)。
  • 百分比编码所有其他字符 %XY,其中X和Y是十六进制 字符0-9和大写字母A-F

  • 百分比编码扩展的UTF-8 %XY%ZA ....

  • 形式的字符
  • 百分比编码空间 字符为%20(而不是+,as 常见的编码方案确实如此。

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