28.3. Applying Cryptography

So far, you have seen the principles of cryptography and how they are achieved through the use of hashing, encryption, and signing algorithms. In this section, you'll walk through a sample that applies these algorithms and illustrates how the .NET Framework can be used to securely pass data between two parties.

28.3.1. Creating Asymmetric Key Pairs

Begin with a new Visual Basic Windows Forms application and divide the form into two vertical columns. You can do this using a TableLayoutPanel with docked Panel controls. Into each of the two vertical columns place a button, btnCreateAsymmetricKey1 and btnCreateAsymmetricKey2 respectively, which will be used to generate the asymmetric keys. Also add two textboxes to each column, which will be used to display the private and public keys. The textboxes in the left column should be named TxtPublicKey1 and TxtPrivateKey1, and the textboxes in the right column should be named TxtPublicKey2 and TxtPrivateKey2. The result should be something similar to Figure 28-1. For reference, add a name label to each of the vertical panels.

Figure 28.1. Figure 28-1

Double-clicking each of the buttons will create event handlers into which you need to add code to generate an asymmetric key pair. In this case use the RSACryptoServiceProvider class, which is an implementation of the RSA algorithm. Creating a new instance of this class automatically generates a new key pair that can be exported via the ToXmlString method, as shown in the following code. This method takes a Boolean parameter that determines whether the private key information should be exported:

Imports System
Imports System.IO
Imports System.Security.Cryptography
Imports System.Net.Sockets
Imports System.Text

Public Class Form1
#Region "Step 1 - Creating Asymmetric Keys"
    Private Sub BtnCreateAsymmetricKey1_Click(ByVal sender As System.Object, _
                                             ByVal e As System.EventArgs) _
                                             Handles btnCreateAsymmetricKey1.Click
        CreateAsymmetricKey(Me.TxtPrivateKey1, Me.TxtPublicKey1)
    End Sub

    Private Sub BtnCreateAsymmetricKey2_Click(ByVal sender As System.Object, _
                                              ByVal e As System.EventArgs) _
                                              Handles btnCreateAsymmetricKey2.Click
        CreateAsymmetricKey(Me.TxtPrivateKey2, Me.TxtPublicKey2)
    End Sub

    Private Sub CreateAsymmetricKey(ByVal txtPrivate As TextBox, _
                                    ByVal txtPublic As TextBox)
        Dim RSA As New RSACryptoServiceProvider()
        txtPrivate.Text = RSA.ToXmlString(True)
        txtPublic.Text = RSA.ToXmlString(False)
    End Sub
#End Region
End Class

In the preceding example you can see that a number of namespaces have been imported, which makes it much easier to work with the cryptography classes. When this application is run and the buttons are invoked, two new key pairs are created and displayed in the appropriate textboxes. Examining the text from one of the private key textboxes, you can see that it is an XML block broken up into a number of sections that represent the different components required by the RSA algorithm:

<RSAKeyValue>

    <Modulus>uUWTj5Ub+x+LN5xE63y8zLQf4JXNU0WAADsShaBK+jF/cDGd
    Xc9VFcuDvRIX0oKLdUslpH
    cRcFh3VLi7djU+oRKAZUfs+75mMCCnoybPEHWWCsRHoIk8s4BAZuJ7KCQ
    O+Jb9DxYQbeeCI9bYm2yYWtHRvq7PJha5sbMvxkLOI1M=</Modulus>
     <Exponent>AQAB</Exponent>

    <P>79tcNXbc02ZVowH9qOuv3vrj6F009BSLdfSBtX6y8sosIAsLUfVqH+
    UEPKQbZO/gLDAyf3U65Qkj 5QZE03CFeQ==</P>

<Q>xb28iwn6BPHqCaDPhxtea6p/OnYNTtJ8f/3Y/zHEl0Mc0aBjtY3Ci1
    ggnkUGvM4j/+BRTBwUOPKG NP9DUE94Kw==</Q>

    <DP>0IkkYytjlLyNSfsKIho/vxrcmYKn7moKUlRxjW2JgcM6l+ViQzCew
    vonM93uH1TazzBcRyqSON0 4gv9vSXGz6Q==</DP>

    <DQ>j3bFICsw1f2dyzZ82o0kyAB/Ji8YIKPd6A6ILT4yX3w1oHE5ZjNff
    jGGGM4DwV/eBnr9ALcuhNK QREsez1mY2Q==</DQ>

    <InverseQ>hS1ygkBiiYWyE7DjFgO1eOFhFQxOaL1vPoqlAxw0YepbSQA
    DBGmP8IB1ygzJjP3dmMEvQ Zhwsbs6MAfPIe/gYQ==</InverseQ>

    <D>r4WC7pxNDfQsaFrb0F00YJqlOJezFhjZ014jhgT+A1mxahEXDTDHYw
    aToCPr/bs/c7flyZIkK1Mk
    elcpAiwfT8ssNgx2H97zhcHkcvCBO8yCgc0r+cSYlRNKLa+UPwsoXcc5N
    XGT0SHQG+GCVl7bywrtrWRryaWOIpSwuHmjZYE=</D>
</RSAKeyValue>

In actual fact, this block shows both the public- and private-key components, which you can see if you look at the corresponding public-key textbox:

<RSAKeyValue>

    <Modulus>uUWTj5Ub+x+LN5xE63y8zLQf4JXNU0WAADsShaBK+jF/cDGd
    Xc9VFcuDvRIX0oKLdUslpH
    cRcFh3VLi7djU+oRKAZUfs+75mMCCnoybPEHWWCsRHoIk8s4BAZuJ7KCQ
    O+Jb9DxYQbeeCI9bYm2yYWtHRvq7PJha5sbMvxkLOI1M=</Modulus>
     <Exponent>AQAB</Exponent>
</RSAKeyValue>

As you will learn later, this public key can be distributed so that it can be used to encrypt and sign information. Of course, the private key should be kept in a secure location.

28.3.2. Creating a Symmetric Key

In the example, only David is going to create a symmetric key (that will be shared with Julie after being encrypted and signed using a combination of their asymmetric keys). A more secure approach would be for both parties to generate symmetric keys and for them to be shared and combined into a single key.

Before adding code to generate the symmetric key, expand the dialog so the key can be displayed. Figure 28-2 shows two textboxes, named TxtSymmetricIV and TxtSymmetricKey, that will contain the IV (Initialization Vector) and the Key. The data being encrypted is broken down into a series of individually encrypted input blocks. If two adjacent blocks are identical, the process of encrypting a stream of data using a simple key would result in two identical blocks in the encrypted output. Combined with the knowledge of the input data, this can be used to recover the key. A solution to this problem is to use the previous input block as a seed for the encryption of the current block. Of course, at the beginning of the data there is no previous block, and it is here that the initialization vector is used. This vector can be as important as the key itself, so it should also be kept secure.

Figure 28.2. Figure 28-2

Add a new button named BtnCreateSymmetric to the form, and label it Create Symmetric Key. In the event handler for this button, you need to create an instance of the TripleDESCryptoServiceProvider class, which is the default implementation of the TripleDES algorithm. Create a new instance of the class and then call the GenerateIV and GenerateKey methods to randomly generate a new key and initialization vector. Because these are both byte arrays, convert them to a base-64 string so they can be displayed in the textbox:

Public Class Form1
#Region "Step 1 - Creating Asymmetric Keys"
'...
#End Region
#Region "Step 2 - Creating Symmetric Keys"
    Private Sub BtnCreateSymmetric_Click(ByVal sender As System.Object, _
                                         ByVal e As System.EventArgs) _
                                                   Handles BtnCreateSymmetric.Click
        Dim TDES As New TripleDESCryptoServiceProvider()
        TDES.GenerateIV()
        TDES.GenerateKey()
        Me.TxtSymmetricIV.Text = Convert.ToBase64String(TDES.IV)
        Me.TxtSymmetricKey.Text = Convert.ToBase64String(TDES.Key)
    End Sub
#End Region
End Class

28.3.3. Encrypting and Signing the Key

Now that we have the symmetric key, we need to encrypt it using Julie's public key and generate a hash value that can be signed using David's private key. The encrypted key and signature can then be transmitted securely to Julie. Three TextBox controls named TxtEncryptedKey, TxtHashValue, and TxtSymmetricSignature, as well as a button named BtnEncryptKey, have been added to the dialog in Figure 28-3, so you can create and display the encrypted key, the hash value, and the signature.

Figure 28.3. Figure 28-3

As we discussed earlier, this step involves three actions: encrypting the symmetric key, generating a hash value, and generating a signature. Encrypting the symmetric key is again done using an instance of the RSACryptoServiceProvider class, which is initialized using Julie's public key. It is then used to encrypt both the initialization vector and the key into appropriate byte arrays. Because you want to create only a single hash and signature, these two byte arrays are combined into a single array, which is prepended with the lengths of the two arrays. This is done so the arrays can be separated before being decrypted.

The single-byte array created as part of encrypting the symmetric key is used to generate the hash value with the SHA1Managed algorithm. This hash value is then signed again using an instance of the RSACryptoServiceProvider, initialized this time with David's private key. An instance of the RSAPKCS1SignatureFormatter class is also required to generate the signature from the hash value:

Public Class Form1
#Region "Step 1 & 2"
'...
#End Region
#Region "Step 3 - Encrypt, Hash and Sign Symmetric Key"
    Private Sub BtnEncryptKey_Click(ByVal sender As System.Object, _
                                    ByVal e As System.EventArgs) _


Handles BtnEncryptKey.Click
        EncryptSymmetricKey()
        Me.TxtHashValue.Text = Convert.ToBase64String _
(CreateSymmetricKeyHash(Me.TxtEncryptedKey.Text))
SignSymmetricKeyHash()
End Sub

Private Sub EncryptSymmetricKey()
Dim iv, key As Byte()
Dim encryptedIV, encryptedkey As Byte()

        iv = Convert.FromBase64String(Me.TxtSymmetricIV.Text)
        key = Convert.FromBase64String(Me.TxtSymmetricKey.Text)

        'Load the RSACryptoServiceProvider class using
        'only the public key
        Dim RSA As New RSACryptoServiceProvider()
        RSA.FromXmlString(Me.TxtPublicKey1.Text)

        'Encrypt the Symmetric Key
        encryptedIV = RSA.Encrypt(iv, False)
        encryptedkey = RSA.Encrypt(key, False)

        'Create a single byte array containing both the IV and Key
        'so that we only need to encrypt and distribute a single value
        Dim keyOutput(2 * 4 - 1 + encryptedIV.Length + encryptedkey.Length) As Byte

Array.Copy(BitConverter.GetBytes(encryptedIV.Length), 0,keyOutput, 0, 4)

Array.Copy(BitConverter.GetBytes(encryptedkey.Length), 0, keyOutput, 4, 4)
        Array.Copy(encryptedIV, 0, keyOutput, 8, encryptedIV.Length)
        Array.Copy(encryptedkey, 0, keyOutput, 8 + encryptedIV.Length, _

encryptedkey.Length)

        Me.TxtEncryptedKey.Text = Convert.ToBase64String(keyOutput)
        End Sub

        Private Function CreateSymmetricKeyHash(ByVal inputString As String) As
Byte()

        'Retrieve the bytes for this string
        Dim UE As New UnicodeEncoding()
        Dim MessageBytes As Byte() = UE.GetBytes(inputString)

        'Use the SHA1Managed provider to hash the input string
        Dim SHhash As New SHA1Managed()
        Return SHhash.ComputeHash(MessageBytes)
    End Function

    Private Sub SignSymmetricKeyHash()
        'The value to hold the signed value.
        Dim SignedHashValue() As Byte

        'Load the RSACryptoServiceProvider using the
        'private key as we will be signing
        Dim RSA As New RSACryptoServiceProvider
        RSA.FromXmlString(Me.TxtPrivateKey2.Text)

'Create the signature formatter and generate the signature
        Dim RSAFormatter As New RSAPKCS1SignatureFormatter(RSA)
        RSAFormatter.SetHashAlgorithm("SHA1")
        SignedHashValue = RSAFormatter.CreateSignature _

(Convert.FromBase64String(Me.TxtHashValue.Text))

        Me.TxtSymmetricSignature.Text = Convert.ToBase64String(SignedHashValue)
    End Sub
#End Region
End Class

At this stage, the encrypted key and signature are ready to be transferred from David to Julie.

28.3.4. Verifying Key and Signature

To simulate the encrypted key and signature being transferred, create additional controls on Julie's side of the dialog. Shown in Figure 28-4, the "Retrieve Key" button will retrieve the key, signature, and public key from David and populate the appropriate textboxes. In a real application, information could potentially be e-mailed, exported as a file and copied, or sent via a socket connection to a remote application. Essentially, it doesn't matter how the key and signature are transferred, as they are encrypted to prevent any unauthorized person from accessing the information.

Because the key and signature might have been sent via an unsecured channel, it is necessary to validate that the sender is who this person claims to be. You can do this by validating the signature using the public key from the sender. Figure 28-4 shows what the form will look like if the "Validate Key" button is pressed and the signature received is successfully validated against the public key from the sender.

Figure 28.4. Figure 28-4

The code to validate the received signature is very similar to that used to create the signature. A hash value is created from the encrypted key. Using the same algorithm that was used to create the received signature, a new signature is created. Finally, the two signatures are compared via the VerifySignature method, and the background color is adjusted accordingly. To build this part of the form, add a button named BtnRetrieveKeyInfo and a button named BtnValidate. Next, add three new TextBox controls named TxtRetrievedKey, TxtRetrievedSignature, and TxtRetrievedPublicKey. Finally, add the following button-event handlers to the code:

Public Class Form1
#Region "Step 1 - 3"
'...
#End Region
#Region "Step 4 - Transfer and Validate Key Information"

    Private Sub BtnRetrieveKeyInfo_Click(ByVal sender As System.Object, _
                                         ByVal e As System.EventArgs) _
                                                   Handles BtnRetrieveKeyInfo.Click
        Me.TxtRetrievedKey.Text = Me.TxtEncryptedKey.Text
        Me.TxtRetrievedSignature.Text = Me.TxtSymmetricSignature.Text
        Me.TxtRetrievedPublicKey.Text = Me.TxtPublicKey2.Text
    End Sub

    Private Sub BtnValidate_Click(ByVal sender As System.Object, _
                                  ByVal e As System.EventArgs) _

Handles BtnValidate.Click
        'Create the expected hash from the retrieved public key
        Dim HashValue, SignedHashValue As Byte()
        HashValue = CreateSymmetricKeyHash(Me.TxtRetrievedKey.Text)

        'Generate the expected signature
        Dim RSA As New RSACryptoServiceProvider()
        RSA.FromXmlString(Me.TxtRetrievedPublicKey.Text)
        Dim RSADeformatter As New RSAPKCS1SignatureDeformatter(RSA)
        RSADeformatter.SetHashAlgorithm("SHA1")
        SignedHashValue = Convert.FromBase64String(Me.TxtRetrievedSignature.Text)

        'Validate against received signature
        If RSADeformatter.VerifySignature(HashValue, SignedHashValue) Then
            Me.TxtRetrievedKey.BackColor = Color.Green
        Else
            Me.TxtRetrievedKey.BackColor = Color.Red
        End If
    End Sub
#End Region
End Class

Now that you have received and validated the encrypted key, the last remaining step before you can use the symmetric key to exchange data is to decrypt the key.

28.3.5. Decrypting the Symmetric Key

Decrypting the symmetric key will return the initialization vector and the key required to use the symmetric key. In Figure 28-5, the dialog has been updated to include the appropriate textboxes to display the decrypted values. These should match the initialization vector and key that were originally created by David. The button has been named BtnDecryptKeyInformation, and the two textboxes TxtDecryptedIV and TxtDecryptedKey.

Figure 28.5. Figure 28-5

To decrypt the symmetric key, reverse the process for encrypting the symmetric key. Start by breaking up the single encrypted byte array into the iv and key byte arrays. To decrypt the key, you again need to create an instance of the RSACryptoServiceProvider class using Julie's private key. Because the data was encrypted using Julie's public key, the corresponding private key needs to be used to decrypt the data. This instance is then used to decrypt the initialization vector and the key:

Public Class Form1
#Region "Step 1 - 4"
'...
#End Region
#Region "Step 5 - Decrypt Symmetric key"
    Private Sub BtnDecryptKeyInformation_Click(ByVal sender As System.Object, _
                                               ByVal e As System.EventArgs) _
                                             Handles BtnDecryptKeyInformation.Click
        Dim iv, key As Byte()

        'Retrieve the iv and key arrays from the single array
        Dim keyOutput As Byte() = Convert.FromBase64String(Me.TxtRetrievedKey.Text)
        ReDim iv(BitConverter.ToInt32(keyOutput, 0) - 1)
        ReDim key(BitConverter.ToInt32(keyOutput, 4) - 1)
        Array.Copy(keyOutput, 8, iv, 0, iv.Length)
        Array.Copy(keyOutput, 8 + iv.Length, key, 0, key.Length)

        'Load the RSACryptoServiceProvider class using Julie's private key

Dim RSA As New RSACryptoServiceProvider()
        RSA.FromXmlString(Me.TxtPrivateKey1.Text)

        'Decrypt the symmetric key and IV.
        Me.TxtDecryptedIV.Text = Convert.ToBase64String(RSA.Decrypt(iv, False))
        Me.TxtDecryptedKey.Text = Convert.ToBase64String(RSA.Decrypt(key, False))
    End Sub
#End Region
End Class

28.3.6. Sending a Message

Both Julie and David have access to the symmetric key, which they can now use to transmit secure data. In Figure 28-6, the dialog has been updated one last time to include three new textboxes and a send button on each side of the form. Text can be entered in the first textbox. Pressing the send button will encrypt the text and place the encrypted data in the second textbox. The third textbox will be used to receive information from the other party. The button on the left is called btnSendAToB, and the associated textboxes are TxtMessageA, TxtMessageAEncrypted, and TxtReceivedMessageFromB. The corresponding button on the right is called BtnSendBToA, and the associated textboxes are TxtMessageB, TxtMessageBEncrypted, and TxtReceivedMessageFromA.

Figure 28.6. Figure 28-6

In the following code, the symmetric key is used to encrypt the text entered in the first textbox, placing the encrypted output in the second textbox. You will notice from the code that the process by which the data is encrypted is different from the process you used with an asymmetric algorithm. Asymmetric algorithms are useful for encrypting short amounts of data, which means that they are typically used for keys and pass phrases. On the other hand, symmetric algorithms can chain data together, enabling large amounts of data to be encrypted. For this reason, they are suitable for a streaming model. During encryption or decryption, the input data can come from any stream, be it a file, the network, or an in-memory stream. Here is the code:

Public Class Form1
#Region "Step 1 - 5"
'...
#End Region
#Region "Step 6 - Sending a Message"
    Private Sub btnSendAToB_Click(ByVal sender As System.Object, _
                                  ByVal e As System.EventArgs) _

Handles btnSendAToB.Click
        Me.TxtMessageAEncrypted.Text = EncryptData(Me.TxtMessageA.Text, _

        Me.TxtDecryptedIV.Text, _

        Me.TxtDecryptedKey.Text)
    End Sub
    Private Sub BtnSendBToA_Click(ByVal sender As System.Object, _
                                  ByVal e As System.EventArgs) _

Handles BtnSendBToA.Click
        Me.TxtMessageBEncrypted.Text = EncryptData(Me.TxtMessageB.Text, _

        Me.TxtSymmetricIV.Text, _

        Me.TxtSymmetricKey.Text)
    End Sub

    Private Function EncryptData(ByVal data As String, ByVal iv As String, _
                                                     ByVal key As String) As String
        Dim KeyBytes As Byte() = Convert.FromBase64String(key)
        Dim IVBytes As Byte() = Convert.FromBase64String(iv)

        'Create the output stream
        Dim strm As New IO.MemoryStream

        'Create the TripleDES class to do the encryption
        Dim Triple As New TripleDESCryptoServiceProvider()

        'Create a CryptoStream with the output stream and encryption algorithm
        Dim CryptStream As New CryptoStream(strm, _

Triple.CreateEncryptor(KeyBytes, IVBytes), _

CryptoStreamMode.Write)

        'Write the text to be encrypted
        Dim SWriter As New StreamWriter(CryptStream)
        SWriter.WriteLine(data)
        SWriter.Close()

        Return Convert.ToBase64String(strm.ToArray)
    End Function
#End Region
End Class

To encrypt the text message to be sent, create another instance of the TripleDESCryptoServiceProvider, which is the same provider you used to create the symmetric key. This, combined with the memory output stream, is used to create the CryptoStream. A StreamWriter is used to provide an interface for writing the data to the stream. The content of the memory stream is the encrypted data.

28.3.7. Receiving a Message

The final stage in this application is for the encrypted data to be transmitted and decrypted. To wire this up, trap the TextChanged event for the encrypted data textboxes. When this event is triggered, the encrypted data will be copied to the receiving side and decrypted, as shown in Figure 28-7. This simulates the information being sent over any unsecured channel.

Figure 28.7. Figure 28-7

Decryption of the encrypted data happens the same way as encryption. An instance of the TripleDESCryptoServiceProvider is used in conjunction with the memory stream, based on the encrypted data, to create the CryptoStream. Via a StreamReader, the decrypted data can be read from the stream:

Public Class Form1
#Region "Step 1 - 6"
'...
#End Region
#Region "Step 7 - Receiving a Message"
    Private Sub TxtMessageAEncrypted_TextChanged(ByVal sender As Object, _
                                                 ByVal e As System.EventArgs) _
                                           Handles TxtMessageAEncrypted.TextChanged
        Me.TxtReceivedMessageFromA.Text = DecryptData( _

        Me.TxtMessageAEncrypted.Text, _

        Me.TxtSymmetricIV.Text, _

        Me.TxtSymmetricKey.Text)
    End Sub

    Private Sub TxtMessageBEncrypted_TextChanged(ByVal sender As Object, _
                                                 ByVal e As System.EventArgs) _
                                           Handles TxtMessageBEncrypted.TextChanged
        Me.TxtReceivedMessageFromB.Text = DecryptData( _

        Me.TxtMessageBEncrypted.Text, _

        Me.TxtDecryptedIV.Text, _

        Me.TxtDecryptedKey.Text)
    End Sub

    Private Function DecryptData(ByVal data As String, ByVal iv As String, _
                                                     ByVal key As String) As String
        Dim KeyBytes As Byte() = Convert.FromBase64String(key)
        Dim IVBytes As Byte() = Convert.FromBase64String(iv)

        'Create the input stream from the encrypted data
        Dim strm As New IO.MemoryStream(Convert.FromBase64String(data))

        'Create the TripleDES class to do the decryption
        Dim Triple As New TripleDESCryptoServiceProvider()

        'Create a CryptoStream with the input stream and decryption algorithm
        Dim CryptStream As New CryptoStream(strm, _

Triple.CreateDecryptor(KeyBytes, IVBytes), _

CryptoStreamMode.Read)

       'Read the stream.
        Dim SReader As New StreamReader(CryptStream)
        Return SReader.ReadToEnd
    End Function
#End Region
End Class

As demonstrated in this example, you can use asymmetric keys to authenticate the communicating parties and securely exchange a symmetric key. This ensures non-repudiation, as only the authenticated parties have access to the key, and the information is securely encrypted to achieve confidentiality and data integrity. Using a combination of algorithms, you have protected your data and achieved the goals of cryptography.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.220.237.24