Avatar of Gordon Saxby
Gordon Saxby
Flag for United Kingdom of Great Britain and Northern Ireland asked on

Secure passwords in a ASP.NET 2.0 Custom Membership Provider

I am writing a custom membership provider which gets logon info from a 3rd party database.

I have it working using plain text passwords but I want to secure the passwords - ideally, so that I can retain the "forgot password" feature but if I have to change it to "reset password" functionality then I could.

Basically, I just need a clear explanation of how I go about encrypting or hashing the password when it is first created and how to validate a user logon. Also, how to retrieve or reset the password, depending on which method is used (encrypt or hash?)
ASP.NETC#

Avatar of undefined
Last Comment
Gordon Saxby

8/22/2022 - Mon
ASKER CERTIFIED SOLUTION
urir10

Log in or sign up to see answer
Become an EE member today7-DAY FREE TRIAL
Members can start a 7-Day Free trial then enjoy unlimited access to the platform
Sign up - Free for 7 days
or
Learn why we charge membership fees
We get it - no one likes a content blocker. Take one extra minute and find out why we block content.
Not exactly the question you had in mind?
Sign up for an EE membership and get your own personalized solution. With an EE membership, you can ask unlimited troubleshooting, research, or opinion questions.
ask a question
Mahone7

ok when your user sign up you should has the password using hash algorithms, recommend SHA-256 using this code

public static String HashPassword(String Pass)
    {
        System.Security.Cryptography.SHA256Cng sha = new System.Security.Cryptography.SHA256Cng();
        UnicodeEncoding uniEnc = new UnicodeEncoding();
        Byte[] hashedPassword = sha.ComputeHash(uniEnc.GetBytes(Pass));
        String password = "";
        foreach (Byte item in hashedPassword)
        {
            password += String.Format("{0:x2}", item);

        }
        //End of Computation
        return password;
    }

then after hashing the password store it in the database insted of the clear password

and each time your user login you should hash the entered password by the user and compare it by the hashed password that you stored it in the database.


check this http://www.codeproject.com/KB/recipes/StoringPasswords.aspx for more info
jorge_toriz

Well with hash the user won't be able to retrieve the current password because hash is one-way encryption, if you want to give them the retrieve current password possibility, you could use this utility to encrypt and decrypt your passwords with a symmetric method.
public class Symetric
{
    public static string Encrypt(string plainText, string passPhrase, string saltValue, string hashAlgorithm, int passwordIterations, string initVector, int keySize)
    {
        byte[] initVectorBytes = Encoding.ASCII.GetBytes(initVector);
        byte[] saltValueBytes = Encoding.ASCII.GetBytes(saltValue);
        byte[] plainTextBytes = Encoding.UTF8.GetBytes(plainText);

        PasswordDeriveBytes password = new PasswordDeriveBytes(passPhrase, saltValueBytes, hashAlgorithm, passwordIterations);

        byte[] keyBytes = password.GetBytes(keySize / 8);

        RijndaelManaged symmetricKey = new RijndaelManaged();
        ICryptoTransform encryptor = symmetricKey.CreateEncryptor(keyBytes, initVectorBytes);
        MemoryStream memoryStream = new MemoryStream();
        CryptoStream cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write);

        cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length);
        cryptoStream.FlushFinalBlock();

        byte[] cipherTextBytes = memoryStream.ToArray();

        memoryStream.Close();
        memoryStream.Dispose();
        cryptoStream.Close();
        cryptoStream.Dispose();
        string cipherText = Convert.ToBase64String(cipherTextBytes);

        return cipherText;
    }
    public static string Decrypt(string cipherText, string passPhrase, string saltValue, string hashAlgorithm, int passwordIterations, string initVector, int keySize)
    {
        byte[] initVectorBytes = Encoding.ASCII.GetBytes(initVector);
        byte[] saltValueBytes = Encoding.ASCII.GetBytes(saltValue);
        byte[] cipherTextBytes = Convert.FromBase64String(cipherText);

        PasswordDeriveBytes password = new PasswordDeriveBytes(passPhrase, saltValueBytes, hashAlgorithm, passwordIterations);

        byte[] keyBytes = password.GetBytes(keySize / 8);

        RijndaelManaged symmetricKey = new RijndaelManaged();
        ICryptoTransform decryptor = symmetricKey.CreateDecryptor(keyBytes, initVectorBytes);
        MemoryStream memoryStream = new MemoryStream(cipherTextBytes);
        CryptoStream cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read);

        byte[] plainTextBytes = new byte[cipherTextBytes.Length];
        int decryptedByteCount = cryptoStream.Read(plainTextBytes, 0, plainTextBytes.Length);

        memoryStream.Close();
        memoryStream.Dispose();
        cryptoStream.Close();
        cryptoStream.Dispose();
        string plainText = Encoding.UTF8.GetString(plainTextBytes, 0, decryptedByteCount);

        return plainText;
    }
}

Open in new window

algen

You will want to invoke some cryptographic measures as others have described. Specifically you should be looking at a cryptographic hash algorithm such as SHA-256. You can find an article about both cryptographic hash functions and specifically SHA-256 on Wikipedia.

One thing you will want to make sure to prevent against is dictionary attacks, you can do this by creating a unique salt value for each password. Make sure that the salts are generated using a cryptographically secure random number generator.

http://en.wikipedia.org/wiki/Cryptographic_hash_function
http://en.wikipedia.org/wiki/Sha256#SHA-2_family
http://en.wikipedia.org/wiki/Cryptographic_salt
http://en.wikipedia.org/wiki/CSPRNG

If you are paranoid as well, you can resist against brute force attacks and length extension attacks by using HMAC on top of SHA-256.

http://en.wikipedia.org/wiki/HMAC

Enjoy.
This is the best money I have ever spent. I cannot not tell you how many times these folks have saved my bacon. I learn so much from the contributors.
rwheeler23
Gordon Saxby

ASKER
After reading more about this, it seems that the best solution is the one-way hash. If the user forgets their password, issue them a new one.

Mahone7 - your solution looks very simple to implement, but I can't quite figure out (yet ... still looking!) whether there is "salting" involved!

urir10 - the example on the page you linked to looks good as well, although it is built to handle multiple options which I wouldn't need. It seems as though you do not need to store the salt value as the routine "VerifyHash" works out what the salt value was ... am I reading that right?
Mahone7

the first solution dose not use salt in the implementation " this is simple one way hashing" and its enough for small to mid size web application you don't need to  Add Salt to your plain text password but any way check this for more info : http://www.obviex.com/samples/hash.aspx you may need use salt

this is modified version that use salt

public static String HashPassword(String Pass,String Salt)
    {
        System.Security.Cryptography.SHA256Cng sha = new System.Security.Cryptography.SHA256Cng();
        UnicodeEncoding uniEnc = new UnicodeEncoding();
        Byte[] hashedPassword = sha.ComputeHash(uniEnc.GetBytes(Pass) + uniEnc.GetBytes(Salt));
        String password = "";
        foreach (Byte item in hashedPassword)
        {
            password += String.Format("{0:x2}", item);

        }
        //End of Computation
        return password;
    }
SOLUTION
Mahone7

Log in or sign up to see answer
Become an EE member today7-DAY FREE TRIAL
Members can start a 7-Day Free trial then enjoy unlimited access to the platform
Sign up - Free for 7 days
or
Learn why we charge membership fees
We get it - no one likes a content blocker. Take one extra minute and find out why we block content.
Not exactly the question you had in mind?
Sign up for an EE membership and get your own personalized solution. With an EE membership, you can ask unlimited troubleshooting, research, or opinion questions.
ask a question
urir10

Im not exactly sure 100% what VerifyHash does, but there is no way to decrypt the hashed value. The salt is only an additional security, you can go fine without it.
Get an unlimited membership to EE for less than $4 a week.
Unlimited question asking, solutions, articles and more.
Gordon Saxby

ASKER
urir10 first gave the link to a useable solution. Mahone7 provided another solution which I used in combination to produce my required solution.