Imports System.IO Imports System.Security.Cryptography Imports System.Text.Encoding Imports DigitalData.Modules.Logging ''' ''' https://stackoverflow.com/questions/10168240/encrypting-decrypting-a-string-in-c-sharp ''' Public Class Encryption ' This constant is used to determine the keysize of the encryption algorithm in bits. ' We divide this by 8 within the code below to get the equivalent number of bytes. Private Const KEY_SIZE As Integer = 256 ' This constant determines the number of iterations for the password bytes generation function. Private Const DERIVATION_ITERATIONS As Integer = 1000 Private Const BLOCK_SIZE As Integer = 256 Private _paddingMode As PaddingMode = PaddingMode.Zeros Private _cipherMode As CipherMode = CipherMode.CBC Private ReadOnly _password As String Private _logger As Logger Public Sub New(LogConfig As LogConfig, Password As String) _logger = LogConfig.GetLogger() If IsNothing(Password) Then Throw New ArgumentNullException("Password") End If _password = Password End Sub Public Async Function EncryptAsync(PlainTextBytes As Byte()) As Task(Of Byte()) Return Await Task.Run(Function() As Byte() Return Encrypt(PlainTextBytes) End Function) End Function Public Function Encrypt(PlainText As String) As String Try Dim oBytes As Byte() = UTF8.GetBytes(PlainText) Dim oEncrypted As Byte() = Encrypt(oBytes) Return UTF8.GetString(oEncrypted) Catch ex As Exception _logger.Error(ex) Throw ex End Try End Function Public Function Encrypt(PlainTextBytes As Byte()) As Byte() Try ' Salt and IV is randomly generated each time, but is preprended to encrypted cipher text ' so that the same Salt and IV values can be used when decrypting. Dim oSaltStringBytes = Generate256BitsOfRandomEntropy() Dim oIvStringBytes = Generate256BitsOfRandomEntropy() Using oPassword = New Rfc2898DeriveBytes(_password, oSaltStringBytes, DERIVATION_ITERATIONS) Dim oKeyBytes = oPassword.GetBytes(KEY_SIZE / 8) Using oSymmetricKey = New RijndaelManaged() oSymmetricKey.BlockSize = BLOCK_SIZE oSymmetricKey.Mode = _cipherMode oSymmetricKey.Padding = _paddingMode Using oEncryptor = oSymmetricKey.CreateEncryptor(oKeyBytes, oIvStringBytes) Using oMemoryStream = New MemoryStream() Using oCryptoStream = New CryptoStream(oMemoryStream, oEncryptor, CryptoStreamMode.Write) oCryptoStream.Write(PlainTextBytes, 0, PlainTextBytes.Length) oCryptoStream.FlushFinalBlock() ' Create the final bytes as a concatenation of the random salt bytes, the random iv bytes and the cipher bytes. Dim oCipherTextBytes = oSaltStringBytes oCipherTextBytes = oCipherTextBytes.Concat(oIvStringBytes).ToArray() oCipherTextBytes = oCipherTextBytes.Concat(oMemoryStream.ToArray()).ToArray() oMemoryStream.Close() oCryptoStream.Close() Return oCipherTextBytes End Using End Using End Using End Using End Using Catch ex As Exception _logger.Error(ex) Throw ex End Try End Function Public Async Function DecryptAsync(CipherTextBytesWithSaltAndIv As Byte()) As Task(Of Byte()) Return Await Task.Run(Function() As Byte() Return Decrypt(CipherTextBytesWithSaltAndIv) End Function) End Function Public Function Decrypt(CipherTextPlainWithSaltAndIv As String) As String Try Dim oBytes As Byte() = UTF8.GetBytes(CipherTextPlainWithSaltAndIv) Dim oDecrypted As Byte() = Decrypt(oBytes) Return UTF8.GetString(oDecrypted) Catch ex As Exception _logger.Error(ex) Throw ex End Try End Function Public Function Decrypt(CipherTextBytesWithSaltAndIv As Byte()) As Byte() Try ' Get the complete stream of bytes that represent: ' [32 bytes of Salt] + [32 bytes of IV] + [n bytes of CipherText] ' Get the saltbytes by extracting the first 32 bytes from the supplied cipherText bytes. Dim oSaltStringBytes = CipherTextBytesWithSaltAndIv.Take(KEY_SIZE / 8).ToArray() ' Get the IV bytes by extracting the next 32 bytes from the supplied cipherText bytes. Dim oIvStringBytes = CipherTextBytesWithSaltAndIv.Skip(KEY_SIZE / 8).Take(KEY_SIZE / 8).ToArray() ' Get the actual cipher text bytes by removing the first 64 bytes from the cipherText string. Dim oCipherTextBytes = CipherTextBytesWithSaltAndIv.Skip((KEY_SIZE / 8) * 2).Take(CipherTextBytesWithSaltAndIv.Length - ((KEY_SIZE / 8) * 2)).ToArray() Using oPassword = New Rfc2898DeriveBytes(_password, oSaltStringBytes, DERIVATION_ITERATIONS) Dim oKeyBytes = oPassword.GetBytes(KEY_SIZE / 8) Using oSymmetricKey = New RijndaelManaged() oSymmetricKey.BlockSize = BLOCK_SIZE oSymmetricKey.Mode = _cipherMode oSymmetricKey.Padding = _paddingMode Using oDecryptor = oSymmetricKey.CreateDecryptor(oKeyBytes, oIvStringBytes) Using oMemoryStream = New MemoryStream(oCipherTextBytes) Using oCryptoStream = New CryptoStream(oMemoryStream, oDecryptor, CryptoStreamMode.Read) Dim oPlainTextBytes = New Byte(oCipherTextBytes.Length - 1) {} Dim oDecryptedByteCount = oCryptoStream.Read(oPlainTextBytes, 0, oPlainTextBytes.Length) oMemoryStream.Close() oCryptoStream.Close() Return oPlainTextBytes End Using End Using End Using End Using End Using Catch ex As Exception _logger.Error(ex) Throw ex End Try End Function Private Shared Function Generate256BitsOfRandomEntropy() As Byte() Dim oRandomBytes = New Byte(31) {} ' 32 Bytes will give us 256 bits. Using oRNGCsp = New RNGCryptoServiceProvider() ' Fill the array with cryptographically secure random bytes. oRNGCsp.GetBytes(oRandomBytes) End Using Return oRandomBytes End Function End Class