2010-02-17 13 views
7

¿Alguno de los usuarios de .net ha averiguado cómo firmar correctamente una firma para utilizarla con contenido privado de CloudFront? Después de un par de días de intentos, todo lo que puedo obtener es Acceso denegado.Cómo cifrar la firma de Amazon CloudFront para el acceso de contenido privado mediante una política enlatada

He estado trabajando con variaciones del siguiente código y también he intentado usar OpenSSL.Net y AWSSDK, pero eso aún no tiene un método de firma para RSA-SHA1.

La firma (datos) se parece a esto

{"Statement":[{"Resource":"http://xxxx.cloudfront.net/xxxx.jpg","Condition":​{"DateLessThan":​{"AWS:EpochTime":1266922799}}}]} 

Actualización: Resuelto todo esto mediante la eliminación de un único espacio en la firma anterior.

¡Si lo hubiera notado antes!

Este método intenta firmar la firma para su uso en la url en lata. Así que de las variaciones se han incluido el candado del relleno utilizado en el has y también la inversión del byte [] antes de firmar, ya que OpenSSL lo hace de esta manera.

public string Sign(string data) 
{ 
    using (SHA1Managed SHA1 = new SHA1Managed()) 
    { 
     RSACryptoServiceProvider provider = new RSACryptoServiceProvider(); 
     RSACryptoServiceProvider.UseMachineKeyStore = false; 

     // Amazon PEM converted to XML using OpenSslKey 
     provider.FromXmlString("<RSAKeyValue><Modulus>....."); 

     byte[] plainbytes = System.Text.Encoding.UTF8.GetBytes(data); 

     byte[] hash = SHA1.ComputeHash(plainbytes); 
     //Array.Reverse(sig); // I have see some examples that reverse the hash 

     byte[] sig = provider.SignHash(hash, "SHA1"); 

    return Convert.ToBase64String(sig); 
    } 
} 

Su útil señalar que he verificado el contenido está configurado correctamente en S3 y CloudFront mediante la generación de una política de URL en lata CloudFront usando el Explorador de mi CloudBerry. ¿Cómo lo hicieron?

Cualquier idea sería muy apreciada. Gracias

+0

Chet, Podría elaborar sobre su solución? Me gustaría implementar contenido privado en el administrador de descargas de PostSharp (ahora usando el contenido público de S3 + CloudFront). Estoy especialmente intrigado por cómo convierte Amazon PEM en XML con OpenSslKey. ¿Podría compartir un enlace a esto? Gracias. -gael –

+0

Para convertir el PEM a XML, puede obtener la versión fuente o en versión de OpenSSLKey desde http://www.jensign.com/opensslkey/index.html Si descarga, simplemente ejecute opensslkey.exe desde la línea del cmd y siga las instrucciones – Chet

+0

Gracias - No fue muy difícil de implementar con esa información. Sin embargo, recomiendo probar que S3/CloudFront está configurado correctamente usando alguna GUI, y luego solo intentar hacer lo mismo con el código. –

Respuesta

6

Aquí está el código completo si alguien si está interesado:

internal class CloudFrontSecurityProvider 
{ 
    private readonly RSACryptoServiceProvider privateKey; 
    private readonly string privateKeyId; 
    private readonly SHA1Managed sha1 = new SHA1Managed(); 

    public CloudFrontSecurityProvider(string privateKeyId, string privateKey) 
    { 
     this.privateKey = new RSACryptoServiceProvider(); 
     RSACryptoServiceProvider.UseMachineKeyStore = false; 

     this.privateKey.FromXmlString(privateKey); 
     this.privateKeyId = privateKeyId; 
    } 
    private static int GetUnixTime(DateTime time) 
    { 
     DateTime referenceTime = new DateTime(1970, 1,1); 
     return (int) (time - referenceTime).TotalSeconds; 

    } 

    public string GetCannedUrl(string url, DateTime expiration) 
    { 

     string expirationEpoch = GetUnixTime(expiration).ToString(); 

     string policy = 
      @"{""Statement"":[{""Resource"":""<url>"",""Condition"":{""DateLessThan"":{""AWS:EpochTime"":<expiration>}}}]}". 
       Replace("<url>", url). 
       Replace("<expiration>", expirationEpoch); 


     string signature = GetUrlSafeString(Sign(policy)); 

     return url + string.Format("?Expires={0}&Signature={1}&Key-Pair-Id={2}", expirationEpoch, signature, this.privateKeyId); 
    } 

    private static string GetUrlSafeString(byte[] data) 
    { 
     return Convert.ToBase64String(data).Replace('+', '-').Replace('=', '_').Replace('/', '~'); 
    } 

    private byte[] Sign(string data) 
    { 
      byte[] plainbytes = Encoding.UTF8.GetBytes(data); 

      byte[] hash = sha1.ComputeHash(plainbytes); 

      return this.privateKey.SignHash(hash, "SHA1"); 
    } 

} 
+0

Tenga cuidado con la expiración tiempo que pasa. Tiene que estar relacionado con la hora UTC. – beckelmw

Cuestiones relacionadas