Amazon SimpleDB for Windows Phone Part 1 - Signature


The first thing to know about the SDK provided by Amazon for .NET (AWSSDK) is that it does not work on Windows Phone. You can't reference the DLL because it hasn't been compiled as a phone class library. If you try to put the source code in and compile it yourself, it won't compile. This is because the SDK contains a lot of code that just doesn't exist in the subset of .NET running on the phone. Amazon has released an SDK for Android and iOS but has yet to release one for Windows Phone. I assume they are working on it, but who knows.

I'm not going to go into how to use the entire AWSSDK with WP7. For my purposes, I only want to use SimpleDB and that's all I'm concerned with in this series of blog posts. Amazon SimpleDB has an API accessible via REST requests and the documentation on creating the REST requests is fairly straightforward, so follow them as needed. For me, the biggest problem I ran into was the creating the signature necessary for a valid request. I kept getting a 403 response code with the error message SignatureDoesNotMatch.

If you look through the AWSSDK to find how Amazon does the signature, you'll find that they cover all their bases. The SDK is broad, configurable, and robust. For example, the SDK allows you to specify a hash algorithm at runtime by changing the configuration. They do this by using a KeyedHashAlgorithm that the hash method uses to hash the parameters. In my case, I don't need a lot of that. Instead, I used a specific hash algorithm as shown below:

[sourcecode language="csharp"] public static string HMACSign(string dataToSign, string key)
{ var hashKey = Encoding.UTF8.GetBytes(key); var hasher = new HMACSHA1(hashKey); var hashedData = hasher.ComputeHash(Encoding.UTF8.GetBytes(dataToSign)); return Convert.ToBase64String(hashedData); } [/sourcecode]

Using the JavaScript Scratchpad for Amazon SimpleDB and some F12 debugging tools in IE9, I was able to verify my signature method was signing the data correctly. But I was still having trouble getting my data to match up with the data from the scratchpad, so I was never getting a correct signature. It turns out, the problem was with the order of the parameters getting signed.

To sign the request, the parameters must be in alphabetical order. That is EXCEPT the AWSAccessKeyId. This has to be before the Action parameter even though it clearly would come after it if the paramters were sorted as is.

AWSSDK uses a SortedList to sort the parameters collection. Once again, this class isn't in WP7. Instead, I used a LINQ query to sort the parameters collection.

[sourcecode language="csharp"] var sorted = from p in parameters orderby p.Key ascending select p; [/sourcecode]

The trick for me was to sort the parameters Dictionary before adding AWSAccessKeyId. When creating the string of data to be signed, I manually append the AWSAccessKeyId before looping through the collection of parameters to add them.

This creates a string like this:

[sourcecode language="csharp"] "GETnsdb.amazonaws.comn/nAWSAccessKeyId=HERESMYKEYYO&Action=GetAttributes&DomainName=AwesomeButtonScores&ItemName=First& SignatureMethod=HmacSHA1&SignatureVersion=2&Timestamp=2011-10-10T18%3A42%3A46.000Z&Version=2009-04-15"

Notice that all the parameters are sorted except for the AWSAccessKeyId. Put that one in there before the sorted ones, then sign that string. Once I made that change, I was able to create requests and sign them successfully. This sample was done using the GetAttributes function of SimpleDB with a GET request. Stay tuned for more posts on this subject. I'm posting as I work through my solution. Eventually I'll share what I'm using SimpleDB for.

Missed the rest of the series? Check ‘em out:

Amazon SimpleDB for Windows Phone Part 2 — Using Fiddler