Last active
September 6, 2016 19:34
-
-
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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