''Cryptography wrapper classes
''Programmed by Keith Ratliff
'' (c) 2003 Keith Ratliff
''Uses code from the RSA library
'' - additional copyrights may need including with your application
''You may use these classes, or modifications of them royalty-free under the
'' following terms:
'' 1) You must state somewhere within your program that you are using
'' encryption routines supplied by Keith Ratliff
'' application and Web site of that application
'' 3) You may not sell these routines in a non-compiled code
'' 4) If your program is a DLL, the parent program must comply with term 1
'' 5) This copyright and notice must remain intact.
'to use this function, do something like this:
'Dim objCP As CryptoPass
'objCP = CreateHash(txtPassword.Text)
'MsgBox(DecryptHash(objCP))
'The objCP will contain a .Hash and .Salt
'You need both to decrypt, so if you are storing the encrypted
'values, store both
'Constants:
Const KeyLen = 31 '0-based key length
Const HKeyLen = 15 'half that size (also 0-based)
'Create Salt Function
' Salt is a generic term for random bits.
Private Function CreateSalt(ByVal size As Integer) As String
' Create a cryptographically generated random number using the
' cryptographic service provider
Dim rng As New System.Security.Cryptography.RNGCryptoServiceProvider()
' Create a buffer to hold this information
Dim buff(size) As Byte
' Fill the buffer with salt
rng.GetBytes(buff)
' Convert to a string for returning.
' Due to null-handling, we will not use this again
Return Convert.ToBase64String(buff)
End Function
'Create Key Function
' Uses the input key to create a cryptographic key in a byte array
Private Function CreateKey(ByVal Key() As Byte) As Byte()
'Create our object that will generate the key, based on the application name and
' supplied key
Dim objPDB As New System.Security.Cryptography.PasswordDeriveBytes(Application.ProductName, Key)
'Send our key back as a byte array
Return objPDB.GetBytes(KeyLen + 1)
End Function
'Create Salt Function
'Same as other function, except that it creates salt based on the
'KeySize constant and returns as a byte array.
Private Function CreateSalt() As Byte()
Dim abytSalt(KeyLen) As Byte
Dim rng As System.Security.Cryptography.RandomNumberGenerator = System.Security.Cryptography.RandomNumberGenerator.Create()
rng.GetBytes(abytSalt)
Return abytSalt
End Function
'Create Hash function
'Takes the inputted text and makes a hash and salt value from it
' In these functions, the salt is used to determine the key (randomly)
' To decrypt, the salt has to be preserved which is the primary purpose
' of the CryptoPass class.
Private Function CreateHash(ByVal sToEncrypt As String) As CryptoPass
Dim abytKey(KeyLen) As Byte
Dim PwdAndSalt As String ' Will store our password, appended with salt
Dim objSalt() As Byte = CreateSalt() ' Get a byte array of salt
PwdAndSalt = sToEncrypt 'Put our string in the PwdAndSalt string
PwdAndSalt += Chr(0) 'Place a null-terminator in the string manually
Dim tmpString As String 'For use with the BtoS function
BtoS(objSalt, tmpString) 'Convert the Salt Byte array to a string
PwdAndSalt += tmpString 'Add the salt to the end of the PwdAndSalt string
Dim abytEnc(255) As Byte 'Byte array for the encrypted data
Dim tmpByte(255) As Byte 'Byte array for the buffer
' Create a buffer to allow the cryptography provider to do its thing
Dim objBuffer As New System.IO.MemoryStream(tmpByte, 0, tmpByte.Length, True, True)
' Change our PwdAndSalt array to a byte array (for use in the cryptography provider)
StoB(PwdAndSalt, tmpByte)
' Create a Symmetric Algorithm Provider (Key Keeper)
Dim objSymm As System.Security.Cryptography.SymmetricAlgorithm = System.Security.Cryptography.SymmetricAlgorithm.Create("Rijndael")
' Create the key based on the salt
abytKey = CreateKey(objSalt)
objSymm.Key = abytKey
' Save the salt for returning from the function since we are about to truncate it
CreateHash = New CryptoPass()
CreateHash.Salt = objSalt
' And truncate to the shorter length for the IV
ReDim Preserve objSalt(HKeyLen)
' And assign to the IV
objSymm.IV = objSalt
' Create the stream object and give it our SymmetricAlgorithm so that it creates
' a hash we can decrypt later
Dim objCrypto As New System.Security.Cryptography.CryptoStream(objBuffer, objSymm.CreateEncryptor(), Security.Cryptography.CryptoStreamMode.Write)
' Have it do it's thing and output to the buffer
objCrypto.Write(tmpByte, 0, tmpByte.Length)
' Tell it to expand to the rest of the buffer using padding
objCrypto.FlushFinalBlock()
' Create a variable to keep the hash
Dim hashedPwd As String
' Reset the buffer pointer
objBuffer.Seek(0, IO.SeekOrigin.Begin)
' Retrieve the buffer as a byte array to the abytEnc byte array
abytEnc = objBuffer.GetBuffer()
' Convert the byte array to a string
BtoS(abytEnc, hashedPwd)
' Store in the object
CreateHash.Hash = hashedPwd
' Close the crypto provider. We cannot close it before now since we needed the
' buffer and closing the provider also closes the buffer.
objCrypto.Close()
End Function
'Decrypt Function.
' Expects the hash and the salt used to create the hash
' Uses the CryptoPass class for this
Private Function DecryptPasswordHash(ByVal objCP As CryptoPass) As String
' Recreate our Symmetric Algorithm using the settings from the encryption routine
Dim objSymm As System.Security.Cryptography.SymmetricAlgorithm = System.Security.Cryptography.SymmetricAlgorithm.Create("Rijndael")
Dim abytKey(KeyLen) As Byte
abytKey = CreateKey(objCP.Salt)
objSymm.Key = abytKey
Dim objSalt() As Byte = objCP.Salt
ReDim Preserve objSalt(HKeyLen)
objSymm.IV = objSalt
' Create a byte array so that we can pass the hash in to the buffer
Dim tmpByte() As Byte
' Fill the byte array with the contents of the Hash from the CP object
StoB(objCP.Hash, tmpByte)
' And now, create that buffer
Dim objBuffer As New System.IO.MemoryStream(tmpByte, 0, tmpByte.Length, True, True)
' Create a decryptor using our Symmetric Alorithm
Dim csDecrypted As New System.Security.Cryptography.CryptoStream(objBuffer, objSymm.CreateDecryptor(), System.Security.Cryptography.CryptoStreamMode.Read)
' Create a stream reader buffer to read from the csDecrypted, the decrypted value
Dim objBuffer2 As New System.IO.StreamReader(csDecrypted)
' Create a string to hold the decrypted value and read it
Dim tmpString As String
tmpString = objBuffer2.ReadToEnd()
' We dont need the decrytor any more, or the buffer, so close them
' Remember that closing the cryptostream also closes the buffer
csDecrypted.Close()
tmpString = tmpString.Substring(0, tmpString.IndexOf(Chr(0)))
'our original string had a termination character.
'Once this is decrypted, attempting to use it results in expected behaviour, since it still has a null
'terminator, but since the btos function converts all of the byte stream (not stopping at the first instance
'of null) it will have a wrong .length size. This fixes that.
Return tmpString
End Function
'Converts a string to a byte array
Private Function StoB(ByVal inString As String, ByRef outBytes() As Byte)
ReDim outBytes(inString.Length)
Dim i As Integer
For i = 0 To inString.Length - 1
outBytes(i) = Asc(inString.Substring(i, 1))
Next
End Function
'converts a byte array to a string. Does not stop at the first null character
Private Function BtoS(ByVal inBytes() As Byte, ByRef outString As String)
outString = ""
Dim i As Integer
For i = 0 To inBytes.Length - 1
outString += Chr(inBytes(i))
Next
End Function
'CryptoPass class. For keeping the hash with the salt
Private Class CryptoPass
Private _Hash As String
Private _Salt As Byte()
Public Property Hash() As String
Get
Return _Hash
End Get
Set(ByVal Value As String)
_Hash = Value
End Set
End Property
Public Property Salt() As Byte()
Get
Return _Salt
End Get
Set(ByVal Value As Byte())
_Salt = Value
End Set
End Property
End Class