I'm working on an semi-internal encryption process for somewhat sensitive information. Email addresses and the like. I'm working with a few other developers at some sister companies on the project, and the requirements are that everyone's encryption can talk to everyone else's. We use a global password, encrypt and decrypt information onsite, and that's about it.
My problem is that my encryption procedure, while matching theirs, is giving me variable results. I'm currently polling our SQL server for the strings to be encrypted in question, iterating through the array of results, and updating the server with the encrypted strings.
The problem is that the first string is always different from all subsequent strings, and isn't recognized as valid by the testing software we're supposed to be basing our solution off of. The second and all subsequent strings come through just fine.
Example:
test#test.com - BrPURPlWW7+VYrR5puJ/JHXoIp/MV5WR
test#test.com - BrPURPlWW79h+n4Tgot0xRmM7SdWQQsy
test#test.com - BrPURPlWW79h+n4Tgot0xRmM7SdWQQsy
I can't quite figure out what's going on, because I can encrypt and decrypt back and forth on my own machine with no issues. Any advice would be lovely.
My encryption function follows:
Private TripleDES As New DESCryptoServiceProvider
Sub New(ByVal key As String)
Dim ivHash(), keyHash() As Byte
keyHash = System.Text.Encoding.UTF8.GetBytes(key)
ReDim Preserve keyHash(7)
TripleDES.Key = keyHash
ivHash = System.Text.Encoding.UTF8.GetBytes(String.Empty)
ReDim Preserve ivHash(7)
TripleDES.IV = ivHash
End Sub
Public Function EncryptData(ByVal Plaintext As String) As String
Dim PlaintextBytes() As Byte = System.Text.Encoding.UTF8.GetBytes(Plaintext)
Dim ms As New System.IO.MemoryStream
Dim encStream As New CryptoStream(ms, TripleDES.CreateEncryptor(), System.Security.Cryptography.CryptoStreamMode.Write)
TripleDES.Mode = CipherMode.ECB
encStream.Write(PlaintextBytes, 0, PlaintextBytes.Length)
encStream.FlushFinalBlock()
Return Convert.ToBase64String(ms.ToArray)
End Function
Public Function DecryptData(ByVal EncryptedText As String) As String
Dim EncryptedBytes() As Byte = Convert.FromBase64String(EncryptedText)
Dim ms As New System.IO.MemoryStream
Dim decStream As New CryptoStream(ms, TripleDES.CreateDecryptor(), System.Security.Cryptography.CryptoStreamMode.Write)
TripleDES.Mode = CipherMode.ECB
decStream.Write(EncryptedBytes, 0, EncryptedBytes.Length)
decStream.FlushFinalBlock()
Return System.Text.Encoding.UTF8.GetString(ms.ToArray)
End Function
You are setting TripleDES.Mode = CipherMode.ECB after you have called TripleDES.CreateEncryptor(), so the first encryption is using the default value of CipherMode.CBC. Since TripleDES is reused, after the first call to EncryptData its Mode is set correctly.
Move TripleDES.Mode = CipherMode.ECB into New and it should work consistently.
Related
I'm trying to copy the encrypted contents of a text file into a memory stream and then decrypt and copy those contents into a new memory stream. When I reach the code where the copy occurs I get a Invalid Data error on debug.
This is the block of code I got:
Function DecryptFile(ByVal sInputFilename As String, ByVal sKey As String) As Byte()
Dim DES As New DESCryptoServiceProvider()
DES.Key() = ASCIIEncoding.ASCII.GetBytes(sKey)
DES.IV = ASCIIEncoding.ASCII.GetBytes(sKey)
Dim desdecrypt As ICryptoTransform = DES.CreateDecryptor()
Dim encryptedByteArray() As Byte
encryptedByteArray = File.ReadAllBytes(sInputFilename)
Dim encryptedMS As MemoryStream = New MemoryStream(encryptedByteArray)
Dim cryptostreamDecr As New CryptoStream(encryptedMS, desdecrypt, CryptoStreamMode.Read)
Dim decryptedMS As MemoryStream = New MemoryStream()
cryptostreamDecr.CopyTo(decryptedMS) 'Error occurs here
cryptostreamDecr.Close()
Return decryptedMS.ToArray()
End Function
I'm following examples I've found scattered around the web and from what I've read, this code should work...
May anyone explain to me what am I doing wrong?
Here's an example to encrypt/decrypt a string and a file using a Key without explicitly providing an Initialization Vector (so yo don't need to store and retrieve it to decrypt encrypted data).
The Encryption provider I'm using here is TripleDESCryptoServiceProvider.
If you need to use a DES provider, it's exactly the same thing, you just need to change TripleDESCryptoServiceProvider to DESCryptoServiceProvider.
But, as you can read in the Docs, better move to the AesCryptoServiceProvider, if/when possible.
The Initialization Vector (IV) is calculated based on the Key specified and it's the same Hashed value if the Key to Decrypt the data is the same as the Key used to Encrypt it.
In this case, you lose some security, but you don't need to store either the Key or the IV (if the Key is provided by a User, who's responsible for protecting the Key).
The Mode is left to its default: CipherMode.CBC.
The Padding Mode to its default: PaddingMode.PKCS7.
Encrypt and decrypt a sting to and from a Base64String:
Dim enc3Des As New TripleDesEncryptor("MyFancyKey")
Dim inputString = "Some fancy string to be encoded to a Base64 string"
Dim encodedB64 = enc3Des.EncryptStringToBase64(inputString)
Dim decoded64 = enc3Des.DecryptBase64String(encoded64)
To encrypt a file, provide the path to the Source file, then save the bytes returned by the Encryption method to a destination file:
Dim enc3Des As New TripleDesEncryptor("MyFancyKey")
Dim plainTextFilePath = [Source file Path]
Dim encryptedFilePath = [Encrypted file Path]
Dim encodedBytes = enc3Des.EncryptFile(plainTextFilePath)
File.WriteAllBytes(encryptedFilePath, encodedBytes)
You can of course decrypt the File when required, using the same Key:
Dim encryptedFilePath = [Encrypted file Path]
Dim decryptedFilePath = [Decrypted file Path]
Dim enc3Des2 As New TripleDesEncryptor("MyFancyKey")
Dim decodedBytes = enc3Des2.DecryptFile(encryptedFilePath)
File.WriteAllBytes(decryptedFilePath, decodedBytes)
The TripleDesEncryptor helper class:
Imports System.IO
Imports System.Security.Cryptography
Imports System.Text
Public NotInheritable Class TripleDesEncryptor
Private tripleDesProvider As New TripleDESCryptoServiceProvider()
Sub New(key As String)
tripleDesProvider.Key = GetKeyHash(key, tripleDesProvider.LegalKeySizes(0).MaxSize \ 8)
tripleDesProvider.IV = GetKeyHash(key, tripleDesProvider.LegalBlockSizes(0).MaxSize \ 8)
End Sub
Public Function EncryptStringToBase64(inputString As String) As String
Dim dataBytes As Byte() = Encoding.Unicode.GetBytes(inputString)
Return Convert.ToBase64String(Encrypt(dataBytes))
End Function
Public Function EncryptFile(fileName As String) As Byte()
Dim dataBytes As Byte() = File.ReadAllBytes(fileName)
Return Encrypt(dataBytes)
End Function
Private Function Encrypt(dataBytes As Byte()) As Byte()
Using ms As New MemoryStream(),
encStream As New CryptoStream(ms, tripleDesProvider.CreateEncryptor(), CryptoStreamMode.Write)
encStream.Write(dataBytes, 0, dataBytes.Length)
encStream.FlushFinalBlock()
Return ms.ToArray()
End Using
End Function
Public Function DecryptBase64String(base64String As String) As String
Dim dataBytes As Byte() = Convert.FromBase64String(base64String)
Return Encoding.Unicode.GetString(Decrypt(dataBytes))
End Function
Public Function DecryptFile(fileName As String) As Byte()
Dim dataBytes As Byte() = File.ReadAllBytes(fileName)
Return Decrypt(dataBytes)
End Function
Private Function Decrypt(encryptedData As Byte()) As Byte()
Using ms As New MemoryStream(),
decStream As New CryptoStream(ms, tripleDesProvider.CreateDecryptor(), CryptoStreamMode.Write)
decStream.Write(encryptedData, 0, encryptedData.Length)
decStream.FlushFinalBlock()
Return ms.ToArray()
End Using
End Function
Private Function GetKeyHash(key As String, length As Integer) As Byte()
Using sha1 = SHA1.Create()
Dim varHash As Byte() = New Byte(length - 1) {}
Dim keyBytes As Byte() = Encoding.Unicode.GetBytes(key)
Dim hash As Byte() = sha1.ComputeHash(keyBytes).Take(length).ToArray()
Array.Copy(hash, 0, varHash, 0, hash.Length)
hash = Nothing
keyBytes = Nothing
Return varHash
End Using
End Function
End Class
Perhaps I should have explained what I'm trying to achieve in the first place.
I have a text file that has over 1000 keywords. The vb.net application will, at some point, read these keywords from the text file to do something with them.
Now, my approach here is to not let prying eyes to edit the text file, changing the key words or even knowing which keywords are on it.
Therefor, what I did was encrypt the keywords and save the encrypted content into a new file and deleted the unencrypted file, so that this way I don't need to care about people checking the encrypted file, because it's just gibberish.
According to Jimi's explanation, posted before, I see now that in order to decrypt the file, I need the same IV I used for encrypting the previous file.
So the only way I see for this to be possible without having an unencrypted file 'lying around' is to store the IV secret key within the application's settings, correct?
I'm setting up a Login Form on Visual Basic .Net. I would like to have this database hosted over the internet, so people can connect wherever they are.
The trouble is, security. If I have a username and password in my code, I can easily be hacked, and my program will be cracked.
Is there any way to have a token that I can use instead of a password, that can only be accessed in through the program itself?
This is my code:
Dim connection As New MySqlConnection("datasource=localhost;port-3306;username;whatever;password=whatever;database=whatever")
And this is something like what I'm looking for:
Dim connection As New MySqlConnection("token=aFjiwqMF93JmHSazhH")
If so, how would I do this, and where would I get the database token and link from?
Anyone able to crack your program, will more likely have the knowledge to crack into MySQL too... I know, it's not an answer, I spent many weeks trying to secure my programs against similar, however, I then thought 'Why...?'
That being said, If you really need to keep your source code under wraps and passwords removed, how about loading the connection string from a text file somewhere?
Simple encryption see system.security.cryptography
I have just looked up my old code for encrypting strings simply, you can have a look at this
Imports System.Security.Cryptography
Imports System.Net
Public NotInheritable Class Encryptorr
Public TDS As New TripleDESCryptoServiceProvider
Private Function EncHash(ByVal key As String, ByVal length As Integer) As Byte()
Dim enc_Sha1 As New SHA1CryptoServiceProvider
Dim keyBytes() As Byte =
System.Text.Encoding.Unicode.GetBytes(key)
Dim hash() As Byte = enc_Sha1.ComputeHash(keyBytes)
ReDim Preserve hash(length - 1)
Return hash
End Function
Sub New(ByVal key As String)
TDS.Key = EncHash(key, TDS.KeySize \ 8)
TDS.IV = EncHash("", TDS.BlockSize \ 8)
End Sub
Public Function EncryptData(ByVal plaintext As String) As String
Dim Strbytes() As Byte = System.Text.Encoding.Unicode.GetBytes(plaintext)
Dim memStr As New System.IO.MemoryStream
Dim encStream As New CryptoStream(memStr, TDS.CreateEncryptor(), System.Security.Cryptography.CryptoStreamMode.Write)
encStream.Write(Strbytes, 0, Strbytes.Length)
encStream.FlushFinalBlock()
Return Convert.ToBase64String(memStr.ToArray)
End Function
Public Function DecryptData(ByVal encryptedtext As String) As String
Try
Dim enc_Bytes() As Byte = Convert.FromBase64String(encryptedtext)
Dim mem_Str As New System.IO.MemoryStream
Dim decStream As New CryptoStream(mem_Str, TDS.CreateDecryptor(), System.Security.Cryptography.CryptoStreamMode.Write)
decStream.Write(enc_Bytes, 0, enc_Bytes.Length)
decStream.FlushFinalBlock()
Return System.Text.Encoding.Unicode.GetString(mem_Str.ToArray)
Catch ex As Exception
Return "Decryption Failed"
End Try
End Function
End Class
Call with
Public Sub TestMe()
Dim encr As Encryptorr = New Encryptorr("AlovelyLong463728KeytoEncryptwith")
Dim encrytedstr As String = encr.EncryptData(textbox1.text)
Textbox2.text = encrytedstr
Dim decry As Encryptorr = New Encryptorr("AlovelyLong463728KeytoEncryptwith")
Dim decryptedtext As String = decry.DecryptData(Textbox2.text)
Textbox3.text = decryptedtext
End Sub
You can then encrypt and decrypt strings read from text files, although back to my original point. If someone can gain access to the program code, they can also work out the decryption too... :(
Still food for thought! Good luck
Update--
Just to add, you could always create the encrytped string, use that as a global variable and the decryt function to pass directly as your connection string. This means isnstead of saving the username and password in a text file, you just use Public Shared Constr as String = fhdasjifhn32437289cj (or whatever the encrypted string is) and the connection would be Dim Con as MySQLConnection = new MySQLConnection(DecryptMyStr(Constr)) with DecryptMyStr being the decrypt function
Okay, so I am attempting to create a system whereby I serialize a dictionary, then encrypt it and then can decrypt it and then restore the dictionary.
It also includes some selection statements based on a setting whereby the user sets whether to always, never or prompt for encryption.
I have been attempting to follow along with the CryptoStream Class documentation, but for some reason this isn't working. I think the encryption might be working, but the file is a lot smaller than the none encrypted .ser equivalent so I don't know. The decryption generates an "Attempting to deserialize an empty stream." error, which is pretty self explanatory, but I can't work out how to fix it.
The backup and restore works fine without encryption.
Here are the relevant subroutines (and the GIT link if it's easier) and any help would be hugely appreciated! This is for an A Level computing project, so I'm not too fussed about the actual strength of the encryption (really don't want to start faffing around with hashing AND salting), just that it works.
Encrypt Backup:
Private Sub encryptBackup()
Dim key As Byte()
Dim IV As Byte() = New Byte() {}
Using MD5 As New MD5CryptoServiceProvider
Dim tmp = System.Text.Encoding.UTF8.GetBytes(InputBox("Please insert password:", "Password Input") & "This is most definitely not an obtuse amount of salt")
key = MD5.ComputeHash(tmp)
IV = MD5.ComputeHash(key)
End Using
Using cryptoRijndael = Rijndael.Create()
Dim cryptoCryptor As ICryptoTransform = cryptoRijndael.CreateEncryptor(key, IV)
Using fStream As New FileStream(fldBackupJobs & "\Backup Files\" & Strings.Replace(Strings.Replace(Now, ":", "_"), "/", ".") & ".bin", FileMode.OpenOrCreate), cStream As New CryptoStream(fStream, cryptoCryptor, CryptoStreamMode.Write)
Dim Formatter As New BinaryFormatter
Formatter.Serialize(cStream, photoJobs)
MsgBox("Written to file")
End Using
End Using
End Sub
Decrypt Backup:
Private Sub decryptBackup(pathsStr As String)
photoJobs = Nothing
Dim key As Byte()
Dim IV As Byte() = New Byte() {}
Using MD5 As New MD5CryptoServiceProvider
Dim tmp = System.Text.Encoding.UTF8.GetBytes(InputBox("Please insert password:", "Password Input") & "This is most definitely not an obtuse amount of salt")
key = MD5.ComputeHash(tmp)
IV = MD5.ComputeHash(key)
End Using
Using cryptoRijndael = Rijndael.Create()
Dim cryptoCryptor As ICryptoTransform = cryptoRijndael.CreateEncryptor(key, IV)
pathstr = OpenFileDialog.FileName
Using fStream As New FileStream(pathstr, FileMode.Open), cStream As New CryptoStream(fStream, cryptoCryptor, CryptoStreamMode.Read)
Dim Formatter As New BinaryFormatter
photoJobs = CType(Formatter.Deserialize(cStream), Dictionary(Of String, PhotoJob))
MsgBox("Backup Restored")
End Using
End Using
End Sub
And the GIT Link: https://github.com/hughesjs/Photo-Gift-Manager
Thanks In Advance!!
The first part of the code gives me pause because (beyond GoTo) it looks like the crypto method is dependent upon the file extension. Since the user could change this via Explorer, it is very brittle. And dont let the user choose: if it is needs to be encrypted, do it; if not, don't. Certainly, the encryption method ought not be up to them (we get the big bucks to make those decisions for them).
Encrypting using a a BindingList(of Animal) which I happen to have handy:
Dim key As Byte()
Dim iv As Byte() = New Byte() {}
' see notes below
Using MD5 As New MD5CryptoServiceProvider
' UTF8 not unicode; convert password to Byte()
Dim tmp = Encoding.UTF8.GetBytes(password & "$*^!#" & password)
' hash the PW to get the crypto Key
key = MD5.ComputeHash(tmp)
' hash the Key to get the IV
iv = MD5.ComputeHash(key)
End Using
Using rijAlg = Rijndael.Create()
' Create cryptor using the Key and IV
Dim cryptor As ICryptoTransform = rijAlg.CreateEncryptor(key, IV)
' Open a filestream for the output file, wrap it with
' a CryptoStream created with the cryptor in WRITE (output) mode
Using fs As New FileStream("C:\Temp\crypto.bin", FileMode.OpenOrCreate),
cs As New CryptoStream(fs, cryptor, CryptoStreamMode.Write)
' serialize collection to CryptoStream (to disk)
Dim bf As New BinaryFormatter
bf.Serialize(cs, mcol)
End Using
End Using
To decrypt, use the same Key and IV:
mcol = Nothing
' the comments above pertain, just in reverse
Using rijAlg = Rijndael.Create()
Dim cryptor As ICryptoTransform = rijAlg.CreateDecryptor(key, iv)
Using fs As New FileStream("C:\Temp\crypto.bin", FileMode.Open),
cs As New CryptoStream(fs, cryptor, CryptoStreamMode.Read)
Dim bf As New BinaryFormatter
' Convert object to type
mcol = CType(bf.Deserialize(cs), BindingList(Of Animal))
End Using
End Using
' test:
For Each a As Animal In mcol
Console.WriteLine(a.Name)
Next
All my animals survived the trip:
Rover
Gizmo
Ziggy
The main thing appears to be that you have too many streams in use. In your decrypter you are trying to deserialize from a memstream which has nothing to do with the cryptostream that reads the file. In fact it was just created the line before. A cryptostream basically just wraps whatever "real" stream you are using.
Also, this line shows you are not using Option Strict:
photoJobs = formatter.Deserialize(memStreamSerial)
Deserialize returns an Object and photoJobs is some sort of collection IIRC from past posts. Note that my code uses CType to convert to BindingList(Of Animal).
Use Option Strict for anything more complex than 'Hello, World`. Always.
Crypto Notes / Cautions
Deriving (hashing) the IV from the password is a bad idea: these should be independent pieces of data. The IV should be unique for each piece of data (which will not be the case when a PW is reused) and unique. I added some arbitrary text to the PW so that the MD5 hash is not directly derived from teh PW, but it is still suboptimal.
Secondly, MD5 is outdated.
To create a random IV
Private Const MinSize = 7
Public Shared Function GetRandomBytes(size As Integer) As Byte()
' dont allow less than a sensible min
Dim data(If(size < MinSize, MinSize, size)) As Byte
Using rng As New RNGCryptoServiceProvider
' fill the array
rng.GetNonZeroBytes(data)
End Using
Return data
End Function
Put this in a crypto tools lib because you will use it for IV's as well as Salt for hashes. Example:
myIV = CryptoUtils.GetRandomBytes(15)
If the IV is unique each time, the trick becomes how to save it so the same values can be used in decryption. The IV need not be secret, so it can be saved to the FileStream before you pass it to the CryptoStream constructor. The Decrypt method does the reverse.
These too can be made into methods so the same process is used each time.
Finally, your questions will get a better reception if they were more concise. The error clearly indicates a crypto problem so those first 2 blocks are more or less noise.
I am trying to encrypt a zip in VB.NET to send to an android device using Air. Then once its on the device, decrypt it using the key and IV.
Here is part of my VB.NET Code:
Private Sub EncryptBytes(ByVal fileIn As String, ByVal fileOut As String, ByVal pass As String, ByVal ivString As String)
Dim crypt As New RijndaelManaged
crypt.KeySize = 256
crypt.BlockSize = 256
crypt.Padding = PaddingMode.PKCS7
crypt.Mode = CipherMode.CFB
'read byte array from file location, ie c:\temp\file.zip
Dim data As Byte() = ReadByteArray(fileIn)
Dim iv As Byte() = System.Text.Encoding.UTF8.GetBytes(ivString)
Dim key As Byte() = System.Text.Encoding.UTF8.GetBytes(pass)
Dim encryptor As ICryptoTransform = crypt.CreateEncryptor(key, iv)
Using ms As New System.IO.MemoryStream
Using cs As New CryptoStream(ms, encryptor, CryptoStreamMode.Write)
cs.Write(data, 0, data.Length)
cs.FlushFinalBlock()
End Using
'write byte array to file location, ie c:\temp\file_e.zip
WriteByteArray(fileOut, ms.ToArray)
End Using
End Sub
Two things, first I don't want to use PaddingMode.PKCS7 but when I change it to PaddingMode.None I get an error which says "Length of the data to encrypt is invalid" during decryption.
Second, I have a decryption SUB and it still works if I send it a bogus IV. Why is the IV not effecting the decryption process.
DECRYPTION
In Air I'm using the com.hurlant.crypto package I found at http://crypto.hurlant.com/docs/.
Here is my function:
public static function decryptZip(src:ByteArray, k:String, iv:String):ByteArray {
var key:ByteArray = Hex.toArray(Hex.fromString(k));
var mode:CFBMode = new CFBMode(new AESKey(key), new PKCS7(256));
mode.IV = Hex.toArray(Hex.fromString(iv));
mode.decrypt(src);
return src;
}
This is not working ... Note that I tried to write a PKCS7 class based on a Java class I found. The hurlant package I downloaded only had PKCS5. VB.NET did not provide any of the same padding classes as hurlant comes with. I wish I could using "None" but I couldn't get passed the error in VB.
I think there may also be an issue with the way I am converting a string into a byte array in VB vs Air.
Please help!
check out this sample code i am not sure if it's the solution you are looking for or not,
http://www.obviex.com/samples/Encryption.aspx
I'm having a great deal of difficulty finding a function or sub for vb (not C) that provides an easy way to convert a given string into a sha-1 (or sha512 ideally) hash.
If someone could provide a function in VB, it'd be extremely helpful.
Nearest attempt:
Function create_hash(ByVal password, ByVal salt)
Dim input As [Char]() = "string to hash".ToCharArray()
Dim secret As New SecureString()
For idx As Integer = 0 To input.Length - 1
secret.AppendChar(input(idx))
Next SecurePassword.MakeReadOnly()
Dim pBStr As IntPtr = Marshal.SecureStringToBSTR(secret)
Dim output As String = Marshal.PtrToStringBSTR(pBStr)
Marshal.FreeBSTR(pBStr)
Dim sha As SHA512 = New SHA512Managed()
Dim result As Byte() = sha.ComputeHash(Encoding.UTF8.GetBytes(output))
Return result
End Function
But this causes visual stuido to blue underline SecurePassword and Marshal at evey use. These are marked as undeclared variables, but declaring them causes other problems which I can't find a way to solve.
Take a look at the documentation for the System.Security.Cryptography.SHA512 class.
Dim data(DATA_SIZE) As Byte
Dim result() As Byte
Dim shaM As New SHA512Managed()
result = shaM.ComputeHash(data)
Like this (ignoring the salting you are doing at the top):
Function create_hash(ByVal password, ByVal salt) As Byte()
Dim sha As SHA512 = New SHA512Managed()
Dim result As Byte() = sha.ComputeHash(Encoding.UTF8.GetBytes(password & salt))
Return result
End Function