Mohsenne
Mohsenne

Reputation: 356

Generating pre-signed Url in .Net for AWS s3

Based on the documentation, with provided sample data, it should be possible to generate a signed key with value of:

aeeed9bbccd4d02ee5c0109b86d86835f995330da4c265957d157751f604d404

Here is my code in .Net:

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;

namespace PlayingWithAmazonS3
{
    public class ReadTextFilePerRest
    {
        private string _regionSample = "us-east-1";
        private string _dateSample = "20130524";
        private string _secretAccessKeySample = "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY";
        private string _canonicalRequestPath = "..\\Files\\SampleFiles\\CanonicalRequest.txt";
        private string _stringToSignPath = "..\\Files\\SampleFiles\\StringToSign.txt";

        private string _canonicalRequest;
        private string _stringToSign;

        public void ReadPayloadFiles()
        {
            _stringToSign = File.ReadAllText(_stringToSignPath);
            _canonicalRequest = File.ReadAllText(_canonicalRequestPath);
        }

        // it needs to return: aeeed9bbccd4d02ee5c0109b86d86835f995330da4c265957d157751f604d404
        public string SigningKey()
        {
            var keyBytes = Encoding.ASCII.GetBytes("AWS4" + _secretAccessKeySample);
            var dateBytes = Encoding.ASCII.GetBytes(_dateSample);
            var regionBytes = Encoding.ASCII.GetBytes(_regionSample);
            var serviceBytes = Encoding.ASCII.GetBytes("s3");
            var requestBytes = Encoding.ASCII.GetBytes("aws4_request");
            var stringToSignBytes = Encoding.ASCII.GetBytes(_stringToSign);

            using (HMACSHA256 hmac = new HMACSHA256(dateBytes))
            {
                var dateKey = hmac.ComputeHash(keyBytes);

                using (HMACSHA256 hmac2 = new HMACSHA256(regionBytes))
                {
                    var dateRegionKey = hmac2.ComputeHash(dateKey);

                    using (HMACSHA256 hmac3 = new HMACSHA256(serviceBytes))
                    {
                        var dateRegionServiceKey = hmac3.ComputeHash(dateRegionKey);

                        using (HMACSHA256 hmac4 = new HMACSHA256(requestBytes))
                        {
                            var signingKey = hmac4.ComputeHash(dateRegionServiceKey);

                            using (HMACSHA256 hmac5 = new HMACSHA256(stringToSignBytes))
                            {
                                var signature = hmac5.ComputeHash(signingKey);

                                return ByteToString(signature);
                            }
                        }
                    }
                }
            }
        }

        private string ByteToString(IEnumerable<byte> buffer)
        {
            var sBinary = buffer.Aggregate("", (current, buff) => current + buff.ToString("X2"));

            return sBinary;
        }
    }
}

However, my generated signed key is different. Can anybody tell me where is my mistake?

Upvotes: 2

Views: 3542

Answers (1)

Mohsenne
Mohsenne

Reputation: 356

using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;

namespace PlayingWithAmazonS3
{
    /// <summary>
    /// this class is only responsible for calculating the final signature for creating a pre-signed Url to
    /// communicate through REST with iam service
    /// </summary>
    public class PreSignedUrlRestSignatureCal
    {
        private const string RegionSample = "us-east-1";
        private const string DateSample = "20150830";
        private const string ServiceSample = "iam";

        // it is provided as an example by AWS
        private const string SecretAccessKeySample = "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY";

        /// <summary>
        /// this method will be called in main
        /// </summary>
        public void ExecuteMethod()
        {
            var finalSignature = SigningKey();

            Console.WriteLine("Final Signature: " + finalSignature);
        }

        private string SigningKey()
        {
            // generating derived signing key
            var derivedSigningKey =
                GetSignatureKey(SecretAccessKeySample, DateSample, RegionSample, ServiceSample);

            // example signingKey provided by aws for test
            var stringToSign = "AWS4-HMAC-SHA256" + "\n" +
                               "20150830T123600Z" + "\n" +
                               "20150830/us-east-1/iam/aws4_request" + "\n" +
                               "f536975d06c0309214f805bb90ccff089219ecd68b2577efef23edd43b7e1a59";

            // generating the final signature
            var signature = HmacSha256(stringToSign, derivedSigningKey);

            // returning the hex value of the final signature
            return ByteToString(signature);
        }

        /// <summary>
        /// calculating hmac-sha256 in .Net
        /// </summary>
        /// <param name="data"></param>
        /// <param name="key"></param>
        /// <returns></returns>
        private byte[] HmacSha256(string data, byte[] key)
        {
            const string algorithm = "HmacSHA256";
            var kha = KeyedHashAlgorithm.Create(algorithm);
            kha.Key = key;

            return kha.ComputeHash(Encoding.UTF8.GetBytes(data));
        }

        /// <summary>
        /// get derived signing key (not the final signature) from provided info 
        /// </summary>
        /// <param name="key"></param>
        /// <param name="dateStamp"></param>
        /// <param name="regionName"></param>
        /// <param name="serviceName"></param>
        /// <returns></returns>
        private byte[] GetSignatureKey(string key, string dateStamp, string regionName, string serviceName)
        {
            var kSecret = Encoding.UTF8.GetBytes(("AWS4" + key).ToCharArray());
            var kDate = HmacSha256(dateStamp, kSecret);
            var kRegion = HmacSha256(regionName, kDate);
            var kService = HmacSha256(serviceName, kRegion);
            var kSigning = HmacSha256("aws4_request", kService);

            return kSigning;
        }

        /// <summary>
        /// it returns the hex value of byte[]
        /// </summary>
        /// <param name="buffer"></param>
        /// <returns></returns>
        private string ByteToString(IEnumerable<byte> buffer)
        {
            var sBinary = buffer.Aggregate("", (current, buff) => current + buff.ToString("X2"));

            return sBinary.ToLower();
        }
    }
}

Upvotes: 1

Related Questions