in Universal Apps

Encrypting and Decrypting data in an Universal Windows App

Today we are going to create an universal windows app that encrypts and decrypts a given string by a simple push of a button.

You can find the whole source code for this blog post here

Why do we need encryption?

Encryption works best if it is ubiquitous and automatic. It should be enabled for everything by default, not a feature you only turn on when you’re doing something you consider worth protecting. – Bruce Schneier, Cryptographer, Privacy and Security Specialist

Real world example

Imagine that you have a sum of money (let’s say 500$), you are in a store in the suburbs with lots of unkind people around you and your only friend asks you how much money you currently have. We’ll assume that if anyone besides your friend hears you say out loud “500$”, they’ll rob you instantly. So, how do you tell your friend how much money do you have?

That’s where encryption comes in – you define a specific communication channel (let’s say hand gestures) and with one hand you display a high-five ✋ (meaning a 5), with the other hand the ok-sign 👌 (meaning that you multiply the previous with 100), you clap your hands 👏 (meaning that you are talking cash) and then you point the finger at him 👉 (meaning that you are sending the encrypted message). Your friend understands your sign language (decrypts and reads the message) and waves an ok-sign 👍 (meaning that he understood the message) then points the finger at you 👈 (sends an encrypted response back). The others don’t understand what you two are communicating, so they get on with their lives.

The project explained

01 MainPage.xaml: User interface implementation consisting of 3 TextBlocks, 3 TextBoxes and 3 Buttons.

MainPage.xaml.cs: Backend implementation consisting of 3 methods used for handlind the click events of each of the 3 buttons.

SymmetricEncryption.cs: Implementation of a basic encryption and decryption capability which I will detaliate below.

The code – MainPage.xaml

<Page
    x:Class="EncryptionDecryption.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:EncryptionDecryption"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <Grid
            HorizontalAlignment="Center"
            VerticalAlignment="Center">
            <Grid.RowDefinitions>
                <RowDefinition Height="33*" />
                <RowDefinition Height="33*" />
                <RowDefinition Height="33*" />
            </Grid.RowDefinitions>

            <StackPanel 
                Grid.Row="0"
                Orientation="Horizontal"
                Margin="0,0,0,10">
                <TextBlock Padding="0,5,0,0" Text="Input data" Width="120" />
                <TextBox x:Name="inputData" PlaceholderText="Write a string" Width="120" />
                <Button Content="Encrypt" Width="75" Margin="10,0,0,0" Click="Encrypt_Button_Click" />
            </StackPanel>

            <StackPanel 
                Grid.Row="1"
                Orientation="Horizontal"
                Margin="0,0,0,10">
                <TextBlock Padding="0,5,0,0" Text="Encrypted data" Width="120" />
                <TextBox x:Name="encryptedData" IsReadOnly="True" PlaceholderText="Encrypt first" Width="120" />
                <Button Content="Decrypt" Width="75" Margin="10,0,0,0" Click="Decrypt_Button_Click" />
            </StackPanel>

            <StackPanel 
                Grid.Row="2"
                Orientation="Horizontal">
                <TextBlock Padding="0,5,0,0" Text="Decrypted data" Width="120" />
                <TextBox x:Name="decryptedData" IsReadOnly="True" PlaceholderText="Decrypt first" Width="120" />
                <Button Content="Reset" Width="75" Margin="10,0,0,0" Click="Reset_Button_Click" />
            </StackPanel>
        </Grid>
    </Grid>
</Page>

Besides the elements and attributes you already know, in this example we will make use of the StackPanelTextBox and Button XAML elements. We will also learn how to create tables using column and row definitions.

We can create rows and columns using the <RowDefinition> and <ColumnDefinition> tags inside (and only inside) the <Grid.RowDefinitions> tag. We the specify the width and height we want for our columns and rows. If we specify the * symbol after a number, then that column will strech to fit the grid’s maximum width/height.

The StackPanel element is used in this context to proper align the elements without that much of a headache. This element behaves just like a stack in which you can specify an Orientation for your data.

We use the TextBox element to collect the information we want to encrypt from the user but also to display the encrypted an decrypted data via the IsReadOnly attribute. In order to manipulate the data from the user interfaces in the backend, we need to specify a variable name to the current textbox. We do that by assigning a unique name to the x:Name attribute (more about XAML namespaces here).

The Margin attribute is used to externally align the current element within the parent element and the Padding attribute is used to internally align the current child elements within the current element.

The Button element is used to invoke an action (delegate an event) so that the application can begin encrypting/decrypting the input data. To specify which method is executed when the user presses the button, we will set the Click attribute with the name of the method we want to call (the method must exist within MainPage.xaml.cs file).

The code – Main.xaml.cs

cusing System;
using Windows.UI.Popups;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;

namespace EncryptionDecryption
{
    /// <summary>
    /// The main page used to demonstrate the encryption and decryption
    /// capabilities in the Universal Windows Platform
    /// </summary>
    public sealed partial class MainPage : Page
    {
        private readonly SymmetricEncryption encryptionProvider;

        public MainPage()
        {
            this.InitializeComponent();

            encryptionProvider = new SymmetricEncryption();
        }

        private async void Encrypt_Button_Click(object sender, RoutedEventArgs e)
        {
            if (string.IsNullOrEmpty(inputData.Text))
            {
                var dialog = new MessageDialog("You need to specify a string to encrypt !!");
                await dialog.ShowAsync();

                return;
            }

            var result = encryptionProvider.Encrypt(inputData.Text);

            encryptedData.Text = result;
        }

        private async void Decrypt_Button_Click(object sender, RoutedEventArgs e)
        {
            if (string.IsNullOrEmpty(encryptedData.Text))
            {
                var dialog = new MessageDialog("You need to encrypt a string first !!");
                await dialog.ShowAsync();

                return;
            }

            var result = encryptionProvider.Decrypt(encryptedData.Text);

            decryptedData.Text = result;
        }

        private void Reset_Button_Click(object sender, RoutedEventArgs e)
        {
            inputData.Text = string.Empty;
            encryptedData.Text = string.Empty;
            decryptedData.Text = string.Empty;
        }
    }
}

The readonlykeyword is used in this context to specify that the encryptionProvider variable should and can only be assigned in the constructor unlike the const keyword, which forces the developer to instantiate/assign the variable at declaration.

To display a pop-up style notification in the UI, we use an instance of the MessageDialog class. We then call the ShowAsync() method and await its termination using the async/await concept in C#.

Encrypt_Button_Click() – This method is called when the user presses the Encrypt button in the UI. All this method does, is to the pass message we want to encrypt to the SymmetricEncryption class (which is viewed in this context as a service).

Decrypt_Button_Click() – This method is called when the user presses the Decrypt button in the UI. All this method does, is to the pass message we want to decrypt to the SymmetricEncryption class.

Reset_Button_Click() – This method is called when the user presses the Reset button in the UI. All this method does, is to put the UI in the original state before encrypting/decrypting text without having to restart the app.

The code – SymmetricEncryption.cs

using System;
using System.Runtime.InteropServices.WindowsRuntime;
using System.Text;
using Windows.Security.Cryptography;
using Windows.Security.Cryptography.Core;
using Windows.Storage.Streams;

namespace EncryptionDecryption
{
    /// <summary>
    /// Provides symmetric encryption and decryption services
    /// 
    /// Original source: https://goo.gl/arhInA
    /// </summary>
    public class SymmetricEncryption
    {
        private readonly IBuffer randomBuffer;
        private readonly IBuffer randomBufferCBC;
        private readonly CryptographicKey cryptographicKey;

        private readonly string algorithmName;
        private readonly SymmetricKeyAlgorithmProvider cryptingProvider;

        /// <summary>
        /// Instantiate with a random generated buffer (not an option if
        /// you want to persist the encryption to disk)
        /// </summary>
        public SymmetricEncryption()
        {
            algorithmName = SymmetricAlgorithmNames.AesEcbPkcs7;
            cryptingProvider = SymmetricKeyAlgorithmProvider.OpenAlgorithm(algorithmName);

            randomBuffer = CryptographicBuffer.GenerateRandom(cryptingProvider.BlockLength);
            randomBufferCBC = null;

            cryptographicKey = cryptingProvider.CreateSymmetricKey(randomBuffer);
        }
        
        /// <summary>
        /// Instantiate with a custom generated buffer (good for
        /// persisting the encryption to disk)
        /// </summary>
        /// <param name="randomBuffer">The custom generated buffer</param>
        public SymmetricEncryption(IBuffer randomBuffer)
            : this()
        {
            this.randomBuffer = randomBuffer;

            cryptographicKey = cryptingProvider.CreateSymmetricKey(randomBuffer);
        }

        /// <summary>
        /// Instantiate with a custom generated buffer (good for
        /// persisting the encryption to disk) and with a custom
        /// generated CBC buffer (is using CBC algorithms)
        /// </summary>
        /// <param name="randomBuffer">The custom generated buffer</param>
        /// <param name="randomBufferCBC">The custom generated CBC buffer</param>
        public SymmetricEncryption(IBuffer randomBuffer, IBuffer randomBufferCBC)
            : this(randomBuffer)
        {
            this.randomBufferCBC = randomBufferCBC;
        }

        private bool IsMultipleOfBlockLength(IBuffer binaryData)
        {
            return (binaryData.Length % cryptingProvider.BlockLength) != 0;
        }

        /// <summary>
        /// Encrypts a given string
        /// </summary>
        /// <param name="data">Data to be encrypted</param>
        /// <returns>An encrypted string in Unicode</returns>
        public string Encrypt(string data)
        {
            var binaryData = Encoding.Unicode.GetBytes(data).AsBuffer();

            if (!algorithmName.Contains("PKCS7") && IsMultipleOfBlockLength(binaryData))
                throw new Exception("Message buffer length must be multiple of block length !!");

            var encryptedBinaryData = CryptographicEngine.Encrypt(cryptographicKey, binaryData, randomBufferCBC);

            return Encoding.Unicode.GetString(encryptedBinaryData.ToArray());
        }

        /// <summary>
        /// Decrypts a string in Unicode
        /// </summary>
        /// <param name="encryptedData">An encrypted string in Unicode</param>
        /// <returns>The decrypted string in Unicode</returns>
        public string Decrypt(string encryptedData)
        {
            var encryptedBinaryData = Encoding.Unicode.GetBytes(encryptedData).AsBuffer();

            var decryptedData = CryptographicEngine.Decrypt(cryptographicKey, encryptedBinaryData, randomBufferCBC);

            return Encoding.Unicode.GetString(decryptedData.ToArray());
        }
    }
}

All the encrypting algorithms are based on pure, hardcore mathematics. The algorithm we will use in this exampl is the Advanced Encryption Standard (AES) algorithm coupled with an electronic codebook (ECB) mode of operation and PKCS#7 padding. If you want to learn more about cryptography and how it works you can check this resource.

I’ve adapted the current example in a way that you can use any algorithm you want that is provided by the SymmetricAlgorithmNames class and whether to persist the encryption to disk or keeping it in RAM. The Encrypt() and Decrypt() methods have been adapted as well to no longer require to include a certain assembly in a class that doesn’t need to expose the encryption service.

Running the application

We are now ready to build, deploy and run our app. We go to Debug > Start debugging or press F5 on our keyboard. After it builds and deploys successfully, you should see the following window pop-up

01

In conclusion

As you may have observed, a bit of C# coding knowledge is required in order to create a basic encrypting/decrypting app in the Universal Windows Platform. For a better understanding of how powerful the C# language really is, you can check out this repository full with basic C# projects. If you want to go deeply into advanced C# topics, you can check out this repository.

So there you have it, a basic encrypting/decrypting UWP app. Stay tuned on this blog (and star the microsoft-dx organization) to emerge in the beautiful world of “there’s an app for that”.

Adapted from: msdn.microsoft.com

Post image source: ophtek.com

Related Posts

Leave a Reply