Skip to main content

Insecure encryption algorithm - MD5

Need

Implementation of secure encryption algorithms for password hashing

Context

  • Usage of C# for building robust and efficient applications
  • Usage of System for accessing and manipulating system-level functionality
  • Usage of System.Security.Cryptography for secure data encryption and decryption
  • Usage of System.Text for string manipulation and encoding

Description

Non compliant code

using System;
using System.Security.Cryptography;
using System.Text;

public class PasswordHashing
{
public static string HashPassword(string password)
{
using (MD5 md5 = MD5.Create())
{
byte[] inputBytes = Encoding.ASCII.GetBytes(password);
byte[] hashBytes = md5.ComputeHash(inputBytes);

StringBuilder sb = new StringBuilder();
for (int i = 0; i < hashBytes.Length; i++)
{
sb.Append(hashBytes[i].ToString("X2"));
}
return sb.ToString();
}
}
}

The above code snippet is a simple implementation of password hashing in a C# ASP.NET Core backend application. The HashPassword function takes a plain text password as an argument and returns a hashed version of the password.

The vulnerability lies in the use of the MD5 hash function, which is considered insecure for password hashing. The MD5 hash function is a widely used cryptographic hash function that produces a 128-bit (16-byte) hash value, and it is commonly used to verify data integrity. However, MD5 is not suitable for further security-related purposes such as SSL certificates or encryption of passwords due to its vulnerabilities.

MD5 is considered to be weak due to its vulnerability to collision attacks, where different inputs produce the same hash output. This makes it possible for an attacker to create a different password that produces the same hash as the user's actual password, effectively bypassing the password check.

In the code, the MD5.Create() method is used to create an instance of the MD5 class. The password is then converted to a byte array using the Encoding.ASCII.GetBytes() method. The md5.ComputeHash() method is then used to compute the hash of the password. The resulting hash byte array is then converted to a hexadecimal string and returned.

Steps

  • Replace the use of MD5 algorithm with a stronger and more secure hashing algorithm such as bcrypt or Argon2.
  • Update the code to use a salt when hashing passwords to add an extra layer of security.
  • Ensure that the salt used for hashing passwords is unique for each user.
  • Implement a secure password storage mechanism such as using a dedicated password hashing library or framework.
  • Regularly update the hashing algorithm and security practices to stay up-to-date with the latest security standards.

Compliant code

using System;
using System.Security.Cryptography;
using System.Text;
using Microsoft.AspNetCore.Cryptography.KeyDerivation;

public class PasswordHashing
{
public static string HashPassword(string password, string salt)
{
byte[] saltBytes = Encoding.ASCII.GetBytes(salt);
byte[] hashed = KeyDerivation.Pbkdf2(
password: password,
salt: saltBytes,
prf: KeyDerivationPrf.HMACSHA256,
iterationCount: 10000,
numBytesRequested: 256 / 8);

return Convert.ToBase64String(hashed);
}
}

The updated code replaces the insecure MD5 hashing algorithm with the more secure PBKDF2 (Password-Based Key Derivation Function 2) algorithm, which is a standard cryptographic function for deriving a cryptographic key from a password.

The KeyDerivation.Pbkdf2 method is used to hash the password. This method takes several parameters:

  • password: The password to hash.
  • salt: A salt value. This should be a unique value for each user. The salt is used to prevent pre-computed dictionary attacks (rainbow tables).
  • prf: A pseudorandom function of two parameters with output length in bytes. Here we use KeyDerivationPrf.HMACSHA256, which uses HMAC-SHA256.
  • iterationCount: The number of iterations. A higher number of iterations adds more security but also adds more processing time. Here we use 10,000 iterations, which is a common value.
  • numBytesRequested: The desired length of the derived key in bytes. Here we request a 256-bit key.

The hashed password is then converted to a string using Convert.ToBase64String.

This code provides a more secure way of hashing passwords compared to the original code. However, it's important to note that security is a constantly evolving field, and it's necessary to stay up-to-date with the latest security standards and practices.

References