1

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.

Avishka Dambawinna
  • 1,180
  • 1
  • 13
  • 29
  • Can you show the code where you store the hash into the database? Do you actually store the hash in a column named password? – Martheen Apr 10 '20 at 09:27
  • No, they are in two different columns password(Hashed) and salt – Avishka Dambawinna Apr 10 '20 at 09:43
  • So you don't store the hash when generating the user? – Martheen Apr 10 '20 at 09:46
  • Yes it does. Sorry, I didn't mention it properly in previous comment.(*corrected) – Avishka Dambawinna Apr 10 '20 at 09:49
  • 1
    A little warning: if this is something you plan on going into production with, you **really** need to know what you're doing here - it's easy to make mistakes in your own password encryption/validation implementation. But it's a great exercise for you, if you're just playing around :) I would advise looking for other libraries that can help you with this otherwise. To address your question: in `generateHash()` you create a 32-byte key but in `AuthenticateUser()` you create a 256-byte key. Those will never be the same. Additionally you seem to use a different number of iterations. – Xerillio Apr 10 '20 at 18:56
  • Also from what I can tell, `Rfc2898DeriveBytes` uses [the SHA1 hashing function](https://learn.microsoft.com/en-us/dotnet/api/system.security.cryptography.rfc2898derivebytes.getbytes?view=netframework-4.8) which is no longer a secure enough hashing algorithm in this day and age – Xerillio Apr 10 '20 at 18:58
  • 1
    @Xerillio, thanks for mentioning about **byte key difference** between `generateHash()` and `AuthenticateUser()` I didn't saw that earlier, Btw I was just playing around, but according to my research on internet PBKDF2, Scrypt, Bcrypt all of these functions are pretty much safe given a **proper implementation** and good cost parameters.[here](https://security.stackexchange.com/questions/47183/is-it-safe-to-use-pbkdf2-for-hashing) – Avishka Dambawinna Apr 11 '20 at 05:16
  • @Avishka: Ah, you may be right. I'm no expert on this but I always heard that SHA1 is bad nowadays. However, [it might not be so bad in this implementation](https://security.stackexchange.com/a/93440) – Xerillio Apr 11 '20 at 09:18

1 Answers1

1

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)

Avishka Dambawinna
  • 1,180
  • 1
  • 13
  • 29