Brian
asked on
Authenticate against password hash & salt
Hello,
I have the following code below that works when authenticating against a username and password in my database. I need the ability to check against the passwordhash and the passwordsalt to authenticate a user.
I'm going to attach the code that i have for the hash and salt below.
I have the following code below that works when authenticating against a username and password in my database. I need the ability to check against the passwordhash and the passwordsalt to authenticate a user.
I'm going to attach the code that i have for the hash and salt below.
Protected Sub pssalogin_click(ByVal sender As Object, ByVal e As ImageClickEventArgs)
Session("username") = txtUsername.Text
' Create Connection to Database
Dim connectionString As String = ConfigurationManager.ConnectionStrings("PSSA").ConnectionString
Dim conn As SqlConnection = New SqlConnection(connectionString)
'declare the command
Dim comm As SqlCommand
comm = New SqlCommand("LoginData", conn)
comm.CommandType = System.Data.CommandType.StoredProcedure
'declare the parameters
comm.Parameters.Add("@username", SqlDbType.VarChar, 50)
comm.Parameters("@username").Value = txtUsername.Text
comm.Parameters.Add("@passwordhash", SqlDbType.VarChar, 128)
comm.Parameters("@passwordhash").Value = txtPassword.Text
Try
conn.Open()
Dim myreader As SqlDataReader
myreader = comm.ExecuteReader(CommandBehavior.CloseConnection)
If myreader.Read() Then
FormsAuthentication.RedirectFromLoginPage(txtUsername.Text, True)
Else
pssaerrors.Text = "your login credentials are invalid!!!"
End If
myreader.Close()
Catch
pssaerrors.Text = "the pssa database is currently offline."
Finally
conn.Close()
End Try
End Sub
HASH AND SALT CODE:
Public Function gfCreatePasswordHash(ByVal vstrPwd As String, ByVal vstrSalt As String) As String
Dim strSaltAndPwd As String = String.Concat(vstrPwd, vstrSalt)
Dim strHashedPwd As String = FormsAuthentication.HashPasswordForStoringInConfigFile(strSaltAndPwd, "SHA1")
Return strHashedPwd
End Function
Public Function gfCreateSalt(ByVal intSize As Integer) As String
' Generate a cryptographic random number using the cryptographic
' service provider
Dim rng As RNGCryptoServiceProvider = New RNGCryptoServiceProvider
Dim buff() As Byte = New Byte(intSize) {}
rng.GetBytes(buff)
' Return a Base64 string representation of the random number
Return Convert.ToBase64String(buff)
End Function
Protected Sub btnAddUser_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnAddUser.Click
If Page.IsValid Then
Dim strSalt As String
Dim conn As SqlConnection
Dim Insertcomm As SqlCommand
Dim connectionString As String = ConfigurationManager.ConnectionStrings("DemoSql").ConnectionString
conn = New SqlConnection(connectionString)
Insertcomm = New SqlCommand("SaltInsert", conn)
Insertcomm.CommandType = CommandType.StoredProcedure
Insertcomm.Parameters.Add("@name", System.Data.SqlDbType.VarChar, 50)
Insertcomm.Parameters("@name").Value = txtName.Text
Insertcomm.Parameters.Add("@email", System.Data.SqlDbType.VarChar, 100)
Insertcomm.Parameters("@email").Value = txtEmail.Text
Insertcomm.Parameters.Add("@username", System.Data.SqlDbType.VarChar, 50)
Insertcomm.Parameters("@username").Value = txtUsername.Text
strSalt = gfCreateSalt(5) 'This creates a 5-digit salt
Insertcomm.Parameters.Add("@passwordsalt", System.Data.SqlDbType.VarChar, 128)
Insertcomm.Parameters("@passwordsalt").Value = strSalt
Insertcomm.Parameters.Add("@passwordhash", System.Data.SqlDbType.VarChar, 128)
Insertcomm.Parameters("@passwordhash").Value = gfCreatePasswordHash(txtPassword.Text, strSalt)
'strSalt was created above and strUserPswd is what the user keyed in
Try
conn.Open()
Insertcomm.ExecuteNonQuery()
Catch ex As Exception
ex.Message.ToString()
Finally
conn.Close()
End Try
End If
End Sub
To verify the login do the following:
(See Function Below)
1. Read the user info from the database.
2. Take the password just keked in anad concatenate it to the Salt
3. Hash the concatenated result
4. Compare it to the encrypted password stored in the database.
The function in the code snippet was derived from one I use. It may not work as it hasn't been tested as written, but it should give you a good idea of what needs to be done.
(See Function Below)
1. Read the user info from the database.
2. Take the password just keked in anad concatenate it to the Salt
3. Hash the concatenated result
4. Compare it to the encrypted password stored in the database.
The function in the code snippet was derived from one I use. It may not work as it hasn't been tested as written, but it should give you a good idea of what needs to be done.
Forgot to attach code snippet...Here it is.
Function VerifyPassword(ByVal vstrUserName As String, ByVal vstrPassword as String) As Integer
Dim bolPasswordMatch As Boolean = False
Dim strDbPasswordHash As String
Dim strDbSalt As String
Dim ObjUserMaster as New UserMaster(vstrUserName)
'Get the user's login info from the database using your preferred method (I use a UserMaster Class)
Try
With objUserMaster
strDbPasswordHash = .WebPin
strDbSalt = .WebPinSalt
If .NbrOfAttempts > 3 Then
.AccountLocked = True
.UpdateRecord()
'They've used up all their login chances, so inform them (by returning -4) and lock their account
Return -4
End If
End With
' Now take the salt and the password entered by the user
' and concatenate them together.
Dim strPasswordAndSalt As String = String.Concat(vstrPassword, strDbSalt)
' Now hash them
Dim strHashedPasswordAndSalt As String = FormsAuthentication.HashPasswordForStoringInConfigFile(strPasswordAndSalt, "SHA1")
' Now verify them.
bolPasswordMatch = strHashedPasswordAndSalt.Equals(strDbPasswordHash)
If bolPasswordMatch = True Then
With objUserMaster
.NbrOfAttempts = 0
.UpdateRecord()
End With
Return 0
Else
With objUserMaster
.NbrOfAttempts += 1
.UpdateRecord()
End With
Return -1
End If
Catch ex As Exception
mstrDisplayMsg = ex.ToString
Finally
objUserMaster.Dispose
System.GC.Collect()
End Try
End Function
ASKER
is there any way i could have a little more help :(
this is the first time dealing with hash and salt and to be honest i don't know where to begin with the following code above.
this is the first time dealing with hash and salt and to be honest i don't know where to begin with the following code above.
ASKER
can i have help filling in the pieces from what i'm use to compared to the function that you supplied?
Protected Sub btnAuthenticate_Click(ByVa l sender As Object, ByVal e As System.EventArgs) Handles btnAuthenticate.Click
Dim connectionString As String = ConfigurationManager.Conne ctionStrin gs("DemoSq l").Connec tionString
Dim conn As SqlConnection = New SqlConnection(connectionSt ring)
Dim comm As SqlCommand
comm = New SqlCommand("PSSA_LoginData ", conn)
comm.CommandType = System.Data.CommandType.St oredProced ure
comm.Parameters.Add("@user name", SqlDbType.VarChar, 50)
comm.Parameters("@username ").Value = txtUsername.Text
comm.Parameters.Add("@pass wordhash", SqlDbType.VarChar, 128)
comm.Parameters("@password hash").Val ue = txtPassword.Text
Try
conn.Open()
Dim myreader As SqlDataReader
myreader = comm.ExecuteReader(Command Behavior.C loseConnec tion)
If myreader.Read() Then
FormsAuthentication.Redire ctFromLogi nPage(txtU sername.Te xt, True)
Else
lblError.Text = "your login credentials are invalid!!!"
End If
myreader.Close()
Catch
lblError.Text = "the pssa database is currently offline."
Finally
conn.Close()
End Try
End Sub
STORED PROCEDURE THAT I'M USING WITH CODE ABOVE:
ALTER PROCEDURE PSSA_LoginData
@username varchar(50),
@password varchar(128)
AS
SELECT [password ] FROM [PSSA_USERS] WHERE (([username ] = @username ) AND ([password ] = @password ))
Protected Sub btnAuthenticate_Click(ByVa
Dim connectionString As String = ConfigurationManager.Conne
Dim conn As SqlConnection = New SqlConnection(connectionSt
Dim comm As SqlCommand
comm = New SqlCommand("PSSA_LoginData
comm.CommandType = System.Data.CommandType.St
comm.Parameters.Add("@user
comm.Parameters("@username
comm.Parameters.Add("@pass
comm.Parameters("@password
Try
conn.Open()
Dim myreader As SqlDataReader
myreader = comm.ExecuteReader(Command
If myreader.Read() Then
FormsAuthentication.Redire
Else
lblError.Text = "your login credentials are invalid!!!"
End If
myreader.Close()
Catch
lblError.Text = "the pssa database is currently offline."
Finally
conn.Close()
End Try
End Sub
STORED PROCEDURE THAT I'M USING WITH CODE ABOVE:
ALTER PROCEDURE PSSA_LoginData
@username varchar(50),
@password varchar(128)
AS
SELECT [password ] FROM [PSSA_USERS] WHERE (([username ] = @username ) AND ([password ] = @password ))
I think you are missing one major point the point. i.e. you should store hashedPassword and Salt in the DB as well.
When you Create the user account ... you do the following:
1: Call gfCreateSalt function and get the Salt
2: Call gfCreatePasswordHash and get hashedPwd
3: Store username,hashedPwd(step 2) and Salt(step 1) in the DB.
Upon login....in your btnAuthenticate_Click:
1: Get Salt and HashedPwd from DB calling call SP PSSA_LoginData
2: Hash txtPassword.Text using Salt you get from step 1 by calling gfCreatePasswordHash .
3: Now compare HashedPwd that was returned by PSSA_LoginData and the hashedPwd you get from step 2.
Note: You will have to modify your PSSA_LoginData stored Proc to take only "username" and return Salt and HashedPwd(that you stored during User account creation).
Hope that is a better explanation ...Sorry I don't have code right now.
When you Create the user account ... you do the following:
1: Call gfCreateSalt function and get the Salt
2: Call gfCreatePasswordHash and get hashedPwd
3: Store username,hashedPwd(step 2) and Salt(step 1) in the DB.
Upon login....in your btnAuthenticate_Click:
1: Get Salt and HashedPwd from DB calling call SP PSSA_LoginData
2: Hash txtPassword.Text using Salt you get from step 1 by calling gfCreatePasswordHash .
3: Now compare HashedPwd that was returned by PSSA_LoginData and the hashedPwd you get from step 2.
Note: You will have to modify your PSSA_LoginData stored Proc to take only "username" and return Salt and HashedPwd(that you stored during User account creation).
Hope that is a better explanation ...Sorry I don't have code right now.
ASKER
Hi guru_sami,
yes hashedPassword and Salt is and has been stored in the DB.
Steps 1,2, and 3 above when creating the user account have been completed and everything works on the user creation end.
>> upon login, this is where i'm having the problems at :(
is the following SP correct that i have below
CREATE PROCEDURE PSSA_LoginData
@username varchar(50),
@passwordhash varchar(128),
@passwordsalt varchar(128)
AS
SELECT [username] FROM [EmpSalt] WHERE (([username] = @username) AND ([passwordhash] = @passwordhash))
yes hashedPassword and Salt is and has been stored in the DB.
Steps 1,2, and 3 above when creating the user account have been completed and everything works on the user creation end.
>> upon login, this is where i'm having the problems at :(
is the following SP correct that i have below
CREATE PROCEDURE PSSA_LoginData
@username varchar(50),
@passwordhash varchar(128),
@passwordsalt varchar(128)
AS
SELECT [username] FROM [EmpSalt] WHERE (([username] = @username) AND ([passwordhash] = @passwordhash))
Is the username,passwordhash and passwordsalt stored in same table?
Looks your storedProc needs some changes...
Your SP should take username as input parameter and return salt and passwordhash for that user.
The idea is you get Salt from the DB ...then Hash the password that User entered using this Salt.
So now you have hashedpwd(for what user entered) and passwordhash that was initally stored for the user when the account was created.
Now you compare that hashedpwd with the "passwordhash" that your storedProc returned.
Hope that helps.
Looks your storedProc needs some changes...
Your SP should take username as input parameter and return salt and passwordhash for that user.
The idea is you get Salt from the DB ...then Hash the password that User entered using this Salt.
So now you have hashedpwd(for what user entered) and passwordhash that was initally stored for the user when the account was created.
Now you compare that hashedpwd with the "passwordhash" that your storedProc returned.
Hope that helps.
ASKER
>> Is the username,passwordhash and passwordsalt stored in same table?
Yes, all three fields are in the same table
I think i understand how i need the SP to look, is the following SP correct now?
@username varchar(50)
AS
SELECT username, passwordhash, passwordsalt FROM EmpSalt WHERE username = @username
Yes, all three fields are in the same table
I think i understand how i need the SP to look, is the following SP correct now?
@username varchar(50)
AS
SELECT username, passwordhash, passwordsalt FROM EmpSalt WHERE username = @username
Yep thats what I am talking about....
Now follow step 2 and 3 as in my previous post.
Now follow step 2 and 3 as in my previous post.
ASKER
ok, step 1 down and 2 to go :)
I modified the btnAuthenticate Code below, can you check to see if i accomplished either Step 2 or 3? This is where things are getting crazy and above me :)
I added the Function Code below:
Public Function gfCreateSalt(ByVal intSize As Integer) As String
' Generate a cryptographic random number using the cryptographic
' service provider
Dim rng As RNGCryptoServiceProvider = New RNGCryptoServiceProvider
Dim buff() As Byte = New Byte(intSize) {}
rng.GetBytes(buff)
' Return a Base64 string representation of the random number
Return Convert.ToBase64String(buf f)
End Function
Protected Sub btnAddUser_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnAddUser.Click
If Page.IsValid Then
Dim strSalt As String
Dim conn As SqlConnection
Dim Insertcomm As SqlCommand
Dim connectionString As String = ConfigurationManager.Conne ctionStrin gs("DemoSq l").Connec tionString
conn = New SqlConnection(connectionSt ring)
Insertcomm = New SqlCommand("SaltInsert", conn)
Insertcomm.CommandType = CommandType.StoredProcedur e
Insertcomm.Parameters.Add( "@name", System.Data.SqlDbType.VarC har, 50)
Insertcomm.Parameters("@na me").Value = txtName.Text
Insertcomm.Parameters.Add( "@email", System.Data.SqlDbType.VarC har, 100)
Insertcomm.Parameters("@em ail").Valu e = txtEmail.Text
Insertcomm.Parameters.Add( "@username ", System.Data.SqlDbType.VarC har, 50)
Insertcomm.Parameters("@us ername").V alue = txtUsername.Text
strSalt = gfCreateSalt(5) 'This creates a 5-digit salt
Insertcomm.Parameters.Add( "@password salt", System.Data.SqlDbType.VarC har, 128)
Insertcomm.Parameters("@pa sswordsalt ").Value = strSalt
Insertcomm.Parameters.Add( "@password hash", System.Data.SqlDbType.VarC har, 128)
Insertcomm.Parameters("@pa sswordhash ").Value = gfCreatePasswordHash(txtPa ssword.Tex t, strSalt)
'strSalt was created above and strUserPswd is what the user keyed in
Try
conn.Open()
Insertcomm.ExecuteNonQuery ()
Catch ex As Exception
ex.Message.ToString()
Finally
conn.Close()
End Try
End If
End Sub
I modified the btnAuthenticate Code below, can you check to see if i accomplished either Step 2 or 3? This is where things are getting crazy and above me :)
I added the Function Code below:
Public Function gfCreateSalt(ByVal intSize As Integer) As String
' Generate a cryptographic random number using the cryptographic
' service provider
Dim rng As RNGCryptoServiceProvider = New RNGCryptoServiceProvider
Dim buff() As Byte = New Byte(intSize) {}
rng.GetBytes(buff)
' Return a Base64 string representation of the random number
Return Convert.ToBase64String(buf
End Function
Protected Sub btnAddUser_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnAddUser.Click
If Page.IsValid Then
Dim strSalt As String
Dim conn As SqlConnection
Dim Insertcomm As SqlCommand
Dim connectionString As String = ConfigurationManager.Conne
conn = New SqlConnection(connectionSt
Insertcomm = New SqlCommand("SaltInsert", conn)
Insertcomm.CommandType = CommandType.StoredProcedur
Insertcomm.Parameters.Add(
Insertcomm.Parameters("@na
Insertcomm.Parameters.Add(
Insertcomm.Parameters("@em
Insertcomm.Parameters.Add(
Insertcomm.Parameters("@us
strSalt = gfCreateSalt(5) 'This creates a 5-digit salt
Insertcomm.Parameters.Add(
Insertcomm.Parameters("@pa
Insertcomm.Parameters.Add(
Insertcomm.Parameters("@pa
'strSalt was created above and strUserPswd is what the user keyed in
Try
conn.Open()
Insertcomm.ExecuteNonQuery
Catch ex As Exception
ex.Message.ToString()
Finally
conn.Close()
End Try
End If
End Sub
Ok that is Step 1..creating user...
I do not see anything about Login ..
I do not see anything about Login ..
ASKER
LOL, sorry please see my btnAuthenticate Code below. Now, the strSalt is not declared because i was not sure how to declare and use it below.
Protected Sub btnAuthenticate_Click(ByVa l sender As Object, ByVal e As System.EventArgs) Handles btnAuthenticate.Click
Dim connectionString As String = ConfigurationManager.Conne ctionStrin gs("DemoSq l").Connec tionString
Dim conn As SqlConnection = New SqlConnection(connectionSt ring)
Dim comm As SqlCommand
comm = New SqlCommand("PSSA_LoginData ", conn)
comm.CommandType = System.Data.CommandType.St oredProced ure
comm.Parameters.Add("@user name", SqlDbType.VarChar, 50)
comm.Parameters("@username ").Value = txtUsername.Text
comm.Parameters.Add("@pass wordhash", SqlDbType.VarChar, 128)
comm.Parameters("@password hash").Val ue = gfCreatePasswordHash(txtPa ssword.Tex t, passwordsalt)
Try
conn.Open()
Dim myreader As SqlDataReader
myreader = comm.ExecuteReader(Command Behavior.C loseConnec tion)
If myreader.Read() Then
FormsAuthentication.Redire ctFromLogi nPage(txtU sername.Te xt, True)
Else
lblError.Text = "your login credentials are invalid!!!"
End If
myreader.Close()
Catch
lblError.Text = "the pssa database is currently offline."
Finally
conn.Close()
End Try
End Sub
Protected Sub btnAuthenticate_Click(ByVa
Dim connectionString As String = ConfigurationManager.Conne
Dim conn As SqlConnection = New SqlConnection(connectionSt
Dim comm As SqlCommand
comm = New SqlCommand("PSSA_LoginData
comm.CommandType = System.Data.CommandType.St
comm.Parameters.Add("@user
comm.Parameters("@username
comm.Parameters.Add("@pass
comm.Parameters("@password
Try
conn.Open()
Dim myreader As SqlDataReader
myreader = comm.ExecuteReader(Command
If myreader.Read() Then
FormsAuthentication.Redire
Else
lblError.Text = "your login credentials are invalid!!!"
End If
myreader.Close()
Catch
lblError.Text = "the pssa database is currently offline."
Finally
conn.Close()
End Try
End Sub
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
ok, let me know if this looks okay now. I now recieve a different error before running which is listed below.
ERROR MESSAGE:
Variable 'strSaltFromDB' is used before it has been assigned a value. A null reference exception could result at runtime.
Protected Sub btnAuthenticate_Click(ByVa l sender As Object, ByVal e As System.EventArgs) Handles btnAuthenticate.Click
Dim strSaltFromDB As String
Dim hashPwdInDB As String
Dim hashPwdEnterd As String
Dim connectionString As String = ConfigurationManager.Conne ctionStrin gs("DemoSq l").Connec tionString
Dim conn As SqlConnection = New SqlConnection(connectionSt ring)
Dim comm As SqlCommand
comm = New SqlCommand("PSSA_LoginData ", conn)
comm.CommandType = System.Data.CommandType.St oredProced ure
comm.Parameters.Add("@user name", SqlDbType.VarChar, 50)
comm.Parameters("@username ").Value = txtUsername.Text
comm.Parameters.Add("@pass wordhash", SqlDbType.VarChar, 128)
comm.Parameters("@password hash").Val ue = gfCreatePasswordHash(txtPa ssword.Tex t, strSaltFromDB)
Try
conn.Open()
Dim myreader As SqlDataReader
myreader = comm.ExecuteReader(Command Behavior.C loseConnec tion)
If myreader.Read() Then
hashPwdInDB = myreader.GetString("passwo rdhash")
strSaltFromDB = myreader.GetString("passwo rdsalt")
hashPwdEnterd = gfCreatePasswordHash(txtPa ssword.Tex t, strSaltFromDB)
If hashPwdEnterd = hashPwdInDB Then
FormsAuthentication.Redire ctFromLogi nPage(txtU sername.Te xt, True)
Else
lblError.Text = "your login credentials are invalid!!!"
End If
End If
myreader.Close()
Catch
lblError.Text = "the pssa database is currently offline."
Finally
conn.Close()
End Try
End Sub
ERROR MESSAGE:
Variable 'strSaltFromDB' is used before it has been assigned a value. A null reference exception could result at runtime.
Protected Sub btnAuthenticate_Click(ByVa
Dim strSaltFromDB As String
Dim hashPwdInDB As String
Dim hashPwdEnterd As String
Dim connectionString As String = ConfigurationManager.Conne
Dim conn As SqlConnection = New SqlConnection(connectionSt
Dim comm As SqlCommand
comm = New SqlCommand("PSSA_LoginData
comm.CommandType = System.Data.CommandType.St
comm.Parameters.Add("@user
comm.Parameters("@username
comm.Parameters.Add("@pass
comm.Parameters("@password
Try
conn.Open()
Dim myreader As SqlDataReader
myreader = comm.ExecuteReader(Command
If myreader.Read() Then
hashPwdInDB = myreader.GetString("passwo
strSaltFromDB = myreader.GetString("passwo
hashPwdEnterd = gfCreatePasswordHash(txtPa
If hashPwdEnterd = hashPwdInDB Then
FormsAuthentication.Redire
Else
lblError.Text = "your login credentials are invalid!!!"
End If
End If
myreader.Close()
Catch
lblError.Text = "the pssa database is currently offline."
Finally
conn.Close()
End Try
End Sub
Did you see my code does not have this:
comm.Parameters.Add("@pass wordhash", SqlDbType.VarChar, 128)
comm.Parameters("@password hash").Val ue = gfCreatePasswordHash(txtPa ssword.Tex t, strSaltFromDB)
there is no need to pass passwordhash to your StoreProc as it just take username as input parameter.
So remove those two lines shown above.
comm.Parameters.Add("@pass
comm.Parameters("@password
there is no need to pass passwordhash to your StoreProc as it just take username as input parameter.
So remove those two lines shown above.
Also you change this which might throw exception:
hashPwdInDB = myreader.GetString("passwo rdhash")
strSaltFromDB = myreader.GetString("passwo rdsalt")
GetString() takes int as input and not String...
So look at my code and use that first and see if it works.
I think this is the other way:
hashPwdInDB = myreader("passwordhash").T oString
strSaltFromDB = myreader("passwordsalt").T oString
hashPwdInDB = myreader.GetString("passwo
strSaltFromDB = myreader.GetString("passwo
GetString() takes int as input and not String...
So look at my code and use that first and see if it works.
I think this is the other way:
hashPwdInDB = myreader("passwordhash").T
strSaltFromDB = myreader("passwordsalt").T
Sorry my explanation was so confusing. I tend to have all my sql and vb code in classes and common code pages. That way my aspx.vb pages aren't so cluttered and can take care of just what's on the web page.
ASKER
THANK YOU VERY MUCH FOR ALL YOUR HELP!!! That worked out GREAT!!
you where right i forgot to remove the following line below and once i did that and applied your changes everything worked.
Thanks again!!
you where right i forgot to remove the following line below and once i did that and applied your changes everything worked.
Thanks again!!
1: Get Salt from DB for txtUsername.Text username
2: Hash txtPassword.Text using Salt you get from step 1.
3: Now call SP LoginData passing the username and hashedPassword from step 2.
I am not sure if thats what your were looking for.