Search code examples
c#visual-studio-2015xampplocalhostsalt-cryptography

How to validate Salted Password and Username for windows application in c#?


I have a simple login windows application. I have successfully created a SQL database in the localhost which contains user information like Username, Password(hashed), Salt and Email, and I have also successfully created a user registration form where a new user can input their details and these details will be added to the database, it works fine.

But I've unable to validate the Username and Password against the stored values in the row containing the user data in the database(localhost) to give access.

I've able to write hashing, salting and validation methods for further use.

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







    }
}

And this is my Login.cs for login form

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

Database Structure enter image description here I would greatly appreciate it if you kindly give me some instructions to how to do that.


Solution

  • I think the problem is with the datatype of salt column in your mysql table. Here,

    string newPass = hashSalt.generateHash(enteredPass, hashSalt.saltToByte(salt));
    

    you're passing salt getting from database to saltToByte() method to convert into byte array, so I think you're planned to store your salt as a string using return value of generateSalt() method. And reconverting it to byte array using generateHash() method when you need to authenticate a user.

    This is a messy implementation. Recommend you to store your salt as a byte array so you don't need to use saltToByte().

    Additioned to that, your byte keys are different in generateSalt() byte key set to

    var salt = new byte[32];
    

    32-bytekey and in AuthenticateUser() you're using 256-byte key rfc2898DeriveBytes.GetBytes(256)