Reputation: 195
I am new to C# and this is my first question here so I apologize in advance for any faux pas.
Context:
When a user registers I call the CreateSaltedHash() method and pass it the user inputted password from the text field. This method salts and hashes the password before storing it in the Password column of my User table.
Question:
How should I validate the password when a user tries to log in?
If I call the CreateSaltedHash() method again it will not match because of the random salt.
Should I be storing the salts in a separate column? Should I be using a delimiter when generating the salted hash? What is the most secure way of validating the input password against the salted and hashed password?
Code: This is what I have so far.
public class PasswordHash
{
public const int SALT_BYTES = 32;
/*
* Method to create a salted hash
*/
public static byte[] CreateSaltedHash(string password)
{
RNGCryptoServiceProvider randromNumberGenerator = new RNGCryptoServiceProvider();
byte[] salt = new byte[SALT_BYTES];
randromNumberGenerator.GetBytes(salt);
HashAlgorithm hashAlgorithm = new SHA256Managed();
byte[] passwordByteArray = Encoding.UTF8.GetBytes(password);
byte[] passwordAndSalt = new byte[passwordByteArray.Length + SALT_BYTES];
for (int i = 0; i < passwordByteArray.Length; i++)
{
passwordAndSalt[i] = passwordByteArray[i];
}
for (int i = 0; i < salt.Length; i++)
{
passwordAndSalt[passwordByteArray.Length + i] = salt[i];
}
return hashAlgorithm.ComputeHash(passwordAndSalt);
}
public static bool OkPassword(string password)
{
//This is where I want to validate the password before logging in.
}
}
Calling the method in the Register class.
User user= new User();
user.password = PasswordHash.CreateSaltedHash(TextBoxUserPassword.Text);
Upvotes: 9
Views: 5862
Reputation: 413
I Suggest you to use SaltedHash of ServiceStack which you can install it from your Nuget.
Simply Enter Install-Package ServiceStack
in your Nuget Console, then you'll be able to use the following imports in your code.
using ServiceStack.ServiceInterface.Auth;
And then you would generate your salt and hash so much easier and absolutely faster than before. Just enter the following codes:
class Security
{
...
public void generate(string Password)
{
string hash, salt;
new SaltedHash().GetHashAndSaltString(Password,out hash,out salt);
//Store the hash and salt
}
...
}
And yes, You must store the hash and salt to be able to run your OkPassword Method.
public bool OkPassword(string Password)
{
var hash = //getStoredHash
var salt = //getStoredSalt
bool verify = new SaltedHash().VerifyHashString(Password, hash , salt);
return verify ;
}
Upvotes: 2
Reputation: 704
You should save the digest and salt. The iterations and digestLength values can be constants in your application.
byte[] getNewSalt(Int32 size)
{
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
byte[] salt = new byte[size];
rng.GetBytes(salt);
return salt;
}
byte[] getPasswordDigest(byte[] value, byte[] salt, Int32 iterations, Int32 digestLength)
{
Rfc2898DeriveBytes deriveBytes = new Rfc2898DeriveBytes(value, salt, iterations);
return deriveBytes.GetBytes(digestLength);
}
Recent articles suggest that to further secure passwords, you can split up the password into parts, hash the individual parts, then store them in separate tables in the DB.
Upvotes: 0
Reputation: 9639
You could use Bcrypt.Net; it has a lot of recommendations for being really secure, plus it is very easy to use. As I understand it, when you create the password it automatically generates a unique salt for you, which is then stored in the hashed password string; so you do not store the salt separately, but in the same field as the hashed password. The point is each password has it own salt, which makes it much more difficult (time consuming) for a hacker to crack multiple passwords. The algorithm Bcrypt uses is also CPU intensive, so it requires a lot of computational power (=money) to crack.
Jeff Atwood (stackoverflow moderator) recommends Bcrypt.
Upvotes: 3
Reputation: 5070
As the other answers states; yes you should store the salt or derive it from for example the username.
You should also use Rfc2898DeriveBytes
to make it more secure.
Here is a good article on that topic: Password salt and hashing in C#
Upvotes: 1
Reputation: 1027
Because you are generating a random salt you would need to store the salt on the database. The problem with that is that if your database becomes compromised, the attacker will have the salt and the hashed password, so they can more easily determine the real password. Ideally you should have a static salt in your code so that if your database is compromised they still don't have the salt and if your code is compromised, they don't have the database just yet.
Another solution could be to use pepper. Pepper is similar to salt but you don't store it the database with the salt and hashed password. It would be stored in the code. This way you have a random salt that is generated and a constant which is stored separate. To make the pepper more random, you could create a sub-string of a larger string that you are using for a pepper which is offset based on some variable, such as the user id. This again is an internal thing that an attack would not know of if they managed to get your data.
Upvotes: 0
Reputation: 3914
And for the longer answer -
The has should be random with every password created. This will make it unique in itself. Due to this 'randomness', you will almost never be able to programatically find the hash associated to the file.
The way you encrypted the password (without the hash) should be the same, so using a reverse of this method will be sufficient every time.
PS: (A more secure way o validating) You can either reverse the encrypted password to its original [Hard], or encrypt the validating password with the hash, and make sure that encrypted password matches that stored in the DB [Preferred].
So, you will need to store the encrypted password, as well as the hash associated to it, in the database.
This will be the way to gather all the information needed to validate the password.
Upvotes: 0
Reputation: 12596
You can either store the salt, or use the same salt every time. I recommend storing the salt as it is more secure than using the same salt across all users.
Most of my tables have a column with the date time of when the row was created. I use the Ticks property of the DateTime
struct of this value to salt the hash, but you can use anything you like, as long as you use the same salt for the user each time. One thing to watch out for is if you use this method, and you are using the SQL type DateTime (and not DateTime2), then there is a precision issue. If you create the DateTime
in code, you will need to truncate it (I believe to hundredths of a second).
Upvotes: 0
Reputation: 6248
You will have to store the salt along with the hash.
Refer to this article to get some background information: http://www.h-online.com/security/features/Storing-passwords-in-uncrackable-form-1255576.html
Upvotes: 1
Reputation: 50104
Should I be storing the salts in a separate column?
Yes.
Should I be using a delimiter when generating the salted hash?
Not necessary, but it also won't hurt as long as you include the same delimiter when validating.
What is the most secure way of validating the input password against the salted and hashed password?
SHA512, SHA-2 or -3 would be more secure than SHA256, but do you need that much more security?
Upvotes: 0
Reputation: 13844
When you first generate the hash, you need to store both the salt and the final hash - then re-use that same salt for future comparisons.
So you'd change your CreateSaltedHash
method to take a password and a salt, and write a new CreateSalt
method to generate the salt when a password is created/changed which is stored alongside the final hash.
Upvotes: 2