Wednesday, 18 March 2015

DataProtectionProvider

The DataProtectionProvider class is used to encrypt and decrypt data and streams, it has two constructors, a parameter-less one used for decryption, and one that accepts a "security descriptor
definition language" (SDDL) string.

The DataProtectionProvider requires that the Enterprise Authentication Capability be selected in the manifest, this should only be done if necessary, meaning that you are developing an application for an enterprise.


ok so lets look at our UI


the xaml to save you some time

<Page
    x:Class="pc.dataProctectionProviderExample.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:pc.dataProctectionProviderExample"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">
   
    <Page.Resources>
        <Style TargetType="TextBox">
            <Setter Property="FontSize" Value="24"/>
            <Setter Property="Height" Value="200"/>
            <Setter Property="TextWrapping" Value="Wrap"/>
        </Style>
        <Style TargetType="Button">
            <Setter Property="FontSize" Value="24"/>
        </Style>
    </Page.Resources>

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <Grid.RowDefinitions>
            <RowDefinition Height="100"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="100"/>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>
        <TextBlock Grid.Column="1" Text="DataProtectionProvider Example"
                   Style="{ThemeResource HeaderTextBlockStyle}"
                   VerticalAlignment="Center"/>
        <StackPanel Grid.Column="1" Grid.Row="1">
            <TextBox x:Name="Message_TXT" Header="Message:"  />
           
            <Button x:Name="Protect_BTN" Content="Protect"/>
            <TextBox x:Name="ProtectedMessage_TXT"
                     Header="Protected Message:"  />
           
            <Button x:Name="Unprotect_BTN" Content="Unprotect"/>
            <TextBox x:Name="UnprotectedMessage_TXT"
                     Header="Unprotected Message:"  />
        </StackPanel>
    </Grid>
</Page>


now let's jump into the code behind

using System;
using Windows.Security.Cryptography;
using Windows.Security.Cryptography.DataProtection;
using Windows.Storage.Streams;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;

namespace pc.dataProctectionProviderExample
{
    public sealed partial class MainPage : Page
    {
        public MainPage()
        {
            this.InitializeComponent();

            //add event recievers
            this.Protect_BTN.Click += Protect_BTN_Click;
            this.Unprotect_BTN.Click += Unprotect_BTN_Click;
        }

        async void Protect_BTN_Click(object sender, RoutedEventArgs e)
        {
            // instantiate DataProtectionProvider for encryption
            var protectionDescriptor = "LOCAL=machine";
            var dpp = new DataProtectionProvider(protectionDescriptor);

            //convert message to Byte array
            IBuffer message =
                CryptographicBuffer.ConvertStringToBinary(Message_TXT.Text, BinaryStringEncoding.Utf8);

            //protect the message
            IBuffer protectedMessage = await dpp.ProtectAsync(message);

            //outpot protected message to textbox
            ProtectedMessage_TXT.Text = CryptographicBuffer.EncodeToBase64String(protectedMessage);
        }

        async void Unprotect_BTN_Click(object sender, RoutedEventArgs e)
        {
            //load protected message to byte array
            IBuffer protectedMessage =
                CryptographicBuffer.DecodeFromBase64String(ProtectedMessage_TXT.Text);

            //instantiate a DataProtectionProvider for decryption
            var dpp = new DataProtectionProvider();

            //decrypt the data
            IBuffer unprotectedMessage = await dpp.UnprotectAsync(protectedMessage);

            //load decrypted data to text box
            UnprotectedMessage_TXT.Text =
                CryptographicBuffer.ConvertBinaryToString(BinaryStringEncoding.Utf8, unprotectedMessage);
        }
    }
}


straight forward enough, but not really all that interesting, so let's make some slight modification, instead of saving our data to a text box, lets save it to a file. let's begin by refactoring our UI a little bit.

Fairly simple basically we use the file open picker and the files save picker to save and open files but encrypt and decrypt the contents based as before on the SDDL. Let's take a look at the XAML

<Page
    x:Class="pc.dataProctectionProviderExample.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:pc.dataProctectionProviderExample"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">
   
    <Page.Resources>
        <Style TargetType="TextBox">
            <Setter Property="FontSize" Value="24"/>
            <Setter Property="Height" Value="200"/>
            <Setter Property="TextWrapping" Value="Wrap"/>
        </Style>
        <Style TargetType="Button">
            <Setter Property="FontSize" Value="24"/>
        </Style>
    </Page.Resources>

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <Grid.RowDefinitions>
            <RowDefinition Height="100"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="100"/>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>
        <TextBlock Grid.Column="1" Text="DataProtectionProvider Example"
                   Style="{ThemeResource HeaderTextBlockStyle}"
                   VerticalAlignment="Center"/>
        <StackPanel Grid.Column="1" Grid.Row="1">
            <TextBox x:Name="Message_TXT" Header="Message:"  />
           
            <StackPanel Orientation="Horizontal">
                <Button x:Name="Protect_BTN" Content="Protect To File"/>
                <Button x:Name="Unprotect_BTN" Content="Unprotect From File"/>
            </StackPanel>
            <TextBox x:Name="UnprotectedMessage_TXT"
                     Header="Unprotected Message:"  />
        </StackPanel>
    </Grid>
</Page>


now let's look at the code.
using System;
using System.Collections.Generic;
using Windows.Security.Cryptography;
using Windows.Security.Cryptography.DataProtection;
using Windows.Storage;
using Windows.Storage.Pickers;
using Windows.Storage.Provider;
using Windows.Storage.Streams;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;

namespace pc.dataProctectionProviderExample
{
    public sealed partial class MainPage : Page
    {
        public MainPage()
        {
            this.InitializeComponent();

            //add event recievers
            this.Protect_BTN.Click += Protect_BTN_Click;
            this.Unprotect_BTN.Click += Unprotect_BTN_Click;
        }

        async void Protect_BTN_Click(object sender, RoutedEventArgs e)
        {
            // instantiate DataProtectionProvider for encryption
            var protectionDescriptor = "LOCAL=machine";
            var dpp = new DataProtectionProvider(protectionDescriptor);

            //convert message to Byte array
            IBuffer message =
                CryptographicBuffer.ConvertStringToBinary(Message_TXT.Text,
                                                    BinaryStringEncoding.Utf8);

            //Instantiate the file save picker
            FileSavePicker fsp = new FileSavePicker();
            fsp.SuggestedStartLocation = PickerLocationId.DocumentsLibrary;

            // Dropdown of file types the user can save the file as
            fsp.FileTypeChoices.Add(
                "Protected Data", new List<string>() { ".data" });

            //Default file name if the user does not type one in or
            //select a file to replace
            fsp.SuggestedFileName = "Protected";

            //open the file save picker and wait for a file
            StorageFile file = await fsp.PickSaveFileAsync();

            //make sure the user didn't cancel
            if (file != null)
            {
                //Open a stream to load data in
                using (var inputStream = new InMemoryRandomAccessStream())

                //create stream to encrypt data to
                using (var fileStream = await file.OpenAsync(FileAccessMode.ReadWrite))
                {
                    //cteate data writer to write data to the input stream
                    using (var dw = new DataWriter(inputStream))
                    {
                        //write data to the stream
                        dw.WriteBuffer(message);
                        await dw.StoreAsync();

                        //encrypte the intput stream into the file stream
                        await dpp.ProtectStreamAsync(inputStream.GetInputStreamAt(0),
                                                     fileStream);
                    }
                }
            }
        }

        async void Unprotect_BTN_Click(object sender, RoutedEventArgs e)
        {
            //instantiate a DataProtectionProvider for decryption
            var dpp = new DataProtectionProvider();

            //Instantiate the File Open Picker
            FileOpenPicker fop = new FileOpenPicker();
            fop.SuggestedStartLocation = PickerLocationId.DocumentsLibrary;
            fop.FileTypeFilter.Add(".data");

            //Get the selected file
            StorageFile file = await fop.PickSingleFileAsync();

            //make sure user didn't hit cancel
            if (file != null)
            {
                //Open a stream to the selected file
                using (var fileStream = await file.OpenAsync(FileAccessMode.ReadWrite))

                //create a stream to decrypte the data to
                using (var outputStream = new InMemoryRandomAccessStream())
                {
                    //decrypt the data
                    await dpp.UnprotectStreamAsync(fileStream, outputStream);

                    //fill the data reader with the content of the outputStream,
                    //but from position 0
                    using (var dr = new DataReader(outputStream.GetInputStreamAt(0)))
                    {
                        //load data from the stream to the dataReader
                        await dr.LoadAsync((uint)outputStream.Size);

                        //load the data from the datareader into a buffer
                        IBuffer data = dr.ReadBuffer((uint)outputStream.Size);

                        //write the contentes of the buffer into a textbox
                        UnprotectedMessage_TXT.Text =
                            CryptographicBuffer.ConvertBinaryToString(BinaryStringEncoding.Utf8, data);
                    }
                }
            }
        }
    }
}


and that's it we're now encrypting our data to a file using the Data Protection Provider