2009-07-23 2 views
6

У меня возникла проблема с кодировкой хэша для версии 2 Подпись API ec2.Amazon 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 есть некоторые изменения, вот DOCO от руководства разработчиков API ...

  1. Создайте канонизированную строку запроса, вам необходимо позднее в этой процедуре:

a. Сортируйте компоненты строки запроса UTF-8 по имени параметра с естественным порядком байтов. Параметры могут быть получены из URI GET или из тела POST (когда Content-Type является приложением/x-www-form-urlencoded).

b. URL-адрес кодирует имя и значения параметров в соответствии со следующими правилами:

• Не кодируйте URL-код любого из безоговорочных символов, определенных в RFC 3986. Эти незаслуженные символы: A-Z, a-z, 0-9, дефис (-), подчеркивание (_), период (.), и тильда (~).
• Процент кодирует все остальные символы с% XY, где X и Y являются шестнадцатеричными символами 0-9 и прописными буквами A-F.
• Процент кодирует расширенные символы UTF-8 в форме% XY% ZA ....
• Процент кодирует пробельный символ как% 20 (и не +, как схемы общего кодирования do).

Примечание
В настоящее время все имена параметров службы AWS используют незарезервированные символы, поэтому вам не нужно кодировать их . Однако вы можете включить код для обработки параметров имен, в которых используются зарезервированные символы, для возможного использования в будущем.

c. Отделите имена закодированных параметров от их закодированных значений знаком равенства (=) (символ ASCII 61), даже если значение параметра пуст.

d. Отделите пары имя-значение амперсандом (&) (код ASCII 38).

  1. Создайте строку для подписи согласно следующей псевдограмматике («\ n» представляет строку новой строки ASCII ). StringToSign = HTTPVerb + "\ п" + ValueOfHostHeaderInLowercase + "\ п" + HTTPRequestURI + "\ п" +
    CanonicalizedQueryString Компонент HTTPRequestURI является HTTP-абсолютный путь компонента URI до, но не в том числе, строка запроса. Если HTTPRequestURI пуст, используйте косую черту (/).
  2. Рассчитайте HMAC, совместимый с RFC 2104, только что созданной вами строкой, ключ секретного доступа в качестве ключа и 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; Кроме того, для описания Amazon о том, как это сделать (минус вычисление хэша), см. Http://docs.amazonwebservices.com/AWSECommerceService/latest/DG/index.html?rest-signature.html – adinas

ответ

7

Хорошо, я это понял .... UrlEncoding в классе HttpUtility не соответствует схеме кодирования Amazon .... grrr (в частности, шестнадцатеричное значение после% в утилите .NET строчный, не прописной)

б. URL кодировать имя параметра и значение в соответствии со следующими правилами:

  • ли не URL закодировать любого из неблокированных символов, что RFC 3986 определяет. Эти незаслуженные символы A-Z, a-z, 0-9, дефис (-), подчеркивание (_), период (.) И тильда (~).
  • Percent закодировать все остальные символы с% XY, где X и Y являются HEX символы 0-9 и прописные A-F.

  • Процент кодирования расширен UTF-8, символы в виде% XY% ZA ....

  • Процент закодировать пространства характер, как% 20 (и не +, как это делают схемы общего кодирования).

Итак, после написания быстрого метода, который кодирует эту схему, он отлично работает.

+0

Приветствия для этого. Помог мне заставить его работать. Однако я обнаружил, что мне все еще нужно кодировать (по крайней мере) дефис. выполнение поиска по ключевым словам с дефис в нем вызвало ошибку «Недействительная подпись». Я еще не тестировал другие специальные символы. – Dermot

+0

Не могли бы вы поделиться кодом для этого метода? Я бы очень признателен. –

+0

@AlirezaNoori, к сожалению, у меня нет доступа к нему больше. Я перешел от компании, где я это сделал. Если я помню, это было не так сложно сделать, если вы используете рефлектор или IL/Spy, вы можете посмотреть, как это делается в классе HttpUtility и просто загладить шестнадцатеричные символы. –