Passwords should never be stored as plain text! They should be hashed with a randomly generated salt (to defend against rainbow table attacks) using a slow password hashing algorithm. A high number of iterations (> 10k) can be used to slow down brute force attacks. A delay of ~100ms is acceptable to a user logging in, but makes breaking a long password difficult. When choosing a number of iterations you should use the maximum tolerable value for your application and increase it as computer performance improves. You will also need to consider stopping repeated requests which could be used as a DoS attack.
When hashing for the first time a salt can be generated for you, the resulting hash and salt can then be stored to a file.
private void firstHash(string userName, string userPassword, int numberOfItterations)
{
Rfc2898DeriveBytes PBKDF2 = new Rfc2898DeriveBytes(userPassword, 8, numberOfItterations); //Hash the password with a 8 byte salt
byte[] hashedPassword = PBKDF2.GetBytes(20); //Returns a 20 byte hash
byte[] salt = PBKDF2.Salt;
writeHashToFile(userName, hashedPassword, salt, numberOfItterations); //Store the hashed password with the salt and number of itterations to check against future password entries
}
Checking an existing users password, read their hash and salt from a file and compare to the hash of the entered password
private bool checkPassword(string userName, string userPassword, int numberOfItterations)
{
byte[] usersHash = getUserHashFromFile(userName);
byte[] userSalt = getUserSaltFromFile(userName);
Rfc2898DeriveBytes PBKDF2 = new Rfc2898DeriveBytes(userPassword, userSalt, numberOfItterations); //Hash the password with the users salt
byte[] hashedPassword = PBKDF2.GetBytes(20); //Returns a 20 byte hash
bool passwordsMach = comparePasswords(usersHash, hashedPassword); //Compares byte arrays
return passwordsMach;
}