Example #1
0
        /// <summary>
        /// Checks whether a passed in password has been pwned previously.
        /// Determines if the password is safe (never been pwned),
        /// at risk (pwned 1-10 times), or unnacceptable(pwned > 10 times).
        /// </summary>
        /// <param name="password">A password</param>
        /// <returns>PasswordStatus which conatins a number and message that determines the security risk.
        /// 0 - no risk. 1 - small risk/recommend change password. 2 - risky/password not accepted
        /// -1 - an error occurred in the http request </returns>
        public async Task <PasswordStatus> IsPasswordSafe(string password)
        {
            if (password.Length < 12)
            {
                PasswordStatus status = new PasswordStatus(-2, "That's not a valid password!");
                return(status);
            }
            else
            {
                //Password converted to bytes and hashed.
                string stringHash = sHash.StringHash(password);
                //Gets the first five characters of the hashed password (prefix)
                string prefix = stringHash.Substring(0, 5);
                //Calls FindPassword to see all pwned passwords that have the same prefix
                //checkPwned is Task<String>
                var checkPwned = await pvs.FindPassword(prefix);

                //restOfHash is part of password hash that is not the prefix
                string restOfHash = stringHash.Substring(5, stringHash.Length - 5);

                //Check if password has been pwned and if its usable. Get object with int representing status & a message.
                //Status number and message are stored in PasswordStatus object
                PasswordStatus status = checkStatus.StatusOfPassword(checkPwned, restOfHash);
                return(status);
            }
        }
        /// <summary>
        /// Gets the status of the password. Gets both a status number and a status message.
        /// </summary>
        /// <param name="checkPwned"></param>
        /// <param name="restOfHash"></param>
        /// <returns>A PasswordStatus object containg the status number and message.</returns>
        public PasswordStatus StatusOfPassword(string checkPwned, string restOfHash)
        {
            int statusNumber;

            //There was an error so checkPwned is empty.
            if (string.IsNullOrEmpty(checkPwned))
            {
                statusNumber = -1;
            }
            //Rest of the hashed password exists in checkpwned
            else if (checkPwned.Contains(restOfHash))
            {
                int index = checkPwned.IndexOf(restOfHash);
                //Represents a colon followed by 1 or more digits
                Regex colon = new Regex(@":(\d+)");
                // will search string for first occurence of given expression, starting from index
                Match counter = colon.Match(checkPwned, index);
                //Number of times password has been pwned is parsed.
                int.TryParse(counter.Value.Substring(1), out int result);

                //Password has been breached a few times(1-10) before, recommend change password.
                if (result > 0 && result < 11)
                {
                    statusNumber = 1;
                }
                //Password breached more than 10 times, must be changed.
                else
                {
                    statusNumber = 2;
                }
            }
            //Password has not been pwned previously.
            else
            {
                statusNumber = 0;
            }
            String         statusMessage = StatusMessages(statusNumber);
            PasswordStatus status        = new PasswordStatus(statusNumber, statusMessage);

            return(status);
        }