如何在 c# 中验证 windows 应用程序的加盐密码和用户名?
How to validate Salted Password and Username for windows application in c#?
我有一个简单的登录 windows 应用程序。我已经在本地主机中成功创建了一个 SQL 数据库,其中包含用户名、密码(散列)、Salt 和电子邮件等用户信息,我还成功创建了一个用户注册表单,新用户可以在其中输入他们的详细信息和这些详细信息将添加到数据库中,它工作正常。
但我无法根据数据库 (localhost) 中包含用户数据的行中的存储值来验证用户名和密码以授予访问权限。
我已经能够编写哈希、加盐和验证方法以供进一步使用。
HashSalt.cs class
// --- constructor to initialize num_of_iterations
public HashSalt(int numOfIterations)
{
num_of_iterations = numOfIterations;
}
// --- Generate Salt ---
public string generateSalt()
{
var salt = new byte[32];
var randomProvider = new RNGCryptoServiceProvider();
randomProvider.GetBytes(salt);
return Convert.ToBase64String(salt); // returns salt as a string
}
// --- converts salt string into byte[]
public byte[] saltToByte(string salt)
{
var byteSalt = Convert.FromBase64String(salt);
return byteSalt;
}
// --- Generate hash of(pass+salt) ---
public string generateHash(string password, byte[] salt)
{
var rfc2898 = new Rfc2898DeriveBytes(password, salt, num_of_iterations);
var Password = rfc2898.GetBytes(32); // gives 32 byte encoded password
return Convert.ToBase64String(Password); // returns hash
}
// --- Authenticate User ---
public bool AuthenticateUser(string enteredPassword, string storedHash, string storedSalt)
{
var saltBytes = Convert.FromBase64String(storedSalt);
var rfc2898DeriveBytes = new Rfc2898DeriveBytes(enteredPassword, saltBytes, 10000);
return Convert.ToBase64String(rfc2898DeriveBytes.GetBytes(256)) == storedHash;
}
}
}
这是我的
Login.cs 用于登录表单
private void btnSignin_Click(object sender, EventArgs e)
{
string enteredPass = txtLoginPassword.Text;
DbHandler db = new DbHandler();
MySqlDataAdapter adapter = new MySqlDataAdapter();
DataTable table = new DataTable();
MySqlCommand cmd = new MySqlCommand("SELECT password, salt FROM student WHERE indexno=@index;", db.getConnection());
db.openConnection(); // open connection
cmd.Parameters.Add("@index", MySqlDbType.VarChar).Value = txtLoginusername.Text;
adapter.SelectCommand = cmd;
adapter.Fill(table);
if (table.Rows.Count > 0)
{
string pass = table.Rows[0][0].ToString();
string salt = table.Rows[0][1].ToString();
string newPass = hashSalt.generateHash(enteredPass, hashSalt.saltToByte(salt));
if (hashSalt.authenticateUser(enteredPass, pass, salt))
{
// MessageBox.Show("correct ='" + pass + "'\nEntered pass ='" + hashSalt.authenticateUser(enteredPass, pass, salt) + "'");
// --- form Records obj
Records gotoRecords = new Records();
gotoRecords.Show(); // goto Records
this.Hide();
}
else
{
string message = "User name & Password did not Match!?";
string title = "Attention!";
MessageBoxButtons buttons = MessageBoxButtons.OK;
DialogResult result = MessageBox.Show(message, title, buttons, MessageBoxIcon.Warning);
}
}
else
{
string message = "User name NotFound!?";
string title = "Attention!";
MessageBoxButtons buttons = MessageBoxButtons.OK;
DialogResult result = MessageBox.Show(message, title, buttons, MessageBoxIcon.Warning);
}
//this.Close();
db.openConnection(); // close connection
数据库结构
如果您能给我一些操作说明,我将不胜感激。
我认为问题出在您 mysql table 中盐列的数据类型上。
这里,
string newPass = hashSalt.generateHash(enteredPass, hashSalt.saltToByte(salt));
你正在传递 salt
从数据库到 saltToByte()
方法转换成
byte array
,所以我认为您计划使用 generateSalt()
的 return 值将盐存储为字符串
方法。当您需要对用户进行身份验证时,使用 generateHash()
方法将其重新转换为 byte array
。
这是一个混乱的实现。
建议您将盐存储为 byte array
,这样您就不需要使用 saltToByte()
.
除此之外,
您的字节键在 generateSalt()
字节键设置为
时有所不同
var salt = new byte[32];
32 字节密钥,而在 AuthenticateUser()
中,您使用的是 256 字节密钥 rfc2898DeriveBytes.GetBytes(256)
我有一个简单的登录 windows 应用程序。我已经在本地主机中成功创建了一个 SQL 数据库,其中包含用户名、密码(散列)、Salt 和电子邮件等用户信息,我还成功创建了一个用户注册表单,新用户可以在其中输入他们的详细信息和这些详细信息将添加到数据库中,它工作正常。
但我无法根据数据库 (localhost) 中包含用户数据的行中的存储值来验证用户名和密码以授予访问权限。
我已经能够编写哈希、加盐和验证方法以供进一步使用。
HashSalt.cs class
// --- constructor to initialize num_of_iterations
public HashSalt(int numOfIterations)
{
num_of_iterations = numOfIterations;
}
// --- Generate Salt ---
public string generateSalt()
{
var salt = new byte[32];
var randomProvider = new RNGCryptoServiceProvider();
randomProvider.GetBytes(salt);
return Convert.ToBase64String(salt); // returns salt as a string
}
// --- converts salt string into byte[]
public byte[] saltToByte(string salt)
{
var byteSalt = Convert.FromBase64String(salt);
return byteSalt;
}
// --- Generate hash of(pass+salt) ---
public string generateHash(string password, byte[] salt)
{
var rfc2898 = new Rfc2898DeriveBytes(password, salt, num_of_iterations);
var Password = rfc2898.GetBytes(32); // gives 32 byte encoded password
return Convert.ToBase64String(Password); // returns hash
}
// --- Authenticate User ---
public bool AuthenticateUser(string enteredPassword, string storedHash, string storedSalt)
{
var saltBytes = Convert.FromBase64String(storedSalt);
var rfc2898DeriveBytes = new Rfc2898DeriveBytes(enteredPassword, saltBytes, 10000);
return Convert.ToBase64String(rfc2898DeriveBytes.GetBytes(256)) == storedHash;
}
}
}
这是我的 Login.cs 用于登录表单
private void btnSignin_Click(object sender, EventArgs e)
{
string enteredPass = txtLoginPassword.Text;
DbHandler db = new DbHandler();
MySqlDataAdapter adapter = new MySqlDataAdapter();
DataTable table = new DataTable();
MySqlCommand cmd = new MySqlCommand("SELECT password, salt FROM student WHERE indexno=@index;", db.getConnection());
db.openConnection(); // open connection
cmd.Parameters.Add("@index", MySqlDbType.VarChar).Value = txtLoginusername.Text;
adapter.SelectCommand = cmd;
adapter.Fill(table);
if (table.Rows.Count > 0)
{
string pass = table.Rows[0][0].ToString();
string salt = table.Rows[0][1].ToString();
string newPass = hashSalt.generateHash(enteredPass, hashSalt.saltToByte(salt));
if (hashSalt.authenticateUser(enteredPass, pass, salt))
{
// MessageBox.Show("correct ='" + pass + "'\nEntered pass ='" + hashSalt.authenticateUser(enteredPass, pass, salt) + "'");
// --- form Records obj
Records gotoRecords = new Records();
gotoRecords.Show(); // goto Records
this.Hide();
}
else
{
string message = "User name & Password did not Match!?";
string title = "Attention!";
MessageBoxButtons buttons = MessageBoxButtons.OK;
DialogResult result = MessageBox.Show(message, title, buttons, MessageBoxIcon.Warning);
}
}
else
{
string message = "User name NotFound!?";
string title = "Attention!";
MessageBoxButtons buttons = MessageBoxButtons.OK;
DialogResult result = MessageBox.Show(message, title, buttons, MessageBoxIcon.Warning);
}
//this.Close();
db.openConnection(); // close connection
数据库结构
我认为问题出在您 mysql table 中盐列的数据类型上。 这里,
string newPass = hashSalt.generateHash(enteredPass, hashSalt.saltToByte(salt));
你正在传递 salt
从数据库到 saltToByte()
方法转换成
byte array
,所以我认为您计划使用 generateSalt()
的 return 值将盐存储为字符串
方法。当您需要对用户进行身份验证时,使用 generateHash()
方法将其重新转换为 byte array
。
这是一个混乱的实现。
建议您将盐存储为 byte array
,这样您就不需要使用 saltToByte()
.
除此之外,
您的字节键在 generateSalt()
字节键设置为
var salt = new byte[32];
32 字节密钥,而在 AuthenticateUser()
中,您使用的是 256 字节密钥 rfc2898DeriveBytes.GetBytes(256)