2013-09-29 93 views
4

我一直在反复阅读代码以查看错误发生的位置,但我无法找到它。我从stackoverflow复制了这段代码,从来没有真正检查过它,或者完全理解它来修复它。 我从Web服务接收密码,哈希,腌制并将其保存到SqlServer 2008. SqlServer上的变量被声明为邮件为nvarchar(64),哈希为varbinary(128),salt为varbinary(128) 。 密码正在保存,但当我尝试检查密码是否正确时,该方法始终返回false。 这是我的方法。将密码散列到SqlServer

public int InsertData(string mail,string Password) 
    { 

     int lineas; 
     UserData usuario = HashPassword(Password); 
     using (SqlConnection connection = new SqlConnection(Connection)) 
     using (SqlCommand command = connection.CreateCommand()) 
     { 
      command.CommandText = "INSERT INTO Usuarios (Mail,Hash,Salt) VALUES (@mail,@hash,@salt)"; 

      command.Parameters.AddWithValue("@mail", mail); 
      command.Parameters.AddWithValue("@hash", usuario.Password); 
      command.Parameters.AddWithValue("@salt", usuario.salt); 


      connection.Open(); 
      lineas=command.ExecuteNonQuery(); 
     } 
     usuario = null; 
     return lineas; 
    } 



private UserData HashPassword(string Password) 
    { 
     //This method hashes the user password and saves it into the object UserData 
     using (var deriveBytes = new Rfc2898DeriveBytes(Password, 20)) 
     { 
      byte[] salt = deriveBytes.Salt; 
      byte[] key = deriveBytes.GetBytes(20); // derive a 20-byte key 
      UserData usuario = new UserData(); 
      usuario.Password = key; 
      usuario.salt = salt; 
      return usuario; 

     } 


    } 

而且下一个方法是我使用的一个验证德密码,它始终返回false

private bool CheckPassword(string Password, byte[] hash, byte[] salt) 
    { 


     // load salt and key from database 

     using (var deriveBytes = new Rfc2898DeriveBytes(Password, salt)) 
     { 
      byte[] newKey = deriveBytes.GetBytes(20); // derive a 20-byte key 

      if (!newKey.SequenceEqual(hash)) 
       return false; 

      else 
       return true; 

     } 
    } 

这个方法接收登录信息

public bool ValidateLogIn(string mail, string Password) 
    { 



     using (SqlConnection connection = new SqlConnection(Connection)) 
     using (SqlCommand command = connection.CreateCommand()) 
     { 
      command.CommandText = "Select * from Usuarios where [email protected]"; 
      command.Parameters.AddWithValue("@mail",mail); 
      connection.Open(); 
      using (SqlDataReader reader = command.ExecuteReader()) 
      { 
       reader.Read(); 
       byte[] hash = (byte[])reader["Hash"]; 
       byte[] salt = (byte[])reader["Salt"]; 
       if(CheckPassword(Password,hash,salt)) 
       { 
        /
        UpdateData(mail, Password); 
        return true; 
       } 
       else 
       { 
        return false; 
       } 

      } 

     } 

    } 

任何想法可能是什么错误?

编辑:我发现在那里我得到的散列码 https://stackoverflow.com/a/4330586/1861617

+1

保存和验证数据时散列和salt是否相同? – Sam

+0

是的,我将散列和盐保存到同一行。然后加载相同的行并根据密码对其进行验证 –

+0

您是否尝试过在代码中的任意位置设置断点并将其执行到100%,确保变量持有您认为它们持有的内容(并验证代码是否按预期工作)?另外,你是否收到任何错误? – Sam

回答

0

与德罗比的答案检查后,仍然没有得到运气。我重新检查并实现了20个字节是120位,因此varbinary无法存储整个盐。将它增加到256后就可以工作了。

0

在测试项目中使用的代码(用文本框+按钮+标签Windows窗体)的链接添加此:

internal class UserData 
    { 
     public byte[] Password { get; set; } 
     public byte[] Salt { get; set; } 
    } 

    public string Connection { get; set; } 

    private void UpdateData(string mail, string password) 
    { 
     // not a clue what to do here.... 
    } 

    private void button1_Click(object sender, EventArgs e) 
    { 
     var password = textBox1.Text; 
     var u = HashPassword(password); 

     var b = new SqlConnectionStringBuilder {DataSource = "127.0.0.1", IntegratedSecurity = true}; 
     Connection = b.ConnectionString; 

     InsertData("[email protected]", password); 

     label1.Text = string.Format("Using direct check: {0}\nVia the database: {1}", 
      CheckPassword(password, u.Password, u.Salt), 
      ValidateLogIn("[email protected]", password)); 
    } 

它返回true;真正没有任何问题。 (VS2010,.NET4 CP,SQL2008R2)

在我使用这个数据库:

CREATE TABLE tempdb..t_hash 
    (
     Mail nvarchar(64) NOT NULL PRIMARY KEY (Mail), 
     Hash varbinary(128), 
     Salt varbinary(128) 
    ) 

我最好的猜测是,你为的UserData CLAS定义是 '有缺陷'?