Hash and Salt Passwords in C#

Hash and salt passwords in C#

Actually this is kind of strange, with the string conversions - which the membership provider does to put them into config files. Hashes and salts are binary blobs, you don't need to convert them to strings unless you want to put them into text files.

In my book, Beginning ASP.NET Security, (oh finally, an excuse to pimp the book) I do the following

static byte[] GenerateSaltedHash(byte[] plainText, byte[] salt)
{
HashAlgorithm algorithm = new SHA256Managed();

byte[] plainTextWithSaltBytes =
new byte[plainText.Length + salt.Length];

for (int i = 0; i < plainText.Length; i++)
{
plainTextWithSaltBytes[i] = plainText[i];
}
for (int i = 0; i < salt.Length; i++)
{
plainTextWithSaltBytes[plainText.Length + i] = salt[i];
}

return algorithm.ComputeHash(plainTextWithSaltBytes);
}

The salt generation is as the example in the question. You can convert text to byte arrays using Encoding.UTF8.GetBytes(string). If you must convert a hash to its string representation you can use Convert.ToBase64String and Convert.FromBase64String to convert it back.

You should note that you cannot use the equality operator on byte arrays, it checks references and so you should simply loop through both arrays checking each byte thus

public static bool CompareByteArrays(byte[] array1, byte[] array2)
{
if (array1.Length != array2.Length)
{
return false;
}

for (int i = 0; i < array1.Length; i++)
{
if (array1[i] != array2[i])
{
return false;
}
}

return true;
}

Always use a new salt per password. Salts do not have to be kept secret and can be stored alongside the hash itself.

How to validate salted and hashed password in c#

Create an column in your user table Username and Hash and Salt

User Register

1) Take input username or password from user in your registration form.

2) Create Hash and Salt for input password with below method.

public class HashSalt
{
public string Hash { get; set; }
public string Salt { get; set; }
}

public static HashSalt GenerateSaltedHash(int size, string password)
{
var saltBytes = new byte[size];
var provider = new RNGCryptoServiceProvider();
provider.GetNonZeroBytes(saltBytes);
var salt = Convert.ToBase64String(saltBytes);

var rfc2898DeriveBytes = new Rfc2898DeriveBytes(password, saltBytes, 10000);
var hashPassword = Convert.ToBase64String(rfc2898DeriveBytes.GetBytes(256));

HashSalt hashSalt = new HashSalt { Hash = hashPassword, Salt = salt };
return hashSalt;
}

Rfc2898DeriveBytes class is used to generate the hash using the RFC2898 specification, which uses a method known as PBKDF2 (Password Based Key Derivation Function #2) and is currently recommend by the IETF (Internet Engineering Task Force) for new applications.

3) Then stored this Hash and Salt with user record in database.

public void Submit1_click(object sender, EventArgs r)
{
//Your code here

HashSalt hashSalt = GenerateSaltedHash(64, password1.Text);

//Your code here

cmd.Parameters.AddWithValue("@hash", hashSalt.Hash);
cmd.Parameters.AddWithValue("@salt", hashSalt.Salt);

//You code here
}

User Login

1) Take input username or password from user in your login form.

2) In Login_click get user by username from database.

3) Pass stored Hash and Salt to below function.

public static bool VerifyPassword(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;
}

4) Then login your user by verifying his/her password.

public void Login_click(object sender, EventArgs r)
{
//You code here

User user = GetUserByUsername(txtUsername.Text);

bool isPasswordMatched = VerifyPassword(txtpassword.Text, user.Hash, user.Salt);

if (isPasswordMatched)
{
//Login Successfull
}
else
{
//Login Failed
}

//Your code here
}

Reference: Effective Password Hashing

Hashing a password with pepper and salt in C# using Rfc2898DeriveBytes

PBKDF2 (with SHA-1) - which the terribly named Rfc2898DeriveBytes implements - uses a repeated HMAC with the password - encoded to bytes - as key. Generally, HMAC simply performs a padding method on the input key (ipad and opad if you want to look it up). This padding goes up to the input block size of the hash function. However, let's look at the definition of HMAC in the HMAC RFC:

We denote by B the byte-length of such
blocks (B=64 for all the above mentioned examples of hash functions),
and by L the byte-length of hash outputs (L=16 for MD5, L=20 for
SHA-1). The authentication key K can be of any length up to B, the
block length of the hash function. Applications that use keys longer
than B bytes will first hash the key using H and then use the
resultant L byte string as the actual key to HMAC.

In your case, if your encoded password is longer than 64 - 16 = 48 bytes (with 16 the pepper size) your HMAC may be slower. A smart PBKDF2 function however could detect this and work around the issue by performing the initial hashing part only once.

So if your password is over 48 byte then you could give some benefit to the attacker if:

  1. your implementation isn't that smart and
  2. the implementation of the attacker is smart.

Note that the hash output size has nothing to do with this. You could use PBKDF2 with SHA-512 - with a block size of 1024 bits rather than 512 bits for SHA-1 and SHA-256 - in case this is a problem.

The hash output size of the hash function within PBKDF2 (SHA-1 by default) does matter if you request more than the output size of bytes. In that case you are also handing back advantage to an attacker. Fortunately you're only asking for 16 bytes in hashSize (a variable name that you might want to change to passwordHashSize to avoid confusion).


I understand that:

Oh dear ;)

  • A hash isn't reversible.

A cryptographic hash function and password hash function isn't reversible, other hash functions may be reversible.

  • A salt and pepper are added to increase security and prevent rainbow table attacks.

You only require a salt for that. A pepper prevents an attacker from guessing the password altogether, if it can be kept safe and if it is strong enough.

  • A salt is a unique and random string, it doesn't have to be secret and can be stored alongside the hash in a database.

That's correct.

  • A pepper is not unique and it is used for every hash. It is a secret and it isn't stored in the database.

Or it is encrypted itself and stored in the database, but yeah, in the end it needs to be secured one way or the other.

  • At least a 128-bit (16 bytes > 16 characters) should be used for the salt and pepper.

Well, it's kind-of the upper limit, I'd say 64 to 128 fully random bits, preferably over 80. However, not every character can be mapped to a byte, so your pepper is unlikely to be fully random - a bad idea for something that is basically a secret key.

Note that the salt configuration option of PBKDF2 may be any size up to 64 - 8 - 4 = 52 bytes before another block encrypt is needed for SHA-1. For that reason the salt & pepper are usually concatenated. This will also allow you use a true random pepper. It leaves more characters (64) for the password as well that way.

  • At least 10.000 iterations should be used for the algorithm.

Commonly we recommend about a million nowadays. But really, any amount of CPU cycles you can spare makes it harder to an adversary. The point is bit moot if the adversary really cannot get to the pepper of course. In that case a single round is enough - but you may want to use a higher iteration count as a second line of defense (e.g. against sysadmins trying to get to passwords of your users, using a copy of the database).

Secure password hashing with salt, but what about storing it in local cookies?

You don't want to store a hashed password in cookies, because that would be the same thing as storing the password itself in cookies. If the hash is all you need to login, then it is the password. The reason you want to hash your user's password with random salt is not to secure the logon process, but to secure your password table. If an attacker steals your password table, and each password is not hashed with unique salt, it will be easy for him/her to figure out many of the passwords. Always hash your user's password with a unique salt. It's fine to store this salt with the hashed password. If you want a secure way to use hashes to authenticate your user based on data in cookies, you will need to go in the direction of temporary credentials or sessions. the simplest I can think of is something like the following:

  1. When your user logs in with his password, create a 'Session'. Assign a value to uniquely identify this session, store the time (to the millisecond) the session was created, and create a random value as salt.

  2. Hash the session's id with the salt. Save this hash and the session id in user's cookies.

  3. Each time a page is requested perform the hash again and compare it with the value stored in the user's cookies. If the values match and too much time hasn't passed since the session was created, your user can view the page. Otherwise send them to login again with their password.

How to hash and add salt to password from csv C#

Assuming a bulk insert via SQL is not a requirement:

Since you're using ASP.NET, use the Crypto class to hash your passwords:

var hashedPassword = Crypto.HashPassword(plainTextPassword);

When you want to verify the plain text version later, use

bool matches = Crypto.VerifyHashedPassword(hashedPassword, plainTextPassword);

The hashed password contains the salt used when hashing, and Crypto knows how to extract the salt from the password hash.

Since you have a stream to read from:

using(var reader = new StreamReader(fileStream))
{
using (DB01Entities dbc = new DB01Entities())
{
while(reader.Peek != -1)
{
var parts = reader.ReadLine().Split(',');
var hashedPassword = Crypto.HashPassword(parts[1]);
dbc.Employees.Add(new Employee { Name = parts[0], Password = hashedPassword });
}

dbc.SaveChanges();
}
}

This also has the advantage of not requiring the file to be saved anywhere, as you can just use the bytes you already have in memory.

How to convert C# password hashing with salt to python for windows

They don't start out the same.

If you add some prints to the C#

    protected static string CreateSHA512Hash(string Password, string Salt)
{
try
{
byte[] bytes_password = Encoding.UTF8.GetBytes(Password);
byte[] bytes_salt = Encoding.UTF8.GetBytes(Salt);
HashAlgorithm sha512hash = (HashAlgorithm)new SHA512CryptoServiceProvider();
for (int index = 0; index < 1000; ++index)
{
if (index < 10)
Console.WriteLine(Convert.ToBase64String(bytes_password));

byte[] bytes_iteration = Encoding.UTF8.GetBytes(Convert.ToBase64String(bytes_password) + Convert.ToBase64String(bytes_salt));
bytes_password = sha512hash.ComputeHash(bytes_iteration);
}
Console.WriteLine("...");
return Convert.ToBase64String(bytes_password);
}
catch (Exception ex)
{
return "Exception" + ex.Message;
}
}

Here's my python port of the same code, with the same debug prints, so you can compare the first 10 values.

import hashlib
from base64 import b64encode

password = "Pass@21"
salt = "SALT(}"

bytes_password = password.encode('utf-8')
bytes_salt = salt.encode('utf-8')
for i in range(1000):
if i < 10:
print(b64encode(bytes_password).decode())

b64pw = b64encode(bytes_password).decode()
b64sa = b64encode(bytes_salt).decode()
bytes_iteration = (b64pw + b64sa).encode('utf-8')

bytes_password = hashlib.sha512(bytes_iteration).digest()

print('...')
print(b64encode(bytes_password).decode())

Your original code wasn't consistent on when it hex encoded and when it computed the hash, and it computed a hash prior to entering the loop.

How to salt and hash a password value using c#?

The most popular way to do this is using a hashing algorithm. There's an excellent blog post here about how to use the MD5 algorithm to hash a string, but there are many other examples in the System.Cryptography namespace.

As for #2, the general step-by-step guide to how this would work would be the following:

On registration:

  1. Hash a user's password using your specified algorithm and store it in the database
  2. Salt this hash (optional, but preferred)

On login / user & password check:

  1. Look up in the database for the username
  2. If it exists, retrieve the hashed password
  3. Hash and salt the entered password and compare it to the retrieved password

It's all relatively long-winded, but it's very secure.

There's another extremely in-depth guide on hashing and salting here.



Related Topics



Leave a reply



Submit