Wednesday, April 20, 2016

Secure Amazon Download using Query String Authentication

// https://docs.aws.amazon.com/AmazonS3/latest/dev/RESTAuthentication.html#RESTAuthenticationQueryStringAuth

using System;
using System.Diagnostics;
using System.Security.Cryptography;
using System.Text;
using System.Web;

namespace ConsoleApplication1
{
    class Program
    {
        static string CreateSignatureAsBase64(string secretKey, string stringToSign)
        {
            byte[] dataToSign = Encoding.UTF8.GetBytes(stringToSign);
            using (var crypt = new HMACSHA1(Encoding.UTF8.GetBytes(secretKey)))
            {
                return Convert.ToBase64String(crypt.ComputeHash(dataToSign));
            }
        }
        

        /// <summary>
        /// Returns date expiration in seconds since 1970
        /// </summary>
        /// <param name="minutesExpiration"></param>
        /// <returns></returns>
        public static long GetExpiration(int minutesExpiration)
        {
            DateTime date   = DateTime.UtcNow;
            DateTime origin = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
            TimeSpan diff   = date.ToUniversalTime() - origin + new TimeSpan(0, minutesExpiration, 0);
            return (long) Math.Floor(diff.TotalSeconds);
        }

        static void Main(string[] args)
        {
            long expiration = GetExpiration(minutesExpiration: 1);
            
            string fileToDownload = "ice-bucket/someFilenameHere.pdf";
            
            var stringToSign = 
                "GET" + "\n" +
                "\n" +
                "\n" +
                expiration + "\n" +
                "/" + fileToDownload;

            string secretAccessKey       = "blah/meh";
            string signature64           = CreateSignatureAsBase64(secretAccessKey, stringToSign);            
            string urlEncodedSignature64 = HttpUtility.UrlEncode(signature64);

            string accessKey = "developerId";
			
            string url = 
                string.Format(@"https://s3-us-west-2.amazonaws.com/{0}?AWSAccessKeyId={1}&Expires={2}&Signature={3}", 
                    fileToDownload, 
                    accessKey,
                    expiration, 
                    urlEncodedSignature64);

            Process.Start(url);

        }
    }
}