gymcode
gymcode

Reputation: 4623

Changing Storage of Password to Storing of Hashes in C# Forms

My current project is using Microsoft's Membership to manage user's credentials.

For now, it stores passwords into SQL DB in plain-text.

I want to change it store hashes instead, or to encrypt/hide password column.


Current code:

protected void BtnSubmit_Click(object sender, EventArgs e)
    {
        Page.Validate();

        if (Page.IsValid)
        {
            NAME_OF_TABLE_Provider provider = new NAME_OF_TABLE_Provider();

            string userName = SPContext.Current.Web.CurrentUser.Name;
            MembershipUserCollection userMembership = Membership.GetAllUsers();

            MembershipUser membershipUser = userMembership[userName];

            if (membershipUser != null)
            {
                try
                {
                    membershipUser.ChangePassword(OldPassword.Text, NewPassword.Text);
                    ConfirmPanel.Visible = true;
                    InvalidPanel.Visible = false;
                    Message.InnerText = "The password is changed successfully";
                }
                catch (Exception ex)
                {
                    ConfirmPanel.Visible = false;
                    InvalidPanel.Visible = true;
                    InvalidPassword.InnerText = "The password is not strong. Please verify.";
                }
            }
        }
    }

#1 Possible(?) Solution: HashBytes

INSERT INTO <tbl> (..., passwd) values (...., HashBytes('SHA1', @password))

SELECT HashBytes('SHA1', @password);

#2 Possible(?) Solution: C# Storing of Hashes

    static void Main(string[] args)
    {
        //Store a password hash:
        PasswordHash hash = new PasswordHash("password");
        byte[] hashBytes = hash.ToArray();
        //For testing purposes
        Console.WriteLine(Convert.ToBase64String(hashBytes));

        //Check password against a stored hash
        byte[] hashBytes2 = hashBytes;//read from store.
        PasswordHash hash2 = new PasswordHash(hashBytes2);

        if (!hash.Verify("password"))
        {
            throw new System.UnauthorizedAccessException();
        }
        else
        {
            Console.WriteLine("True");
        }
        Console.ReadLine();
    }

    }

    public sealed class PasswordHash
    {
        const int SaltSize = 16, HashSize = 20, HashIter = 10000;
        readonly byte[] _salt, _hash;
        public PasswordHash(string password)
        {
            new RNGCryptoServiceProvider().GetBytes(_salt = new byte[SaltSize]);
            _hash = new Rfc2898DeriveBytes(password, _salt, HashIter).GetBytes(HashSize);
        }
        public PasswordHash(byte[] hashBytes)
        {
            Array.Copy(hashBytes, 0, _salt = new byte[SaltSize], 0, SaltSize);
            Array.Copy(hashBytes, SaltSize, _hash = new byte[HashSize], 0, HashSize);
        }
        public PasswordHash(byte[] salt, byte[] hash)
        {
            Array.Copy(salt, 0, _salt = new byte[SaltSize], 0, SaltSize);
            Array.Copy(hash, 0, _hash = new byte[HashSize], 0, HashSize);
        }
        public byte[] ToArray()
        {
            byte[] hashBytes = new byte[SaltSize + HashSize];
            Array.Copy(_salt, 0, hashBytes, 0, SaltSize);
            Array.Copy(_hash, 0, hashBytes, SaltSize, HashSize);
            return hashBytes;
        }
        public byte[] Salt { get { return (byte[])_salt.Clone(); } }
        public byte[] Hash { get { return (byte[])_hash.Clone(); } }
        public bool Verify(string password)
        {
            byte[] test = new Rfc2898DeriveBytes(password, _salt, HashIter).GetBytes(HashSize);
            for (int i = 0; i < HashSize; i++)
                if (test[i] != _hash[i])
                    return false;
            return true;
        }

#3 Possible(?) Solution: Transact-SQL to encrypt single column

https://learn.microsoft.com/en-us/sql/relational-databases/security/encryption/encrypt-a-column-of-data?view=sql-server-2017#TsqlProcedure


May I know what is the correct approach? Thank you.

Upvotes: 2

Views: 76

Answers (1)

nvoigt
nvoigt

Reputation: 77285

It goes without saying that any solution is better than the current one.

  • The first solution looks solid, but I could not find out if a salt is used. If not, that's a disadvantage. You also are now dependent on this database vendor and cannot switch.

  • The second solution looks good, but I didn't look too closely, you should probably head over to CodeReview, they do reviews of working code to look for improvements.

  • The last solution is not really a solution. Passwords are hashed not exncrypted for a reason. If you can decrypt them, the attacker who gets access to the system and steals them will have the same access to the decryption means as you do. So it's a layer of inconvenience, not security.

So pick number two and let somebody look over it for weaknesses or bugs.

Upvotes: 1

Related Questions