Question I get System.Byte[] when SELECT DES_DECRYPT()

maquinadehielo

New member
Joined
Nov 8, 2013
Messages
3
Location
San Jose, Costa Rica
Programming Experience
Beginner
Hello, i'm trying to decrypt a previously encrypted password from my database on visual studio 2012 (vb.net) but when i do the comparaison between my Textbox(Named TXT_Password) and the decrypted password i'm getting a value named System.Byte[] on the side of the Query, here's the code:

Public Function Return_Pass(ByVal User As String, ByVal Password As String) As Boolean

DB_Comand.Connection = DB_Conexion
DB_Comand.CommandType = CommandType.Text

If User <> "" Then
If Password <> "" Then
DB_Comand.CommandText = "SELECT DES_DECRYPT( PASSWORD ) FROM users WHERE user = '" & User & "'"
DB_DataReader = DB_Comand.ExecuteReader()
DB_DataReader.Read()
If DB_DataReader.HasRows Then
Dim Read_Password As String
Read_Password = DB_DataReader(0).ToString
DB_DataReader.Close() 'HERE'S THE PROBLEM
If Read_Password = Password Then

'Read_Password is getting System.Byte[] Instead of the decrypted password, the Query is 'Okay because when i execute it on MySQL it returns me the decrypted password...

Return_Pass = True
Else
MessageBox.Show("Wrong Password", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
Return_Pass = False
End If
Else
MessageBox.Show("Wrong User", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
Return_Pass = False
End If
Else
MessageBox.Show("Empty Password", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
Return_Pass = False
End If
Else
MessageBox.Show("Empty User", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
Return_Pass = False
End If

Return Return_Pass
End Function

Sorry for bad english...
 
Passwords are not stored as strings because a good encryption key doesn't contain only letters and numbers. You just need to convert your byte array to a string. .ToString doesn't work, because it tries to convert the object itself (a System.Byte[]) to a string representation.

Change this:
Read_Password = DB_DataReader(0).ToString


To this:
 Read_Password = System.Text.Encoding.ASCII.GetString(DB_DataReader)
 
Last edited:
In addition, this is a really bad way to verify passwords. First, instead of storing the password itself, even encrypted, you should create a MD5 hash of the password at creation and store the hash, encrypted or not. Encrypted is better, but less necessary when you hash the password. When a user enters a password, you should hash the password he entered, fetch/decrypt the hash from the database, and compare the hashes. This way you don't need to store the password anywhere, just a fingerprint of it. If you want to go all the way, when the user creates an account, use the password they enter, hash it, and use the MD5 hash as the encryption key (instead of as the encrypted data). Generate a random strong key (128-bits+) as the user's key, hash it, encrypt it with the hash of the password as key, and store only the encrypted cipher text in the database. When a user logs on, he enters a password, you hash it, use the hash as the key to decrypt the user's strong key hash, and compare that final hash to verify the login. This way every password in the database is encrypted with a different key, and the complexity makes it that much harder to hack logins. You can also go a step further and compound that with a private strong key verification server side. Assuming you use DotFuscator CE on your assembly, and you have enough code to be obfuscated in the hash reassembly, it will be very hard for anyone to get the private key hash back, and even if they did they would still have to properly decrypt the user key.

It's also a bad idea to give feedback that the username is bad. If the user/password combination is bad, just issue a generic login failed, otherwise an attacker could relatively easily brute force a list of valid users, and then they already have half of what they need. Since most users have a tendency to choose really poor passwords, a dictionary attack might give out a surprisingly good amount of valid logins after only a few hours.

You should also enforce a throttle and possibly a lockout on the login attempts. For example, if someone enters a bad user/password 5 times, block their IP address (assuming this is a web app) for 5 minutes. Or 5 bad passwords in a row for the same user, block the user until he does a password reset.

Also, this is a place where it is VERY important to use a Command object with parameters, and to validate the user name entered. What happens if someone enters " ' OR user LIKE '% " as the username and intercepts the SQL response with a debugger or otherwise? The attacker now has a decrypted list of all the user passwords in your database, and only needs to match them to user names (which as we established above is quite easy, as he already has a list of all the users; all the complexity of your encryption is reduced to a simple 1:1 match loop and your whole system is compromised, in mere minutes...).

If the password is for actual access to the database, it's all much much easier to use the SQL Server integrated security.
 
Last edited:
Ok, I'm New at This Security Stuff, but you helped me a lot..! :)

I'm going to use(and investigate) the MD5 Hash...

And i've already done the lockout at 5 attempts..!
5 Minutes locked if i insert a wrong password 5 Times

Right Here:

MessageBox.Show("Wrong Password", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
Attempts = Attempts + 1
Return_Pass = False

The password isn't to access to the database, it is to access a form depending of the kind of user, for example:

An Administrator user will Enter directly to an Administrator panel
A Quality_Control user will Enter to a Form With a Record
Stuff like that

By the way: Thank you for the advice! The second comment teached me a lot!
 
There's one thing i didn't understand:
What do you mean with: "this is a place where it is VERY important to use a Command object with parameters", ?Could you give me an example?

Also, are you telling me to change this:

If User <> "" Then
If Password <> "" Then

To this or something like this:

If User <> "" OR User.Length <= 1 Then
If Password <> "" OR Password.Length <=1 Then

???
 
There's one thing i didn't understand:
What do you mean with: "this is a place where it is VERY important to use a Command object with parameters", ?Could you give me an example?


Follow the Blog link in my signature and check out my post on Parameters In ADO.NET.
 
Also, are you telling me to change this:

If User <> "" Then
If Password <> "" Then

To this or something like this:

If User <> "" OR User.Length <= 1 Then
If Password <> "" OR Password.Length <=1 Then

???

You should validate the username entered and limit its alphabet. For example, you could reject any spaces or special characters except a few (@, _, .,).
 
Back
Top