Question

I'm trying to create a SimpleDB persistence framework for a Xamarin component. I can't use the .NET SDK since not all the required assemblies are present in a PCL project. For that reason I'm trying create REST request myself but i keep getting SignatureDoesNotMatch when trying to POST my request.

Can someone help and see if there is something wrong with my signature generation.

Here is the request to be signed

https://sdb.amazonaws.com/?Action=PutAttributes&DomainName=test&ItemName=0&Attribute.1.Name=test&Attribute.1.Value=test&AWSAccessKeyId=AAAAAAAAAAAAAAAAAAAA&Version=2009-04-15&SignatureVersion=2&SignatureMethod=HmacSHA256&Timestamp=2014-04-20T11%3A04%3A10%2B02%3A00

Here is the string being signed

POST\n sdb.amazonaws.com\n /\n &AWSAccessKeyId=AAAAAAAAAAAAAAAAAAAA&Action=PutAttributes&Attribute.1.Name=test&Attribute.1.Value=test&DomainName=test&ItemName=0&SignatureMethod=HmacSHA256&SignatureVersion=2&Timestamp=2014-04-20T11%3A03%3A12%2B02%3A00&Version=2009-04-15

Here is the signed request.

https://sdb.amazonaws.com/?Action=PutAttributes&DomainName=test&ItemName=0&Attribute.1.Name=test&Attribute.1.Value=test&AWSAccessKeyId=AAAAAAAAAAAAAAAAAAAA&Version=2009-04-15&Signature=h0lNLh%2BfpDLzM2ipBozPnH6dDKFU%2BFTDwH82H42ptI8%3D&SignatureVersion=2&SignatureMethod=HmacSHA256&Timestamp=2014-04-20T11%3A05%3A05%2B02%3A00

Test AWSAccessKeyId = AAAAAAAAAAAAAAAAAAAA Test AWSSecretKey = BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB

I have included C# files of my hashing and the request builder

public class PutAttributesRequestMarshaller
{
    private const string ACTION = "PutAttributes";
    private const string METHOD = "POST";
    private const string SIGNATURE_METHOD = "HmacSHA256";
    private const string SIGNATURE_VERSION = "2";
    private const string VERSION = "2009-04-15";
    private SortedDictionary<string, string> AttributesDic = new SortedDictionary<string, string> ();
    private PutAttributesRequest request;

    public PutAttributesRequestMarshaller (PutAttributesRequest request)
    {
        this.request = request;

        for (int i = 0; i < request.Attributes.Count; i++) {
            ReplaceableAttribute Attribute = request.Attributes [i];
            AttributesDic.Add ("Attribute." + (i + 1) + ".Name", Attribute.Name);
            AttributesDic.Add ("Attribute." + (i + 1) + ".Value", Attribute.Value);
            if (Attribute.Replace.Value) {
                AttributesDic.Add ("Attribute." + (i + 1) + ".Replace", Attribute.Replace.ToString ().ToLower ());
            }
        }
    }

    public String Marshal ()
    {
        StringBuilder sb = new StringBuilder ();

        sb.Append ("https://" + Region + "/");
        sb.Append ("?Action=" + ACTION);
        sb.Append ("&DomainName=" + request.DomainName);
        sb.Append ("&ItemName=" + request.ItemName);
        sb.Append (Attributes);
        sb.Append ("&Version=" + VERSION);
        sb.Append ("&Timestamp=" + Timestamp);

        string signature = GenerateSignature ();
        string encoded = System.Net.WebUtility.UrlEncode (signature);

        sb.Append ("&Signature=" + encoded);
        sb.Append ("&SignatureVersion=" + SIGNATURE_VERSION);
        sb.Append ("&SignatureMethod=" + SIGNATURE_METHOD);
        sb.Append ("&AWSAccessKeyId=" + AWSAccessKeyId);

        return sb.ToString ();
    }

    private string Attributes {
        get {
            StringBuilder sb = new StringBuilder ();
            var enumerator = AttributesDic.GetEnumerator ();
            while (enumerator.MoveNext ()) {
                var entry = enumerator.Current;
                sb.Append ("&");
                sb.Append (System.Net.WebUtility.UrlEncode (entry.Key));
                sb.Append ("=");
                sb.Append (System.Net.WebUtility.UrlEncode (entry.Value));
            }
            return sb.ToString ();
        }
    }

    private  string AWSAccessKeyId {
        get {
            return ServiceContainer.Resolve<SimpleDBClient> ().AWSAccessKeyId;
        }
    }

    private  string AWSSecretKey {
        get {
            return ServiceContainer.Resolve<SimpleDBClient> ().AWSSecretKey;
        }
    }

    private  string Timestamp {
        get {

            DateTime withOutMili = DateTime.Now;
            string formatted = withOutMili.ToString ("yyyy-MM-ddTHH:mm:sszzzzz");
            string encoded = System.Net.WebUtility.UrlEncode (formatted);
            return encoded;
        }
    }

    public  string Region {
        get {
            return ServiceContainer.Resolve<SimpleDBClient> ().Region;
        }
    }

    private string GenerateSignature ()
    {
        StringBuilder sb = new StringBuilder ();
        sb.Append (METHOD + "\n");
        sb.Append (Region + "\n");
        sb.Append ("/\n");
        sb.Append ("&AWSAccessKeyId=" + AWSAccessKeyId);
        sb.Append ("&Action=" + ACTION);
        sb.Append (Attributes);
        sb.Append ("&DomainName=" + request.DomainName);
        sb.Append ("&ItemName=" + request.ItemName);
        sb.Append ("&SignatureMethod=" + SIGNATURE_METHOD);
        sb.Append ("&SignatureVersion=" + SIGNATURE_VERSION);
        sb.Append ("&Timestamp=" + Timestamp);
        sb.Append ("&Version=" + VERSION);

        string signature = sb.ToString ();

        ISHA256Service service = ServiceContainer.Resolve<ISHA256Service> ();

        string hashed = service.CreateHash (signature, AWSSecretKey);

        return hashed;
    }

    private  SimpleDBClient Client {
        get {
            return ServiceContainer.Resolve<SimpleDBClient> ();
        }
    }

public string CreateHash (string message, string secret)
    {
        var encoding = new System.Text.ASCIIEncoding ();
        byte[] keyByte = encoding.GetBytes (secret);
        byte[] messageBytes = encoding.GetBytes (message);
        using (var hmacsha256 = new HMACSHA256 (keyByte)) {
            byte[] hashmessage = hmacsha256.ComputeHash (messageBytes);
            return Convert.ToBase64String (hashmessage);
        }
    }

Thank you in advance.

Was it helpful?

Solution

I found several problems with my code, the biggest was to that i used 2 different timestamps.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top