The major difference between symmetric and asymmetric algorithms is key management. Symmetric algorithms have one key, and asymmetric algorithms have two keys: public key for encrypting data and private key for decrypting data. The public key can be available to everyone who wants to encrypt data, the private key should be available only to those decrypting information.

You don’t need to include a way to select the algorithm in asymmetric encryption utility class, because the .NET Framework ships with only one asymmetric algorithm for real data encryption – RSA:

 

Public NotInheritable Class AsymmetricEncryptionUtility

Private Sub New()

End Sub

Public Shared Function GenerateKey(TargetFile As String) As String

End Function

Private Shared Sub ReadKey(Algorithm As RSACryptoServiceProvider, KeyFile As String)

End Sub

Public Shared Function EncryptData(Data As String, PublicKey As String) As Byte()

End Function

Public Shared Function DecryptData(Data As Byte(), KeyFile As String) As String

End Function

End Class

 

The GenerateKey method creates an instance of the RSA algorithm for generating the key. It stores only the private key in the file secured through the DPAPI and returns the public key representation as an XML string using the ToXmlString() method of the algorithm. The private key is usually kept as a secret by the application, while the public key is shared with others to be able to encrypt information that then is decrypted by the application using its secret private key:

 

Public Shared Function GenerateKey(TargetFile As String) As String

Dim Algorithm As New RSACryptoServiceProvider()

 

‘ Save the private key

Dim CompleteKey As String = Algorithm.ToXmlString(True)

Dim KeyBytes As Byte() = Encoding.UTF8.GetBytes(CompleteKey)

KeyBytes = ProtectedData.Protect(KeyBytes, Nothing, DataProtectionScope.LocalMachine)

 

Using fs As New FileStream(TargetFile, FileMode.Create)

fs.Write(KeyBytes, 0, KeyBytes.Length)

End Using

 

‘ Return the public key

Return Algorithm.ToXmlString(False)

End Function

 

The caller of the function needs to store the public key somewhere, because this is necessary for encrypting information. You can retrieve the key as an XML representation through a method called ToXmlString(). The parameter specifies whether private key information is included (true) or not (false). As a result, the GenerateKey function first calls the ToXmlString() function with the true parameter to store the complete key information in the file and then calls it with the false parameter to include the public key only. Subsequently, the ReadKey() method just reads the key from the file and then initializes the passed algorithm instance through FromXml(), the opposite of the ToXmlString() method:

 

Private Shared Sub ReadKey(Algorithm As RSACryptoServiceProvider, KeyFile As String)

 

Dim KeyBytes As Byte()

Using Fs As New FileStream(KeyFile, FileMode.Open)

KeyBytes = New Byte(Fs.Length – 1) {}

Fs.Read(KeyBytes, 0, CInt(Fs.Length))

End Using

 

KeyBytes = ProtectedData.Unprotect(KeyBytes, Nothing, DataProtectionScope.LocalMachine)

Algorithm.FromXmlString(Encoding.UTF8.GetString(KeyBytes))

End Sub

 

The EncryptData() function requires the caller to pass in the XML string representation of the public key returned by the GenerateKey() method, because the private key is not required for encryption. Encryption and decryption with RSA takes place as follows:

 

Public Shared Function EncryptData(Data As String, PublicKey As String) As Byte()

‘ Create the algorithm based on the public key

Dim Algorithm As New RSACryptoServiceProvider()

 

Algorithm.FromXmlString(PublicKey)

‘ Now encrypt the data

Return Algorithm.Encrypt(Encoding.UTF8.GetBytes(Data), True)

End Function

 

Public Shared Function DecryptData(Data As Byte(), KeyFile As String) As String

Dim Algorithm As New RSACryptoServiceProvider()

ReadKey(Algorithm, KeyFile)

 

Dim ClearData As Byte() = Algorithm.Decrypt(Data, True)

Return Convert.ToString(Encoding.UTF8.GetString(ClearData))

End Function