如何将hash-password与普通密码进行比较?

时间:2012-06-02 13:55:55

标签: c# asp.net .net

我在使用来自登录页面的普通密码验证来自数据库的哈希密码时遇到了大麻烦。 如何通过比较这两个密码来验证用户。这是我的注册页面代码:

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

如何将此密码与来自登录页面的密码进行比较...帮帮我们......

带有SALT的HASH代码: -

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

    }

}

4 个答案:

答案 0 :(得分:4)

简单。您对来自登录页面的密码进行哈希处理,并将哈希代码与数据库中的哈希代码进行比较。


由于文本应该同时处理相同的内容,因此为该部分创建单个函数。在将文本转换为字节时使用UTF-8,ASCII编码不处理所有字符:

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

答案 1 :(得分:2)

<强>更新

既然您更新了代码,我仍然会看到一些问题。你应该使用Salt,但首先你需要你的代码才能真正起作用。添加盐很容易。

“mypassword”的简单SHA哈希导致字符串远大于20个字符。你无法在20个字符的字段中使用base64'd散列密码。更改列大小和代码以支持更大的哈希值。

更新2

以下是哈希值上的Salt代码。您必须更新您的RegisterUser存储过程以存储salt以及用户名和散列密码。每个用户需要一个新的Salt。盐本身不需要进行散列或加密。

您还需要从LogInUser存储过程中返回salt。

阅读以下评论:

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

答案 2 :(得分:2)

从安全角度来看,您的代码非常糟糕:

  1. 使用盐。通常是随机值(64位或更多)与db中的散列一起存储。
  2. 使用慢速KDF,例如PBKDF2,bcrypt或scrypt
    PBKDF2最简单,因为.net已经包含一个实现:Rfc2898DeriveBytes Class
  3. 请勿使用Encoding.ASCII,而是使用Encoding.UTF8。包含非ASCII字符的其他密码变得非常弱。
  4. 然后验证输入的密码,从db中读取哈希值和salt。使用从db中读取的salt来哈希候选密码,并比较哈希值。


    ASP.net还包含一个名为Membership的库,但我对它不太熟悉。

答案 3 :(得分:0)

你可以在db端进行散列,而不是应用程序端。这将是最简单的,你将密码作为纯文本发送到寄存器存储过程,它将散列它(与sha1之类的东西) 然后,当用户执行登录时,您将再次发送密码,存储过程将查找您发送的用户名,然后将密码哈希并将其与注册时保存的密码进行比较。