我一遍又一遍地阅读代码以查看错误发生的位置,但我无法找到它。我已经从stackoverflow复制了这个代码,从来没有真正检查它或完全理解它来修复它。 我从Web服务接收密码,散列,腌制并将其保存到SqlServer 2008。 SqlServer上的变量声明为mail为nvarchar(64),hash为varbinary(128),salt为varbinary(128)。 密码正在保存,但是当我尝试检查密码是否正确时,该方法始终返回false。 这是我的方法。
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 Mail=@mail";
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答案 0 :(得分: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("test@domain.com", password);
label1.Text = string.Format("Using direct check: {0}\nVia the database: {1}",
CheckPassword(password, u.Password, u.Salt),
ValidateLogIn("test@domain.com", password));
}
它返回true; 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的定义是“有缺陷的”?
答案 1 :(得分:0)
用deroby的答案检查后仍然没有运气。我重新检查并实现了20个字节是120位,因此varbinary无法存储整个盐。将它增加到256后就可以了。