2010-02-17 13 views
7

Qualcuno che ha utilizzato .net ha effettivamente elaborato come firmare correttamente una firma da utilizzare con contenuto privato CloudFront? Dopo un paio di giorni di tentativi tutto ciò che posso ottenere è Accesso negato.Come crittografare la firma di Amazon CloudFront per l'accesso al contenuto privato utilizzando criteri predefiniti

Ho lavorato con varianti del seguente codice e ho anche provato a utilizzare OpenSSL.Net e AWSSDK ma non ha ancora un metodo di firma per RSA-SHA1.

La firma (dati) si presenta così

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

Aggiornamento: Risolto tutto questo rimuovendo un singolo spazio nella firma sopra.

Se solo l'avessi notato prima!

Questo metodo tenta di firmare la firma per l'utilizzo nell'URL in scatola. Quindi tra le varianti è incluso il chanding del padding usato nell'hash e anche il contrario del byte [] prima di firmare come OpenSSL appropriatamente.

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

Il suo utile notare che ho verificato il contenuto è configurato correttamente in S3 e CloudFront generando un URL politica in scatola CloudFront usando il mio CloudBerry Explorer. Come lo fanno?

Qualsiasi idea sarebbe molto apprezzata. Grazie

+0

Chet, Potrebbe approfondire la vostra soluzione? Vorrei implementare il contenuto privato nel gestore di download PostSharp (che ora utilizza il contenuto pubblico S3 + CloudFront). Sono particolarmente incuriosito dal modo in cui converti il ​​PEM di Amazon in XML con OpenSslKey. Potresti condividere un link a questo? Grazie. -gael –

+0

Per convertire il PEM in XML è possibile prendere la sorgente o versione ridotta di OpenSSLKey da http://www.jensign.com/opensslkey/index.html Se si esegue il download, eseguire semplicemente opensslkey.exe da la linea cmd e segui le istruzioni – Chet

+0

Grazie - Non è stato troppo difficile da implementare con tali informazioni. Tuttavia, ti consiglio di provare che S3/CloudFront sia configurato correttamente usando una GUI, e quindi provi solo a fare la stessa cosa con il codice. –

risposta

6

Ecco il codice completo, se qualcuno se interessato:

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

Attenzione alla scadenza tempo passato. Deve essere correlato all'ora UTC. – beckelmw