public void TestHashMatches() { byte[] storedHash = Convert.FromBase64String(KnownHashAndSalt); byte[] salt = PasswordHashing.ExtractStoredSalt(storedHash); byte[] curHash = Convert.FromBase64String(PasswordHashing.EncodePassword(KnownPassword.ToSecureString(), salt)); Assert.That(PasswordHashing.HashesMatch(storedHash, curHash), Is.True); }
public void TestGenerateAndCompareHashMatch() { byte[] saltAndHash = Convert.FromBase64String(PasswordHashing.EncodePassword(KnownPassword.ToSecureString(), null)); byte[] salt = PasswordHashing.ExtractStoredSalt(saltAndHash); Assert.That(salt, Is.Not.Null); Assert.That(PasswordHashing.HashesMatch(Convert.FromBase64String(PasswordHashing.EncodePassword(KnownPassword.ToSecureString(), salt)), saltAndHash)); }
public void TestEncode() { byte[] storedHash = Convert.FromBase64String(KnownHashAndSalt); byte[] salt = PasswordHashing.ExtractStoredSalt(storedHash); byte[] curHash = Convert.FromBase64String(PasswordHashing.EncodePassword(KnownPassword.ToSecureString(), salt)); Assert.That(storedHash, Is.EqualTo(curHash), "Hashed Passphrase 'HACK' should be the same"); }
public void TestExtractSalt() { byte[] expectedSalt = Convert.FromBase64String(KnownSalt); byte[] storedHash = Convert.FromBase64String(KnownHashAndSalt); byte[] salt = PasswordHashing.ExtractStoredSalt(storedHash); Assert.That(salt, Is.EqualTo(expectedSalt)); }
public void TestExtractNoSaltProvided() { byte[] expectedSalt = Convert.FromBase64String(KnownSalt); byte[] storedHash = Convert.FromBase64String(""); Assert.That(storedHash.Length, Is.LessThan(expectedSalt.Length)); byte[] salt = PasswordHashing.ExtractStoredSalt(storedHash); Assert.That(salt, Is.Not.EqualTo(expectedSalt)); }
public void TestExtractBadSalt() { byte[] expectedSalt = Convert.FromBase64String(KnownSalt); byte[] storedHash = Convert.FromBase64String("W4HzBdwizUNGfhTQJnP="); Assert.That(storedHash.Length, Is.LessThan(expectedSalt.Length)); byte[] salt = PasswordHashing.ExtractStoredSalt(storedHash); Assert.That(salt, Is.Not.EqualTo(expectedSalt)); }
/// <summary> /// Retrieve user information after validating provided userId and passphrase. /// If valid then returns true and updates user with UserDetails /// Otherwise returns false and sets user to null /// </summary> /// <param name="userId"></param> /// <param name="passphrase"></param> /// <param name="user">creates new instance and returns validated user information</param> /// <returns>true if user input valid and user object container user information; false on any error validating</returns> public bool ValidateUser(string userId, SecureString passphrase, out UserDetail user) { logger.Trace(nameof(ValidateUser)); // ensure we initialize user to null unless a valid userId and passphrase is provided user = null; // if not a valid value for DB key then fail early if (string.IsNullOrWhiteSpace(userId)) { return(false); } try { // retrieve corresponding user information from DB // Note: userId [UserDetail DB table key] is stored in lower case (using CultureInvariant form) var possibleUser = GetUserDetailsFor(userId); // invalid userId or error loading from DB - failed to validate; Note early exit allows determination of usernames if (possibleUser == null) { logger.Warn($"Failed to obtain possible user details for {userId}."); return(false); } // get attempted password, exit early if obviously invalid passphrase (blank) // if (string.IsNullOrWhiteSpace(passphrase.ToString())) return false; -- passphrase is now a SecureString, don't defeat point and convert to string if ((passphrase == null) || (passphrase.Length < 1)) { logger.Warn($"Passphrase provided for {userId} is invalid."); return(false); } // split apart stored hash so we can hash attempted password & compare bool isValid; try { byte[] storedHash = Convert.FromBase64String(possibleUser.hashedPassphrase); byte[] salt = PasswordHashing.ExtractStoredSalt(storedHash); // get hashed version of attempted password byte[] curHash = Convert.FromBase64String(PasswordHashing.EncodePassword(passphrase, salt)); // determine if hashed passphrases are a match isValid = PasswordHashing.HashesMatch(storedHash, curHash); } catch (System.FormatException e) // invalid Base64 string { logger.Warn("Error validating credentials, likely stored passphrase corrupted / not base64 encoded!", e); isValid = false; } // validated supplied password, now confirm user account not currently disabled isValid = isValid && possibleUser.isActive; // only return any information if user credentials successfully validated if (isValid) { logger.Info("Valid user."); user = possibleUser; } else { logger.Warn($"Failed to validate credentials for user {userId}."); } return(isValid); } catch (Exception e) { logger.Error(e, $"Error occured when validating user - {e.Message}"); throw; } }