/// <summary> /// Creates a new instance of <see cref="PasswordHasher"/>. /// </summary> public PasswordHasher() { var options = new PasswordHasherOptions(); rng = RandomNumberGenerator.Create(); iterCount = options.IterationCount; symKey = new RijndaelManaged { Mode = CipherMode.CBC, Padding = PaddingMode.PKCS7 }; }
public void OptionsRoundTrip(PasswordHasherAlgorithms algorithm, int expectedSize) { // Arrange var options = new PasswordHasherOptions(algorithm); // Act & assert - success case Assert.Equal(expectedSize, options.HashSize); // Arrange options.HashAlgorithm = PasswordHasherAlgorithms.SHA1; options.SaltSize = expectedSize; options.HashAlgorithm = algorithm; // Act & assert - failure case Assert.Equal(expectedSize, options.HashSize); }
public static IOptions <PasswordHasherOptions> BuildOptions(int?saltSize = null, int?iterations = null) { var options = new PasswordHasherOptions(); if (saltSize.HasValue) { options.SaltSize = saltSize.Value; } if (iterations.HasValue) { options.Iterations = iterations.Value; } return(Options.Create(options)); }
public PasswordHasher(IOptions <PasswordHasherOptions> options = null) { if (options == null) { options = Options.Create(new PasswordHasherOptions()); } _options = options.Value; switch (_options.Version) { case PasswordHasherVersion.V1: _hasher = new PassowrdHasherV1(this); break; default: break; } }
/// <summary> /// Resets all options back to default. This should generally not be called after the application sets Application specific options. /// </summary> public static void ResetDefaults() { ////////////////////////////////////////////////////////// // Hasher Initialize ////////////////////////////////////////////////////////// HasherOptions = new HasherOptions() { HashFingerprintLowercase = true, Salt = "GLOBALSALT_902834vtn029384ytv20384tyvb13084tyv1b08ty1084vn", UseSalt = false }; ////////////////////////////////////////////////////////// // PasswordHasher Initialize ////////////////////////////////////////////////////////// PasswordHasherOptions = new PasswordHasherOptions() { // NOTE: Changing these Value will break existing encrypted data. // These are defaults only. It is recommended that each Application // create a custom Salt for individual security Salt = "6c5573acf3177dd019aa3cc3349349370d27b472744a9e5ed7a0385f686cdbb3fdba9d79b88a0b2a500543d5375a20e25177cf65c493f7a9a65dab85c9d71bab", PepperChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqurtuvwxyz0123456789!@#$%^&*()_+?><:" }; ////////////////////////////////////////////////////////// // SymmetricEncryptorOptions Initialize ////////////////////////////////////////////////////////// SymmetricEncryptorOptions = new SymmetricEncryptorOptions() { // NOTE: Changing these Value will break existing encrypted data. // These are defaults only. It is recommended that each Application // create a custom Salt for individual security Salt = "13c035d5c0b55becec39f3cf6c8adc81c5db5818f8e4fc537d5cccd805df2b5bfb22c43d6846e50b364794d2784fbb90922e9c62882f464385162186f6035168", HashFingerprintLowercase = true, InitializationVector = "29C7B95FA4B76027B183EF75A10325D40AFF4FA5D444C45BEE714CBFDF92EE6C1D5E0D82D190B714AD5EEF0AC947C19596DF460F6F154C4A0C85EF39F95A2F8E", KeySalt = "72E7D56BAD8C4377C1E57E29EEE9BB0AD218D898EA3714F175702AD5D0E507873257B5B429624A8E406435CC8BBDD89194F5E0A42E92C5FA061D881B972FC56B", IVSalt = "F755FC686D4F2DA387D54F92B9C70CCF1B267B525A5DED28B8504C03A56E1B47EA33BFDC3C241041469AA28C0732A66671D7A8A51FCEBD6FE3B72758CDC2EC63", }; }
/// <summary> /// Derives a key from the specified password. /// </summary> /// <param name="password">The password.</param> /// <param name="options">The options.</param> /// <returns></returns> /// <exception cref="ArgumentExcetption">If the given hash lengh exceeds the lenght defined in the rfc standard</exception> public override string Compute(string password, PasswordHasherOptions options) { throw new NotSupportedException(); // create a new HMAC HMAC hmac = HMACFactory.CreateInstance(options.HashType); ulong hLen = Convert.ToUInt64(hmac.HashSize / 8); ulong dkLen = Convert.ToUInt64(options.HashSize); // sanity check, section 5.2 in rfc standard. ulong maxLength = UInt32.MaxValue * hLen; if (options.HashSize > maxLength) { throw new ArgumentException("Provided hash length is too big for the current options, it violates the rfc standard"); } // algorithm start uint byteBlocks = Convert.ToUInt32(Math.Ceiling( (decimal)options.HashSize / (decimal)hLen)); uint bytesInLastBlock = Convert.ToUInt32(dkLen - (byteBlocks - 1) * hLen); IList<byte[]> blocks = new List<byte[]>(); // the algorithm is 1 based in the RFC, so add a dummy byte at index 0 blocks.Add(new byte[0]); for (uint i = 1; i <= byteBlocks; i++) { byte[] current = F(password, options.Salt, Convert.ToUInt32(Math.Pow(2.0d, options.WorkFactor)), i, options.HashType, hLen); blocks.Add(current); } // copy all blocks except the last one into the resulting hash ulong resultingHashSize = byteBlocks * hLen; if (byteBlocks > 1) { resultingHashSize += bytesInLastBlock; } byte[] resultingHash = new byte[resultingHashSize]; int startIndex = 0; for (uint i = 1; i < blocks.Count-1; i++) { byte[] current = blocks[(int)i]; startIndex = Convert.ToInt32((i - 1) * hLen); current.CopyTo(resultingHash, startIndex); } // copy "bytesInLastBlock" bytes into the resulting hash byte[] last = blocks[blocks.Count-1]; for (int i = 0; i < bytesInLastBlock; i++) { resultingHash[startIndex] = last[i]; startIndex++; } string encodedHash = String.Format("$9d${0}${1}${2}", options.WorkFactor.ToString().PadLeft(2, '0'), Convert.ToBase64String(options.Salt), Convert.ToBase64String(resultingHash)); hmac.Clear(); return encodedHash; }
/// <summary> /// Defines the password hasher options. /// </summary> /// <param name="options">The password hasher options</param> public static void PasswordHasher(PasswordHasherOptions options) { options.IterationCount = 12000; }
/// <summary> /// Derives a key from the specified password. /// </summary> /// <param name="password">The password.</param> /// <param name="options">The options.</param> /// <returns></returns> public abstract string Compute(string password, PasswordHasherOptions options);
public PasswordOptions() { Hasher = new PasswordHasherOptions(); Validation = new PasswordValidationOptions(); }
public void UpdateMasterKey() { HashEncryptionParameters encryption1 = new(123, HashEncryptionAlgorithm.AES128, new byte[] { 43, 12, 64, 63, 1, 6, 74, 123, 4, 15, 11, 84, 26, 125, 11, 6 }); HashEncryptionParameters encryption2 = new(456, HashEncryptionAlgorithm.AES128, new byte[] { 44, 12, 64, 63, 1, 6, 74, 123, 4, 15, 11, 84, 26, 125, 11, 6 }); var options1 = new PasswordHasherOptions { EncryptionParameters = encryption1, }; var options2_0 = new PasswordHasherOptions { EncryptionParameters = encryption2, }; var options2_1 = new PasswordHasherOptions { EncryptionParameters = encryption2, LegacyEncryptionParameters = { encryption1 }, }; var hasher = new PasswordHasher(PasswordHashAlgorithm.SHA512, 1000); string hash = hasher.Hash(Password); Assert.IsTrue(hasher.Verify(hash, Password)); Assert.IsFalse(hasher.Verify(hash, NotThePassword)); var hasher1 = new PasswordHasher(PasswordHashAlgorithm.SHA512, 1000, options1); Assert.IsTrue(hasher1.RequiresUpdate(hash)); string hash1 = hasher1.Update(hash) !; Assert.AreNotEqual(hash1, hash); Assert.IsTrue(hasher1.Verify(hash1, Password)); Assert.IsFalse(hasher1.Verify(hash1, NotThePassword)); Assert.ThrowsException <FormatException>(() => hasher.Verify(hash1, Password)); var hasher2_0 = new PasswordHasher(PasswordHashAlgorithm.SHA512, 1000, options2_0); Assert.IsTrue(hasher2_0.RequiresUpdate(hash)); Assert.ThrowsException <FormatException>(() => hasher2_0.RequiresUpdate(hash1)); string hash2_0 = hasher2_0.Update(hash) !; Assert.IsTrue(hasher2_0.Verify(hash2_0, Password)); Assert.IsFalse(hasher2_0.Verify(hash2_0, NotThePassword)); Assert.ThrowsException <FormatException>(() => hasher2_0.Update(hash1)); var hasher2_1 = new PasswordHasher(PasswordHashAlgorithm.SHA512, 1000, options2_1); Assert.IsTrue(hasher2_1.RequiresUpdate(hash)); Assert.IsTrue(hasher2_1.RequiresUpdate(hash1)); string hash2_1 = hasher2_1.Update(hash1) !; Assert.AreNotEqual(hash2_1, hash2_0); // AES IV values should be different for each encryption Assert.AreNotEqual(hash2_1, hash1); Assert.IsTrue(hasher2_1.Verify(hash, Password)); Assert.IsTrue(hasher2_1.Verify(hash1, Password)); Assert.IsTrue(hasher2_1.Verify(hash2_1, Password)); Assert.IsFalse(hasher2_1.Verify(hash, NotThePassword)); Assert.IsFalse(hasher2_1.Verify(hash1, NotThePassword)); Assert.IsFalse(hasher2_1.Verify(hash2_1, NotThePassword)); }
public static IOptions <PasswordHasherOptions> BuildOptions(PasswordHasherAlgorithms algorithm, int?saltSize = null, int?iterations = null) { var options = new PasswordHasherOptions(algorithm, saltSize, iterations); return(Options.Create(options)); }
public override string Compute(string password, PasswordHasherOptions options) { string encodedHash = BCrypt.HashPassword(password, (int)options.WorkFactor ); return encodedHash; }