jj: Database version 0.0.3
This commit is contained in:
105
Filesystem/Encryption.vb
Normal file
105
Filesystem/Encryption.vb
Normal file
@@ -0,0 +1,105 @@
|
||||
Imports System.IO
|
||||
Imports System.Security.Cryptography
|
||||
|
||||
''' <summary>
|
||||
''' https://stackoverflow.com/questions/10168240/encrypting-decrypting-a-string-in-c-sharp
|
||||
''' </summary>
|
||||
Friend 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 Keysize As Integer = 256
|
||||
' This constant determines the number of iterations for the password bytes generation function.
|
||||
Private Const DerivationIterations As Integer = 1000
|
||||
Private ReadOnly password As String
|
||||
|
||||
Public Sub New(password As String)
|
||||
If IsNothing(password) Then
|
||||
Throw New ArgumentNullException("password")
|
||||
End If
|
||||
|
||||
Me.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(plainTextBytes As Byte()) As Byte()
|
||||
' 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 saltStringBytes = Generate256BitsOfRandomEntropy()
|
||||
Dim ivStringBytes = Generate256BitsOfRandomEntropy()
|
||||
Using password = New Rfc2898DeriveBytes(Me.password, saltStringBytes, DerivationIterations)
|
||||
Dim keyBytes = password.GetBytes(Keysize / 8)
|
||||
Using symmetricKey = New RijndaelManaged()
|
||||
symmetricKey.BlockSize = 256
|
||||
symmetricKey.Mode = CipherMode.CBC
|
||||
symmetricKey.Padding = PaddingMode.PKCS7
|
||||
Using encryptor = symmetricKey.CreateEncryptor(keyBytes, ivStringBytes)
|
||||
Using memoryStream = New MemoryStream()
|
||||
Using cryptoStream = New CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write)
|
||||
cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length)
|
||||
cryptoStream.FlushFinalBlock()
|
||||
' Create the final bytes as a concatenation of the random salt bytes, the random iv bytes and the cipher bytes.
|
||||
Dim cipherTextBytes = saltStringBytes
|
||||
cipherTextBytes = cipherTextBytes.Concat(ivStringBytes).ToArray()
|
||||
cipherTextBytes = cipherTextBytes.Concat(memoryStream.ToArray()).ToArray()
|
||||
memoryStream.Close()
|
||||
cryptoStream.Close()
|
||||
Return cipherTextBytes
|
||||
End Using
|
||||
End Using
|
||||
End Using
|
||||
End Using
|
||||
End Using
|
||||
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(cipherTextBytesWithSaltAndIv As Byte()) As Byte()
|
||||
' 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 saltStringBytes = cipherTextBytesWithSaltAndIv.Take(Keysize / 8).ToArray()
|
||||
' Get the IV bytes by extracting the next 32 bytes from the supplied cipherText bytes.
|
||||
Dim ivStringBytes = cipherTextBytesWithSaltAndIv.Skip(Keysize / 8).Take(Keysize / 8).ToArray()
|
||||
' Get the actual cipher text bytes by removing the first 64 bytes from the cipherText string.
|
||||
Dim cipherTextBytes = cipherTextBytesWithSaltAndIv.Skip((Keysize / 8) * 2).Take(cipherTextBytesWithSaltAndIv.Length - ((Keysize / 8) * 2)).ToArray()
|
||||
|
||||
Using password = New Rfc2898DeriveBytes(Me.password, saltStringBytes, DerivationIterations)
|
||||
Dim keyBytes = password.GetBytes(Keysize / 8)
|
||||
Using symmetricKey = New RijndaelManaged()
|
||||
symmetricKey.BlockSize = 256
|
||||
symmetricKey.Mode = CipherMode.CBC
|
||||
symmetricKey.Padding = PaddingMode.PKCS7
|
||||
Using decryptor = symmetricKey.CreateDecryptor(keyBytes, ivStringBytes)
|
||||
Using memoryStream = New MemoryStream(cipherTextBytes)
|
||||
Using cryptoStream = New CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read)
|
||||
Dim plainTextBytes = New Byte(cipherTextBytes.Length - 1) {}
|
||||
Dim decryptedByteCount = cryptoStream.Read(plainTextBytes, 0, plainTextBytes.Length)
|
||||
memoryStream.Close()
|
||||
cryptoStream.Close()
|
||||
Return plainTextBytes
|
||||
End Using
|
||||
End Using
|
||||
End Using
|
||||
End Using
|
||||
End Using
|
||||
End Function
|
||||
|
||||
Private Shared Function Generate256BitsOfRandomEntropy() As Byte()
|
||||
Dim randomBytes = New Byte(31) {}
|
||||
' 32 Bytes will give us 256 bits.
|
||||
Using rngCsp = New RNGCryptoServiceProvider()
|
||||
' Fill the array with cryptographically secure random bytes.
|
||||
rngCsp.GetBytes(randomBytes)
|
||||
End Using
|
||||
Return randomBytes
|
||||
End Function
|
||||
End Class
|
||||
Reference in New Issue
Block a user