Pages

Tuesday, 12 October 2010

Standardising String Cryptography

I was writing the new Twitter Client for TweetPivot when I hit a problem. I needed to store a small amount of information on our users' machines; specifically in isolated storage. Most of this would be fine as plain text but one field needed to be encrypted. This meant I had to solve a problem I seem to come back to again and again - simple string cryptography.

Crypto Rule #1 seems to be "Don't roll your own.". OK fine, so give me something pre-rolled. C# / .Net doesn't contain the method I was looking for:

string Encrypt(string plainText, string password, string salt);

Luckily, @blowdart came to my rescue and posted this code. Now, there's a few things worth pointing out about this:
  1. Barry's book sales suggest he might actually know what he's doing, but who else amongst us has the confidence and knowledge to say that it's safe and reliable?
  2. Did anyone read the code and think "actually, TripleDES would suit my needs, not Rijndael"?
Answer: probably no.

So, given that a) it's hard to do correctly and b) this standard method would probably suit 99% of developers 99% of the time why, then, do we not find this in the BCL? If I want to open a file I can use System.IO.File.OpenRead(string path). If I need to take more control over the process I can use a StreamReader and dictate encodings etc.

I've included my final code below (you deserve something for reading this far!). Porting it into Silverlight simplifies matters - mainly because there's only one implementation of SymmetricAlgorithm. "But Barry defaulted to Rijndael. Does this mean that Silverlight is less secure than standard .Net applications?" Another crypto conundrum!

I do feel that this functionality needs abstracting behind a simplified facade. I genuinely don't care how long my initialisation vector is or whether I'm using DES, DoubleDES or even TripleDES. Cryptography is simply a tool for hiding stuff and it should be easier, safer and more confidence-imspiring than it currently is. @blowdart's subsequent tweet kinda sums up the complexity of the subject. Signatures, really? You might just as well have asked me if I wanted tweeters with it! #referenceToOldJoke
using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;

public static class CryptographicExtensions
{
  public static string Encrypt(this string plainText, string password, string salt)
  {
    var algorithm = new AesManaged();

    algorithm.SetKeyAndIV(password, salt);

    return Encrypt(algorithm, plainText);
  }

  public static string Encrypt(this string plainText, ref byte[] key, ref byte[] iv)
  {
    if (string.IsNullOrEmpty(plainText))
      return plainText;

    var algorithm = new AesManaged();

    if (key != null)
      algorithm.Key = key;
    else
      key = algorithm.Key;

    if (iv != null)
      algorithm.IV = iv;
    else
      iv = algorithm.IV;

    return Encrypt(algorithm, plainText);
  }

  private static string Encrypt(SymmetricAlgorithm algorithm, string plainText)
  {
    var plainTextAsBytes = Encoding.UTF8.GetBytes(plainText);

    using (ICryptoTransform transform = algorithm.CreateEncryptor())
    {
      using (var outputStream = new MemoryStream())
      {
        using (var inputStream = new CryptoStream(outputStream, transform, CryptoStreamMode.Write))
        {
          inputStream.Write(plainTextAsBytes, 0, plainText.Length);
          inputStream.FlushFinalBlock();
          var cipherText = outputStream.ToArray();
          return Convert.ToBase64String(cipherText);
        }
      }
    }
  }

  public static string Decrypt(this string cypherText, string password, string salt)
  {
    var algorithm = new AesManaged();

    algorithm.SetKeyAndIV(password, salt);

    return Decrypt(algorithm, cypherText);
  }

  public static string Decrypt(this string cypherText, byte[] key, byte[] iv)
  {
    if (string.IsNullOrEmpty(cypherText))
      return cypherText;

    if (key == null)
      throw new ArgumentNullException("key");

    if (iv == null)
      throw new ArgumentNullException("iv");

    var algorithm = new AesManaged() { Key = key, IV = iv };

    return Decrypt(algorithm, cypherText);
  }

  private static string Decrypt(SymmetricAlgorithm algorithm, string cypherText)
  {
    var cipherTextAsBytes = Convert.FromBase64String(cypherText);

    using (ICryptoTransform transform = algorithm.CreateDecryptor())
    {
      using (var outputStream = new MemoryStream())
      {
        using (var inputStream = new CryptoStream(outputStream, transform, CryptoStreamMode.Write))
        {
          inputStream.Write(cipherTextAsBytes, 0, cipherTextAsBytes.Length);
          inputStream.FlushFinalBlock();
          var plainTextAsBytes = outputStream.ToArray();

          return Encoding.UTF8.GetString(plainTextAsBytes, 0, plainTextAsBytes.Length);
        }
      }
    }
  }

  public static void SetKeyAndIV(this SymmetricAlgorithm algorithm, string password, string salt)
  {
    string paddedSalt = salt;

    while (paddedSalt.Length < 8)
      paddedSalt += salt;

    var rfc2898 = new Rfc2898DeriveBytes(password, Encoding.UTF8.GetBytes(paddedSalt));

    algorithm.Key = rfc2898.GetBytes(algorithm.KeySize / 8);
    algorithm.IV = rfc2898.GetBytes(algorithm.BlockSize / 8);
  }
}

Tuesday, 21 September 2010

Great, another Pivot!

The word 'Pivot' seems to be somewhat of a favourite amongst the tech community these days. It all started with Pivot tables back in the late 80's. In the past few years we've added 3 new pivots to the list:


If that wasn't enough we now have a fifth! The final Windows Phone 7 SDK launched a couple of days ago and contains, wait for it, a Windows Phone 7 Pivot Application template.

I work with two of these (the Lean Startup and Live Labs) and it's already confusing trying to explain to potential customers which pivots our business uses.

Seriously, no more. Please?

Maybe this is a compelling reason for companies to trademark their products?

Wednesday, 18 August 2010

A Rebuke of Twifficiency

Unless you've been asleep under a stone for the past 48 hours you couldn't have failed to notice the Twitter phenomenon that is Twifficiency. Created by James Cunningham it generated an efficiency score based on your Twitter usage. In order to access the service, though, you had to grant the application access to your Twitter account.

Unwittingly, or not, James had violated one of Twitter's codes of practice re: abuse of privileged access to accounts. Specifically, the application automatically tweeted a message from the user's account in the format:

My Twifficiency score is x%. What's yours? http://twifficiency.com

Generally, this annoyed people but, because of its viral nature, the term "Twifficiency" started trending worldwide.

Now, can we please get some perspective on this?

Yes, it trended. Yes, it spread like wildfire. Yes, everyone's talking about it; but so what? This is the Twitter version of "Britain's Got Talented X-Factor for me Nan". It was hugely popular but, ultimately, worthless. Shouldn't we be discouraging this kind of sensationalism and, instead, be encouraging the trending of remarkable products (to quote Seth Godin). The mere fact that it trended says nothing about its worth - because it trended itself automatically, virally. This is the complete opposite of something that trends because users want to tell their friends about it. In fact self-promotion obfuscates this valuable measure.

James is, undoubtedly, a very nice chap who was just experimenting with an idea, but for some people to be considering offering him a job! Seriously, no. Stop.

Tech Crunch hits the nail on the head in their blog post and I would like to add to that by pointing out that Stephen Fry only scored 3%!!!

Now, if James had created the site with an opt-in option for re-tweeting (as opposed to its new opt-out option) and it had still trended; then, wow! That would have been a truly remarkable feat. The fact is, though, that you've removed any meaningful way of measuring your success.

I have no doubt that James will go on to great things but, I'm afraid, I think he should be infamous, not famous, for Twifficiency.

Monday, 16 August 2010

Immutable, Auto-Implemented Properties in C#

Over the past few months I've been getting a lot more into immutability. If you want to know why you should be using immutable types start with this blog post by Bertrand Le Roy.

Until recently I, like most other developers had been creating my properties like this...

public class Person
{
  public DateTime BirthDate { get; private set; }

  public string FavouriteSong { get; set;}

  public Person(DateTime birthDate)
  {
    BirthDate = birthDate;
  }
}

Pretty straight forward - the BirthDate is required and must be set during construction of the object whilst the FavouriteSong is optional. The other reason for writing properties this way is simplicity and code succinctness. It also allows more 'interesting' properties to be more easily identified. For instance, this new Age property stands out from the other two and 'asks' to be unit tested.

public class Person
{
  public DateTime BirthDate { get; private set; }

  public string FavouriteSong { get; set;}

  public int Age
  {
    get
    {
      var now = DateTime.Today;
      var age = now.Year - bday.Year;

      if (bday > now.AddYears(-age))
        age--;    

      return age;
    }
  }

  public Person(DateTime birthDate)
  {
    BirthDate = birthDate;
  }
}

I should, however, be making the BirthDate property immutable - it isn't gonna change! This does make the code less neat though...

public class Person
{
  private readonly DateTime _birthDate;
  public DateTime BirthDate { get { return _birthDate; } }

  public string FavouriteSong { get; set;}

  public int Age
  {
    get
    {
      var now = DateTime.Today;
      var age = now.Year - bday.Year;

      if (bday > now.AddYears(-age))
        age--;    

      return age;
    }
  }

  public Person(DateTime birthDate)
  {
    _birthDate = birthDate;
  }
}

Auto-implemented properties are a .Net construct and are used as a template, at design-time, to create a 'real' pair of _get _set methods. So, what I'd like to be able to do is this ...

public class Person
{
  public DateTime BirthDate { get; private readonly set; }

  public Person(DateTime birthDate)
  {
    _birthDate = birthDate;
  }
}

Anyone from Microsoft like to chime in?

Wednesday, 11 August 2010

I've been scammed! A follow-up to Twitter Auth Issues

This is a follow-up post to Social Network Authorisation Needs to Change.

Having written the above post over a month ago and considering myself to be quite net-savvy, I'm hugely embarrassed and mortified to admit that I've just been victim to a Twitter-related scam. This is the scam site that duped me: http://www.ipadappstesting.com/. It's safe to browse to it - JUST DON'T LOG IN!

I received a Twitter Direct Message (DM) from a trusted friend that invited me to go to the site so that I could sign up to be an iPad tester. At the end of the test period I would get to keep the hardware. Superb! Yeh, right.

My spidey-senses were working well enough that I didn't complete the in-depth financial survey they put in front of me. What did happen, however, was their servers sent DMs to, presumably ALL, my friends inviting them to do the same. Needless to say that this was without my knowledge - let alone my consent.

Twitter, seriously guys, this needs to change quickly otherwise you're going to go the way of Facebook.

The access granted to my account for an application needs to be segmented and I need to have the ability to REVOKE any aspect I'm not entire happy with at login time. For instance, the shill application in question should have had to request DM read / write access during their registration with Twitter. This should then have appeared as a checkbox on the Twitter OAuth screen. I would then have unchecked it.

Feeling rather violated now but, hey, how was I to know? I currently just have to put my trust in the application developers and I don't think that's either fair or sustainable.

Monday, 12 July 2010

Faking PivotViewer in Blend 4

If you've been using the new PivotViewer Silverlight control then you've probably come across the Blend problem. Basically, it doesn't work and you get the following error...

"Error HRESULT E_FAIL has been returned from a call to a COM component."

This problem does not occur in Visual Studio 2010 (VS2010) - although the page view does look a little suspect. Some people have suggested commenting out the PivotViewer element when opening the page in Blend, but there's a much better approach - fakes.

First, create a new "Silverlight Class Library" project in VS2010 called FakePivot and, once loaded, delete the Class1.cs file. Now add a new Code File called PivotViewer.cs with the following starting code:

using System;

namespace FakePivot
{
    public class PivotViewer
    {

    }
}

Next add a reference to the PivotViewer library (System.Windows.Pivot.dl) and the SharedUI library (System.Windows.Pivot.SharedUI.dll). If you don't find them under the .Net tab you can browse for them at <Program Files>\Microsoft SDKs\Silverlight\v4.0\PivotViewer\Jun10\Bin\. Now update your PivotViewer class to look like this...

using System;

namespace FakePivot
{
    public class PivotViewer : System.Windows.Pivot.PivotViewer
    {

    }
}

Right click on Microsoft's PivotViewer and choose "Go To Definition". You should now see the following metadata file:

#region Assembly System.Windows.Pivot.dll, v2.0.50727
// C:\Program Files\Microsoft SDKs\Silverlight\v4.0\PivotViewer\Jun10\Bin\System.Windows.Pivot.dll
#endregion

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Resources;
using System.Windows;
using System.Windows.Browser;
using System.Windows.Controls;

namespace System.Windows.Pivot
{
    [ScriptableType]
    [TemplatePart(Name = "PART_Container", Type = typeof(Grid))]
    public class PivotViewer : Control, INotifyPropertyChanged
    {
        public PivotViewer();
        public PivotViewer(ResourceDictionary colorScheme);

        public IDictionary<string, IList<string>> AppliedFilters { get; }
        public int CollectionItemCount { get; }
        public string CollectionName { get; }
        public Uri CollectionUri { get; }
        public string CurrentItemId { get; set; }
        public ICollection<string> InScopeItemIds { get; }
        public string SortFacetCategory { get; }
        public string ViewerState { get; }

        public event EventHandler CollectionLoadingCompleted;
        public event EventHandler<CollectionErrorEventArgs> CollectionLoadingFailed;
        public event EventHandler<ItemActionEventArgs> ItemActionExecuted;
        public event EventHandler<ItemEventArgs> ItemDoubleClicked;
        public event EventHandler<LinkEventArgs> LinkClicked;
        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual List<CustomAction> GetCustomActionsForItem(string itemId);
        public PivotItem GetItem(string id);
        public void LoadCollection(string collectionUri, string viewerState);
        public override void OnApplyTemplate();
        public static void SetResourceManager(ResourceManager resourceManager);
    }
}


What we want to do next is extract the interface for the standard PivotViewer class. If you have a refactoring tool I'd use it, otherwise you just have to do it manually. Either way, we should now have an interface in our project called IPivotViewer.cs ...

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows.Pivot;

namespace FakePivot
{
    public interface IPivotViewer : INotifyPropertyChanged
    {
        IDictionary<string, IList<string>> AppliedFilters { get; }
        int CollectionItemCount { get; }
        string CollectionName { get; }
        Uri CollectionUri { get; }
        string CurrentItemId { get; set; }
        ICollection<string> InScopeItemIds { get; }
        string SortFacetCategory { get; }
        string ViewerState { get; }

        event EventHandler CollectionLoadingCompleted;
        event EventHandler<CollectionErrorEventArgs> CollectionLoadingFailed;
        event EventHandler<ItemActionEventArgs> ItemActionExecuted;
        event EventHandler<ItemEventArgs> ItemDoubleClicked;
        event EventHandler<LinkEventArgs> LinkClicked;
        
        PivotItem GetItem(string id);
        void LoadCollection(string collectionUri, string viewerState);
    }
}

Next, we want to go back to our PivotViewer class and make it extend Control and implement our new IPivotViewer interface like this...

using System;
using System.Collections.Generic;
using System.Windows.Pivot;
using System.ComponentModel;
using System.Windows.Controls;

namespace FakePivot
{
    public class PivotViewer : Control, IPivotViewer
    {
        public IDictionary<string, IList<string>> AppliedFilters { get { throw new NotImplementedException(); } }

        public int CollectionItemCount { get { throw new NotImplementedException(); } }

        public string CollectionName { get { throw new NotImplementedException(); } }

        public Uri CollectionUri { get { throw new NotImplementedException(); } }

        public string CurrentItemId { get { throw new NotImplementedException(); } set { throw new NotImplementedException(); } }

        public ICollection<string> InScopeItemIds { get { throw new NotImplementedException(); } }

        public string SortFacetCategory { get { throw new NotImplementedException(); } }

        public string ViewerState { get { throw new NotImplementedException(); } }

        public event EventHandler CollectionLoadingCompleted;

        public event EventHandler<CollectionErrorEventArgs> CollectionLoadingFailed;

        public event EventHandler<ItemActionEventArgs> ItemActionExecuted;

        public event EventHandler<ItemEventArgs> ItemDoubleClicked;

        public event EventHandler<LinkEventArgs> LinkClicked;

        public event PropertyChangedEventHandler PropertyChanged;

        public PivotItem GetItem(string id) { throw new NotImplementedException(); }

        public void LoadCollection(string collectionUri, string viewerState) { throw new NotImplementedException(); }
    }
}

OK, I know, I know - this is pretty convoluted. But, what we now have is a 'real' Silverlight control that exposes the same interface as Microsoft's control. Here's how to use it...

Let's add a new "Silverlight Application" project to our solution - we'll call it PivotViewerApp. For this example we don't need to "Host the Silverlight application in a new Web site". Now add three references to this project (2 of which we already added to our FakePivot project):

  1. System.Windows.Pivot
  2. System.Windows.Pivot.SharedUI
  3. Our FakePivot project

VS2010 should have opened the MainPage.xaml file in "split view" mode. Let's add some references to our 2 namespaces of interest (pivot and fakepivot) and then create our pivot control...

<UserControl x:Class="PivotViewerApp.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"             
    xmlns:pivot="clr-namespace:System.Windows.Pivot;assembly=System.Windows.Pivot"
    xmlns:fakepivot="clr-namespace:FakePivot;assembly=FakePivot"
    mc:Ignorable="d"
    d:DesignHeight="300" d:DesignWidth="400">

    <Grid x:Name="LayoutRoot" Background="White">
        <pivot:PivotViewer x:Name="pivotViewer1" />
    </Grid>
</UserControl>

If you now right click on MainPage.xaml in the Solution Explorer and choose "Open in Expression Blend" you'll see the exception I mentioned at the start of this post. So let's go back to VS2010 and change the namespace of our pivotViewer1 control from pivot to fakepivot...


<UserControl x:Class="PivotViewerApp.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"             
    xmlns:pivot="clr-namespace:System.Windows.Pivot;assembly=System.Windows.Pivot"
    xmlns:fakepivot="clr-namespace:FakePivot;assembly=FakePivot"
    mc:Ignorable="d"
    d:DesignHeight="300" d:DesignWidth="400">

    <Grid x:Name="LayoutRoot" Background="White">
        <fakepivot:PivotViewer x:Name="pivotViewer1" />
    </Grid>
</UserControl>

Because both namespaces contain a PivotViewer class our xaml is perfectly happy and the solution will still compile. Now go ahead and reopen the same file in Blend - ta dah, no exceptions.

The real beauty of this approach, however, becomes evident when working with the fake control in Blend. Because it exposes exactly the same events, methods and properties as the Microsoft control we can use the Blend UI to hook into these. Selecting pivotViewer1 in our Objects and Timeline window we can then click the Events button in the Properties tab and see all the events that we'd expect our real control to expose.

Once we've done your design work in Blend we, obviously, have to revert our fakepivot namespace to pivot before we can build anything useful. One option is to go back to VS2010 to do this. However, if you hide the Design window in Blend and just have the XAML window visible you can change it there and successfully compile it.

Hopefully, that wasn't too complicated and, once you have your FakePivot library, you can reuse it in any related projects. If anyone want me to do a video of this process please let me know in the comments.

Finally, click here to download the example solution for this post.

Tuesday, 6 July 2010

Social Network Authorisation Needs to Change

A few weeks ago I took a look at a website that needed my twitter login to work. The nature of the site was overtly read-only so I was happy to grant it access via twitter's OAuth process. Yesterday I took another exploratory look at a Facebook application which requested access to my account. Again, the nature of this application was completely read-only. Both apps were mildly interesting and I'd achieved what I'd set out to do. Done.

Imagine my [surprise | outrage | fury] (you choose!) when I discovered that both apps had posted public comments from my account. WTF!? Both used the familiar template of 'I have just used [appX] to do [functionY]. Go to [urlA] to try it yourself.'.

OK, so nothing malicious in that - but I didn't authorise either of these posts. Facebook does give you the ability to deny an application from posting in your name, but only after you've installed it. If the app posts immediately there's nothing you can do about it.

Now, don't get me wrong, good applications deserve to be blown along on the virtual word-of-mouth jet stream; but, and here's the critical bit:

"It should be my decision to publicise my usage of your site."

At TweetPivot we made a very conscious decision to enable a user to promote our site easily but not to presume that that's what they wanted. If the site's good enough they will, but automatically doing it for them removes any worth from the act.

So, what should happen now?

Well, you have to apply to Twitter if you want your application to be able to use their OAuth process. At that point you are asked whether your application requires read-only or read-write access to users' accounts. When I enter my details into the popup OAuth window I want to be told whether I'm giving write rights to the app and, if that's not acceptable to me, I want to be able to decline that 'write' request. If you want me to try out an application that I know has no reason to write to my account then I need confirmation that you can't.

I would hate to see the Twitter authentication process get as complicated as Facebook's became; but it does need improving. The API that all 3rd-parties hook into has very specific, well defined methods. Developers should have to declare, individually, which ones they need to invoke. For instance, if I gave you read-only access to my account how can I be sure that you haven't just farmed off all my private Direct Messages?

Ultimately, this is going to be bad news for application developers that require integration to social networks. The next time I'm asked to try something like this I might hesitate. The time after that I might decline. Good developers are going to be punished and their great apps ignored by the unacceptable actions of the few.