Пример #1
0
        public void AccountsForTurnPositionsDirectionsAndStartingKey()
        {
            var match = new SpatialMatch
            {
                Token        = "zxcvbn",
                Graph        = "qwerty",
                Turns        = 3,
                ShiftedCount = 0,
                i            = 1,
                j            = 2,
            };

            var l        = match.Token.Length;
            var s        = SpatialGuessesCalculator.KeyboardStartingPositions;
            var d        = SpatialGuessesCalculator.KeyboardAverageDegree;
            var expected = 0.0;

            for (var i = 2; i <= l; i++)
            {
                for (var j = 1; j <= Math.Min(match.Turns, i - 1); j++)
                {
                    expected += PasswordScoring.Binomial(i - 1, j - 1) * s * Math.Pow(d, j);
                }
            }

            var actual = SpatialGuessesCalculator.CalculateGuesses(match);

            actual.Should().Be(expected);
        }
        /// <summary>
        /// Calculates the number of uppercase variations in the word.
        /// </summary>
        /// <param name="token">The token.</param>
        /// <returns>The number of possible variations.</returns>
        internal static double UppercaseVariations(string token)
        {
            if (token.All(c => char.IsLower(c)) || token.ToLower() == token)
            {
                return(1);
            }

            if ((char.IsUpper(token.First()) && token.Skip(1).All(c => char.IsLower(c))) ||
                token.All(c => char.IsUpper(c)) ||
                (char.IsUpper(token.Last()) && token.Take(token.Length - 1).All(c => char.IsLower(c))))
            {
                return(2);
            }

            var u          = token.Count(c => char.IsUpper(c));
            var l          = token.Count(c => char.IsLower(c));
            var variations = 0.0;

            for (var i = 1; i <= Math.Min(u, l); i++)
            {
                variations += PasswordScoring.Binomial(u + l, i);
            }

            return(variations);
        }
        /// <summary>
        /// Calculates the number of l33t variations in the word.
        /// </summary>
        /// <param name="match">The match.</param>
        /// <returns>The number of possible variations.</returns>
        internal static double L33tVariations(DictionaryMatch match)
        {
            if (!match.L33t)
            {
                return(1);
            }

            var variations = 1.0;

            foreach (var subbed in match.Sub.Keys)
            {
                var unsubbed = match.Sub[subbed];
                var s        = match.Token.ToLower().Count(c => c == subbed);
                var u        = match.Token.ToLower().Count(c => c == unsubbed);

                if (s == 0 || u == 0)
                {
                    variations *= 2;
                }
                else
                {
                    var p             = Math.Min(u, s);
                    var possibilities = 0.0;
                    for (var i = 1; i <= p; i++)
                    {
                        possibilities += PasswordScoring.Binomial(u + s, i);
                    }
                    variations *= possibilities;
                }
            }

            return(variations);
        }
 public void BinomialTest()
 {
     Assert.AreEqual(1, PasswordScoring.Binomial(0, 0));
     Assert.AreEqual(1, PasswordScoring.Binomial(1, 0));
     Assert.AreEqual(0, PasswordScoring.Binomial(0, 1));
     Assert.AreEqual(1, PasswordScoring.Binomial(1, 1));
     Assert.AreEqual(56, PasswordScoring.Binomial(8, 3));
     Assert.AreEqual(2598960, PasswordScoring.Binomial(52, 5));
 }
Пример #5
0
        /// <summary>
        /// Estimates the attempts required to guess the password.
        /// </summary>
        /// <param name="match">The match.</param>
        /// <returns>The guesses estimate.</returns>
        public static double CalculateGuesses(SpatialMatch match)
        {
            int    s;
            double d;

            if (match.Graph == "qwerty" || match.Graph == "dvorak")
            {
                s = KeyboardStartingPositions;
                d = KeyboardAverageDegree;
            }
            else
            {
                s = KeypadStartingPositions;
                d = KeypadAverageDegree;
            }

            double guesses = 0;
            var    l       = match.Token.Length;
            var    t       = match.Turns;

            for (var i = 2; i <= l; i++)
            {
                var possibleTurns = Math.Min(t, i - 1);
                for (var j = 1; j <= possibleTurns; j++)
                {
                    guesses += PasswordScoring.Binomial(i - 1, j - 1) * s * Math.Pow(d, j);
                }
            }

            if (match.ShiftedCount > 0)
            {
                var shifted   = match.ShiftedCount;
                var unshifted = match.Token.Length - match.ShiftedCount;
                if (shifted == 0 || unshifted == 0)
                {
                    guesses *= 2;
                }
                else
                {
                    double variations = 0;
                    for (var i = 1; i <= Math.Min(shifted, unshifted); i++)
                    {
                        variations += PasswordScoring.Binomial(shifted + unshifted, i);
                    }

                    guesses *= variations;
                }
            }

            return(guesses);
        }
            /// <summary>
            /// Calculate entropy for a math that was found on this adjacency graph
            /// </summary>
            public double CalculateEntropy(int matchLength, int turns, int shiftedCount)
            {
                // This is an estimation of the number of patterns with length of matchLength or less with turns turns or less
                var possibilities = Enumerable.Range(2, matchLength - 1).Sum(i =>
                {
                    var possible_turns = Math.Min(turns, i - 1);
                    return(Enumerable.Range(1, possible_turns).Sum(j =>
                    {
                        return StartingPositions * Math.Pow(AverageDegree, j) * PasswordScoring.Binomial(i - 1, j - 1);
                    }));
                });

                var entropy = Math.Log(possibilities, 2);

                // Entropy increaeses for a mix of shifted and unshifted
                if (shiftedCount > 0)
                {
                    var unshifted = matchLength - shiftedCount;
                    entropy += Math.Log(Enumerable.Range(0, Math.Min(shiftedCount, unshifted) + 1).Sum(i => PasswordScoring.Binomial(matchLength, i)), 2);
                }

                return(entropy);
            }
Пример #7
0
 public void PasswordScoringBinomialScoresCorrectly(int n, int k, int score)
 {
     PasswordScoring.Binomial(n, k).Should().Be(score);
 }
Пример #8
0
        // ReSharper disable once InconsistentNaming
        private static void CalulateL33tEntropy(L33tDictionaryMatch match)
        {
            // I'm a bit dubious about this function, but I have duplicated zxcvbn functionality regardless

            var possibilities = 0;

            foreach (var kvp in match.Subs)
            {
                var subbedChars   = match.Token.Count(c => c == kvp.Key);
                var unsubbedChars = match.Token.Count(c => c == kvp.Value); // Won't this always be zero?

                possibilities += Enumerable.Range(0, Math.Min(subbedChars, unsubbedChars) + 1).Sum(i => (int)PasswordScoring.Binomial(subbedChars + unsubbedChars, i));
            }

            var entropy = Math.Log(possibilities, 2);

            // In the case of only a single subsitution (e.g. 4pple) this would otherwise come out as zero, so give it one bit
            match.L33tEntropy = (entropy < 1 ? 1 : entropy);
            match.Entropy    += match.L33tEntropy;

            // We have to recalculate the uppercase entropy -- the password matcher will have used the subbed password not the original text
            match.Entropy         -= match.UppercaseEntropy;
            match.UppercaseEntropy = PasswordScoring.CalculateUppercaseEntropy(match.Token);
            match.Entropy         += match.UppercaseEntropy;
        }