2009-07-23 14 views
6

Tengo un problema con la codificación del hash para la versión 2 Firma de la API ec2.Amazon ec2 API versión 2 codificación de firma con C#

Nota mi versión 1 de la firma hash funciona bien, pero esto es amortizado y que tendrá que mover a la versión 2. Así que en primer lugar, aquí es el código que funciona ...

parámetros es sólo un diccionario, lo que lo que tengo que hacer es simplemente ordenar los parámetros por clave y anexar cada par de valores sin ningún delimetro, luego ajustar esa cadena contra mi clave. (De nuevo, tenga en cuenta que esto funciona muy bien)

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; 
} 

Ahora, con la versión 2 hay algunos cambios, aquí está el mana de la guía de desarrolladores de la API ...

  1. Crear la cadena de consulta que forma canónica necesitará más adelante en este procedimiento:

a. Ordene los componentes de cadena de consulta UTF-8 por nombre de parámetro con ordenamiento natural de bytes. Los parámetros pueden provenir del URI GET o del cuerpo POST (cuando Content-Type es application/x-www-form-urlencoded).

b. La URL codifica el nombre del parámetro y los valores de acuerdo con las siguientes reglas:

• No codifique URL de ninguno de los caracteres no reservados que RFC 3986 define. Estos caracteres no reservados son A-Z, a-z, 0-9, guión (-), guión bajo (_), punto (.), y tilde (~).
• El porcentaje codifica todos los demás caracteres con% XY, donde X e Y son caracteres hexadecimales 0-9 y mayúsculas A-F.
• Porcentaje codifica caracteres UTF-8 extendidos en el formato% XY% ZA ....
• El porcentaje codifica el carácter de espacio como% 20 (y no +, como lo hacen los esquemas de codificación comunes do).

Nota
Actualmente, todos los nombres de los parámetros de servicio AWS utilizar caracteres no reservados, por lo que no necesita codificarlos. Sin embargo, es posible que desee incluir código para manejar los nombres de los parámetros que usan caracteres reservados, para un posible uso futuro.

c. Separe los nombres de los parámetros codificados de sus valores codificados con el signo igual (=) (carácter ASCII 61), incluso si el valor del parámetro está vacío.

d. Separe los pares nombre-valor con un signo de y comercial (&) (código ASCII 38).

  1. Cree la cadena para firmar de acuerdo con la siguiente pseudo-gramática (la "\ n" representa una nueva línea ASCII ). StringToSign = HTTPVerb + "\ n" + ValueOfHostHeaderInLowercase + "\ n" + HTTPRequestURI + "\ n" +
    CanonicalizedQueryString El componente HTTPRequestURI es el componente ruta absoluta HTTP de la URI hasta, pero no incluyendo, la cadena de consulta. Si HTTPRequestURI está vacío, use una barra inclinada (/).
  2. Calcule un HMAC compatible con RFC 2104 con la cadena que acaba de crear, su clave secreta de acceso como clave, y SHA256 o SHA1 como el algoritmo hash. Para obtener más información, vaya al http://www.rfc.net/rfc2104.html.
  3. Convierta el valor resultante a base64.
  4. Utilice el valor resultante como el valor del parámetro de solicitud de Firma.

Así que lo que tengo es ....

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; 
} 

esté completo aquí es la implementación IComparer ....

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

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

    #endregion 
    } 

Por lo que yo puedo decir que he hecho todo lo Tengo que hacer este hash, pero recibo un error del servidor que me dice que mi firma es incorrecta. Ayuda ...

+1

La clase en el ejemplo anterior tendría: usando System.Security.Cryptography; Además, para la descripción de Amazon de cómo hacer esto (menos el cálculo del hash), consulte http://docs.amazonwebservices.com/AWSECommerceService/latest/DG/index.html?rest-signature.html – adinas

Respuesta

7

Ok, lo descubrí ... El UrlEncoding en la clase HttpUtility no se ajusta al esquema de codificación de Amazon .... grrr (específicamente el valor hexadecimal después del% en la utilidad .NET es minúscula, no mayúscula)

b. URL codificar el nombre y los valores de parámetros de acuerdo a las siguientes reglas:

  • ¿No URL codificar cualquiera de los personajes sin reservas de que RFC 3986 define. Estos caracteres no reservados son A-Z, a-z, 0-9, guión (-), guión bajo (_), punto (.) Y tilde (~).
  • Porcentaje codificar todos los demás caracteres con% XY, donde X e Y son hex caracteres 0-9 y mayúsculas A-F.

  • Porcentaje codificar extendió UTF-8 caracteres en la forma% XY% ZA ....

  • Porcentaje codificar el espacio carácter como% 20 (y no +, como esquemas de codificación común hacen).

Después de escribir un método rápido que codifica este esquema, funciona bien.

+0

Saludos por esto. Me ayudó a hacerlo funcionar. Sin embargo, encontré que todavía necesito codificar (al menos) el guión. hacer una búsqueda por palabra clave con un guión en el mismo causó un error de "Firma Inválida". Todavía no he probado otros caracteres especiales. – Dermot

+0

¿Podría compartir el código de este método? Realmente lo apreciaría. –

+0

@AlirezaNoori desafortunadamente no tengo acceso a él más. Pasé de la empresa donde hice esto. Sin embargo, si recuerdo, no fue demasiado difícil hacer esto, si usas el reflector o IL/Spy puedes echar un vistazo a cómo se hace en la clase HttpUtility y simplemente en mayúsculas los caracteres hexadecimales. –