2009-07-23 53 views
6

我有问题编码ec2 API版本2签名的散列。亚马逊ec2 API版本2的签名编码与c#

注意我的第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. 创建规范化查询字符串,你需要稍后在此过程中:

a。按照自然字节顺序通过参数名称对UTF-8查询字符串组件进行排序。 参数可以来自GET URI或来自POST主体(当Content-Type 是application/x-www-form-urlencoded时)。

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

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

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

c。即使参数值为空,也可以使用等号(=) (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. 使用结果值作为签名请求参数的值。

所以我有什么是....

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

以上示例中的类将具有: 使用System.Security.Cryptography; 此外,亚马逊的描述如何做到这一点(减去计算散列),请参阅http://docs.amazonwebservices.com/AWSECommerceService/latest/DG/index.html?rest-signature.html – adinas 2009-09-13 11:57:21

回答

7

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

b。 URL按照以下规则进行编码的参数名称和值:

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

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

  • 百分比编码的空间 字符为%20(而不是+,作为 共同编码方案一样)。

因此,编写一个快速的方法编码到这个方案后,它工作正常。

+0

干杯。帮助我得到它的工作。但是我发现我仍然需要编码(至少)连字符。用连字符进行关键字搜索会导致“无效签名”错误。我还没有测试过其他特殊字符。 – Dermot 2012-02-17 07:26:05

+0

请问你能分享一下这个方法的代码吗?我真的很感激它。 – 2013-09-12 21:00:42

+0

@AlirezaNoori很遗憾,我无法再访问它了。我已经从我做这件事的公司转移了下来。如果我回想一下,这样做并不困难,如果你使用反射器或IL/Spy,你可以看看它在HttpUtility类中的完成方式,并简单地用大写字母表示十六进制字符。 – 2013-09-12 21:56:18