Advertisements
//
archives

Archive for

Amazon SimpleDB for Windows Phone Part 4 — TVMClient

Today I was made aware that in my series on Amazon SimpleDB for Windows Phone, I had mentioned that part 4 would contain some code samples and talk about encryption. I was confused for a second because I knew there was no part 4 and I thought the series was done. The series is not done. This is part 4 where we’ll show how to decrypt the credentials sent from the TVM. This one goes out to reader @jayborseth.

One thing to note is that since I started the series, an AWS SDK for Windows Phone has been released in beta form. The example I’m about to show does not use this SDK (and I don’t think the SDK has any work with the TVM).

As a refresher, the Token Vending Machine allows for an application to obtain temporary credentials for access to AWS services. In the anonymous way of obtaining credentials, there are 3 steps:

 

Step 1 – Register Device

Here is my code to register the device:

public void RegisterDevice(string deviceId, string tvmKey, Action callback)
{
    IDictionary parameters = new Dictionary();

    parameters["uid"] = deviceId;
    parameters["key"] = tvmKey;

    string queryString = GetParametersAsString(parameters);

    var uri = new Uri(string.Format("{0}/registerdevice?{1}", TvmUrl, queryString));

    var hwr = WebRequest.Create(uri) as HttpWebRequest;
    if (hwr != null)
    {
        hwr.Method = "GET";
    }

    TemporaryTokenPackage tokenPackage = new TemporaryTokenPackage() { DeviceId = deviceId, Request = hwr };

    AsyncCallback responseHandler = (async) =>
    {
        TemporaryTokenPackage temporaryTokenPackage = (TemporaryTokenPackage)async.AsyncState;
        HttpWebRequest request = temporaryTokenPackage.Request;

        HttpWebResponse response = null;
        try
        {
            response = (HttpWebResponse)request.EndGetResponse(async);
            callback(true, null);

        }
        catch (WebException we)
        {
            if (((HttpWebResponse)we.Response).StatusDescription == "Conflict")
            {
                callback(true, null);
            }
            else
            {
                callback(false, we);
            }

        }
    };

    hwr.BeginGetResponse(responseHandler, tokenPackage);
}

Couple of things. Here is my TemporaryTokenPackage which I used to pass pieces of data around the async handlers:

public class TemporaryTokenPackage
{
    public HttpWebRequest Request { get; set; }
    public string DeviceId { get; set; }
}

In the RegisterDevice method, we setup a typical request having a device ID and a tvm key. The tvm key is a Guid string without dashes. So,

tvmKey = Guid.NewGuid().ToString().Replace(“-“, “”);

You set the key and tell the TVM what key you are going to use using this call. The TVM will eventually use that key to encrypt the credentials.

The /registerdevice HTTP call doesn’t do much. If it returns, then you’ve successfully registered the device. If you get any error, you did not register the device and something is wrong. Try again.

Step 2 – Ask for Temporary Credentials

This is the part of the process where you ask the TVM for temporary credentials. If you already have a set of temporary credentials and they haven’t expired, you don’t need to ask for another set. Otherwise, get out your knee pads and beg. Here is how I did it:

public void GetTemporaryCredentials(string deviceId, string tvmKey, Action callback)
{
    string timeStamp = GetFormattedTimestampIso8601(0);
    string signature = Hmac2556Sign(timeStamp, tvmKey);

    IDictionary parameters = new Dictionary();
    parameters["uid"] = deviceId;
    parameters["timestamp"] = timeStamp;
    parameters["signature"] = signature;

    string queryString = GetParametersAsString(parameters);
    var uri = new Uri(string.Format("{0}/gettoken?{1}", TvmUrl, queryString));

    var hwr = WebRequest.Create(uri) as HttpWebRequest;
    AsyncCallback responseHandler = async =>
    {
        var request = (HttpWebRequest)async.AsyncState;

        HttpWebResponse response = null;
        try
        {
            response = (HttpWebResponse) request.EndGetResponse(async);

        }
        catch (WebException we)
        {
            callback(null, we);
        }

        if (IsGoodResponse(response))
        {
            Stream stream = response.GetResponseStream();
            var sr = new StreamReader(stream);

            var responseText = sr.ReadToEnd();
            sr.Close();

            var dataToDecrypt = Convert.FromBase64String(responseText);
            var plainText = Decrypt(dataToDecrypt, tvmKey);

            var temporaryCredentials = AwsTemporaryCredentialFactory.Create(plainText);

            callback(temporaryCredentials, null);

            return;

        }
        else
        {
            string responseText = "noresponse";

            if (response != null)
            {
                responseText = response.StatusCode.ToString();
            }

            callback(null, new WebException("Bad web response, StatusCode=" + responseText));

        }
    };

    hwr.BeginGetResponse(responseHandler, hwr);
}

Step 3 – Decrypt Your New Creds

This is where, as they say on MTV Cribs, the magic happens. Note that at the start of this method, we’re calculating the signature. This is what we talked about in Part 1. The bulk of this method is setting up the async HTTP call and dealing with the response. If we have a good HTTP response, we know that the TVM sent us something secret and we need to get it out. After encrypting the temporary credentials, the TVM will Base64 encode the result. So we need to decode that data using the .NET framework methods and we simply call Convert.FromBase64String which gives us a lovely byte array. Oh byte array.

This byte array is the raw encrypted credentials and we need to decrypt it. I pass into the Decrypt method the binary data to decrypt and the same tvm key that we used to register the device. Here’s the Decrypt method:

public string Decrypt(byte[] dataToDecrypt, string secretKey)
{
    var secretKeyToUse = DecodeHex(secretKey.ToCharArray());
    var cipher = CipherUtilities.GetCipher("AES/CBC/PKCS7Padding");

    cipher.Init(false, new KeyParameter(secretKeyToUse));

    int size =  cipher.GetOutputSize(dataToDecrypt.Length);
    var results = new byte[size];

    int olen = cipher.ProcessBytes(dataToDecrypt, 0, dataToDecrypt.Length, results, 0);
    cipher.DoFinal(results, olen);

    var result = Encoding.UTF8.GetString(results, 0, results.Length);

    return result;
}

///
<summary> /// Used to decode a plain text key into a key that can be used to decrypt. The data being passed in is assumed to be a
/// series of hex digits and this converts those 2-digit hex bytes into a single byte array.
/// </summary>
/// This is adapated from the org.apache.commons.codec.binary.Hex java source code at http://kickjava.com/src/org/apache/commons/codec/binary/Hex.java.htm
///
///An array of characters containing hex digits
/// A byte array containing the decoded hex data in binary format.
public static byte[] DecodeHex(char[] data)
{
    int len = data.Length;

    if ((len & 0x01) != 0)
    {
        throw new DataLengthException("Odd number of characters.");
    }

    var outresult = new byte[len >> 1];

    // two characters form the hex value.
    for (int i = 0, j = 0; j < len; i++)
    {
        var f = Convert.ToInt32(data[j++].ToString(), 16) << 4;
        f = f | Convert.ToInt32(data[j++].ToString(), 16);

        outresult[i] = (byte)(f & 0xFF);
    }

    return outresult;
}

Unfortunately, the key as we have it in memory is not what the TVM used to encrypt with. We need the DecodeHex method to rearrange the bits until we get a key that is the same format as was used to encrypt. Using this decoded key, we’re using the Bouncy Castle CipherUtilities to do the actual decryption. Assuming this works, we’ll end up with a UTF8 encoded string of decrypted data. But wait! There’s more!

Just having this string doesn’t give us everything. We need to split this packed string into a useable set of credentials. I used a factory to unpack this string into its constituent pieces of data (note that this is nearly identical to how the Andoid SDK sample did it):

public class AwsTemporaryCredentialFactory
{
    private const string AccessKeyName = "accessKey";
    private const string SecretKeyName = "secretKey";
    private const string SecurityTokenKeyName = "securityToken";
    private const string ExpirationDateKeyName = "expirationDate";

    ///
<summary> /// Used to create a set of temporary security credentials from the response provided by the
 /// Token Vending Machine.
 /// </summary>
    ///The response from the Token Vending Machine
    /// A set of temporary AWS credentials
    public static AwsTemporaryCredentials Create(string credentialString)
    {
        AwsTemporaryCredentials credentials = new AwsTemporaryCredentials
                                                  {
                                                      AccessKey = ExtractElement(credentialString, AccessKeyName),
                                                      SecretKey = ExtractElement(credentialString, SecretKeyName),
                                                      SecurityToken =
                                                          ExtractElement(credentialString, SecurityTokenKeyName),
                                                      ExpirationDate =
                                                          AwsTemporaryCredentials.GetExpirationTimeFromMilliseconds(
                                                              ExtractElement(credentialString,
                                                                             ExpirationDateKeyName))
                                                  };

        return credentials;

    }

    ///
<summary> /// Used to extract a piece of data from a json string.
 /// </summary>
    /// This is a C# port of the Java version written by Amazon.com
    ///The raw string to exctract the element from.
    ///the name of the piece of data to extract.
    /// The value of the exctracted element.
    private static String ExtractElement(String json, String element)
    {
        bool hasElement = (json.IndexOf(element) != -1);
        if (hasElement)
        {
            int elementIndex = json.IndexOf(element);
            int startIndex = json.IndexOf("\"", elementIndex);
            int endIndex = json.IndexOf("\"", startIndex + 1);

            return json.Substring(startIndex + 1, endIndex - (startIndex + 1));
        }

        return null;
    }
}

This retrieves a AwsTemporaryCredentials object which I’ve defined as:

public class AwsTemporaryCredentials
{
    public string AccessKey { get; set; }
    public string SecretKey { get; set; }
    public string SecurityToken { get; set; }
    public DateTime ExpirationDate { get; set; }

    ///
<summary> /// Handles converting milliseconds since 01-01-1970 into a useable DateTime.
 /// </summary>
    ///The number of milliseconds since 01-01-1970 as a string
    /// A DateTime that is 01-01-1970 plus the number of milliseconds
    public static DateTime GetExpirationTimeFromMilliseconds(string milliseconds)
    {
        long longMillseconds;
        Int64.TryParse(milliseconds, out longMillseconds);

        return GetExpirationTimeFromMilliseconds(longMillseconds);

    }

    ///
<summary> /// Handles converting milliseconds since 01-01-1970 into a useable DateTime.
 /// </summary>
    ///The number of milliseconds since 01-01-1970
    /// A DateTime that is 01-01-1970 plus the number of milliseconds
    public static DateTime GetExpirationTimeFromMilliseconds(long milliseconds)
    {
        var ticks = milliseconds*TimeSpan.TicksPerMillisecond;
        var correctedDate = new DateTime(1970, 1, 1).Add(new TimeSpan(ticks));
        return correctedDate;
    }

}

So there you go. 3 steps necessary to obtain temporary credentials from the Token Vending Machine (using the anonymous method). Once we have a set of temporary credentials, we can use those credentials just as we would with a “normal” set of credentials to utilize Amazon AWS services. Tired yet?

Questions? Comments? Confused? Drop a comment below if you need any help. Don’t forget to follow me on Twitter @kenstone.

Advertisements

Time to Pick an Ultrabook

I’m in the market for a new laptop. I want an Ultrabrook as I feel like my 2011 Macbook Pro is just too heavy. I’d like to park that machine and start using a super lightweight laptop as my daily driver. I want a good screen, solid battery, and I don’t want to pay a ton. My new startup is paying for this machine, so it can’t be too expensive.

So Many Choices

I looked at product specs from Engadget to determine how I want to proceed. I’ve picked a few options to limit the scope of my search as the Ultrabook options are vast. Some specs that are facts are listed (Screen, RAM, SSD, Price), but the Windows 7 battery life results are from Engadget (i.e., not manufacturer provided).

 

Macbook Air

This is an obvious choice and it’s hard to say no. I use a 2011 Macbook Pro right now that’s issued from my day job, so I have some experience with this product line. I like the keyboard a lot and the battery does last. The looks are appealing, but it comes at a price. Given that I want to run Windows 7 or Windows 8, if I run BootCamp, I’d also be on the hook for a license to run Windows, which is not included with the Mac.

Screen: 13.3″, 1440 x 900
RAM: 4 GB
SSD: 128 GB
Price: $1,299 (not including Windows 7 license, newegg.com)
Battery Life: 4:12

 

Asus Zenbook UX31

Sure does look like a Macbook Air, doesn’t it? Meh. I’m not so interested about that super tapered edge, but this machine does look sharp. It’s got some advantages that are clear. It’s $250 less than a Macbook Air and that’s significant. $50 wouldn’t have been so bad, but $250 on a budget is a lot. There’s been some talk about the keyboard and the trackpad. It sounds like the trackpad has been fixed, but that some people don’t like the keyboard. I tried this keyboard out at a retail store and I didn’t seem to have any trouble with it in my tests.

Also, look at the battery life. These are Engadget’s numbers running Windows 7. The Zenbook lasts 89 minutes longer. Again, that’s significant. 5 or 10 minutes wouldn’t have made a dent in my decision, but 89? Cra-a-a-zy.

Screen: 13.3″, 1600 x 900
RAM: 4 GB
SSD: 128 GB
Price: $1,049 (newegg.com)
Battery Life: 5:41

Lenovo Ideapad U300s

I like the looks of this machine and I’ve always known Lenovo machines to be solid, well built products. Their current offering also comes in a silver finish, but unlike the other two, it is the same thickness all the way across the body. This machine has the lowest resolution of the three and that’s a problem. I’m using this machine for Visual Studio, light Photoshop and Illustrator, and writing. Those are some beefy programs that like to take up room, so the widest resolution possible is necessary. The Lenovo comes in last place in this spec.

Screen: 13.3″, 1366 x 768
RAM: 4 GB
SSD:
Price: $1,049 (newegg.com)
Battery Life: 5:08

So What’s it Gonna Be?

From this perspective, it seems clear. The Asus Zenbook UX31 is the winner. The only thing holding me up right now is that the next revision of the machine is about to be released. So do I wait? Or just go for it? Hopefully this won’t be a decision I need to make, but time is running out until I need to make the purchase as my decision will be forced. If I was doing iOS development, perhaps the Air would have won, but with that extra $250, I can buy a printer that is so badly needed and some other startup necessities. What would your decision be?

Be sure to follow me on twitter @kenstone

Me and My Lumia 900 – a pseudo-review

Make no mistake, I am a Windows Phone fanboy. I’m not a phone reviewer, but wanted to give a few notes on my transition from a Samsung Focus to the Nokia Lumia 900.

Pros

Beauty

The aesthetic beauty of this phone is undeniable. I find myself taking it out in public more than usual just so people can get a glimpse of it (we are talking about phones, right?). The cyan colored body reflects light differently so it seems to color shift as I go from cloudy daylight to office flourescent to homey incandescent. The hand feel is, in a word, solid. It’s as if the phone is invoking Paul Hogan, “Heh. That’s not a phone. That’s a phone.

There are no parts that give way to pressure, like a battery compartment would. Nor does the screen give in when pushed. It pushes you. Having one completely smooth side unblemished by plasticky buttons feels anthropomorphically delightful.  If you haven’t read the book, Universal Principles of Design by William Lidwell, you should. In it, you’ll see so many things that Nokia got right about this phone listed in that book.

Soft Keys

One of my biggest complaints about the Samsung Focus was the soft keys found on all Windows Phones; they seemed so sensitive! Any fleeting touch would trigger them and, because of the bottom curve of the phone, you would constantly be in proximity to them while holding the phone. Anyone with a meaty thumb pad knows what I mean. My kid would be watching Netflix and in a flash be back at the home screen.  She’s really good at knowing how not to hold the phone, and she’s not even three.

The Lumia 900, in contrast, has the squared off bezel and additional room between the bottom of the phone and the buttons. This bezel not only gives something meaty to hold on to (particularly in landscape mode), but keeps your hands from hitting those buttons accidentally. Beyond that, the buttons seem less sensitive and thus less prone to tossing you over to cute animal land in Bing. That bezel is your home row and it gives your hands something to do without fear of blowing the whole thing up. It’s another design feature that helps users feel safe while using the device. You, my friendly tech geek cohort will hear your mom say, “Oh no! What did I do?” less when you loan her your phone.

Nokia Apps

The Nokia apps that I installed are App Highlights, Nokia Drive, Creative Studio, and Nokia Maps. I don’t live is a super populated area, so I’m unable to test some of the features of the Nokia Maps. My biggest plus is the Nokia Drive app which finally gives turn-by-turn driving. The Bing maps directions are great, but I really disliked having to keep tapping the screen to go to the next step. Creative Studio does the same thing with photo filters that a hundred other do, so maybe Nokia can sell that to someone for $1 billion some day.

Bigger Screen

Yup, it’s got a bigger screen than the Samsung Focus did. As a developer, I’m grateful that the resolution requirement hasn’t changed yet. I figure it will someday, but until then, I don’t need to change any of my artwork. I get to see everything a little bigger (and, if I’m being honest, I need to see things a little bigger lately).

Others

I have a Jabra CRUISER (which I highly recommend) that I use in my car to control my phone and talk hands-free. I’ve noticed that the Lumia connects to the bluetooth noticeably faster than my Focus did. And Visual Voicemail is here! I have my voicemail forward  to Google Voice where it is transcribed and sent back, so I’m not likely to use this feature much as I am not fond of voicemail. Voice Quality: every time I think the voice quality is a little weak, I realize my ear is not near the earpiece. So that’s straight up user error and the quality is superb when I’m in the zone.

Cons

It wasn’t until after I had pre-ordered the 900 that I realized it didn’t have the same curved glass screen of the Lumia 800 , which I was really looking forward to. Not only is it not curved glass, but the screen has a lip on it before stopping abruptly into the curve of the body. Instead of a dead flat surface, it has a rim. It probably works well enough to keep your beverage contained when you need an impromptu coaster (what else am I gonna use the gorilla glass for?) I’m guessing this was a cost consideration to get the phone down to the $99 street price, so I suppose its understandable. But I don’t have to like it.

This is not a con of the phone, but of the upgrade process in general. Moving from one phone to another phone is much more difficult than it should be. Things get lost. In my case, game data, SMS messages, and settings.

Conclusion

Yes, you should go out and get a Lumia 900. Now. Tomorrow. Especially now that it looks like they’re giving $100 credits to all purchasers before April 21. Get one for your mom and dad. And one for your spouse and probably a kid or two.

*drops the mike*

*picks the mike back up*

Don’t forget to subscribe to my blog and follow me on Twitter @kenstone. Let’s get that follower count above 100!

WordPress on Azure – Troubleshooting Setup

So you want to try installing WordPress on Windows Azure? You want to store your media files in Azure Storage? Good idea. It’s certainly more work than paying a 3rd party to host it for you, but let’s give it a go. First off, let’s set some ground rules. This is not an advanced troubleshooter. This is a guide that helps to clear up some of the confusing parts of the existing documentation for the absolute Azure newb.

Basic Setup

The go to guide for setting up WordPress on Azure is located at http://azurephp.interoperabilitybridges.com/articles/how-to-deploy-wordpress-using-the-windows-azure-sdk-for-php-wordpress-scaffold. There’s a few prerequisites so make sure you read the entire document first before getting to work. It’s like a food recipe with a few sub-recipes. Essentially here are the steps flattened into a single list:

  1. Install PHP
  2. Install Azure Dev Environment
  3. Update your PATH to point to the PHP folders
  4. Setup Windows Azure SDK for PHP
  5. Create an Azure Hosted Service
  6. Create an Azure Storage Account
  7. Setup your SQL Azure DB
  8. Download WordPress scaffold
  9. Run the scaffolder
  10. Create the project
  11. Package WordPress project
  12. Deploy to Azure
  13. Setup your WordPress installation.
  14. Configure Windows Azure Storage Plugin

Those are the main steps smashed together into one list. However, there can be a few gotchas in going through the documentation.

3. Update your PATH to point to the PHP folders:

I had to do more than what the documentation said. Here are the two locations I needed to add to my path:

C:\Program Files\Windows Azure SDK for PHP\bin
C:\Program Files (x86)\PHP\v5.3

9. Run the scaffolder

Here the directions can confuse. Under the “Parameters” section, “sync_account” and “sync_key” are listed as required for the scaffolder. As far as I can tell, putting the data in here does nothing. You still need to put them in during step 14. So, try leaving it out. I put mine in there, but I don’t think it did any good.

There is one more caveat. The directions say, “NOTE: Inside of this storage account you will need to create a public container called ‘wpsync’“. Unfortunately, the directions do not say HOW to do this. If you are brand new to this, this will keep you hung up for a bit.

Create a container the Azure Storage Account called wpsync

What you want to do is download Azure Storage Explorer and install that. Put in your storage account name and the primary access key. Using that tool, create a container called ‘wpsync’. That’s all you need to do in this tool.

That being said, the screenshot provided in the guide shows a different container name in use. So, who knows. Just create the wpsync container. It works.

Permissions

At this point, I got all the way through step 14. But then, as I tried to upload media to the blog, I got an error that caused a few days of trouble:

The uploaded file could not be moved to E:\sitesroot/wp-content/uploads/2012/04

You can follow the discussion on this problem on the codeplex discussions site: http://phpazure.codeplex.com/discussions/349701

Essentially this problem comes down to permissions on the virtual machine. The recommendation by the guide author is to enable remote desktop on your WebRole and check permissions. I’m not sure you need to do this, which is why I didn’t include it in the steps list above. If you want to, here is a good documention on how to enable remote desktop:

http://azurephp.interoperabilitybridges.com/articles/enable-remote-desktop

I did this and found a couple things. First, when I reuploaded the deployment package over the top of the existing one, my E drive would be replaced with an F drive. Yet WordPress was still looking to drop temporary files into an E drive. For me, the way around it was to make sure that I deleted and recreated the deployment when updating. This clearly has issues for production instances, so I’m not sure what to recommend in a production setting. If you’re running the recommended 2 instances, simply restarting each instance individually may solve it.

Through that discussion, the recommendation came to update your install-php-impl.cmd file (located at “WordPress\WebRole\bin\install-php-impl.cmd” wherever you ran the scaffolder). Change the line:

CALL icacls ..\wp-content /grant "NETWORK SERVICE":F /T

to

CALL icacls %RoleRoot% /grant "NETWORK SERVICE":F /T

After redeploying the package with this change, my uploads worked. BE WARNED: I have no idea how this change affects proper security on your instance. Overall, I’m unsure of how the permissions for WordPress need to be set, so don’t complain to me if you end up with a security gap.

Importing

If you’re moving a blog from wordpress.com to Azure, you probably want to import your content. I wanted to give this a go and it sort-of worked for me. Here are the steps:

  1. Download the importer plug-in
  2. Place it in the plug-ins folder on your machine
  3. Repackage and redeploy
  4. Activate the importer in the plug-in folder and give it a go.

My blog isn’t that big yet, so I was surprised when even I had problems importing. Essentially, I think the connection timed out before the import had completely succeeded. I ended up running the importer again and all the content seemed to get moved over the second time. YMMV.

Like this post? Be sure to comment or follow me on Twitter @kenstone

Advertisements

I'm Ken Stone. I'm an indie developer with a focus on .NET and Windows Phone development. I have a day job, but everything I say is mine alone.

TechEd 2012July 11th, 2012
Let the learning begin.