Change password with the use of a existing Salt - c#

I make a user and save this in an SQLite database. The user gets a password and a salt.
public bool SaveNewUser(string databaseFileName)
{
bool faulted = true;
string SQL = string.Empty;
using (SQLiteConnection m_dbConnection = new SQLiteConnection("Data Source=" + databaseFileName))
{
var passwordSalt = EncryptDecryptUserData.GenerateSalt();
var passwordHash = EncryptDecryptUserData.ComputeHash(Password, passwordSalt);
var usereroleHash = EncryptDecryptUserData.ComputeHash(UserName + Role_Name, passwordSalt); //to avoid copy role to an other user the combi username+rolenam ara saved
if (Id == -1) //-New User =
{
SQL = "insert into QB_USER_LIST (GUID, USERNAME, PASSWORD, SALT, ROLE_NAME, GROUP_NAME, DATUM_AANGEMAAKT, AANGEMAAKT_DOOR, USER_ROLE ) ";
SQL += "values (#GUID, #USERNAME, #PASSWORD, #SALT ,#ROLE_NAME, #GROUP_NAME, #DATUM_AANGEMAAKT, #AANGEMAAKT_DOOR, #USER_ROLE )";
}
else
{
//change existing user
SQL = "UPDATE QB_USER_LIST set USERNAME = #USERNAME,";
}
m_dbConnection.Open();
SQLiteCommand command = new SQLiteCommand(SQL, m_dbConnection);
command.Prepare();
command.Parameters.Add(new SQLiteParameter("#USERNAME", UserName));
if (Id == -1)
{
command.Parameters.Add(new SQLiteParameter("#PASSWORD", Convert.ToBase64String(passwordHash)));
command.Parameters.Add(new SQLiteParameter("#SALT", Convert.ToBase64String(passwordSalt)));
command.Parameters.Add(new SQLiteParameter("#ROLE_NAME", Role_Name));
command.Parameters.Add(new SQLiteParameter("#GROUP_NAME", Group_Name));
command.Parameters.Add(new SQLiteParameter("#DATUM_AANGEMAAKT", DateTime.Now));
command.Parameters.Add(new SQLiteParameter("#AANGEMAAKT_DOOR", Environment.UserName));
command.Parameters.Add(new SQLiteParameter("#GUID", Guid));
command.Parameters.Add(new SQLiteParameter("#USER_ROLE", Convert.ToBase64String(usereroleHash)));
}
try
{
command.ExecuteNonQuery();
Logging.WriteToLog("INFORMATIE", "De gegevens van een nieuwe gebruiker zijn opgeslagen. (Nieuwe gebruiker = "+ UserName + ")."); //AANGEPAST
faulted = false;
}
Then i want to change data from the user and use the same salt
string Salt = GetUserSalt(databaseFileName); //This is "select salt from QB_USER_LIST"
var passwordSalt = Convert.FromBase64String(Salt); //Get the excisting salt
var passwordHash = EncryptDecryptUserData.ComputeHash(Password, passwordSalt); //create the new paspordhash with the same salt --> goes wrong
I seems like i can't use the same salt again. I want to re use it because I use the salt to hash the field UserRole. Later when I want to change just the UserRole of a user I need to compare it with the salt.

Found it. The password in my verifypassword function was not the password but the hashed password. So i was comparing 2 different things.

Related

Why my login function let users login with a random password?

i have a little problem. My Script lets users login with a random password. How can i fix it? Here are all informations: Passworts are stored in MySQL DB V8, and they crypted correctly with BCrypt.
Bcrypt Code:
private static string GetRandomSalt()
{
return BCrypt.Net.BCrypt.GenerateSalt(10);
}
public static string HashPassword(string password)
{
return BCrypt.Net.BCrypt.HashPassword(password, GetRandomSalt());
}
public static bool ValidatePassword(string username, string password)
{
return BCrypt.Net.BCrypt.Verify(username, password);
}
This is my code where i got the problem:
[RemoteEvent("loginUser")]
public void loginUserEvent(Client player, String username, String password)
{
if (player.HasData("waitLogando"))
{
player.SendNotification("Wait...");
return;
}
player.SetData("waitLogando", true);
using (MySqlConnection Mainpipeline = new MySqlConnection(Main.myConnectionString))
{
Mainpipeline.Open();
MySqlCommand query = Mainpipeline.CreateCommand();
query.CommandType = CommandType.Text;
query.CommandText = "SELECT * FROM `users` WHERE ( `Username` = '" + username + "' OR `email` = '" + username + "')";
query.ExecuteNonQuery();
DataTable dt = new DataTable();
using (MySqlDataAdapter da = new MySqlDataAdapter(query))
{
da.Fill(dt);
int i = 0;
i = Convert.ToInt32(dt.Rows.Count.ToString());
if (i == 0)
{
string query2 = "SELECT * FROM users (username, password) VALUES (#username, #password)";
MySqlCommand LoginAccount = new MySqlCommand(query2, Mainpipeline);
LoginAccount.Parameters.AddWithValue("#username", "" + username + "");
LoginAccount.Parameters.AddWithValue("#password", "" + AccountManage.ValidatePassword(username, password) + "");
LoginAccount.ExecuteNonQuery();
player.SendNotification("Wrong password");
player.ResetData("waitLogando");
}
else
{
NAPI.ClientEvent.TriggerClientEvent(player, "clearLoginWindow");
AccountManage.LoadAccount(player, username);
player.ResetData("waitLogando");
}
}
}
}
I really hope you can help me, thanks for your time! If you need more informations, im here.
You are not checking the password in the first query, you only check user name or email.
Ah, query2 is also incorrect (did you mean INSERT instead of SELECT?).

Bcrypt validate password

I'm trying to store hashed passwords in db. Here is my code:
string passwords = textBox2.Text;
string salt = BCrypt.Net.BCrypt.GenerateSalt(12);
string hashPwd = BCrypt.Net.BCrypt.HashPassword(passwords, salt);
try
{
SQLiteCommand command = new SQLiteCommand();
connection.Open();
command.Connection = connection;
command.CommandText = ((#"INSERT INTO acc (UserName, Pass) VALUES ('" + textBox1.Text + "','" + hashPwd+ "');"));
command.ExecuteNonQuery();
connection.Close();
}
catch (Exception ex)
{
MessageBox.Show("Error:" + ex.ToString());
return;
}
Login/verification code:
try
{
SQLiteDataAdapter sqlad = new SQLiteDataAdapter("SELECT COUNT(*) From acc WHERE Username = '" + textBox1.Text + "' AND Pass = '" + textBox2.Text + "' ", connection);
DataTable dt = new DataTable();
sqlad.Fill(dt);`
string userid = dt.Rows[0]["UserName"].ToString();
string password = dt.Rows[0]["Pass"].ToString();
bool flag = BCrypt.Net.BCrypt.Verify(textBox2.Text, password);
if (userid == textBox1.Text && flag == true)
{
Form2 frm = new Form2();
frm.Show();
}
else
{
MessageBox.Show("Invalid UserId or password");
}
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
return;
}
I can't verify Password, I'm getting error, could you help me please? One more question, should I save salt too in database?
There are a couple of problems with your code:
1. SQL Injection
Both your insert and verification code blocks are vulnerable to SQL injection, since they allow text you take directly from user input into the SQL string executed, a vulnerability they can use to either subvert the login check, or destroy your database. Don't do it!
2. Your selection of the hashed password back from the database does not select the hashed password.. or anything of interest.
Consider what you have here:
SQLiteDataAdapter sqlad = new SQLiteDataAdapter(#"
SELECT
COUNT(*)
From
acc
WHERE
Username = '" + textBox1.Text + "'
AND
Pass = '" + textBox2.Text + "' ", connection);
So, let's say I gave my username as "Steve" and password as "hello", which got hashed to "ab123cdef", and inserted to your acc table as:
UserName Pass
Steve ab123cdef
And when I come to verify this with the original correct user and password, your select statement says "give me the number of rows with username 'Steve' and pass 'hello'", which will duly return zero.
Your code should throw an exception here:
string userid = dt.Rows[0]["UserName"].ToString();
Since the result set doesn't contain the username as an output.
Here is a basic little example using the libraries you've chosen to show how you could insert and verify a password successfully.
Regarding what to do with the salt, the function HashPassword has prepended the salt to the password hash, so if you store the output of this, you are storing the salt. The verify function you use in verification will handle and check this for you.
static void CreateUser(string username, string password)
{
if (UserExists(username))
throw new InvalidOperationException("User already exists");
string salt = BCrypt.Net.BCrypt.GenerateSalt(12);
// if you look at the hashed password, notice that it's prepended with the salt generated above
string hashedPassword = BCrypt.Net.BCrypt.HashPassword(password, salt);
using (SQLiteConnection connection = new SQLiteConnection(connectionString))
{
connection.Open();
SQLiteCommand insertCommand = new SQLiteCommand(connection);
insertCommand.CommandText = #"INSERT INTO acc (UserName, Pass) VALUES (#username, #hashedPass);";
// use parameterised queries to mitigate sql injection
insertCommand.Parameters.Add(new SQLiteParameter("#username", username));
insertCommand.Parameters.Add(new SQLiteParameter("#hashedPass", hashedPassword));
insertCommand.ExecuteNonQuery();
}
}
To verify a given username/password, all we need back from the database is the output of the hash function to verify against what we've been given.
static bool Verify(string username, string password)
{
using (SQLiteConnection connection = new SQLiteConnection(connectionString))
{
connection.Open();
SQLiteCommand checkUserCommand = new SQLiteCommand(connection)
{
CommandText = #"SELECT Pass FROM acc WHERE UserName = #username;"
};
checkUserCommand.Parameters.Add(new SQLiteParameter("#username", username));
var hashedPassword = (string)checkUserCommand.ExecuteScalar();
return BCrypt.Net.BCrypt.Verify(password, hashedPassword);
}
}
Usage would be something like..
if (!UserExists(username))
{
CreateUser(username, password);
Console.WriteLine("User {0} created", username);
}
else
{
bool loginOk = Verify(username, password);
Console.WriteLine("Login ok?: {0}", loginOk);
}

How to return true if name and password both match? (MySQL/C#)

I am currently working on a simple login system with C# and MySQL and I have everything working so far but I can't seem to get the login verification working, I can't work out the correct way of checking the records in the table as I have tried a few different ways that I found online but none were working.
public bool loginCorrect(String name, String password)
{
if (this.OpenConnection() == true) {
using (MySqlCommand cmd = new MySqlCommand ("SELECT * FROM logins WHERE name = #UserName AND password = #Password")) {
cmd.Parameters.AddWithValue ("#UserName", name);
cmd.Parameters.AddWithValue ("#Password", password);
//Now we are going to read the data imput
MySqlDataReader myLoginReader = cmd.ExecuteReader ();
//if the data matches the rows (username, password), then you enter to the page
bool isExist = myLoginReader.HasRows();
//Close Reader
myLoginReader.Close ();
}
//Close Connection
this.CloseConnection ();
}
return isExist;
}
This is the current code for the login verification which doesn't work. I want the boolean to return true when the passed parameters name and password match which the ones in the database table 'logins'.
Below is my working Insert method just in case you need to compare the structure.
public void Insert(String username, String password)
{
string query = "INSERT INTO logins (name, password) VALUES ('" + username + "','" + password + "')";
//open connection
if (this.OpenConnection () == true)
{
//Create command and assign query
MySqlCommand cmd = new MySqlCommand(query, connection);
//Execute command
cmd.ExecuteNonQuery();
//close connection
this.CloseConnection();
}
}
EDIT:
I have altered the loginCorrect method as suggested and I get these errors when compiling:
bool isExist = myLoginReader.HasRows(); // Non-Invocable member 'System.Data.Common.DbDataReader.HasRows' cannot be used like a method.
And:
return isExist; // The name 'isExist' does not exist in the current context.
EDIT 2
Current Code
public void Insert(String name, String password)
{
//open connection
if (this.OpenConnection())
{
string query = "INSERT INTO logins (name, password) VALUES (#UserName, #Password)";
//Create command and assign query
MySqlCommand cmd = new MySqlCommand(query, connection);
//Add parameters
cmd.Parameters.AddWithValue ("#UserName", name);
cmd.Parameters.AddWithValue ("#Password", password);
//Execute command
cmd.ExecuteNonQuery();
//close connection
this.CloseConnection();
}
}
public bool loginCorrect(String name, String password)
{
bool isExist = false;
if (this.OpenConnection()) {
using (MySqlCommand cmd = new MySqlCommand ("SELECT * FROM logins WHERE `name` = #UserName AND password = #Password")) {
cmd.Parameters.AddWithValue ("#UserName", name);
cmd.Parameters.AddWithValue ("#Password", password);
//Now we are going to read the data imput
MySqlDataReader myLoginReader = cmd.ExecuteReader ();
//if the data matches the rows (username, password), then you enter to the page
isExist = myLoginReader.HasRows;
//Close Reader
myLoginReader.Close ();
}
//Close Connection
this.CloseConnection ();
}
return isExist;
}
Which gives
System.InvalidOperationException: Connection must be valid and open.
SOLUTION
public void Insert(String name, String password)
{
//open connection
if (this.OpenConnection())
{
string query = "INSERT INTO logins (name, password) VALUES (#UserName, #Password)";
//Create command and assign query
MySqlCommand cmd = new MySqlCommand(query, connection);
//Add parameters
cmd.Parameters.AddWithValue ("#UserName", name);
cmd.Parameters.AddWithValue ("#Password", password);
//Execute command
cmd.ExecuteNonQuery();
//close connection
this.CloseConnection();
}
}
public bool loginCorrect(String name, String password)
{
bool isExist = false;
if (this.OpenConnection()) {
using (MySqlCommand cmd = new MySqlCommand ("SELECT * FROM logins WHERE `name` = #UserName AND password = #Password", connection)) {
cmd.Parameters.AddWithValue ("#UserName", name);
cmd.Parameters.AddWithValue ("#Password", password);
//Now we are going to read the data imput
MySqlDataReader myLoginReader = cmd.ExecuteReader ();
//if the data matches the rows (username, password), then you enter to the page
isExist = myLoginReader.HasRows;
//Close Reader
myLoginReader.Close ();
}
//Close Connection
this.CloseConnection ();
}
return isExist;
}
The problem was not passing the connection in the loginCorrect method
Try this, combined with some of the comments we gave you:
User check:
public bool loginCorrect(String name, String HASHED_AND_SALTED_PASSWORD)
{
bool isExist;
if (this.OpenConnection()) {
using (SqlCommand cmd = new SqlCommand ("SELECT * FROM logins WHERE `name` = #UserName AND password = #Password")) {
cmd.Parameters.AddWithValue ("#UserName", name);
cmd.Parameters.AddWithValue ("#Password", HASHED_AND_SALTED_PASSWORD);
//Now we are going to read the data imput
SqlDataReader myLoginReader = cmd.ExecuteReader ();
//if the data matches the rows (username, password), then you enter to the page
isExist = myLoginReader.HasRows;
//Close Reader
myLoginReader.Close ();
}
//Close Connection
this.CloseConnection ();
}
return isExist;
}
If you return inside the if, the connections won't be closed.
Insert - I'm not too experienced with C# classes, hope I did it correctly.
public void Insert(String username, String password)
{
//Hash and salt password here (this is pseudo code)
String HASHED_AND_SALTED_PASSWORD = StrongHash(password + GenerateSalt());
//open connection
if (this.OpenConnection())
{
string query = "INSERT INTO logins (`name`, password) VALUES (#UserName, #Password)";
//Create command and assign query
MySqlCommand cmd = new MySqlCommand(query, connection);
//Add parameters
cmd.Parameters.AddWithValue ("#UserName", name);
cmd.Parameters.AddWithValue ("#Password", HASHED_AND_SALTED_PASSWORD);
//Execute command
cmd.ExecuteNonQuery();
//close connection
this.CloseConnection();
}
}
A few other things - Make sure you store a properly hashed and salted password, using a strong hashing algorithm. Even if this is for a school project, you'd want to get used to best practices.
I've fixed a few unnecessary things I saw like if (this.OpenConnection() == true).
Let us know if this works.
EDIT:
Sorry, my bad. HasRows is a property, not a function. Try this instead: myLoginReader.HasRows; (Removed parentheses)
Also, declare Bool isExist at the top.

Hashed password is not recognized after changing it

I have hased my password right there on in the registration.aspx. having this code in my business layer:
public static string CreateSHAHash(string Phrase)
{
SHA512Managed HashTool = new SHA512Managed();
Byte[] PhraseAsByte = System.Text.Encoding.UTF8.GetBytes(string.Concat(Phrase));
Byte[] EncryptedBytes = HashTool.ComputeHash(PhraseAsByte);
HashTool.Clear();
return Convert.ToBase64String(EncryptedBytes);
}
and this code in the register page:
scm.Parameters.AddWithValue("#Password", BusinessLayer.ShoppingCart.CreateSHAHash(txtPW.Text));
Having the codes above, the password are being hashed in the DB and it is working fine when I log in with this code:
protected void btn_Login_Click(object sender, EventArgs e)
{
SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["RegistrationConnectionString"].ConnectionString);
conn.Open();
string checkuser = "select count(*) from UserData where Username = '" + txtUser.Text + "'";
SqlCommand scm = new SqlCommand(checkuser, conn);
int temp = Convert.ToInt32(scm.ExecuteScalar().ToString());
conn.Close();
if (temp == 1)
{
conn.Open();
string checkPassword = "select Password from UserData where Username ='" + txtUser.Text + "'";
SqlCommand passCom = new SqlCommand(checkPassword, conn);
string password = passCom.ExecuteScalar().ToString();
if (password == BusinessLayer.ShoppingCart.CreateSHAHash(txtPassword.Text))
{
Session["New"] = txtUser.Text;
Response.Write("<script>alert('Logged In')</script>");
Response.Redirect("OrderNow.aspx");
}
else
{
lblcrederror.Text = ("Credentials dont match");
}
}
else
{
lblcrederror.Text = ("Credentials dont match");
}
However when I change it having this code in my changepassword.aspx, its not letting me in with my new password.
protected void btn_update_Click(object sender, EventArgs e)
{
SqlConnection con = new SqlConnection(conn);
con.Open();
str = "select * from UserData ";
com = new SqlCommand(str, con);
SqlDataReader reader = com.ExecuteReader();
while (reader.Read())
{
if (BusinessLayer.ShoppingCart.CreateSHAHash(txt_cpassword.Text) == reader["Password"].ToString())
{
up = 1;
}
}
reader.Close();
con.Close();
if (up == 1)
{
con.Open();
str = "update UserData set Password=#Password where UserName='" + Session["New"].ToString() + "'";
com = new SqlCommand(str, con);
com.Parameters.Add(new SqlParameter("#Password", SqlDbType.VarChar, 50));
com.Parameters["#Password"].Value = BusinessLayer.ShoppingCart.CreateSHAHash(txt_npassword.Text);
com.ExecuteNonQuery();
con.Close();
lbl_msg.Text = "Password changed Successfully";
}
else
{
lbl_msg.Text = "Please enter correct Current password";
}
}
What am I missing here?
Check if the 50 truncates the hash.
com.Parameters.Add(new SqlParameter("#Password", SqlDbType.VarChar, 50));
On a sidenote i see that your solution is very open to SQL injection.
"select Password from UserData where Username ='" + txtUser.Text + "'";
A user can write sql statements in the textbox, and hijack your database, create his own tables or drop the whole database. You should always parameterize the queries. I see that you did that to the Update statement, but you should consider doing it for all of your variables.
This quickly creates a lot of code, so i would also consider making an SQL wrapper, that wraps in all of the things you repeat. When you are done refactoring it could look something like this:
var sql = new SqlWrapper("select Password from UserData where Username = #username", txtUser.Text);
var dataSet = sql.Execute();
Then you can hide all of your connectionstring, commands++ behind this wrapper and only tell the wrapper what you actually care about.
You should also consider using a salt for your password. If you and I have the same password, the hash will be the same. A salt will fix this problem.
A good article about password security -> https://crackstation.net/hashing-security.htm

How to get other column value if login successfull in c#

I have one table called Users, which have 4 columns
UserId
UserName
Password
Role
If login is successful, I want to know the UserId and Role values ,
for login validate I wrote following function,
private bool ValidationFunction(string username, string pwd)
{
bool boolReturnValue = false;
string s = "correct connection string";
SqlConnection con = new SqlConnection(s);
con.Open();
string sqlUserName;
sqlUserName = "SELECT UserName,Password FROM Users WHERE UserName ='" + username + "' AND Password ='" + pwd + "'";
SqlCommand cmd = new SqlCommand(sqlUserName, con);
string CurrentName;
CurrentName = (string)cmd.ExecuteScalar();
if (CurrentName != null)
{
boolReturnValue = true;
}
else
{
Session["UserName"] = "";
boolReturnValue = false;
}
return boolReturnValue;
}
ExecuteScalar() function returns only the top record value of the first column. So you need to use ExecuteReader() instead.
Other important thing is you better use a parameterised query to pass those user typed values into the database. You are open for sql injection attacks this way.
Try this:
using (SqlConnection cnn = new SqlConnection("yourConnectionString"))
{
string sql= "select userId,role from users " +
"where username=#uName and password=#pWord";
using (SqlCommand cmd = new SqlCommand(sql,cnn))
{
cmd.Parameters.AddWithValue("#uName", username);
cmd.Parameters.AddWithValue("#pWord", pwd);
cnn.Open();
SqlDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
//get the reader values here.
}
}
}
If UserID and Role are in the Users table, you can use the code below. It has the added benefit of protection from SQL injection attacks using parameters.
private class User
{
public int UserID {get;set;}
public string Role {get;set;}
public string UserName {get;set;}
}
private bool ValidationFunction(string username, string pwd, out User)
{
bool boolReturnValue = false;
string s = "correct connection string";
SqlConnection con = new SqlConnection(s);
con.Open();
string sqlUserName;
sqlUserName = "SELECT UserName,Password,UserID,Role FROM Users WHERE UserName =#usr AND Password=#pwd";
SqlCommand cmd = new SqlCommand(sqlUserName, con);
cmd.Parameters.Add(new SqlParameter("usr", username));
cmd.Parameters.Add(new SqlParameter("pwd", pwd));
SqlDataReader reader = command.ExecuteReader();
if (reader.Read())
{
boolReturnValue = true;
User = new User(){UserName = username, UserID=reader.GetInt32(2), Role=reader.GetString(3)};
}
else
{
Session["UserName"] = "";
boolReturnValue = false;
}
return boolReturnValue;
}
Use query
SqlDataReaer reader= Select *from Users where password="yourPassword"
and then you can get whatever you want i.e. reader["userName"] etc

Categories