Skip to content

Instantly share code, notes, and snippets.

@izackp
Last active September 6, 2016 19:34
Show Gist options
  • Select an option

  • Save izackp/e1c5bb8868b9d6a06d6d9b75721257a0 to your computer and use it in GitHub Desktop.

Select an option

Save izackp/e1c5bb8868b9d6a06d6d9b75721257a0 to your computer and use it in GitHub Desktop.
PBKDF2 simplified interface in C# - To anyone reading this: just use the BCrypt library its simpler and safer.
using System;
using System.Security.Cryptography;
namespace Security
{
public static class PBKDF2
{
const int cSaltByteLength = 24;
const int cDerivedKeyLength = 24;
const int cIterationCount = 2;
public static byte[] GenerateRandomSalt(int length)
{
var csprng = new RNGCryptoServiceProvider();
var salt = new byte[length];
csprng.GetBytes(salt);
return salt;
}
public static byte[] CreatePasswordHash(byte[] password, int iterationCount = cIterationCount)
{
var salt = GenerateRandomSalt(cSaltByteLength);
byte[] hashValue = GenerateHashValue(password, salt, iterationCount);
var iterationCountBtyeArr = BitConverter.GetBytes(iterationCount);
var valueToSave = new byte[cSaltByteLength + cDerivedKeyLength + iterationCountBtyeArr.Length];
Buffer.BlockCopy(salt, 0, valueToSave, 0, cSaltByteLength);
Buffer.BlockCopy(hashValue, 0, valueToSave, cSaltByteLength, cDerivedKeyLength);
Buffer.BlockCopy(iterationCountBtyeArr, 0, valueToSave, salt.Length + hashValue.Length, iterationCountBtyeArr.Length);
return valueToSave;
}
static byte[] GenerateHashValue(byte[] password, byte[] salt, int iterationCount)
{
byte[] hashValue;
using (var pbkdf2 = new Rfc2898DeriveBytes(password, salt, iterationCount))
{
hashValue = pbkdf2.GetBytes(cDerivedKeyLength);
}
return hashValue;
}
public static bool VerifyPassword(byte[] actualSavedHashResults, byte[] passwordGuess)
{
var salt = new byte[cSaltByteLength];
var actualPasswordByteArr = new byte[cDerivedKeyLength];
int iterationCountLength = actualSavedHashResults.Length - (salt.Length + actualPasswordByteArr.Length);
var iterationCountByteArr = new byte[iterationCountLength];
Buffer.BlockCopy(actualSavedHashResults, 0, salt, 0, cSaltByteLength);
Buffer.BlockCopy(actualSavedHashResults, cSaltByteLength, actualPasswordByteArr, 0, actualPasswordByteArr.Length);
Buffer.BlockCopy(actualSavedHashResults, (salt.Length + actualPasswordByteArr.Length), iterationCountByteArr, 0, iterationCountLength);
byte[] passwordGuessByteArr = GenerateHashValue(passwordGuess, salt, BitConverter.ToInt32(iterationCountByteArr, 0));
return ConstantTimeComparison(passwordGuessByteArr, actualPasswordByteArr);
}
private static bool ConstantTimeComparison(byte[] passwordGuess, byte[] actualPassword)
{
uint difference = (uint)passwordGuess.Length ^ (uint)actualPassword.Length;
for (var i = 0; i < passwordGuess.Length && i < actualPassword.Length; i++)
{
difference |= (uint)(passwordGuess[i] ^ actualPassword[i]);
}
return difference == 0;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment