Hashing data

There are multiple hash algorithms you can choose from in .NET Core. Some do not use any key, some use symmetric keys, and some use asymmetric keys.

There are two important factors to consider when choosing a hash algorithm:

  • Collision resistance: How rare is it to find two inputs that share the same hash?
  • Preimage resistance: For a hash, how difficult would it be to find another input that shares the same hash?

Here are some common hashing algorithms:

Algorithm

Hash size

Description

MD5

16 bytes

This is commonly used because it is fast, but it is not collision-resistant.

SHA1, SHA256, SHA384, SHA512

20 bytes, 32 bytes, 48 bytes, 64 bytes

These are Secure Hashing Algorithm 2nd generation algorithms (SHA2) with different hash sizes. The use of SHA1s on the Internet has been deprecated since 2011.

Tip

Good Practice

Avoid MD5 and SHA1 because they have known weaknesses. Choose a larger hash size to reduce the possibility of repeated hashes.

Hashing with SHA256

In the Ch11_CryptographyLib class library project, add a new class named User. This will represent a user stored in memory, a file, or a database:

    namespace Packt.CS7 
    { 
      public class User 
      { 
        public string Name { get; set; } 
        public string Salt { get; set; } 
        public string SaltedHashedPassword { get; set; } 
      } 
    } 

Add the following code to the Protector class. We will use a dictionary to store multiple users in memory. There are two methods, one to register a new user and one to validate their password when they subsequently log in:

    private static Dictionary<string, User> Users =  
      new Dictionary<string, User>(); 
 
    public static User Register(string username, string password) 
    { 
      // generate a random salt 
      var rng = RandomNumberGenerator.Create(); 
      var saltBytes = new byte[16]; 
      rng.GetBytes(saltBytes); 
      var saltText = Convert.ToBase64String(saltBytes); 
 
      // generate the salted and hashed password 
      var sha = SHA256.Create(); 
      var saltedPassword = password + saltText; 
      var saltedhashedPassword = Convert.ToBase64String( 
        sha.ComputeHash(Encoding.Unicode.GetBytes(saltedPassword))); 
 
      var user = new User 
      { 
        Name = username, 
        Salt = saltText, 
        SaltedHashedPassword = saltedhashedPassword 
      }; 
      Users.Add(user.Name, user); 
 
      return user; 
    } 
 
    public static bool CheckPassword(string username, string password) 
    { 
      if (!Users.ContainsKey(username)) 
      { 
        return false; 
      } 
      var user = Users[username]; 
 
      // re-generate the salted and hashed password 
      var sha = SHA256.Create(); 
      var saltedPassword = password + user.Salt; 
      var saltedhashedPassword = Convert.ToBase64String( 
        sha.ComputeHash(Encoding.Unicode.GetBytes(saltedPassword))); 
 
      return (saltedhashedPassword == user.SaltedHashedPassword); 
    } 

Add a new console application project named Ch11_HashingApp. Add a reference to the Ch11_CryptographyLib assembly as you did before, and then import the following namespace and type:

    using Packt.CS7; 
    using static System.Console; 

In the Main method, add the following statements to register a user and prompt to register a second user, and then prompt to log in as one of those users and validate the password:

    WriteLine("A user named Alice has been registered with Pa$$w0rd as
    her password."); 
    var alice = Protector.Register("Alice", "Pa$$w0rd"); 
    WriteLine($"Name: {alice.Name}"); 
    WriteLine($"Salt: {alice.Salt}"); 
    WriteLine( 
      $"Salted and hashed password: {alice.SaltedHashedPassword}"); 
    WriteLine(); 
    Write("Enter a different username to register: "); 
    string username = ReadLine(); 
    Write("Enter a password to register: "); 
    string password = ReadLine(); 
    var user = Protector.Register(username, password); 
    WriteLine($"Name: {user.Name}"); 
    WriteLine($"Salt: {user.Salt}"); 
    WriteLine( 
      $"Salted and hashed password: {user.SaltedHashedPassword}"); 
 
    bool correctPassword = false; 
    while (!correctPassword) 
    { 
      Write("Enter a username to log in: "); 
      string loginUsername = ReadLine(); 
      Write("Enter a password to log in: "); 
      string loginPassword = ReadLine(); 
      correctPassword = Protector.CheckPassword( 
        loginUsername, loginPassword); 
         if (correctPassword) 
      { 
        WriteLine( 
          $"Correct! {loginUsername} has been logged in."); 
      } 
      else 
      { 
        WriteLine("Invalid username or password. Try again."); 
      } 
    } 

Note

When using multiple projects in Visual Studio Code, remember to manually restore dependencies by entering the dotnet restore command before entering the dotnet run command.

Run the console application and view the output:

A user named Alice has been registered with Pa$$w0rd as her password.
Name: Alice
Salt: tLn3gRn9DXmp2oeuvBSxTg==
Salted and hashed password:
  w8Ub2aH5NNQ8MJarYsUgm29bbbl0lV/9dlozjWs2Ipk=
Enter a different username to register: Bob
Enter a password to register: Pa$$w0rd
Name: Bob
Salt: zPU9YyFLaz0idhQkKpzY+g==
Salted and hashed password:
  8w14w8WNHoZddEeIx2+UJhpHQqSs4EmyoazqjbmmEz0=
Enter a username to log in: Bob
Enter a password to log in: secret
Invalid username or password. Try again.
Enter a username to log in: Alice
Enter a password to log in: secret
Invalid username or password. Try again.
Enter a username to log in: Bob
Enter a password to log in: Pa$$w0rd
Correct! Bob has been logged in.

Note

Even if two users register with the same password, they have randomly generated salts so that their salted and hashed passwords are different.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.133.142.2