Reputation: 43
I have big trouble in verifying the hash password from the database with the ordinary one coming from the login page. How to validate a user by comparing this two passwords.Here is my code for registration page:
protected void Button1_Click(object sender, EventArgs e)
{
SHA384CryptoServiceProvider sh = new SHA384CryptoServiceProvider();
byte[] plainbytes = Encoding.ASCII.GetBytes(TextBox2.Text);
var sha = sh.ComputeHash(plainbytes);
byte[] hashbytes = sh.Hash;
SqlConnection con = new SqlConnection(constr);
SqlCommand cmd = new SqlCommand("RegisterUser",con);
cmd.CommandType = CommandType.StoredProcedure;
SqlParameter param = null;
param = cmd.Parameters.Add("@username",SqlDbType.VarChar,10);
param.Value = TextBox1.Text;
param = cmd.Parameters.Add("@password", SqlDbType.VarChar, 20);
param.Value = BitConverter.ToString(hashbytes);
try
{
con.Open();
cmd.ExecuteNonQuery();
Label4.Text = "Successfully added account!!!";
}
catch (Exception ex)
{
throw new Exception("Exception adding account"+ex.Message);
}
finally
{
con.Close();
}
}
How to compare this password with the one coming from login page... Help me out guys...
Code for HASH with SALT:-
private static string CreateSalt(int size)
{
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
byte[] buff = new byte[size];
rng.GetBytes(buff);
return Convert.ToBase64String(buff);
}
private static string CreatePasswordHash(string pwd, string salt)
{
string saltAndPwd = String.Concat(pwd, salt);
string hashedPwd =
FormsAuthentication.HashPasswordForStoringInConfigFile(saltAndPwd, "SHA1");
hashedPwd = String.Concat(hashedPwd, salt);
return hashedPwd;
}
protected void btnregister_Click(object sender, EventArgs e)
{
int saltSize = 5;
string salt = CreateSalt(saltSize);
string passwordHash = CreatePasswordHash(txtPassword.Text, salt);
try
{
StoreAccountDetails(txtUserName.Text, passwordHash);
}
catch (Exception ex)
{
lblMessage.Text = ex.Message;
}
}
private void StoreAccountDetails( string userName,string passwordHash )
{
SqlConnection conn = new SqlConnection(constr);
SqlCommand cmd = new SqlCommand("INSERT INTO Users VALUES(@userName, @passwordHash)", conn);
SqlParameter sqlParam = null;
sqlParam = cmd.Parameters.Add("@userName", SqlDbType.VarChar,20);
sqlParam.Value = userName;
sqlParam = cmd.Parameters.Add("@passwordHash ", SqlDbType.VarChar,50);
sqlParam.Value = passwordHash;
try
{
conn.Open();
cmd.ExecuteNonQuery();
lblMessage.Text = "User Added Successfully!!!";
}
catch( Exception ex )
{
throw new Exception("Exception adding account. " + ex.Message);
}
finally
{
conn.Close();
}
}
private bool VerifyPassword(string suppliedUserName,string suppliedPassword )
{
bool passwordMatch=false;
SqlConnection conn = new SqlConnection(constr);
SqlCommand cmd = new SqlCommand( "SELECT PasswordHash FROM Users WHERE UserName = @userName", conn );
SqlParameter sqlParam = cmd.Parameters.Add("@userName",SqlDbType.VarChar,20);
sqlParam.Value = suppliedUserName;
try
{
conn.Open();
SqlDataReader reader = cmd.ExecuteReader();
reader.Read();
string dbPasswordHash = reader.GetString(0);
int saltSize = 5;
string salt = CreateSalt(saltSize);
reader.Close();
string hashedPasswordAndSalt =CreatePasswordHash(suppliedPassword, salt);
passwordMatch = hashedPasswordAndSalt.Equals(dbPasswordHash);
}
catch (Exception ex)
{
throw new Exception("Execption verifying password. " +ex.Message);
}
finally
{
conn.Close();
}
return passwordMatch;
}
protected void btnlogon_Click(object sender, EventArgs e)
{
bool passwordVerified=false;
try
{
passwordVerified =VerifyPassword(txtUserName.Text, txtPassword.Text);
}
catch (Exception ex)
{
lblMessage.Text = ex.Message;
return;
}
if (passwordVerified == true)
{
lblMessage.Text = "Logon successful: User is authenticated";
}
else
{
lblMessage.Text = "Invalid username or password";
}
}
Upvotes: 1
Views: 4065
Reputation: 13628
Update
Now that you updated your code I still see a few problems. You should use a Salt, but first you need your code to actually work. Adding a salt is easy.
A simple SHA hash of "mypassword" results in a string much larger than 20 characters. There is no way you can fit the base64'd hashed password in a 20 character field. Change the column size and your code to support larger hashes.
Update 2
Here is the code with the Salt on the hash. You have to update your RegisterUser stored procedure to store the salt along with the username and hashed password. You need a new Salt per user. The salt itself does not need to be hashed or encrypted.
You also need to return the salt from your LogInUser stored procedure.
Read comments below:
private byte[] Combine(byte[] a, byte[] b)
{
byte[] c = new byte[a.Length + b.Length];
System.Buffer.BlockCopy(a, 0, c, 0, a.Length);
System.Buffer.BlockCopy(b, 0, c, a.Length, b.Length);
return c;
}
protected void Button1_Click(object sender, EventArgs e)
{
byte[] salt = new byte[16];
RNGCryptoServiceProvider random = new RNGCryptoServiceProvider();
random.GetNonZeroBytes(salt);
SHA384CryptoServiceProvider sh = new SHA384CryptoServiceProvider();
byte[] plainbytes = Encoding.ASCII.GetBytes(TextBox2.Text);
var saltedBytes = Combine (salt, plainbytes);
var sha = sh.ComputeHash(saltedBytes);
SqlConnection con = new SqlConnection(constr);
SqlCommand cmd = new SqlCommand("RegisterUser",con);
cmd.CommandType = CommandType.StoredProcedure;
SqlParameter param = null;
param = cmd.Parameters.Add("@username",SqlDbType.VarChar,10);
param.Value = TextBox1.Text;
param = cmd.Parameters.Add("@password", SqlDbType.VarChar, 128);
param.Value = Convert.ToBase64String(sha);
// Store salt to use when comparing.
param = cmd.Parameters.Add("@salt", SqlDbType.VarChar, 128);
param.Value = Convert.ToBase64String(salt);
try
{
con.Open();
cmd.ExecuteNonQuery();
Label4.Text = "Successfully added account!!!";
}
catch (Exception ex)
{
throw new Exception("Exception adding account"+ex.Message);
}
finally
{
con.Close();
}
}
public bool searchtable()
{
SqlConnection con = new SqlConnection(constr);
SqlCommand cmd = new SqlCommand("LogInUser",con);
cmd.CommandType = CommandType.StoredProcedure;
SqlParameter param = null;
param = cmd.Parameters.Add("@username",SqlDbType.VarChar,10);
param.Value = TextBox1.Text;
try
{
con.Open();
SqlDataReader reader = cmd.ExecuteReader();
reader.Read();
// Get the salt hashed password
string dbpassmatch = reader.GetString(0);
// Get the salt
byte[] salt = Convert.FromBase64String(reader.GetString(1));
// Recreate the salted hashed password
byte[] plainbyte = Encoding.ASCII.GetBytes(TextBox2.Text);
SHA384CryptoServiceProvider sh = new SHA384CryptoServiceProvider();
var saltedBytes = Combine (salt, plainbytes);
var sha = sh.ComputeHash(saltedBytes);
// Now it matches what you did in insert.
String dbpassword = Convert.ToBase64String(sha);
reader.Close();
return dbpassword.Equals(dbpassmatch);
}
catch (Exception ex)
{
throw new Exception("Exception adding account" + ex.Message);
}
finally
{
con.Close();
}
}
Upvotes: 2
Reputation: 700152
Simple. You hash the password coming from the login page, and compare the hash code to the hash code in the database.
As the text should be handled the same both times, make a single function for that part. Use UTF-8 when converting the text to bytes, the ASCII encoding doesn't handle all characters:
public static string HashString(string value) {
SHA384CryptoServiceProvider sh = new SHA384CryptoServiceProvider();
byte[] plainbytes = Encoding.UTF8.GetBytes(value);
byte[] hash = sh.ComputeHash(plainbytes);
return BitConverter.ToString(hashbytes);
}
Upvotes: 4
Reputation: 108790
Your code is pretty bad from a security point of view:
Encoding.ASCII
, but Encoding.UTF8
. Else passwords containing non ASCII characters become very weak.Then to verify an entered password, read the hash and salt from the db. Hash the candidate password with the salt you read from the db, and compare the hashes.
ASP.net also contains a library called Membership
, but I'm not too familiar with it.
Upvotes: 2
Reputation: 4700
you could do the hashing in the db side, not the application side. that would be the easiest, youll send the password as plain text to the register stored proceudre, it will hash it (with something like sha1) then you will send the password again when the user performs a login, the stored procedure will look for the username you have sent, then will hash the password and compare it to the password saved during registration.
Upvotes: 0