biki biki - 1 month ago 18
ASP.NET (C#) Question

How to compare the hash-password with ordinary one?

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";

}

}

Answer

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();
    }
}
Comments