Symmetric encryption algorithms use one key for encrypting and decrypting data. You can create a utility class that performs the encryption and decryption of sensitive data:
Imports System
Imports System.IO
Imports System.Text
Imports System.Security.Cryptography
Public NotInheritable Class SymmetricEncryptionUtility
Private Sub New()
End Sub
Private Shared _ProtectKey As Boolean
Private Shared _AlgorithmName As String
‘ You can use this property to specify the name of the algorithm (DES, TripleDES, Rijndael and RC2 )
Public Shared Property AlgorithmName() As String
Get
Return _AlgorithmName
End Get
Set(value As String)
_AlgorithmName = value
End Set
End Property
‘ You can use this property to specify whether the key should be protected through the DPAPI.
Public Shared Property ProtectKey() As Boolean
Get
Return _ProtectKey
End Get
Set(value As Boolean)
_ProtectKey = value
End Set
End Property
Public Shared Sub GenerateKey(TargetFile As String)
End Sub
Public Shared Sub ReadKey(Algorithm As SymmetricAlgorithm, KeyFile As String)
End Sub
Public Shared Function EncryptData(Data As String, KeyFile As String) As Byte()
End Function
Public Shared Function DecryptData(Data As Byte(), KeyFile As String) As String
End Function
End Class
Because the class is a utility class with static members only, you can make it a static class. To use this class, you must:
1. Set the algorithm name.
2. Generate a key if none exists.
3. Call the EncryptData and DecryptData methods, which internally call the ReadKey method for initializing the algorithm.
You can generate encryption keys through the algorithm classes and the GenerateKey() method looks like this:
Public Shared Sub GenerateKey(TargetFile As String)
‘ Create the algorithm
Dim Algorithm As SymmetricAlgorithm = SymmetricAlgorithm.Create(AlgorithmName)
Algorithm.GenerateKey()
‘ Get the key
Dim Key As Byte() = Algorithm.Key
If ProtectKey Then
‘ Use DPAPI to encrypt key
Key = ProtectedData.Protect(Key, Nothing, DataProtectionScope.LocalMachine)
End If
‘ Store the key in a file called key.config
Using fs As New FileStream(targetFile, FileMode.Create)
fs.Write(Key, 0, Key.Length)
End Using
End Sub
The ReadKey method reads the key from the file created by the GenerateKey method, as follows:
Public Shared Sub ReadKey(Algorithm As SymmetricAlgorithm, KeyFile As String)
Dim Key As Byte()
Using Fs As New FileStream(KeyFile, FileMode.Open)
Key = New Byte(Fs.Length – 1) {}
Fs.Read(Key, 0, CInt(Fs.Length))
End Using
If ProtectKey Then
Algorithm.Key = ProtectedData.Unprotect(Key, Nothing, DataProtectionScope.LocalMachine)
Else
Algorithm.Key = Key
End If
End Sub
You can use EncryptData method to encrypt a string to a byte array:
Public Shared Function EncryptData(Data As String, KeyFile As String) As Byte()
‘ Convert string data to byte array, because all the encryption functions of the algorithms
‘ require byte arrays as input parameters, by using Encoding class of System.Text namespace
Dim ClearData As Byte() = System.Text.Encoding.UTF8.GetBytes(Data)
‘ Create the algorithm according to the AlgorithmName property of the class.
‘ This value can be one of the names RC2, Rijndael, DES, or TripleDES.
‘ The factory method of the SymmetricAlgorithm creates the appropriate instance, while you can register
‘ additional cryptography classes through the <cryptographySettings> section in the machine.config file.
Dim Algorithm As SymmetricAlgorithm = SymmetricAlgorithm.Create(AlgorithmName)
ReadKey(Algorithm, KeyFile)
‘ Encrypt information. In this case you use memory stream as the target of your encryption operation
Dim Target As New MemoryStream()
‘ Generate a random initialization vector (IV) to use for the algorithm
Algorithm.GenerateIV()
Target.Write(Algorithm.IV, 0, Algorithm.IV.Length)
‘ Encrypt actual data
Dim Cs As New CryptoStream(Target, Algorithm.CreateEncryptor(), CryptoStreamMode.Write)
Cs.Write(ClearData, 0, ClearData.Length)
Cs.FlushFinalBlock()
‘ Return the encrypted stream of data as a byte array
Return Target.ToArray()
End Function
Important note:
In the code above GenerateIV method is used. If your application exchanges the same information multiple times between a client and a server, simple encryption will always result in the same encrypted representation of the information. This makes brute-force attacks easier. To add some sort of random information, symmetric algorithms support IV. These IVs are not only added to the encrypted stream of bytes themselves but are also used as input for encrypting the first block of data. When you are using the CryptoStream for encrypting information, you should call the FlushFinalBlock method to make sure that the last block of encrypted data is written appropriately to the target. You have to add the IV itself to the encrypted set of bytes because you need the information later to be able to decrypt the encrypted content entirely.
You can use DecryptData method to decrypt a byte array to a string:
Public Shared Function DecryptData(Data As Byte(), KeyFile As String) As String
‘ Create the algorithm
Dim Algorithm As SymmetricAlgorithm = SymmetricAlgorithm.Create(AlgorithmName)
ReadKey(Algorithm, KeyFile)
‘ Decrypt information
Dim Target As New MemoryStream()
‘ Read IV and initialize the algorithm with it
Dim ReadPos As Integer = 0
Dim IV As Byte() = New Byte(Algorithm.IV.Length – 1) {}
Array.Copy(Data, IV, IV.Length)
Algorithm.IV = IV
ReadPos += Algorithm.IV.Length
Dim Cs As New CryptoStream(Target, Algorithm.CreateDecryptor(), CryptoStreamMode.Write)
Cs.Write(Data, ReadPos, Data.Length – ReadPos)
Cs.FlushFinalBlock()
‘ Get the bytes from the memory stream and convert them to text
Return Encoding.UTF8.GetString(Target.ToArray())
End Function