Saturday 14 March 2015

Hybrid approach

Now using asymmetric encryption is great because we can send out our public key which can be used to encrypt data then sent to us and only encrypted with our private key. However it's very resource intensive and not practical for large amounts of data.

Symmetric encryption is great because it is efficient, but the down side is that both parties need to have the key; if you use symmetric encryption you somehow need to share your symmetric key with whomever your communicating.

Enter the hybrid approach two companies, well call them A and B

  1. Both companies create their own Private, Public key combination and a symmetric key.
  2. They exchange their public keys.
  3. Company A uses Company B's public key to encrypt their own Symmetric key.
  4. Company B uses Company A's public key to encrypt their own Symmetric key.
  5. The companies send each other their own encrypted symmetric keys.
  6. Company A decrypts Company B's Symmetric Key using their private key
  7. Company B decrypts Company A's Symmetric Key using their private key
  8. the companies can now communicate securly using each others symmetric keys.

take a look at the graphic below

and finally of coarse we need a demo


lets take a look at the xaml to make this happen.
<Page
    x:Class="pc.symmetricKeyExchange.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:pc.symmetricKeyExchange"
    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="Button">
            <Setter Property="HorizontalAlignment" Value="Stretch"/>
            <Setter Property="VerticalAlignment" Value="Stretch"/>
        </Style>
    </Page.Resources>
    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <Grid.RowDefinitions>
            <RowDefinition Height="100"/>
            <RowDefinition Height="auto"/>
            <RowDefinition Height="auto" />
            <RowDefinition Height="auto"/>
            <RowDefinition Height="auto"/>
            <RowDefinition Height="auto"/>
            <RowDefinition Height="auto"/>
            <RowDefinition Height="auto"/>
            <RowDefinition Height="auto"/>
            <RowDefinition Height="auto"/>
            <RowDefinition Height="auto"/>
            <RowDefinition Height="auto"/>
            <RowDefinition Height="auto"/>
            <RowDefinition Height="auto"/>
            <RowDefinition Height="auto"/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="100"/>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="auto"/>
            <ColumnDefinition Width="10"/>
            <ColumnDefinition Width="auto"/>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="20"/>
        </Grid.ColumnDefinitions>
       
        <TextBlock Grid.Column="1" Grid.ColumnSpan="3"
                   Text="Symmetric Key Exchange" VerticalAlignment="Center"
                   Style="{ThemeResource HeaderTextBlockStyle}" />
        <ComboBox x:Name="AsymetricAlgorithm_CB" Header="Asymetric Algorithm"
                  Grid.Column="1" Grid.Row="1" Grid.ColumnSpan="2" />
        <!--Company A-->
        <TextBlock Grid.Column="1" Grid.Row="2" Text="Company A"
                   Style="{ThemeResource SubheaderTextBlockStyle}"
                   Margin="0 0 0 20"/>

        <!--Assymetric -->
        <TextBox x:Name="aPrivateKey_TXT" Header="Assymetric Private Key:"
                 Grid.Row="3" Grid.Column="1" />
        <TextBox x:Name="aPublicKey_TXT"  Header="Assymetric Public Key:"
                 Grid.Row="4" Grid.Column="1"/>
        <Button x:Name="aGenerateAssymetric_BTN" Content="Generate"
                Grid.Column="2" Grid.Row="3" Grid.RowSpan="2" />
        <Button x:Name="aSendAssymetricPublicKey_BTN"
                Grid.Row="5" Grid.Column="2"  Content="Send Public Key>"/>

        <!--Recieved Public Key-->
        <TextBox x:Name="aRecievedPublicKey_TXT"
            Grid.Row="6" Grid.Column="1" Grid.ColumnSpan="2"
            Header="Recieved Public Key:" IsEnabled="False"/>

        <!--Symmetric Key-->
        <TextBox x:Name="aSymmetricKey_TXT" Header="Symmetric Key:"
                 Grid.Row="7" Grid.Column="1"  />
        <Button x:Name="aGenerateSymetricKey_BTN" Content="Generate"
                Grid.Row="7" Grid.Column="2" />

        <TextBox x:Name="aEncryptedSymmetric_TXT"
                 Grid.Row="8" Grid.Column="1" IsEnabled="False"
                 Header="Encrypted Symmetric Key:" />
        <Button x:Name="aEncryptSymmetricKey_BTN"
                Grid.Row="8" Grid.Column="2" Content="Encrypt"/>

        <Button x:Name="aSendEncryptedKey_BTN"
                Grid.Row="9" Grid.Column="2"
                Content="Send Key >"/>

        <!--Recieved Symmetric Key-->
        <TextBox x:Name="aRecievedKey_TXT"
                 Grid.Row="10" Grid.Column="1"  Grid.ColumnSpan="2"
                 IsEnabled="False" Header="Recieved Symmetric Key:"/>
        <TextBox x:Name="aDecryptedKey_TXT" Header="Decrypted Symmetric Key:"
                 Grid.Row="11" Grid.Column="1" />
        <Button x:Name="aDecryptSymmetricKey_BTN"
                Grid.Row="11" Grid.Column="2" Content="Decrypt"/>
       
        <!--Messaging-->
        <Button x:Name="aSend_BTN" Content="Send >"
                Grid.Row="12" Grid.Column="2" />
        <TextBox x:Name="aMessage_TXT" Header="Message:"
                 Grid.Row="12" Grid.Column="1"  
                 TextWrapping="Wrap" Height="100"/>

        <StackPanel Grid.Row="13" Grid.Column="1" Grid.ColumnSpan="2"
                    Orientation="Horizontal" HorizontalAlignment="Right">
            <Button x:Name="aEncryptMessage_BTN" Content="Encrypt"/>
            <Button x:Name="aDecryptMessage_BTN" Content="Decrypt"/>
        </StackPanel>

        <!--Symmetric Combo box-->
        <ComboBox x:Name="SymmetricAlgorithms_CB" Header="Symetric Algorithm"
                  Grid.Column="4" Grid.Row="1" Grid.ColumnSpan="2" />

        <!--Company B-->
        <TextBlock Grid.Column="4" Grid.Row="2" Grid.ColumnSpan="2"
                   Text="Company B" Margin="0 0 0 20"
                   Style="{ThemeResource SubheaderTextBlockStyle}" />

        <!--Assymetric -->
        <TextBox x:Name="bPrivateKey_TXT" Header="Assymetric Private Key:"
                 Grid.Row="3" Grid.Column="5" />
        <TextBox x:Name="bPublicKey_TXT"  Header="Assymetric Public Key:"
                 Grid.Row="4" Grid.Column="5"/>
        <Button x:Name="bGenerateAssymetric_BTN" Content="Generate"
                Grid.Row="3" Grid.Column="4"  Grid.RowSpan="2" />

        <!--Recieved Public Key-->
        <TextBox x:Name="bRecievedPublicKey_TXT"
            Grid.Row="5" Grid.Column="4" Grid.ColumnSpan="2"
            Header="Recieved Public Key:" IsEnabled="False"/>
       
        <Button x:Name="bSendAssymetricPublicKey_BTN"
                Grid.Row="6" Grid.Column="4"  Content="&lt; Send Public Key"/>


        <!--Symmetric Key-->
        <TextBox x:Name="bSymmetricKey_TXT" Header="Symmetric Key:"
                 Grid.Row="7" Grid.Column="5" />
        <Button x:Name="bGenerateSymetricKey_BTN"
                Grid.Row="7" Grid.Column="4" Content="Generate"/>

        <TextBox x:Name="bEncryptedSymmetric_TXT" Header="Encrypted Symmetric Key:"
                 IsEnabled="False" Grid.Row="8" Grid.Column="5" />
        <Button x:Name="bEncryptSymmetricKey_BTN" Content="Encrypt"
                Grid.Row="8" Grid.Column="4"/>

        <Button x:Name="bSendEncryptedKey_BTN"
                Grid.Row="10" Grid.Column="4" Content="&lt; Send Key"/>

        <!--Recieved Symmetric Key-->
        <TextBox x:Name="bRecievedKey_TXT"
                 Grid.Row="9" Grid.Column="4"  Grid.ColumnSpan="2"
                 IsEnabled="False" Header="Recieved Symmetric Key:"/>
        <Button x:Name="bDecryptSymmetricKey_BTN" Content="Decrypt"
                Grid.Row="11" Grid.Column="4" />
        <TextBox x:Name="bDecryptedKey_TXT" Header="Decrypted Symmetric Key:"
                 Grid.Row="11" Grid.Column="5" />

        <!--Messaging-->
        <Button x:Name="bSend_BTN" Grid.Row="12" Grid.Column="4"
                Content="&lt; Send"/>
        <TextBox x:Name="bMessage_TXT" Grid.Row="12" Grid.Column="5"
                 Header="Message:" TextWrapping="Wrap" Height="100"/>

        <StackPanel Grid.Row="13" Grid.Column="4" Grid.ColumnSpan="2"
                    Orientation="Horizontal" HorizontalAlignment="Left">
            <Button x:Name="bEncryptMessage_BTN" Content="Encrypt"/>
            <Button x:Name="bDecryptMessage_BTN" Content="Decrypt"/>
        </StackPanel>
    </Grid>
</Page>


next lets look at the code behind.
using System;
using Windows.Security.Cryptography;
using Windows.Security.Cryptography.Core;
using Windows.Storage.Streams;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;

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

            //Only assymetric algorithms that who have the encrypt function implemented
            AsymetricAlgorithm_CB.ItemsSource = new string[]{
                AsymmetricAlgorithmNames.RsaOaepSha1, AsymmetricAlgorithmNames.RsaOaepSha256,
                AsymmetricAlgorithmNames.RsaOaepSha384, AsymmetricAlgorithmNames.RsaOaepSha512,
                AsymmetricAlgorithmNames.RsaPkcs1,
            };

            //Use a subset of symmetric algorithms for simplicity, because
            //pkcs7 alorithms don't need to be padded.
            SymmetricAlgorithms_CB.ItemsSource = new string[]{
                SymmetricAlgorithmNames.AesEcbPkcs7,
                SymmetricAlgorithmNames.DesEcbPkcs7,
                SymmetricAlgorithmNames.Rc2EcbPkcs7,
                SymmetricAlgorithmNames.TripleDesEcbPkcs7};

            //Handlers for company A
            this.aGenerateAssymetric_BTN.Click += aGenerateAssymetric_BTN_Click;
            this.aSendAssymetricPublicKey_BTN.Click += aSendAssymetricPublicKey_BTN_Click;
            this.aGenerateSymetricKey_BTN.Click += aGenerateSymetricKey_BTN_Click;
            this.aEncryptSymmetricKey_BTN.Click += aEncryptSymmetricKey_BTN_Click;
            this.aSendEncryptedKey_BTN.Click += aSendEncryptedKey_BTN_Click;
            this.aDecryptSymmetricKey_BTN.Click += aDecryptSymmetricKey_BTN_Click;
            this.aSend_BTN.Click += aSend_BTN_Click;
            this.aEncryptMessage_BTN.Click+=aEncryptMessage_BTN_Click;
            this.aDecryptMessage_BTN.Click += aDecryptMessage_BTN_Click;

            //Handlers for company B
            this.bGenerateAssymetric_BTN.Click += bGenerateAssymetric_BTN_Click;
            this.bSendAssymetricPublicKey_BTN.Click += bSendAssymetricPublicKey_BTN_Click;
            this.bGenerateSymetricKey_BTN.Click += bGenerateSymetricKey_BTN_Click;
            this.bEncryptSymmetricKey_BTN.Click += bEncryptSymmetricKey_BTN_Click;
            this.bSendEncryptedKey_BTN.Click += bSendEncryptedKey_BTN_Click;
            this.bDecryptSymmetricKey_BTN.Click += bDecryptSymmetricKey_BTN_Click;
            this.bSend_BTN.Click += bSend_BTN_Click;
            this.bEncryptMessage_BTN.Click += bEncryptMessage_BTN_Click;
            this.bDecryptMessage_BTN.Click += bDecryptMessage_BTN_Click;
        }

        #region Assymetric Key
        void aGenerateAssymetric_BTN_Click(object sender, RoutedEventArgs e)
        {
            GenerateAssymetricKey(aPrivateKey_TXT, aPublicKey_TXT);
        }

        void bGenerateAssymetric_BTN_Click(object sender, RoutedEventArgs e)
        {
            GenerateAssymetricKey(bPrivateKey_TXT, bPublicKey_TXT);
        }

        void GenerateAssymetricKey(TextBox PrivateKey, TextBox PublicKey)
        {
            //get the assymetric key provider
            var algorithmName = AsymetricAlgorithm_CB.SelectedValue.ToString();
            var providor = AsymmetricKeyAlgorithmProvider.OpenAlgorithm(algorithmName);

            //get the assymetric key
            CryptographicKey keyPair = providor.CreateKeyPair(GetKeySize(algorithmName));

            //write the private key to the textbox
            IBuffer privateKey = keyPair.Export();
            PrivateKey.Text = CryptographicBuffer.EncodeToBase64String(privateKey);

            //write the public key to the textbox
            IBuffer publicKey = keyPair.ExportPublicKey(GetCryptographicPublicKeyBlobType(algorithmName));
            PublicKey.Text = CryptographicBuffer.EncodeToBase64String(publicKey);
        }

        void bSendAssymetricPublicKey_BTN_Click(object sender, RoutedEventArgs e)
        {
            aRecievedPublicKey_TXT.Text = bPublicKey_TXT.Text;
        }

        void aSendAssymetricPublicKey_BTN_Click(object sender, RoutedEventArgs e)
        {
            bRecievedPublicKey_TXT.Text = aPublicKey_TXT.Text;
        }

        #endregion

        #region Symmetric Key
        #region Generate Symmetric key
        void aGenerateSymetricKey_BTN_Click(object sender, RoutedEventArgs e)
        {
            GenerateSymetricKey(aSymmetricKey_TXT);
        }

        void bGenerateSymetricKey_BTN_Click(object sender, RoutedEventArgs e)
        {
            GenerateSymetricKey(bSymmetricKey_TXT);
        }

        void GenerateSymetricKey(TextBox SymmetricKey)
        {
            //get the symmetric key provider
            string algorithmname = SymmetricAlgorithms_CB.SelectedValue.ToString();
            SymmetricKeyAlgorithmProvider providor =
                SymmetricKeyAlgorithmProvider.OpenAlgorithm(algorithmname);

            //create a random symmetric key and write it to its textbox
            IBuffer key = CryptographicBuffer.GenerateRandom(providor.BlockLength);
            SymmetricKey.Text = CryptographicBuffer.EncodeToBase64String(key);
        }
        #endregion

        #region Encrypt Symmetric key
        void aEncryptSymmetricKey_BTN_Click(object sender, RoutedEventArgs e)
        {
            EncryptSymmetricKey(aEncryptedSymmetric_TXT, aSymmetricKey_TXT, aRecievedPublicKey_TXT);
        }

        void bEncryptSymmetricKey_BTN_Click(object sender, RoutedEventArgs e)
        {
            EncryptSymmetricKey(bEncryptedSymmetric_TXT, bSymmetricKey_TXT, bRecievedPublicKey_TXT);
        }

        void EncryptSymmetricKey(TextBox EcryptedSymmetricKey, TextBox SymmetricKey, TextBox RecievedPublicKey)
        {
            //get the assymetric key provider
            string algorithmName = AsymetricAlgorithm_CB.SelectedValue.ToString();
            AsymmetricKeyAlgorithmProvider provider =
                AsymmetricKeyAlgorithmProvider.OpenAlgorithm(algorithmName);

            // get the symetric key
            IBuffer symmetricKey = CryptographicBuffer.ConvertStringToBinary(SymmetricKey.Text, BinaryStringEncoding.Utf8);

            //encrypte the symmetric key using the other companies public key
            IBuffer recievedPublicKey = CryptographicBuffer.DecodeFromBase64String(RecievedPublicKey.Text);
            CryptographicKey key = provider.ImportPublicKey(recievedPublicKey, GetCryptographicPublicKeyBlobType(algorithmName));

            //write the encrypted symmetric key to a textbox
            IBuffer EncryptedSymmetricKey = CryptographicEngine.Encrypt(key, symmetricKey, null);
            EcryptedSymmetricKey.Text = CryptographicBuffer.EncodeToBase64String(EncryptedSymmetricKey);
        }
        #endregion

        #region Send Symmetric Key
        private void aSendEncryptedKey_BTN_Click(object sender, RoutedEventArgs e)
        {
            bRecievedKey_TXT.Text = aEncryptedSymmetric_TXT.Text;
        }

        void bSendEncryptedKey_BTN_Click(object sender, RoutedEventArgs e)
        {
            aRecievedKey_TXT.Text = bEncryptedSymmetric_TXT.Text;
        }


        #endregion

        #region Decrypt Symmetric Key
        void aDecryptSymmetricKey_BTN_Click(object sender, RoutedEventArgs e)
        {
            DecryptSymmetricKey(aRecievedKey_TXT, aPrivateKey_TXT, aDecryptedKey_TXT);
        }

        void bDecryptSymmetricKey_BTN_Click(object sender, RoutedEventArgs e)
        {
            DecryptSymmetricKey(bRecievedKey_TXT, bPrivateKey_TXT, bDecryptedKey_TXT);
        }

        void DecryptSymmetricKey(TextBox EncryptedSymmetricKey, TextBox PrivateKey, TextBox DecryptedKey)
        {
            //get the assymetric key provider
            var algorithmName = AsymetricAlgorithm_CB.SelectedValue.ToString();
            var provider = AsymmetricKeyAlgorithmProvider.OpenAlgorithm(algorithmName);

            //get the other companies encrypted symmetric key
            var encryptedKey = CryptographicBuffer.DecodeFromBase64String(EncryptedSymmetricKey.Text);

            //get the companies private key
            var privateKey = CryptographicBuffer.DecodeFromBase64String(PrivateKey.Text);

            //get assymetric key using the private key
            CryptographicKey key = provider.ImportKeyPair(privateKey);

            //decrypt the other companies symmetric key using the pirvate key and write to textbox
            var decryptedKey = CryptographicEngine.Decrypt(key, encryptedKey, null);
            DecryptedKey.Text = CryptographicBuffer.ConvertBinaryToString(BinaryStringEncoding.Utf8, decryptedKey);
        }
        #endregion

        #region Send Message
        void bSend_BTN_Click(object sender, RoutedEventArgs e)
        {
            aMessage_TXT.Text = bMessage_TXT.Text;
        }

        void aSend_BTN_Click(object sender, RoutedEventArgs e)
        {
            bMessage_TXT.Text = aMessage_TXT.Text;
        }

        void aEncryptMessage_BTN_Click(object sender, RoutedEventArgs e)
        {
            EncryptMessage(aMessage_TXT, aDecryptedKey_TXT);
        }

        void bEncryptMessage_BTN_Click(object sender, RoutedEventArgs e)
        {
            EncryptMessage(bMessage_TXT, bDecryptedKey_TXT);
        }

        void EncryptMessage(TextBox Message, TextBox DecryptedKey)
        {
            //get the symmetric key provider
            var algorithmName = SymmetricAlgorithms_CB.SelectedValue.ToString();
            var provider = SymmetricKeyAlgorithmProvider.OpenAlgorithm(algorithmName);

            //get the other companies decrypted key
            var decryptedKey = CryptographicBuffer.DecodeFromBase64String(DecryptedKey.Text);

            //get the symmetric key
            CryptographicKey key = provider.CreateSymmetricKey(decryptedKey);

            //get the message to encrypt
            IBuffer message = CryptographicBuffer.ConvertStringToBinary(Message.Text,BinaryStringEncoding.Utf8);

            //encrypt the message using the other companies symmetric key and write to textbox
            var encryptedMessage = CryptographicEngine.Encrypt(key, message, null);
            Message.Text = CryptographicBuffer.EncodeToBase64String(encryptedMessage);
        }

        void aDecryptMessage_BTN_Click(object sender, RoutedEventArgs e)
        {
            DecryptMessage(aMessage_TXT, aSymmetricKey_TXT);
        }

        void bDecryptMessage_BTN_Click(object sender, RoutedEventArgs e)
        {
            DecryptMessage(bMessage_TXT, bSymmetricKey_TXT);
        }

        void DecryptMessage(TextBox Message, TextBox SymmetricKey) {

            //get the symmetric key provider
            var algorithmName = SymmetricAlgorithms_CB.SelectedValue.ToString();
            var provider = SymmetricKeyAlgorithmProvider.OpenAlgorithm(algorithmName);

            //get the encrypted message
            var encryptedMessage = CryptographicBuffer.DecodeFromBase64String(Message.Text);

            //get the symmetric key value
            var key = CryptographicBuffer.DecodeFromBase64String(SymmetricKey.Text);

            //get the symmetric key
            CryptographicKey symmetricKey = provider.CreateSymmetricKey(key);
           
            //decrypt the message using symmetric key and write it to a textbox
            var decryptedMessage = CryptographicEngine.Decrypt(symmetricKey, encryptedMessage, null);
            Message.Text = CryptographicBuffer.ConvertBinaryToString(BinaryStringEncoding.Utf8, decryptedMessage);

        }
        #endregion
        #endregion

        //get the min key size required for the algorithm
        uint GetKeySize(string AglorithmName)
        {
            switch (AglorithmName)
            {
                case "ECDSA_P256_SHA256":
                    return 256;

                case "ECDSA_P384_SHA384":
                    return 384;

                case "DSA_SHA1":
                case "RSA_PKCS1":
                case "RSASIGN_PKCS1_SHA1":
                case "RSASIGN_PKCS1_SHA256":
                case "RSASIGN_PSS_SHA1":
                case "RSASIGN_PSS_SHA256":
                case "RSASIGN_PSS_SHA384":
                    return 512;

                case "ECDSA_P521_SHA512":
                    return 521;

                case "RSA_OAEP_SHA1":
                case "RSA_OAEP_SHA256":
                case "RSASIGN_PKCS1_SHA384":
                case "RSASIGN_PKCS1_SHA512":
                case "RSASIGN_PSS_SHA512":
                    return 1024;

                case "DSA_SHA256":
                case "RSA_OAEP_SHA384":
                case "RSA_OAEP_SHA512":
                    return 2048;

                default:
                    return 512;
            }
        }


        // get the type of public key used by the algorithm, not 100% on this,
        CryptographicPublicKeyBlobType GetCryptographicPublicKeyBlobType(string AsymmetricAlgorithmName)
        {
            switch (AsymmetricAlgorithmName)
            {
                case "DSA_SHA1":
                case "RSA_OAEP_SHA256":
                case "RSA_OAEP_SHA512":
                case "RSA_PKCS1":
                case "RSASIGN_PKCS1_SHA1":
                case "RSASIGN_PKCS1_SHA256":
                case "RSASIGN_PKCS1_SHA384":
                case "RSASIGN_PKCS1_SHA512":
                case "RSASIGN_PSS_SHA1":
                case "RSASIGN_PSS_SHA256":
                case "RSASIGN_PSS_SHA384":
                case "RSASIGN_PSS_SHA512":
                    return CryptographicPublicKeyBlobType.Capi1PublicKey;
                case "DSA_SHA256":
                case "ECDSA_P256_SHA256":
                case "ECDSA_P384_SHA384":
                case "ECDSA_P521_SHA512":
                case "RSA_OAEP_SHA1":
                case "RSA_OAEP_SHA384":
                    return CryptographicPublicKeyBlobType.BCryptPublicKey;
                default:
                    throw new ArgumentOutOfRangeException("AsymmetricAlgorithmName", "No such algorithm");
            }
        }
    }
}


and that's it, i found the trickiest part was keeping track of when i encoded buffers into base 64, just make sure to decode what you encode.