@Override public double exec(Match match) { match.baseGuesses = (double) match.rank; int uppercaseVariations = uppercaseVariations(match); int l33tVariations = l33tVariations(match); int reversedVariations = match.reversed ? 2 : 1; return match.rank * uppercaseVariations * l33tVariations * reversedVariations; }
@Override public double exec(Match match) { if (match.guesses != null) return match.guesses; int minGuesses = 1; if (match.token.length() < password.length()) { minGuesses = match.token.length() == 1 ? MIN_SUBMATCH_GUESSES_SINGLE_CHAR : MIN_SUBMATCH_GUESSES_MULTI_CHAR; } final Guess guess; switch (match.pattern) { case Bruteforce: guess = new BruteforceGuess(); break; case Dictionary: guess = new DictionaryGuess(); break; case Spatial: guess = new SpatialGuess(); break; case Repeat: guess = new RepeatGuess(); break; case Sequence: guess = new SequenceGuess(); break; case Regex: guess = new RegexGuess(); break; case Date: guess = new DateGuess(); break; default: guess = null; break; } double guesses = guess != null ? guess.exec(match) : 0; match.guesses = Math.max(guesses, minGuesses); match.guessesLog10 = Scoring.log10(match.guesses); return match.guesses; } }
@Override public double exec(Match match) { if (CHAR_CLASS_BASES.containsKey(match.regexName)) { return Math.pow(CHAR_CLASS_BASES.get(match.regexName), match.token.length()); } else if ("recent_year".equals(match.regexName)) { double yearSpace = Math.abs(parseInt(match.token) - REFERENCE_YEAR); yearSpace = Math.max(yearSpace, MIN_YEAR_SPACE); return yearSpace; } return 0; }
@Test public void testCalcGuessesYear() throws Exception { Match match = MatchFactory.createDateMatch(0, 0, "1977", "/", 1977, 7, 14); String msg = "estimate_guesses delegates based on pattern"; assertEquals(msg, new EstimateGuess("1977").exec(match), new DateGuess().exec(match), 0.0); }
@Test public void testDictionaryGuessesMixed() throws Exception { Map<Character, Character> sub = new HashMap<>(); sub.put('@', 'a'); Match match = new Match.Builder(Pattern.Dictionary, 0, 0, "AaA@@@").sub(sub).l33t(true).rank(32).build(); String msg = "extra guesses are added for both capitalization and common l33t substitutions"; int expected = 32 * new DictionaryGuess().l33tVariations(match) * new DictionaryGuess().uppercaseVariations(match); assertEquals(msg, expected, new DictionaryGuess().exec(match), 0.0); }
@Test public void testDictionaryGuessesCapitalization() throws Exception { Match match = new Match.Builder(Pattern.Dictionary, 0, 0, "AAAaaa").rank(32).build(); String msg = "extra guesses are added for capitalization"; assertEquals(msg, 32 * new DictionaryGuess().uppercaseVariations(match), new DictionaryGuess().exec(match), 0.0); }
@Test public void testL33tVariants() throws Exception { Match match = MatchFactory.createDictionaryMatch(0, 0, "", "", 0, ""); assertEquals("1 variant for non-l33t matches", 1.0, new DictionaryGuess().l33tVariations(match), 0.0); } }
@Test public void testDictionaryGuesses133t() throws Exception { Map<Character, Character> sub = new HashMap<>(); sub.put('@', 'a'); Match match = new Match.Builder(Pattern.Dictionary, 0, 0, "aaa@@@").sub(sub).l33t(true).rank(32).build(); String msg = "extra guesses are added for common l33t substitutions"; assertEquals(msg, 32 * new DictionaryGuess().l33tVariations(match), new DictionaryGuess().exec(match), 0.0); }
@Test public void testCalcGuessesPassword() throws Exception { Match match = new Match.Builder(Pattern.Dictionary, 0, 8, "password").guesses(1.0).build(); String msg = "estimate_guesses returns cached guesses when available"; assertEquals(msg, 1, new EstimateGuess("password").exec(match), 0.0); }
@Test public void testDictionaryGuessesSameWithRank() throws Exception { Match match = new Match.Builder(Pattern.Dictionary, 0, 0, "aaaa").rank(32).build(); String msg = "base guesses == the rank"; assertEquals(msg, 32, new DictionaryGuess().exec(match), 0.0); }
@Test public void testSequenceGuesses() throws Exception { Match match = new Match.Builder(Pattern.Sequence, 0, 0, token).ascending(ascending).build(); String msg = String.format("the sequence pattern '%s' has guesses of %s", token, expectedGuesses); assertEquals(msg, expectedGuesses, new SequenceGuess().exec(match), 0.0); }
@Test public void testUppercaseVariants() throws Exception { DictionaryGuess dictionaryGuess = new DictionaryGuess(); Method uppercaseVariationsMethod = DictionaryGuess.class.getDeclaredMethod("uppercaseVariations", Match.class); uppercaseVariationsMethod.setAccessible(true); Match match = new Match.Builder(Pattern.Dictionary, 0, 0, word).sub(new HashMap<Character, Character>()).l33t(true).build(); String msg = String.format("guess multiplier of %s is %s", word, variants); assertEquals(msg, variants, uppercaseVariationsMethod.invoke(dictionaryGuess, match)); }
public int uppercaseVariations(Match match) { String word = match.token; if (ALL_LOWER.matcher(word).find(0) || word.toLowerCase().equals(word)) return 1; for(Pattern pattern: new Pattern[] { START_UPPER, END_UPPER, ALL_UPPER }) if (pattern.matcher(word).find()) return 2; Pattern upper = Pattern.compile("[A-Z]"); Pattern lower = Pattern.compile("[a-z]"); int u = 0; int l = 0; for (String str: word.split("")) if (upper.matcher(str).find()) u++; for (String str: word.split("")) if (lower.matcher(str).find()) l++; int variations = 0; for (int i = 1; i <= Math.min(u, l); i++) variations += nCk(u + l, i); return variations; }
@Override public double exec(Match match) { Keyboard keyboard = Keyboard.of(match.graph); int s = keyboard.getStartingPositions(); double d = keyboard.getAverageDegree(); double guesses = 0; int l = match.token.length(); int t = match.turns; for (int i = 2; i <= l; i++) { int possibleTurns = Math.min(t, i - 1); for (int j = 1; j <= possibleTurns; j++) { guesses += nCk(i - 1, j - 1) * s * Math.pow(d, j); } } if (match.shiftedCount != null && match.shiftedCount > 0) { int shiftedCount = match.shiftedCount; int unshiftedCount = match.token.length() - match.shiftedCount; if (shiftedCount == 0 || unshiftedCount == 0) { guesses *= 2; } else { int shiftedVariations = 0; for (int i = 1; i <= Math.min(shiftedCount, unshiftedCount); i++) { shiftedVariations += nCk(shiftedCount + unshiftedCount, i); } guesses *= shiftedVariations; } } return guesses; } }
@Override public double exec(Match match) { if (match.guesses != null) return match.guesses; int minGuesses = 1; if (match.token.length() < password.length()) { minGuesses = match.token.length() == 1 ? MIN_SUBMATCH_GUESSES_SINGLE_CHAR : MIN_SUBMATCH_GUESSES_MULTI_CHAR; } final Guess guess; switch (match.pattern) { case Bruteforce: guess = new BruteforceGuess(); break; case Dictionary: guess = new DictionaryGuess(); break; case Spatial: guess = new SpatialGuess(); break; case Repeat: guess = new RepeatGuess(); break; case Sequence: guess = new SequenceGuess(); break; case Regex: guess = new RegexGuess(); break; case Date: guess = new DateGuess(); break; default: guess = null; break; } double guesses = guess != null ? guess.exec(match) : 0; match.guesses = Math.max(guesses, minGuesses); match.guessesLog10 = Scoring.log10(match.guesses); return match.guesses; } }
@Override public double exec(Match match) { match.baseGuesses = (double) match.rank; int uppercaseVariations = uppercaseVariations(match); int l33tVariations = l33tVariations(match); int reversedVariations = match.reversed ? 2 : 1; return match.rank * uppercaseVariations * l33tVariations * reversedVariations; }
@Test public void testL33tVariants() throws Exception { Match match = new Match.Builder(Pattern.Dictionary, 0, 0, word).sub(sub).l33t(!sub.isEmpty()).build(); String msg = String.format("extra l33t guesses of %s is %s", word, variants); assertEquals(msg, variants, new DictionaryGuess().l33tVariations(match)); }
@Test public void testDictionaryGuessesReverse() throws Exception { Match match = new Match.Builder(Pattern.Dictionary, 0, 0, "aaa").reversed(true).rank(32).build(); String msg = "guesses are doubled when word is reversed"; assertEquals(msg, 32 * 2, new DictionaryGuess().exec(match), 0.0); }
@Override public double exec(Match match) { if (CHAR_CLASS_BASES.containsKey(match.regexName)) { return Math.pow(CHAR_CLASS_BASES.get(match.regexName), match.token.length()); } else if ("recent_year".equals(match.regexName)) { double yearSpace = Math.abs(parseInt(match.token) - REFERENCE_YEAR); yearSpace = Math.max(yearSpace, MIN_YEAR_SPACE); return yearSpace; } return 0; }
public int uppercaseVariations(Match match) { String word = match.token; if (ALL_LOWER.matcher(word).find(0) || word.toLowerCase().equals(word)) return 1; for(Pattern pattern: new Pattern[] { START_UPPER, END_UPPER, ALL_UPPER }) if (pattern.matcher(word).find()) return 2; Pattern upper = Pattern.compile("[A-Z]"); Pattern lower = Pattern.compile("[a-z]"); int u = 0; int l = 0; for (String str: word.split("")) if (upper.matcher(str).find()) u++; for (String str: word.split("")) if (lower.matcher(str).find()) l++; int variations = 0; for (int i = 1; i <= Math.min(u, l); i++) variations += nCk(u + l, i); return variations; }