I have an application in vb.net using mysql as database. The application has a login form. There is also a registration form that can enter a new password in the archive using bcrypt.net, as shown at this site:
This is my code for registering a new user (public procedure Clean is for clean the forms):
Private Sub btSignUp_Click(sender As Object, e As EventArgs) Handles btSignUp.Click
dim hash as string
hash = HashPassword(txConfirmPass.Text)
If (txPass.Text <> txConfirmPass.Text) Then
MessageBox.Show("Passwords don't matches")
Else
Dim sql As String = "INSERT INTO fusion_login(name,user,password) VALUES (@name,@user,@pass)"
Using myconnection As MySqlConnection = Connection.getInstance.getConnection()
Using mycommand As New MySqlCommand()
With mycommand
.CommandText = sql
.CommandType = CommandType.Text
.Connection = myconnection
.Parameters.Add("@name", MySqlDbType.VarChar).Value = txName.Text
.Parameters.Add("@user", MySqlDbType.VarChar).Value = txUser.Text
.Parameters.Add("@pass", MySqlDbType.VarChar).Value = hash
End With
Try
myconnection.Open()
mycommand.ExecuteNonQuery()
If (MessageBox.Show("Do you insert a new user again?", "Register", MessageBoxButtons.YesNo, MessageBoxIcon.Question) = Windows.Forms.DialogResult.Yes) Then
Clean(Me)
Else
Me.Hide()
Login.Show()
End If
Catch ex As MySqlException
MessageBox.Show("Error: " + ex.ToString)
Finally
myconnection.Close()
End Try
End Using
End Using
End If
End Sub
This code works!
Now I'm trying to implement the code that authenticates a user created using the above procedure, but I can't get it to work. Here is what I have so far:
Private Sub btLogin_Click(sender As Object, e As EventArgs) Handles btLogin.Click
Dim hash as String
hash = HashPassword(txPass.text)
Dim sql As String = "SELECT user,password FROM fusion_login WHERE user = @user AND password = @pass"
Using myconnection As MySqlConnection = Connection.getInstance.getConnection()
Using mycommand As New MySqlCommand()
With mycommand
.CommandText = sql
.CommandType = CommandType.Text
.Connection = myconnection
.Parameters.Add("@user", MySqlDbType.VarChar).Value = txUser.Text
.Parameters.Add("@pass", MySqlDbType.VarChar).Value = hash
End With
Try
myconnection.Open()
myreader = mycommand.ExecuteReader
If myreader.HasRows = 0 Then
Me.Hide()
FusionPrincipal.Show()
Else
MessageBox.Show("Error", "Login", MessageBoxButtons.OK, MessageBoxIcon.Warning)
txUser.Focus()
End If
Catch ex As MySqlException
MessageBox.Show("Error: " + ex.ToString)
Finally
myconnection.Close()
myreader.Close()
End Try
End Using
End Using
I'm not sure whether I'm inserting the password wrong, or comparing the username/password wrong at login. What could be the problem here?
The problem is this line:
In this code,
myreader.HasRowsis Boolean, but0is an integer. To make this comparison, the0value must first be implicitly cast to a boolean. Casting0to a boolean results inFalse. This means the code will only enter thatIfblock if the data reader did not return any results. I believe this is the opposite of what you want to happen. Instead, just do this:or, even better:
While I'm here, it's not enough to just hash the password. You also need to set a salt value for each user, and combine that with the password before creating the hash. When you authenticate the user, you much retrieve the salt for that username, combine it with the supplied password, and then compare it to the result. The password comparison code should look more like this:
Of course, you'll also need to update the
HashPassword()function to allow the additional parameter, your insert code to generate the salt in the first place, and your database table to have space to store the value.One more thing... even this isn't totally correct. If you really want to do it right, you need to ensure that the plaintext password is only ever held in memory with a SecureString object.