Hashing turns your password (or any other piece of data) into a short string of letters and/or numbers using an encryption algorithm. If a website is hacked, cyber criminals don't get access to your password. Instead, they just get access to the encrypted “hash” created by your password.
So we pass the password as a byte array to the GenerateFromPassword() function firstly and then pass the cost, which in this example we have set to an arbitrary value of 8 . We get back the hashed password as a byte array and a possible error, which for the example we have ignored with the underscore.
A cryptographic hash function is an algorithm that takes an arbitrary amount of data input—a credential—and produces a fixed-size output of enciphered text called a hash value, or just “hash.” That enciphered text can then be stored instead of the password itself, and later used to verify the user.
A cryptographic salt is made up of random bits added to each password instance before its hashing. Salts create unique passwords even in the instance of two users choosing the same passwords. Salts help us mitigate hash table attacks by forcing attackers to re-compute them using the salts for each user.
You were really close actually. The link you have given shows you how you can call the Rfc2898DeriveBytes function to get PBKDF2 hash results. However, you were thrown off by the fact that the example was using the derived key for encryption purposes (the original motivation for PBKDF1 and 2 was to create "key" derivation functions suitable for using as encryption keys). Of course, we don't want to use the output for encryption but as a hash on its own.
You can try the SimpleCrypto.Net library written for exactly this purpose if you want PBKDF2. If you look at the implementation, you can see that it is actually just a thin wrapper around (you guessed it) Rfc2898DeriveBytes.
You can try the C# implementation named (what else) BCrypt.NET if you want to experiment with this variant.
Disclaimer: I have not used or tested any of the libraries that I have linked to... YMMV
First of all, I urge everyone to use a cryptographically verified reference algorithm included with the platform itself.
Do not use 3rd party packages and non-verified OSS components or any other code you just copy-pasted from the Internet.
For .NET use PBKDF2 and not bCrypt because there's no certified implementation of bCrypt for .NET
I don't mean any disrespect for any noble open-source devs (being one myself), but you can never be sure their website won't be hacked in 10 years and you end up getting a malware package from Nuget/npm or other package managers.
More info about verification can be found in this SO answer
Now, back to PBKDF2, here's the simple code
public static byte[] PBKDF2Hash(string input, byte[] salt)
{
// Generate the hash
Rfc2898DeriveBytes pbkdf2 = new Rfc2898DeriveBytes(input, salt, iterations: 5000);
return pbkdf2.GetBytes(20); //20 bytes length is 160 bits
}
If you need a string representation of the hash (not byte-array) - you can use this superfast conversion class from this answer http://stackoverflow.com/a/624379/714733
It took me forever (days it took days) to find what to actually code to get hashed passwords to work!! so I put it here for convenience.
You do need to read the documentation and theory1 theory2 and then some or you could be open to security loopholes. Security is a very big topic! Buyer Beware!
Add the NuGet Package BCrypt.Net to the solution
const int WorkFactor = 14;
var HashedPassword = BCrypt.Net.BCrypt.HashPassword(Password, WorkFactor);
You should adjust the WorkFactor to what is appropriate see discussions. Its a log2 function
"The number is log2, so every time computers double in speed, add 1 to the default number."
Then you store the hashed password in your db as passwordFromLocalDB
and to test an incoming password
like this:
if (BCrypt.Net.BCrypt.Verify(password, passwordFromLocalDB) == true)
Good Luck!
Microsoft has a page up with sample code using PBKDF2 for anyone using .Net Core:
Hash passwords in ASP.NET Core
From the article:
using System;
using System.Security.Cryptography;
using Microsoft.AspNetCore.Cryptography.KeyDerivation;
public class Program
{
public static void Main(string[] args)
{
Console.Write("Enter a password: ");
string password = Console.ReadLine();
// generate a 128-bit salt using a secure PRNG
byte[] salt = new byte[128 / 8];
using (var rng = RandomNumberGenerator.Create())
{
rng.GetBytes(salt);
}
Console.WriteLine($"Salt: {Convert.ToBase64String(salt)}");
// derive a 256-bit subkey (use HMACSHA1 with 10,000 iterations)
string hashed = Convert.ToBase64String(KeyDerivation.Pbkdf2(
password: password,
salt: salt,
prf: KeyDerivationPrf.HMACSHA1,
iterationCount: 10000,
numBytesRequested: 256 / 8));
Console.WriteLine($"Hashed: {hashed}");
}
}
/*
* SAMPLE OUTPUT
*
* Enter a password: Xtw9NMgx
* Salt: NZsP6NnmfBuYeJrrAKNuVQ==
* Hashed: /OOoOer10+tGwTRDTrQSoeCxVTFr6dtYly7d0cPxIak=
*/
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With