private static double L33tVariations(DictionaryMatch dictionaryMatch) { if (dictionaryMatch.GetType() != typeof(L33tDictionaryMatch)) { return(1); } double variations = 1; L33tDictionaryMatch ldm = (L33tDictionaryMatch)dictionaryMatch; foreach (KeyValuePair <char, char> val in ldm.Subs) { char subbed = val.Key; char unsubbed = val.Value; char[] chrs = ldm.Token.ToLower().ToCharArray(); int S = chrs.Where(c => c == subbed).Count(); int U = chrs.Where(c => c == unsubbed).Count(); if (S == 0 || U == 0) { variations *= 2; } else { int p = (int)Math.Min(U, S); double possibilities = 0; foreach (int i in EnumerableUtility.Range(1, p + 1)) { possibilities += nCk(U + S, i); } variations *= possibilities; } } return(variations); }
private static double UppercaseVariations(DictionaryMatch dictionaryMatch) { string word = dictionaryMatch.Token; Regex all_lower = new Regex(@"^[^a-z]+$"); if (all_lower.IsMatch(word) || word.ToLower().Equals(word)) { return(1); } Regex startUpper = new Regex(@"^[A-Z][^A-Z]+$"); Regex endUpper = new Regex(@"^[^A-Z]+[A-Z]$"); Regex allUpper = new Regex(@"^[^A-Z]+$"); foreach (Regex r in new Regex[] { startUpper, endUpper, allUpper }) { if (r.IsMatch(word)) { return(2); } } int U = word.ToCharArray().Where(c => char.IsUpper(c)).Count(); int L = word.ToCharArray().Where(c => char.IsLower(c)).Count(); double variations = 0; int end = (int)Math.Min(U, L); foreach (int i in EnumerableUtility.Range(1, end + 1)) { variations += nCk(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); }
/// <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(DictionaryMatch match) { match.BaseGuesses = match.Rank; match.UppercaseVariations = UppercaseVariations(match.Token); match.L33tVariations = L33tVariations(match); var reversedVariations = match.Reversed ? 2 : 1; return(match.BaseGuesses * match.UppercaseVariations * match.L33tVariations * reversedVariations); }
private static double DictionaryGuesses(Match match) { DictionaryMatch dm = (DictionaryMatch)match; double uppercase_variations = UppercaseVariations(dm); double l33t_variatioins = L33tVariations(dm); int reversedVariations = (dm.Reversed) ? 2 : 1; return(dm.Rank * uppercase_variations * l33t_variatioins * reversedVariations); }
public void MakesBaseGuessesEqualTheRank() { var match = new DictionaryMatch { Token = "aaaaa", Rank = 32, DictionaryName = "dic", i = 1, j = 2, L33t = false, MatchedWord = "a", Reversed = false, }; var expected = 32; var actual = DictionaryGuessesCalculator.CalculateGuesses(match); actual.Should().Be(expected); }
public void IsDelegatedToByEstimateGuesses() { var match = new DictionaryMatch { Token = "aaaaa", Rank = 32, DictionaryName = "dic", i = 1, j = 2, L33t = false, MatchedWord = "a", Reversed = false, }; var expected = 32; var actual = PasswordScoring.EstimateGuesses(match, "aaaaa"); actual.Should().Be(expected); }
public void AddsExtraGuessesForCapitilization() { var match = new DictionaryMatch { Token = "AAAaaa", Rank = 32, DictionaryName = "dic", i = 1, j = 2, L33t = false, MatchedWord = "a", Reversed = false, }; var expected = 32 * DictionaryGuessesCalculator.UppercaseVariations(match.Token); var actual = DictionaryGuessesCalculator.CalculateGuesses(match); actual.Should().Be(expected); }
public void AddsDoubleGuessesForReversedWords() { var match = new DictionaryMatch { Token = "aaaaa", Rank = 32, DictionaryName = "dic", i = 1, j = 2, L33t = false, MatchedWord = "a", Reversed = true, }; var expected = 32 * 2; var actual = DictionaryGuessesCalculator.CalculateGuesses(match); actual.Should().Be(expected); }
public void AddsExtraGuessesForCommonL33tSubstitutions() { var match = new DictionaryMatch { Token = "aaa@@@", Rank = 32, DictionaryName = "dic", i = 1, j = 2, L33t = true, MatchedWord = "a", Reversed = false, L33tSubs = new Dictionary <char, char> { { '@', 'a' } }, }; var expected = 32 * DictionaryGuessesCalculator.L33tVariations(match); var actual = DictionaryGuessesCalculator.CalculateGuesses(match); actual.Should().Be(expected); }
public void IgnoresCapitilizationForL33tVariations() { var expected = 21; var match = new DictionaryMatch { Token = "Aa44aA", Rank = 32, DictionaryName = "dic", i = 1, j = 2, L33t = true, MatchedWord = "a", Reversed = false, L33tSubs = new Dictionary <char, char>() { { '4', 'a' } }, }; var actual = DictionaryGuessesCalculator.L33tVariations(match); actual.Should().Be(expected); }
public void GetsCorrectL33tVariantsForWord() { var expected = 1; var match = new DictionaryMatch { Token = string.Empty, Rank = 32, DictionaryName = "dic", i = 1, j = 2, L33t = false, MatchedWord = "a", Reversed = false, L33tSubs = new Dictionary <char, char>(), }; var actual = DictionaryGuessesCalculator.L33tVariations(match); actual.Should().Be(expected); expected = 1; match = new DictionaryMatch { Token = "a", Rank = 32, DictionaryName = "dic", i = 1, j = 2, L33t = false, MatchedWord = "a", Reversed = false, L33tSubs = new Dictionary <char, char>(), }; actual = DictionaryGuessesCalculator.L33tVariations(match); actual.Should().Be(expected); expected = 1; match = new DictionaryMatch { Token = "abcet", Rank = 32, DictionaryName = "dic", i = 1, j = 2, L33t = false, MatchedWord = "a", Reversed = false, L33tSubs = new Dictionary <char, char>(), }; actual = DictionaryGuessesCalculator.L33tVariations(match); actual.Should().Be(expected); expected = 2; match = new DictionaryMatch { Token = "4", Rank = 32, DictionaryName = "dic", i = 1, j = 2, L33t = true, MatchedWord = "a", Reversed = false, L33tSubs = new Dictionary <char, char>() { { '4', 'a' } }, }; actual = DictionaryGuessesCalculator.L33tVariations(match); actual.Should().Be(expected); expected = 2; match = new DictionaryMatch { Token = "4pple", Rank = 32, DictionaryName = "dic", i = 1, j = 2, L33t = true, MatchedWord = "a", Reversed = false, L33tSubs = new Dictionary <char, char>() { { '4', 'a' } }, }; actual = DictionaryGuessesCalculator.L33tVariations(match); actual.Should().Be(expected); expected = 2; match = new DictionaryMatch { Token = "4bcet", Rank = 32, DictionaryName = "dic", i = 1, j = 2, L33t = true, MatchedWord = "a", Reversed = false, L33tSubs = new Dictionary <char, char>() { { '4', 'a' } }, }; actual = DictionaryGuessesCalculator.L33tVariations(match); actual.Should().Be(expected); expected = 2; match = new DictionaryMatch { Token = "a8cet", Rank = 32, DictionaryName = "dic", i = 1, j = 2, L33t = true, MatchedWord = "a", Reversed = false, L33tSubs = new Dictionary <char, char>() { { '8', 'b' } }, }; actual = DictionaryGuessesCalculator.L33tVariations(match); actual.Should().Be(expected); expected = 2; match = new DictionaryMatch { Token = "abce+", Rank = 32, DictionaryName = "dic", i = 1, j = 2, L33t = true, MatchedWord = "a", Reversed = false, L33tSubs = new Dictionary <char, char>() { { '+', 't' } }, }; actual = DictionaryGuessesCalculator.L33tVariations(match); actual.Should().Be(expected); expected = 4; match = new DictionaryMatch { Token = "48cet", Rank = 32, DictionaryName = "dic", i = 1, j = 2, L33t = true, MatchedWord = "a", Reversed = false, L33tSubs = new Dictionary <char, char>() { { '4', 'a' }, { '8', 'b' } }, }; actual = DictionaryGuessesCalculator.L33tVariations(match); actual.Should().Be(expected); expected = 21; match = new DictionaryMatch { Token = "a4a4aa", Rank = 32, DictionaryName = "dic", i = 1, j = 2, L33t = true, MatchedWord = "a", Reversed = false, L33tSubs = new Dictionary <char, char>() { { '4', 'a' } }, }; actual = DictionaryGuessesCalculator.L33tVariations(match); actual.Should().Be(expected); expected = 21; match = new DictionaryMatch { Token = "4a4a44", Rank = 32, DictionaryName = "dic", i = 1, j = 2, L33t = true, MatchedWord = "a", Reversed = false, L33tSubs = new Dictionary <char, char>() { { '4', 'a' } }, }; actual = DictionaryGuessesCalculator.L33tVariations(match); actual.Should().Be(expected); expected = 30; match = new DictionaryMatch { Token = "a44att+", Rank = 32, DictionaryName = "dic", i = 1, j = 2, L33t = true, MatchedWord = "a", Reversed = false, L33tSubs = new Dictionary <char, char>() { { '4', 'a' }, { '+', 't' } }, }; actual = DictionaryGuessesCalculator.L33tVariations(match); actual.Should().Be(expected); }
private void GetDictionaryMatchFeedback(DictionaryMatch match, bool isSoleMatch, PasswordMetricResult result) { if (match.DictionaryName.Equals("passwords")) { //todo: add support for reversed words if (isSoleMatch == true && !(match is L33tDictionaryMatch)) { if (match.Rank <= 10) { result.warning = Warning.Top10Passwords; } else if (match.Rank <= 100) { result.warning = Warning.Top100Passwords; } else { result.warning = Warning.CommonPasswords; } } else if (PasswordScoring.CrackTimeToScore(PasswordScoring.EntropyToCrackTime(match.Entropy)) <= 1) { result.warning = Warning.SimilarCommonPasswords; } } else if (match.DictionaryName.Equals("english")) { if (isSoleMatch == true) { result.warning = Warning.WordEasy; } } else if (match.DictionaryName.Equals("surnames") || match.DictionaryName.Equals("male_names") || match.DictionaryName.Equals("female_names")) { if (isSoleMatch == true) { result.warning = Warning.NameSurnamesEasy; } else { result.warning = Warning.CommonNameSurnamesEasy; } } else { result.warning = Warning.Empty; } string word = match.Token; if (Regex.IsMatch(word, PasswordScoring.StartUpper)) { result.suggestions.Add(Suggestion.CapsDontHelp); } else if (Regex.IsMatch(word, PasswordScoring.AllUpper) && !word.Equals(word.ToLowerInvariant())) { result.suggestions.Add(Suggestion.AllCapsEasy); } //todo: add support for reversed words //if match.reversed and match.token.length >= 4 // suggestions.push "Reversed words aren't much harder to guess" if (match is L33tDictionaryMatch) { result.suggestions.Add(Suggestion.PredictableSubstitutionsEasy); } }
private static FeedbackItem GetDictionaryMatchFeedback(DictionaryMatch match, bool isSoleMatch) { var warning = string.Empty; if (match.DictionaryName == "passwords") { if (isSoleMatch && !match.L33t && !match.Reversed) { if (match.Rank <= 10) { warning = "This is a top-10 common password"; } else if (match.Rank <= 100) { warning = "This is a top-100 common password"; } else { warning = "This is a very common password"; } } else if (match.GuessesLog10 <= 4) { warning = "This is similar to a commonly used password"; } } else if (match.DictionaryName == "english" && isSoleMatch) { warning = "A word by itself is easy to guess"; } else if (match.DictionaryName == "surnames" || match.DictionaryName == "male_names" || match.DictionaryName == "female_names") { if (isSoleMatch) { warning = "Names and surnames by themselves are easy to guess"; } else { warning = "Common names and surnames are easy to guess"; } } var suggestions = new List <string>(); var word = match.Token; if (char.IsUpper(word[0])) { suggestions.Add("Capitalization doesn't help very much"); } else if (word.All(c => char.IsUpper(c)) && word.ToLower() != word) { suggestions.Add("All-uppercase is almost as easy to guess as all-lowercase"); } if (match.Reversed && match.Token.Length >= 4) { suggestions.Add("Reversed words aren't much harder to guess"); } if (match.L33t) { suggestions.Add("Predictable substitutions like '@' instead of 'a' don't help very much"); } return(new FeedbackItem { Suggestions = suggestions, Warning = warning, }); }
private static FeedbackItem GetDictionaryMatchFeedback(DictionaryMatch match, bool isSoleMatch) { var warning = string.Empty; if (match.DictionaryName == "passwords" || match.DictionaryName == "fr-password") { if (isSoleMatch && !match.L33t && !match.Reversed) { if (match.Rank <= 10) { // warning = "This is a top-10 common password"; warning = "Ce mot de passe fait parti des 10 les plus utilisé"; } else if (match.Rank <= 100) { // warning = "This is a top-100 common password"; warning = "Ce mot de passe fait parti des 100 les plus utilisé"; } else { // warning = "This is a very common password"; warning = "Ce mot de passe est trés commun"; } } else if ( (match.DictionaryName == "english" || match.DictionaryName == "fr") && isSoleMatch) { // warning = "A word by itself is easy to guess"; warning = "Un mot, seul, est trés simple à deviner"; } else if (match.DictionaryName == "surnames" || match.DictionaryName == "male_names" || match.DictionaryName == "female_names" || match.DictionaryName == "nom_femme" || match.DictionaryName == "nom_homme") { if (isSoleMatch) { // warning = "Names and surnames by themselves are easy to guess"; warning = "Les noms propres sont trés simples à deviner"; } else { // warning = "Common names and surnames are easy to guess"; warning = "Les noms propres sont trés simples à deviner"; } } } var suggestions = new List <string>(); var word = match.Token; if (char.IsUpper(word[0])) { // suggestions.Add("Capitalization doesn't help very much"); suggestions.Add("Les lettres capitales n'avancent en rien."); } else if (word.All(c => char.IsUpper(c)) && word.ToLower() != word) { // suggestions.Add("All-uppercase is almost as easy to guess as all-lowercase"); suggestions.Add("Tout en lettres capitales est aussi simple à deviner que tout en lettres minuscules"); } if (match.Reversed && match.Token.Length >= 4) { // suggestions.Add("Reversed words aren't much harder to guess"); suggestions.Add("Les mots inversés ne sont pas difficiles à deviner"); } if (match.L33t) { // suggestions.Add("Predictable substitutions like '@' instead of 'a' don't help very much"); suggestions.Add("Les substitutions simples comme un '@' à la place d'un 'a' sont simples à deviner"); } return(new FeedbackItem { Suggestions = suggestions, Warning = warning, }); }