com.nulabinc.zxcvbn.matchers.L33tMatcher Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of zxcvbn Show documentation
Show all versions of zxcvbn Show documentation
This is a java port of zxcvbn, which is a JavaScript password strength generator.
package com.nulabinc.zxcvbn.matchers;
import com.nulabinc.zxcvbn.WipeableString;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class L33tMatcher extends BaseMatcher {
private final Map> rankedDictionaries;
public L33tMatcher() {
this(new HashMap>());
}
public L33tMatcher(Map> rankedDictionaries) {
if (rankedDictionaries == null) {
this.rankedDictionaries = new HashMap<>();
} else {
this.rankedDictionaries = rankedDictionaries;
}
}
private static final Map> L33T_TABLE = new HashMap<>();
static {
L33T_TABLE.put('a', Arrays.asList('4', '@'));
L33T_TABLE.put('b', Arrays.asList('8'));
L33T_TABLE.put('c', Arrays.asList('(', '{', '[', '<'));
L33T_TABLE.put('e', Arrays.asList('3'));
L33T_TABLE.put('g', Arrays.asList('6', '9'));
L33T_TABLE.put('i', Arrays.asList('1', '!', '|'));
L33T_TABLE.put('l', Arrays.asList('1', '|', '7'));
L33T_TABLE.put('o', Arrays.asList('0'));
L33T_TABLE.put('s', Arrays.asList('$', '5'));
L33T_TABLE.put('t', Arrays.asList('+', '7'));
L33T_TABLE.put('x', Arrays.asList('%'));
L33T_TABLE.put('z', Arrays.asList('2'));
}
public Map> relevantL33tSubTable(CharSequence password) {
return relevantL33tSubTable(password, L33T_TABLE);
}
public Map> relevantL33tSubTable(CharSequence password, Map> table) {
HashMap passwordChars = new HashMap<>();
for (int n = 0; n < password.length(); n++) {
passwordChars.put(password.charAt(n), true);
}
Map> subTable = new HashMap<>();
for (Map.Entry> l33tRowRef : table.entrySet()) {
Character letter = l33tRowRef.getKey();
List subs = l33tRowRef.getValue();
List relevantSubs = new ArrayList<>();
for (Character sub : subs) {
if (passwordChars.containsKey(sub)) {
relevantSubs.add(sub);
}
}
if (relevantSubs.size() > 0) {
subTable.put(letter, relevantSubs);
}
}
return subTable;
}
@Override
public List execute(CharSequence password) {
List matches = new ArrayList<>();
Map> subTable = relevantL33tSubTable(password);
L33tSubDict l33tSubs = new L33tSubDict(subTable);
for (Map sub : l33tSubs) {
if (sub.isEmpty()) break;
CharSequence subbedPassword = translate(password, sub);
for (Match match : new DictionaryMatcher(rankedDictionaries).execute(subbedPassword)) {
WipeableString token = WipeableString.copy(password, match.i, match.j + 1);
WipeableString lower = WipeableString.lowerCase(token);
if (lower.equals(match.matchedWord)) {
token.wipe();
lower.wipe();
continue;
}
Map matchSub = new HashMap<>();
for (Map.Entry subRef : sub.entrySet()) {
Character subbedChr = subRef.getKey();
Character chr = subRef.getValue();
if (token.indexOf(subbedChr) != -1) {
matchSub.put(subbedChr, chr);
}
}
List subDisplays = new ArrayList<>();
for (Map.Entry matchSubRef : matchSub.entrySet()) {
Character k = matchSubRef.getKey();
Character v = matchSubRef.getValue();
subDisplays.add(String.format("%s -> %s", k, v));
}
String subDisplay = Arrays.toString(subDisplays.toArray(new String[]{}));
matches.add(MatchFactory.createDictionaryL33tMatch(
match.i,
match.j,
token,
match.matchedWord,
match.rank,
match.dictionaryName,
match.reversed,
matchSub,
subDisplay));
// Don't wipe token as the Match needs it
lower.wipe();
}
}
List lst = new ArrayList<>();
for (Match match : matches) if (match.tokenLength() > 1) lst.add(match);
return this.sorted(lst);
}
}