Using an X.509 (pfx) certificate in Windows 8 Metro-style application for encryption, decryption and signing

One of the things that you need to live with if you are creating a metro-style application is that you are in a sandbox and consequently you don’t have the full .NET runtime available to you. Thus, when I wanted to do some signing using a pfx certificate in my Windows 8 application I was sad, but not surprised to see that the awesome System.Security namespace isn’t available. Instead you need to deal with the Windows.Security namespace, which is a cut-down set of cryptographic functionality with a completely different API to what you might be used to!

Most of the code samples I could find were demonstrating how to create a new public/private keypair and then use that to perform the signing etc., but that wasn’t useful for me in this instance because I wanted to use a private key we already had (and trusted).

The trick of course was to try and load our certificate in, and looking through all of the classes and methods in the namespace it wasn’t immediately clear how to do that. I originally tried using the CertificateEnrollmentManager.ImportPfxDataAsync method, but apart from the fact I wasn’t able to figure out how to get my pfx file data into a format that method would select I eventually realised this wouldn’t help me. This method imports the certificate into the sandboxed certificate store the app has, but this isn’t helpful because:

  1. There is no way to use the certificates in the store programmatically
  2. I managed to figure out the store is just for using HTTP client certificates rather than as a general certificate store

The solution

Firstly you need to grab your pfx and convert it to CSP format (I did this in LinqPad):

var cert = new System.Security.Cryptography.X509Certificates.X509Certificate2(@"c:pathtomypfx_file.pfx", "password", System.Security.Cryptography.X509Certificates.X509KeyStorageFlags.Exportable);
var privateKey = cert.PrivateKey as System.Security.Cryptography.RSACryptoServiceProvider;
var cspBlob = privateKey.ExportCspBlob(true);
Console.WriteLine(Convert.ToBase64String(cspBlob));

Then put the resultant text in a .txt file in your metro app and mark the file as content and the following code should work (this example for signing, but the same applies for using the CryptographicEngine to decrypt, encrypt etc.):

    public async Task<IBuffer> Sign(IBuffer toSign)
    {
        var file = await (StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///path/to/my/csp_key.txt")));
        var contents = await FileIO.ReadBufferAsync(file);
        var contentsAsArray = contents.ToArray();
        var base64Contents = Encoding.UTF8.GetString(contentsAsArray.ToArray(), 0, contentsAsArray.ToArray().Length);

        var algorithm = AsymmetricKeyAlgorithmProvider.OpenAlgorithm(AsymmetricAlgorithmNames.RsaSignPkcs1Sha1);
        var key = algorithm.ImportKeyPair(Convert.FromBase64String(base64Contents).AsBuffer(), CryptographicPrivateKeyBlobType.Capi1PrivateKey);

        return CryptographicEngine.Sign(key, toSign);
    }

If doing this you should note that you are storing the private key in a non-encrypted form inside your app package, which isn’t secure if you don’t trust the machine that the app will be deployed to.

Using a FlipView with SemanticZoom in Windows 8 Metro-style application

This post outlines how I managed to get a FlipView control working inside of a Semantic Zoom when developing a Windows 8 metro-style application using C# / XAML.

An aside about XAML vs HTML for Windows 8 development

As anyone following me on Twitter would have seen I’ve found myself fortunate enough to be in a situation where I’m not only (finally) learning XAML, but also creating a Windows 8 “metro-style” proof-of-concept application.

While I come from a web background I was recommended to use C# XAML rather than HTML 5 to create the application. While creating the application I’ve come across a fair bit of documentation and sample applications using HTML 5 / JavaScript rather than XAML / C#. While I haven’t done any windows 8 apps in JavaScript yet, I suspect that using XAML is more powerful and expressive, even if it’s a little bit more verbose and slightly less convenient to style. Regardless, at this point that’s just pure conjecture on my part.

What I wanted to achieve and why

Back to the point: One thing I wanted to demonstrate in my proof-of-concept application was the use of semantic zoom because I think it’s a very powerful user interface concept and led quite naturally to provide that little bit more convenient and natural navigation to the application I was creating.

At the same time I was adamant that I wanted to use a flip view because I had a small number of discrete items that I wanted to each take up a page. While there is a concept of providing a context indicator control I wanted to also have an app bar and felt that the semantic zoom provided a cleaner way of providing that high level navigation (as well as there were few enough items in the list and they were always the same that the user always knew where they were so didn’t need any indication).

The problem

SemanticZoom only allows you to use a GridView or ListView within it and while there are posts out there about how you can come up with custom controls they only seem to apply to HTML / JavaScript and not XAML.

As explained above I didn’t want a continuously scrolling control, I wanted to use the FlipView Control. Initially I tried this by nesting a FlipView directly inside a GridViewItem and a ListViewItem, but that looks really ugly because of the default hover, selection and click semantics on those controls. As well as that, the items weren’t being bounded to the parent and thus my content was being cut off.

The solution

What I ended up doing was the following.

MyView.xaml

            <SemanticZoom>
                <SemanticZoom.ZoomedOutView>
                    <ListView HorizontalAlignment="Center" VerticalAlignment="Center">
                        <ListView.ItemsPanel>
                            <ItemsPanelTemplate>
                                <StackPanel Orientation="Horizontal" />
                            </ItemsPanelTemplate>
                        </ListView.ItemsPanel>
                        <ListViewItem Background="#E30000" Style="{StaticResource SemanticZoomListItem}" Tapped="Category1Selected">
                            <Grid>
                                <TextBlock Text="Category1" Style="{StaticResource SemanticZoomListItemTitle}" />
                                <Image Source="ms-appx:///Assets/Category1.png" Style="{StaticResource SemanticZoomListItemImage}" />
                            </Grid>
                        </ListViewItem>
                        <ListViewItem Background="#FF6400" Style="{StaticResource SemanticZoomListItem}" Tapped="Category2Selected">
                            <Grid>
                                <TextBlock Text="Category2" Style="{StaticResource SemanticZoomListItemTitle}" />
                                <Image Source="ms-appx:///Assets/Category2.png" Style="{StaticResource SemanticZoomListItemImage}" />
                            </Grid>
                        </ListViewItem>
                        <ListViewItem Background="#009600" Style="{StaticResource SemanticZoomListItem}" Tapped="Category3Selected">
                            <Grid>
                                <TextBlock Text="Category3" Style="{StaticResource SemanticZoomListItemTitle}" />
                                <Image Source="ms-appx:///Assets/Category3.png" Style="{StaticResource SemanticZoomListItemImage}" />
                            </Grid>
                        </ListViewItem>
                        <ListViewItem Background="#006BE3" Style="{StaticResource SemanticZoomListItem}" Tapped="Category4Selected">
                            <Grid>
                                <TextBlock Text="Category4" Style="{StaticResource SemanticZoomListItemTitle}" />
                                <Image Source="ms-appx:///Assets/Category4.png" Style="{StaticResource SemanticZoomListItemImage}" />
                            </Grid>
                        </ListViewItem>
                    </ListView>
                </SemanticZoom.ZoomedOutView>
                <SemanticZoom.ZoomedInView>
                    <GridView ScrollViewer.HorizontalScrollMode="Disabled" ScrollViewer.VerticalScrollMode="Disabled"  SelectionMode="None" IsItemClickEnabled="False" IsHoldingEnabled="False" IsSwipeEnabled="False" CanReorderItems="False" CanDragItems="False" ItemContainerStyle="{StaticResource ZenGridViewItemStyle}">
                        <GridViewItem>
                            <FlipView x:Name="FlipParent">
                                <FlipViewItem x:Name="Category1FlipView">
                                    <Controls:Category1 />
                                </FlipViewItem>
                                <FlipViewItem x:Name="Category2FlipView">
                                    <Controls:Category2 />
                                </FlipViewItem>
                                <FlipViewItem x:Name="Category3FlipView">
                                    <Controls:Category3 />
                                </FlipViewItem>
                                <FlipViewItem x:Name="Category4FlipView">
                                    <Controls:Category4 />
                                </FlipViewItem>
                            </FlipView>
                        </GridViewItem>
                    </GridView>
                </SemanticZoom.ZoomedInView>
            </SemanticZoom>

App.xaml

            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="Common/StandardStyles.xaml"/>
                <ResourceDictionary Source="Common/ZenStyles.xaml"/>
            </ResourceDictionary.MergedDictionaries>
...
            <Style x:Key="SemanticZoomListItem" TargetType="ListViewItem">
                <Setter Property="Padding" Value="4" />
                <Setter Property="Width" Value="128" />
                <Setter Property="Height" Value="128" />
                <Setter Property="Margin" Value="0" />
                <Setter Property="HorizontalContentAlignment" Value="Stretch" />
                <Setter Property="VerticalContentAlignment" Value="Stretch" />
            </Style>
            <Style x:Key="SemanticZoomListItemTitle" TargetType="TextBlock" BasedOn="{StaticResource BasicTextStyle}">
                <Setter Property="FontSize" Value="20" />
                <Setter Property="FontWeight" Value="SemiLight" />
                <Setter Property="HorizontalAlignment" Value="Left" />
                <Setter Property="VerticalAlignment" Value="Bottom" />
            </Style>
            <Style x:Key="SemanticZoomListItemImage" TargetType="Image">
                <Setter Property="HorizontalAlignment" Value="Center" />
                <Setter Property="VerticalAlignment" Value="Center" />
                <Setter Property="Width" Value="64" />
                <Setter Property="Height" Value="64" />
            </Style>

Common/ZenStyles.xaml

Copied from The taming of the Metro GridView.

MyView.xaml.cs

This bit is the bit I like the least and I’m sure there is a less verbose way of doing it, but I’m happy enough with it for now. This is to get around the fact that we aren’t using the ListView or GridView so we need to manually set the correct FlipViewItem to display when the top level category is selected. I’ll be honest this part is a bit of a hack, but hey – it works!

        private void Category1Selected(object sender, TappedRoutedEventArgs e)
        {
            FlipParent.SelectedItem = Category1FlipView;
        }

        private void Category2Selected(object sender, TappedRoutedEventArgs e)
        {
            FlipParent.SelectedItem = Category2FlipView;
        }

        private void Category3Selected(object sender, TappedRoutedEventArgs e)
        {
            FlipParent.SelectedItem = Category3FlipView;
        }

        private void Category4Selected(object sender, TappedRoutedEventArgs e)
        {
            FlipParent.SelectedItem = Category4FlipView;
        }

Edit 27/08/2012: Changes needed for RTM

I just tried this out in RTM VS 2012 and Wind 8 SDK and noticed that it was broken. The fix was to change from the PointerReleased event to the Tapped event.