Thursday, 5 March 2015

Digital Signature & Asymmetric Encryption

A digital signature is very similar to a Messaging Authentication Code (MAC), the difference is that a MAC uses a symmetric key, that is a shared secrete (a password) that both parties must have, whereas a digital signature utilizes asymmetric keys. That is a pair of private and public keys, these are two keys that are mathematically linked to each other; the private one needs to be kept a secrete and the public one can be shared. It is impossible to discover one of them without knowing the other, so again only as secure as the private key with the advantage that you never have to share the private one.

Data can be encrypted using the public key, but only decrypted using the private key, now just because you can doesn't mean you should. Asymmetric encryption is slow, so it's usually only used for signing.

Whereas data signed with the private key can be verified with the public key and this is a digital signature.

Clear as mud, so there are numerous asymmetric encryption algorithms that you can use:
Asymmetric Algorithms

now the catch is that from my experimenting I've noticed that the algorithms in winrt that allow you to sign data do not allow you to encrypt it, and vice-versa, strange, if you're reading this and know something i don't please fill me in.

now from my investigation I found the following,
Algorithm
Min Byte Key size
Sign
Encrypt
"RSA_OAEP_SHA1"
1024
0
1
"RSA_OAEP_SHA256"
1024
0
1
"RSA_OAEP_SHA384"
2048
0
1
"RSA_OAEP_SHA512"
2048
0
1
"RSA_PKCS1"
512
1
0
"DSA_SHA1"
512
1
0
"DSA_SHA256"
2048
1
0
"ECDSA_P256_SHA256"
256
1
0
"ECDSA_P384_SHA384"
384
1
0
"ECDSA_P521_SHA512"
521
1
0
"RSASIGN_PKCS1_SHA1"
512
1
0
"RSASIGN_PKCS1_SHA256"
512
1
0
"RSASIGN_PKCS1_SHA384"
1024
1
0
"RSASIGN_PKCS1_SHA512"
1024
1
0
"RSASIGN_PSS_SHA1"
512
1
0
"RSASIGN_PSS_SHA256"
512
1
0
"RSASIGN_PSS_SHA384"
512
1
0
"RSASIGN_PSS_SHA512"
1024
1
0
It doesn't sit well with me, that none of the algorithms can do both, and the exam ref guide for 70-485 doesn't event touch the subject of encryption using an asymmetric key so for now i'll leave it at that.

OK let's take a look at a working example, first a screen shot of our demo

There's a lot going on, so i'll try and explain it, basically you can see that there's two vertical sections, the top one is for the creator of the private key. you never share your private in asymmetric encryption, you create both the public and private key, but you only ever share the private key.

the bottom half is for consumers of the public key.

now there's three horizontal sections, the first has the two message boxes, they are you data input.

the second  horizontal section is used for signing and validating messages, basically in the top section you create a private public key combination and sign your message, then you send the message, the public key and the signature to the bottom section, the bottom section acts as the recipient and validates the message by using the three in combination.

finally the third horizontal section is for demonstrating the encryption capability. what you do in the top section is create a private and public key combination, then you send the public key to the bottom section; in turn the bottom section can encrypt data from the bottom message box using the public key and then send it back to the top which can then decrypt it using the private key.

Ok let's look at all the XAML
<Page
    x:Class="pc.DigitalSignatureExample.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:pc.DigitalSignatureExample"
    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"/>
        </Style>
        <Style TargetType="Button">
            <Setter Property="FontSize" Value="24"/>
            <Setter Property="VerticalAlignment" Value="Bottom"/>
        </Style>
        <Style TargetType="ComboBox">
            <Setter Property="FontSize" Value="24"/>
            <Setter Property="Height" Value="84"/>
        </Style>
    </Page.Resources>
   
    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <Grid.RowDefinitions>
            <RowDefinition Height="100"/>
            <RowDefinition Height="*"/>
            <RowDefinition Height="10"/>
            <RowDefinition Height="*"/>
            <RowDefinition Height="100"/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="100"/>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="10"/>
            <ColumnDefinition Width="2*"/>
            <ColumnDefinition Width="10"/>
            <ColumnDefinition Width="2*"/>
            <ColumnDefinition Width="20"/>
        </Grid.ColumnDefinitions>

        <TextBlock Grid.Column="1" Grid.Row="0" Grid.ColumnSpan="4"
                   Text="Digital Signature Example" VerticalAlignment="Center"
                   Style="{ThemeResource HeaderTextBlockStyle}" />
       
        <!-- Private Key creator -->
        <TextBox x:Name="Private_Message_TXT" Header="Message:"
                 Grid.Column="1" Grid.Row="1"
                 TextWrapping="Wrap"
                 Text="Place Holder Text"/>
        <!-- For Signing -->
        <StackPanel Grid.Column="3" Grid.Row="1">
            <Grid>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="*"/>
                    <ColumnDefinition Width="auto"/>
                </Grid.ColumnDefinitions>

                <ComboBox x:Name="SignAlgorithm_CB" Header="Sign Algorithm:" />
                <Button x:Name="Sign_BTN" Content="Sign" Grid.Column="1" />
            </Grid>


            <TextBox x:Name="Private_Signature_TXT" Header="Signature" />
            <TextBox x:Name="Private_SignaturePrivateKey_TXT" Header="Private key:" />

            <TextBox x:Name="Private_SignaturePublicKey_TXT" Header="Public key:"  />
            <Button x:Name="Private_SignatureSend_BTN" Content="Send" />
        </StackPanel>

        <!-- For Encrypting -->
        <StackPanel Grid.Column="5" Grid.Row="1">
            <Grid>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="*"/>
                    <ColumnDefinition Width="auto"/>
                </Grid.ColumnDefinitions>

                <ComboBox x:Name="EncryptionAlgorithm_CB" Header="Encrypt Algorithm:" />
                <Button x:Name="KeysForEncryption_BTN" Content="Get Keys" Grid.Column="1" />
            </Grid>

            <TextBox x:Name="Private_EncryptionPrivateKey_TXT" Header="Private key:" />

            <TextBox x:Name="Private_EncryptionPublicKey_TXT" Header="Public key:"  />
            <StackPanel Orientation="Horizontal">
                <Button x:Name="Private_EncryptionSend_BTN" Content="Send Public Key" />
                <Button x:Name="Private_Decrypt_BTN" Content="Decrypt"/>
            </StackPanel>
        </StackPanel>



        <!-- Public key recipient -->
        <!-- Varifying data -->
        <TextBox x:Name="Public_Message_TXT" Header="Message:" Grid.Column="1"
                 Grid.Row="3" TextWrapping="Wrap" />
        <StackPanel Grid.Column="3" Grid.Row="3">
            <TextBox x:Name="Public_PublicKey_TXT" Header="Public Key:" />
            <TextBox x:Name="Public_Signature_TXT" Header="Signature:" />
           
            <Button x:Name="Public_Validate_BTN" Content="Validate" />
        </StackPanel>

        <!-- Encrypting Data -->
        <StackPanel Grid.Column="5" Grid.Row="3">
            <TextBox x:Name="Public_EncryptionPublicKey_TXT" Header="Public Key:" />
            <StackPanel Orientation="Horizontal">
                <Button x:Name="Public_Encrypt_BTN" Content="Encrypt" />
                <Button x:Name="Public_Send_BTN" Content="Send"/>
            </StackPanel>
        </StackPanel>
    </Grid>
</Page>


not too bad, I tried commenting the different sections to make it easier to follow.

Anyway let's look at the whole code behind, then I'll dissect it
using System;
using Windows.Security.Cryptography;
using Windows.Security.Cryptography.Core;
using Windows.Storage.Streams;
using Windows.UI.Popups;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;

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

            //set algorithms that can sign data
            SignAlgorithm_CB.ItemsSource = new string[] {
                AsymmetricAlgorithmNames.DsaSha1, AsymmetricAlgorithmNames.DsaSha256,
                AsymmetricAlgorithmNames.EcdsaP256Sha256, AsymmetricAlgorithmNames.EcdsaP384Sha384,
                AsymmetricAlgorithmNames.EcdsaP521Sha512, AsymmetricAlgorithmNames.RsaSignPkcs1Sha1,
                AsymmetricAlgorithmNames.RsaSignPkcs1Sha256, AsymmetricAlgorithmNames.RsaSignPkcs1Sha384,
                AsymmetricAlgorithmNames.RsaSignPkcs1Sha512, AsymmetricAlgorithmNames.RsaSignPssSha1,
                AsymmetricAlgorithmNames.RsaSignPssSha256, AsymmetricAlgorithmNames.RsaSignPssSha384,
                AsymmetricAlgorithmNames.RsaSignPssSha512 };

            //set algorithms that can encrypt data
            EncryptionAlgorithm_CB.ItemsSource = new string[]{
                AsymmetricAlgorithmNames.RsaOaepSha1, AsymmetricAlgorithmNames.RsaOaepSha256,
                AsymmetricAlgorithmNames.RsaOaepSha384, AsymmetricAlgorithmNames.RsaOaepSha512,
                AsymmetricAlgorithmNames.RsaPkcs1,
            };

            //private key owner evnets
            Sign_BTN.Click += Sign_BTN_Click;
            Private_SignatureSend_BTN.Click += Private_SignatureSend_BTN_Click;


            KeysForEncryption_BTN.Click += GeneratePublicPrivateKeysForEncryption_Click;
            Private_EncryptionSend_BTN.Click += Private_EncryptionSend_BTN_Click;
            Private_Decrypt_BTN.Click += Private_Decrypt_BTN_Click;
           
            //public key user events
            Public_Validate_BTN.Click += Public_Validate_BTN_Click;
            Public_Encrypt_BTN.Click += EncryptData_Click;
            Public_Send_BTN.Click += Public_Send_BTN_Click;
        }

        // create public & private Key for encryption
        void GeneratePublicPrivateKeysForEncryption_Click(object sender, RoutedEventArgs e)
        {
            //get the algorithm to use
            string algorithmName = EncryptionAlgorithm_CB.SelectedValue.ToString();
            AsymmetricKeyAlgorithmProvider asymmetricKeyProvider =
                AsymmetricKeyAlgorithmProvider.OpenAlgorithm(algorithmName);

            //differnet algorithms have different min key sizes, I tried to figure it out
            CryptographicKey keyPair = asymmetricKeyProvider.CreateKeyPair(GetKeySize(algorithmName));

            //get the public key
            IBuffer publicKey = keyPair.ExportPublicKey(GetCryptographicPublicKeyBlobType(algorithmName));
            Private_EncryptionPublicKey_TXT.Text = CryptographicBuffer.EncodeToBase64String(publicKey);

            //get the private key
            IBuffer privateKey = keyPair.Export();
            Private_EncryptionPrivateKey_TXT.Text = CryptographicBuffer.EncodeToBase64String(privateKey);
        }

        //use the public key by the recipient to encrypt data.
        void EncryptData_Click(object sender, RoutedEventArgs e)
        {
            //get algorithm to use
            string algorithmName = EncryptionAlgorithm_CB.SelectedValue.ToString();
            AsymmetricKeyAlgorithmProvider asymmetricKeyProvider =
                AsymmetricKeyAlgorithmProvider.OpenAlgorithm(algorithmName);

            //Convert the message to a buffer
            IBuffer message = CryptographicBuffer.ConvertStringToBinary(Public_Message_TXT.Text, BinaryStringEncoding.Utf8);

            //get the public key to use
            IBuffer publicKey = CryptographicBuffer.DecodeFromBase64String(Public_EncryptionPublicKey_TXT.Text);

            //get the public key to use, again did my best, might not be 100%
            CryptographicKey keyPublic =
                asymmetricKeyProvider.ImportPublicKey(publicKey, GetCryptographicPublicKeyBlobType(algorithmName));

            //encrypt the data using the public key, and set the message box to the result
            var encryptedData = CryptographicEngine.Encrypt(keyPublic, message, null);
            Public_Message_TXT.Text = CryptographicBuffer.EncodeToBase64String(encryptedData);
        }

        //Decrypt
        void Private_Decrypt_BTN_Click(object sender, RoutedEventArgs e)
        {
            //Get the algorithm to use
            string aglorithmName = EncryptionAlgorithm_CB.SelectedValue.ToString();
            AsymmetricKeyAlgorithmProvider asymmetricKeyProvider =
                AsymmetricKeyAlgorithmProvider.OpenAlgorithm(aglorithmName);

            //get the recieved message from the recipient
            IBuffer message = CryptographicBuffer.DecodeFromBase64String(Private_Message_TXT.Text);

            //get the private key
            IBuffer privateKey = CryptographicBuffer.DecodeFromBase64String(Private_EncryptionPrivateKey_TXT.Text);
            CryptographicKey key = asymmetricKeyProvider.ImportKeyPair(privateKey);

            //Decrypt the message
            IBuffer decryptedMessage = CryptographicEngine.Decrypt(key, message, null);

            //set the message box to display the message
            Private_Message_TXT.Text = CryptographicBuffer.ConvertBinaryToString(BinaryStringEncoding.Utf8, decryptedMessage);
        }

        //Send the encrypted message from the recipient to the Private key holder
        void Public_Send_BTN_Click(object sender, RoutedEventArgs e)
        {
            Private_Message_TXT.Text = Public_Message_TXT.Text;
        }

        //Send public key from the private key holder to the recipient
        void Private_EncryptionSend_BTN_Click(object sender, RoutedEventArgs e)
        {
            Public_EncryptionPublicKey_TXT.Text = Private_EncryptionPublicKey_TXT.Text;
        }

        //Sign Data with private key
        void Sign_BTN_Click(object sender, RoutedEventArgs e)
        {
            //get the algorithm to use
            string algorithmName = SignAlgorithm_CB.SelectedValue.ToString();
            AsymmetricKeyAlgorithmProvider asymmetricKeyProvider =
                AsymmetricKeyAlgorithmProvider.OpenAlgorithm(algorithmName);
           
            //create the key pair, both private and public
            CryptographicKey keyPair = asymmetricKeyProvider.CreateKeyPair(GetKeySize(algorithmName));
        
            //convert the message to be signed and sent to a buffer
            IBuffer binaryMessage = CryptographicBuffer.ConvertStringToBinary(Private_Message_TXT.Text, BinaryStringEncoding.Utf8);

            //sign the message using the keypair, but onlyr requires the private key
            IBuffer signature = CryptographicEngine.Sign(keyPair, binaryMessage);
            this.Private_Signature_TXT.Text = CryptographicBuffer.EncodeToBase64String(signature);

            //extract the public key from the key pair
            IBuffer publicKey = keyPair.ExportPublicKey(GetCryptographicPublicKeyBlobType(algorithmName));
            Private_SignaturePublicKey_TXT.Text = CryptographicBuffer.EncodeToBase64String(publicKey);

            //extract the private key from the key pair
            IBuffer privateKey = keyPair.Export();
            Private_SignaturePrivateKey_TXT.Text = CryptographicBuffer.EncodeToBase64String(privateKey);
        }

  
        //validate the message receieved from the private key holder using the public key,
        // signature and the message itself
        async void Public_Validate_BTN_Click(object sender, RoutedEventArgs e)
        {
            // get the algorithm to use
            var algorithmName = SignAlgorithm_CB.SelectedValue.ToString();
            AsymmetricKeyAlgorithmProvider asymmetricKeyProvider =
                AsymmetricKeyAlgorithmProvider.OpenAlgorithm(algorithmName);

            //extract the signature
            IBuffer signature = CryptographicBuffer.DecodeFromBase64String(Public_Signature_TXT.Text);

            //extract the public key
            IBuffer publicKey = CryptographicBuffer.DecodeFromBase64String(Public_PublicKey_TXT.Text);

            //import the public key
            CryptographicKey keyPublic = asymmetricKeyProvider.ImportPublicKey(publicKey, GetCryptographicPublicKeyBlobType(algorithmName));

            //convert the message to a buffer
            IBuffer message = CryptographicBuffer.ConvertStringToBinary(Public_Message_TXT.Text, BinaryStringEncoding.Utf8);

            //validate the message and notify the user
            if (CryptographicEngine.VerifySignature(keyPublic, message, signature))
                await new MessageDialog("Message is valid").ShowAsync();
            else
                await new MessageDialog("Message is invalid").ShowAsync();
        }

        //send the message, signature and public key to the user.
        void Private_SignatureSend_BTN_Click(object sender, RoutedEventArgs e)
        {
            Public_Message_TXT.Text = Private_Message_TXT.Text;
            Public_Signature_TXT.Text = Private_Signature_TXT.Text;
            Public_PublicKey_TXT.Text = Private_SignaturePublicKey_TXT.Text;
        }

        //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");
            }
        }
    }
}


first lets look at the page constructor.

public MainPage()
{
    this.InitializeComponent();

    //set algorithms that can sign data
    SignAlgorithm_CB.ItemsSource = new string[] {
        AsymmetricAlgorithmNames.DsaSha1, AsymmetricAlgorithmNames.DsaSha256,
        AsymmetricAlgorithmNames.EcdsaP256Sha256, AsymmetricAlgorithmNames.EcdsaP384Sha384,
        AsymmetricAlgorithmNames.EcdsaP521Sha512, AsymmetricAlgorithmNames.RsaSignPkcs1Sha1,
        AsymmetricAlgorithmNames.RsaSignPkcs1Sha256, AsymmetricAlgorithmNames.RsaSignPkcs1Sha384,
        AsymmetricAlgorithmNames.RsaSignPkcs1Sha512, AsymmetricAlgorithmNames.RsaSignPssSha1,
        AsymmetricAlgorithmNames.RsaSignPssSha256, AsymmetricAlgorithmNames.RsaSignPssSha384,
        AsymmetricAlgorithmNames.RsaSignPssSha512 };

    //set algorithms that can encrypt data
    EncryptionAlgorithm_CB.ItemsSource = new string[]{
        AsymmetricAlgorithmNames.RsaOaepSha1, AsymmetricAlgorithmNames.RsaOaepSha256,
        AsymmetricAlgorithmNames.RsaOaepSha384, AsymmetricAlgorithmNames.RsaOaepSha512,
        AsymmetricAlgorithmNames.RsaPkcs1,
    };

    //private key owner evnets
    Sign_BTN.Click += Sign_BTN_Click;
    Private_SignatureSend_BTN.Click += Private_SignatureSend_BTN_Click;


    KeysForEncryption_BTN.Click += GeneratePublicPrivateKeysForEncryption_Click;
    Private_EncryptionSend_BTN.Click += Private_EncryptionSend_BTN_Click;
    Private_Decrypt_BTN.Click += Private_Decrypt_BTN_Click;
           
    //public key user events
    Public_Validate_BTN.Click += Public_Validate_BTN_Click;
    Public_Encrypt_BTN.Click += EncryptData_Click;
    Public_Send_BTN.Click += Public_Send_BTN_Click;

}

all it does is populates the two compbox's with their respective options and creates event handlers for all the different button.

next lets look at the sign event handler.

//Sign Data with private key
void Sign_BTN_Click(object sender, RoutedEventArgs e)
{
    //get the algorithm to use
    string algorithmName = SignAlgorithm_CB.SelectedValue.ToString();
    AsymmetricKeyAlgorithmProvider asymmetricKeyProvider =
        AsymmetricKeyAlgorithmProvider.OpenAlgorithm(algorithmName);
           
    //create the key pair, both private and public
    CryptographicKey keyPair = asymmetricKeyProvider.CreateKeyPair(GetKeySize(algorithmName));
        
    //convert the message to be signed and sent to a buffer
    IBuffer binaryMessage = CryptographicBuffer.ConvertStringToBinary(Private_Message_TXT.Text, BinaryStringEncoding.Utf8);

    //sign the message using the keypair, but only requires the private key
    IBuffer signature = CryptographicEngine.Sign(keyPair, binaryMessage);
    this.Private_Signature_TXT.Text = CryptographicBuffer.EncodeToBase64String(signature);

    //extract the public key from the key pair
    IBuffer publicKey = keyPair.ExportPublicKey(GetCryptographicPublicKeyBlobType(algorithmName));
    Private_SignaturePublicKey_TXT.Text = CryptographicBuffer.EncodeToBase64String(publicKey);

    //extract the private key from the key pair
    IBuffer privateKey = keyPair.Export();
    Private_SignaturePrivateKey_TXT.Text = CryptographicBuffer.EncodeToBase64String(privateKey);

}

this one is pretty cool, it generates the public private keys based on the the selected algorithm then uses the private key to create a signature of the message, that is basically a hash using the private key but can be verified using the public key.

Once our data is signed, we send it to the recipient where it is validated

//validate the message receieved from the private key holder using the public key,
// signature and the message itself
async void Public_Validate_BTN_Click(object sender, RoutedEventArgs e)
{
    // get the algorithm to use
    var algorithmName = SignAlgorithm_CB.SelectedValue.ToString();
    AsymmetricKeyAlgorithmProvider asymmetricKeyProvider =
        AsymmetricKeyAlgorithmProvider.OpenAlgorithm(algorithmName);

    //extract the signature
    IBuffer signature = CryptographicBuffer.DecodeFromBase64String(Public_Signature_TXT.Text);

    //extract the public key
    IBuffer publicKey = CryptographicBuffer.DecodeFromBase64String(Public_PublicKey_TXT.Text);

    //import the public key
    CryptographicKey keyPublic = asymmetricKeyProvider.ImportPublicKey(publicKey, GetCryptographicPublicKeyBlobType(algorithmName));

    //convert the message to a buffer
    IBuffer message = CryptographicBuffer.ConvertStringToBinary(Public_Message_TXT.Text, BinaryStringEncoding.Utf8);

    //validate the message and notify the user
    if (CryptographicEngine.VerifySignature(keyPublic, message, signature))
        await new MessageDialog("Message is valid").ShowAsync();
    else
        await new MessageDialog("Message is invalid").ShowAsync();

}

so  what we do here is verify the signature using the public key, the message, and the signature. this will let us now if the message came from the private key holder and in turn validating it's authenticity.

next let's take a look at the method for creating a public private key combination for decryption and sharing it with a recipient who will in turn be able to encrypt data using the public key.

// create public & private Key for encryption
void GeneratePublicPrivateKeysForEncryption_Click(object sender, RoutedEventArgs e)
{
    //get the algorithm to use
    string algorithmName = EncryptionAlgorithm_CB.SelectedValue.ToString();
    AsymmetricKeyAlgorithmProvider asymmetricKeyProvider =
        AsymmetricKeyAlgorithmProvider.OpenAlgorithm(algorithmName);

    //differnet algorithms have different min key sizes, I tried to figure it out
    CryptographicKey keyPair = asymmetricKeyProvider.CreateKeyPair(GetKeySize(algorithmName));

    //get the public key
    IBuffer publicKey = keyPair.ExportPublicKey(GetCryptographicPublicKeyBlobType(algorithmName));
    Private_EncryptionPublicKey_TXT.Text = CryptographicBuffer.EncodeToBase64String(publicKey);

    //get the private key
    IBuffer privateKey = keyPair.Export();
    Private_EncryptionPrivateKey_TXT.Text = CryptographicBuffer.EncodeToBase64String(privateKey);

}

pretty simple all it does is use the selected algorithm to generate public and private keys of which we send the public one to a recipient

once we have our private public keys we can share the public one with a recipient and then that recipient can encrypt data and pass it back to us so that we can decrypt it with our private key, so lets look at the encrypt function the recipient would use.

//use the public key by the recipient to encrypt data.
void EncryptData_Click(object sender, RoutedEventArgs e)
{
    //get algorithm to use
    string algorithmName = EncryptionAlgorithm_CB.SelectedValue.ToString();
    AsymmetricKeyAlgorithmProvider asymmetricKeyProvider =
        AsymmetricKeyAlgorithmProvider.OpenAlgorithm(algorithmName);

    //Convert the message to a buffer
    IBuffer message = CryptographicBuffer.ConvertStringToBinary(Public_Message_TXT.Text, BinaryStringEncoding.Utf8);

    //get the public key to use
    IBuffer publicKey = CryptographicBuffer.DecodeFromBase64String(Public_EncryptionPublicKey_TXT.Text);

    //get the public key to use, again did my best, might not be 100%
    CryptographicKey keyPublic =
        asymmetricKeyProvider.ImportPublicKey(publicKey, GetCryptographicPublicKeyBlobType(algorithmName));

    //encrypt the data using the public key, and set the message box to the result
    var encryptedData = CryptographicEngine.Encrypt(keyPublic, message, null);
    Public_Message_TXT.Text = CryptographicBuffer.EncodeToBase64String(encryptedData);

}

Basically all it does is encrypt our message using our asymmetric algorithm and public key, then we would send the encrypted data to the private key holder.

and here we just decrypt the message using the corresponding private key

//Decrypt
void Private_Decrypt_BTN_Click(object sender, RoutedEventArgs e)
{
    //Get the algorithm to use
    string aglorithmName = EncryptionAlgorithm_CB.SelectedValue.ToString();
    AsymmetricKeyAlgorithmProvider asymmetricKeyProvider =
        AsymmetricKeyAlgorithmProvider.OpenAlgorithm(aglorithmName);

    //get the recieved message from the recipient
    IBuffer message = CryptographicBuffer.DecodeFromBase64String(Private_Message_TXT.Text);

    //get the private key
    IBuffer privateKey = CryptographicBuffer.DecodeFromBase64String(Private_EncryptionPrivateKey_TXT.Text);
    CryptographicKey key = asymmetricKeyProvider.ImportKeyPair(privateKey);

    //Decrypt the message
    IBuffer decryptedMessage = CryptographicEngine.Decrypt(key, message, null);

    //set the message box to display the message
    Private_Message_TXT.Text = CryptographicBuffer.ConvertBinaryToString(BinaryStringEncoding.Utf8, decryptedMessage);

}

and that's it.

now I also create two helper methods for my demo app

get key size
//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;
    }
}


this method gets the minimum key size for each algorithm to work, i made it mostly using trial and error so forgive me if it's not 100%.

and on method to get the public key blob type

// 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");
    }

}

again my understanding of this is rather rudimentary so i apologize if again it's not a 100% it's the result of trial and error.