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
- Both companies create their own Private, Public key combination and a symmetric key.
- They exchange their public keys.
- Company A uses Company B's public key to encrypt their own Symmetric key.
- Company B uses Company A's public key to encrypt their own Symmetric key.
- The companies send each other their own encrypted symmetric keys.
- Company A decrypts Company B's Symmetric Key using their private key
- Company B decrypts Company A's Symmetric Key using their private key
- 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="<
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="< 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="<
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>
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");
}
}
}
}