Skip to content

Instantly share code, notes, and snippets.

@Gummiees
Last active October 28, 2020 12:51
Show Gist options
  • Save Gummiees/a8dffcd76b310945a984b75c700e3a61 to your computer and use it in GitHub Desktop.
Save Gummiees/a8dffcd76b310945a984b75c700e3a61 to your computer and use it in GitHub Desktop.
Secure encryption and password verification for C#
using System;
using System.Security.Cryptography;
public class Program
{
/**
* You can try this code at https://dotnetfiddle.net/ZkY1HV
*/
private const int SALT_LENGTH = 16;
private const int HASH_LENGTH = 32;
private const int ITERATIONS = 1000;
// https://stackoverflow.com/questions/4181198/how-to-hash-a-password/10402129#10402129
public static void Main()
{
string password = "Test!123";
string wrongPassword = "t3st$124";
string encrypted = Encrypt(password);
string wrongEncrypted = Encrypt(wrongPassword);
Console.WriteLine($"Password encrypted: {encrypted}");
Console.WriteLine($"Wrong password encrypted: {wrongEncrypted}");
// This one will work since it's the same password.
Login(encrypted, password);
// This one won't because the password is different.
Login(encrypted, wrongPassword);
}
public static bool Login(string encryptedPassword, string password)
{
try
{
bool correctPassword = VerifyPassword(encryptedPassword, password);
Console.WriteLine($"Password {password} is correct! Successfully logged in.");
return true;
}
catch (UnauthorizedAccessException)
{
Console.WriteLine($"Password {password} is incorrect! Try again.");
}
return false;
}
public static string Encrypt(string password)
{
// STEP 1 Create the salt value with a cryptographic PRNG
byte[] salt = new byte[SALT_LENGTH];
new RNGCryptoServiceProvider().GetBytes(salt);
// STEP 2 Create the Rfc2898DeriveBytes and get the hash value
using (Rfc2898DeriveBytes pbkdf2 = new Rfc2898DeriveBytes(password, salt, ITERATIONS, HashAlgorithmName.SHA256))
{
byte[] hash = pbkdf2.GetBytes(HASH_LENGTH);
// STEP 3 Combine the salt and password bytes for later use
byte[] hashBytes = new byte[SALT_LENGTH + HASH_LENGTH];
Array.Copy(salt, 0, hashBytes, 0, SALT_LENGTH);
Array.Copy(hash, 0, hashBytes, SALT_LENGTH, HASH_LENGTH);
// STEP 4 Turn the combined salt+hash into a string for storage
string savedPasswordHash = Convert.ToBase64String(hashBytes);
return savedPasswordHash;
}
}
public static void VerifyPassword(string savedPasswordHash, string password)
{
// Verify the user-entered password against a stored password
/* Extract the bytes */
byte[] hashBytes = Convert.FromBase64String(savedPasswordHash);
/* Get the salt */
byte[] salt = new byte[SALT_LENGTH];
Array.Copy(hashBytes, 0, salt, 0, SALT_LENGTH);
/* Compute the hash on the password the user entered */
using (Rfc2898DeriveBytes pbkdf2 = new Rfc2898DeriveBytes(password, salt, ITERATIONS, HashAlgorithmName.SHA256))
{
byte[] hash = pbkdf2.GetBytes(HASH_LENGTH);
/* Compare the results */
for (int i = 0; i < HASH_LENGTH; i++)
{
if (hashBytes[i + SALT_LENGTH] != hash[i])
{
throw new UnauthorizedAccessException();
}
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment