/// <summary> /// Compares a given (plain text) password with the (already hashed) password that is inside the hashData object. /// </summary> /// <param name="givenPassword">Plain text password to compare with</param> /// <param name="hashData"> /// The <see cref="PasswordHashingData" /> object that contains salt size, current hashed password, etc. for use in the /// comparison /// of the two passwords /// </param> public CommandResult ComparePasswords(string givenPassword, PasswordHashingData hashData) { if (String.IsNullOrWhiteSpace(givenPassword) || String.IsNullOrWhiteSpace(hashData?.HashedPassword) || String.IsNullOrWhiteSpace(hashData.Salt)) { return(CommandResultFactory.Fail("The given data to compare passwords was invalid.", false)); } var saltByteArray = hashData.Salt.ToHexBytes(); // Run initial hash at an application level var appHashedPassword = GetAppLevelPasswordHash(givenPassword); // Take the output of the initial hashing and run it through proper hashing with key stretching var hashedPasswordResult = ComputePasswordAndSaltBytes(saltByteArray, appHashedPassword, hashData.NumberOfIterations) .Then(computedBytes => { var hashedPassword = computedBytes.ToHexString(); return(CommandResultFactory.Ok <string>(hashedPassword)); }); if (hashedPasswordResult.IsFailure) { return(CommandResultFactory.Fail( $"Computing the hash for the given password was not successful due to the following:\n{hashedPasswordResult.Message}")); } return(hashedPasswordResult.Value == hashData.HashedPassword ? CommandResultFactory.Ok() : CommandResultFactory.Fail("Passwords did not match")); }
/// <summary> /// Computes a hash for a given password and returns a <see cref="PasswordHashingData" /> object to hold the elements /// that made up the /// hashed password /// </summary> /// <param name="givenPassword"></param> public CommandResult <PasswordHashingData> HashPassword(string givenPassword) { if (String.IsNullOrWhiteSpace(givenPassword)) { return(CommandResultFactory.Fail("The given password was null or empty", (PasswordHashingData)null)); } var hashData = new PasswordHashingData(); var rand = new Random(); // Set the hash data hashData.NumberOfIterations = rand.Next(MinIterationRange, MaxIterationRange); hashData.SaltSize = rand.Next(MinSaltSize, MaxSaltSize); var saltByteArray = GetRandomSalt(hashData.SaltSize); hashData.Salt = saltByteArray.ToHexString(); // Run initial hash at an application level var appHashedPassword = GetAppLevelPasswordHash(givenPassword); // Take the output of the initial hashing and run it through proper hashing with key stretching var hashedPasswordResult = ComputePasswordAndSaltBytes(saltByteArray, appHashedPassword, hashData.NumberOfIterations) .Then(computedBytes => { var hashedPassword = computedBytes.ToHexString(); return(CommandResultFactory.Ok <string>(hashedPassword)); }); if (hashedPasswordResult.IsFailure) { return(CommandResultFactory.Fail(hashedPasswordResult.Message, hashData)); } hashData.HashedPassword = hashedPasswordResult.Value; return(CommandResultFactory.Ok(hashData)); }