commit
5fb7f48ad1
|
@ -21,6 +21,7 @@ func init() {
|
||||||
AdjacencyGph["dvorak"] = BuildDvorak()
|
AdjacencyGph["dvorak"] = BuildDvorak()
|
||||||
AdjacencyGph["keypad"] = BuildKeypad()
|
AdjacencyGph["keypad"] = BuildKeypad()
|
||||||
AdjacencyGph["macKeypad"] = BuildMacKeypad()
|
AdjacencyGph["macKeypad"] = BuildMacKeypad()
|
||||||
|
AdjacencyGph["l33t"] = BuildLeet()
|
||||||
}
|
}
|
||||||
|
|
||||||
func BuildQwerty() AdjacencyGraph {
|
func BuildQwerty() AdjacencyGraph {
|
||||||
|
@ -51,6 +52,13 @@ func BuildMacKeypad() AdjacencyGraph {
|
||||||
}
|
}
|
||||||
return GetAdjancencyGraphFromFile(data, "mac_keypad")
|
return GetAdjancencyGraphFromFile(data, "mac_keypad")
|
||||||
}
|
}
|
||||||
|
func BuildLeet() AdjacencyGraph {
|
||||||
|
data, err := zxcvbn_data.Asset("data/L33t.json")
|
||||||
|
if err != nil {
|
||||||
|
panic("Can't find asset")
|
||||||
|
}
|
||||||
|
return GetAdjancencyGraphFromFile(data, "keypad")
|
||||||
|
}
|
||||||
|
|
||||||
func GetAdjancencyGraphFromFile(data []byte, name string) AdjacencyGraph {
|
func GetAdjancencyGraphFromFile(data []byte, name string) AdjacencyGraph {
|
||||||
|
|
||||||
|
|
|
@ -156,7 +156,7 @@ func SequenceEntropy(match match.Match, dictionaryLength int, ascending bool) fl
|
||||||
baseEntropy = float64(0)
|
baseEntropy = float64(0)
|
||||||
} else {
|
} else {
|
||||||
baseEntropy = math.Log2(float64(dictionaryLength))
|
baseEntropy = math.Log2(float64(dictionaryLength))
|
||||||
//TODO: should this be just the first or any char
|
//TODO: should this be just the first or any char?
|
||||||
if unicode.IsUpper(rune(firstChar)) {
|
if unicode.IsUpper(rune(firstChar)) {
|
||||||
baseEntropy++
|
baseEntropy++
|
||||||
}
|
}
|
||||||
|
@ -167,3 +167,28 @@ func SequenceEntropy(match match.Match, dictionaryLength int, ascending bool) fl
|
||||||
}
|
}
|
||||||
return baseEntropy + math.Log2(float64(len(match.Token)))
|
return baseEntropy + math.Log2(float64(len(match.Token)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ExtraLeetEntropy(match match.Match, password string) float64 {
|
||||||
|
var subsitutions float64
|
||||||
|
var unsub float64
|
||||||
|
subPassword := password[match.I:match.J]
|
||||||
|
for index, char := range subPassword {
|
||||||
|
if string(char) != string(match.Token[index]) {
|
||||||
|
subsitutions++
|
||||||
|
} else {
|
||||||
|
//TODO: Make this only true for 1337 chars that are not subs?
|
||||||
|
unsub++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var possibilities float64
|
||||||
|
|
||||||
|
for i := float64(0); i <= math.Min(subsitutions, unsub)+1; i++ {
|
||||||
|
possibilities += zxcvbn_math.NChoseK(subsitutions+unsub, i)
|
||||||
|
}
|
||||||
|
|
||||||
|
if possibilities <= 1 {
|
||||||
|
return float64(1)
|
||||||
|
}
|
||||||
|
return math.Log2(possibilities)
|
||||||
|
}
|
||||||
|
|
|
@ -8,7 +8,6 @@ import (
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
// "github.com/deckarep/golang-set"
|
|
||||||
"github.com/nbutton23/zxcvbn-go/entropy"
|
"github.com/nbutton23/zxcvbn-go/entropy"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -65,6 +64,7 @@ func loadFrequencyList() {
|
||||||
KEYBOARD_STARTING_POSITIONS = len(adjacency.AdjacencyGph["querty"].Graph)
|
KEYBOARD_STARTING_POSITIONS = len(adjacency.AdjacencyGph["querty"].Graph)
|
||||||
KEYPAD_AVG_DEGREE = adjacency.AdjacencyGph["keypad"].CalculateAvgDegree()
|
KEYPAD_AVG_DEGREE = adjacency.AdjacencyGph["keypad"].CalculateAvgDegree()
|
||||||
KEYPAD_STARTING_POSITIONS = len(adjacency.AdjacencyGph["keypad"].Graph)
|
KEYPAD_STARTING_POSITIONS = len(adjacency.AdjacencyGph["keypad"].Graph)
|
||||||
|
L33T_TABLE = adjacency.AdjacencyGph["l33t"]
|
||||||
|
|
||||||
ADJACENCY_GRAPHS = append(ADJACENCY_GRAPHS, adjacency.AdjacencyGph["qwerty"])
|
ADJACENCY_GRAPHS = append(ADJACENCY_GRAPHS, adjacency.AdjacencyGph["qwerty"])
|
||||||
ADJACENCY_GRAPHS = append(ADJACENCY_GRAPHS, adjacency.AdjacencyGph["dvorak"])
|
ADJACENCY_GRAPHS = append(ADJACENCY_GRAPHS, adjacency.AdjacencyGph["dvorak"])
|
||||||
|
@ -83,6 +83,7 @@ func loadFrequencyList() {
|
||||||
MATCHERS = append(MATCHERS, SpatialMatch)
|
MATCHERS = append(MATCHERS, SpatialMatch)
|
||||||
MATCHERS = append(MATCHERS, RepeatMatch)
|
MATCHERS = append(MATCHERS, RepeatMatch)
|
||||||
MATCHERS = append(MATCHERS, SequenceMatch)
|
MATCHERS = append(MATCHERS, SequenceMatch)
|
||||||
|
MATCHERS = append(MATCHERS, l33tMatch)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -319,34 +320,67 @@ func spatialMatchHelper(password string, graph adjacency.AdjacencyGraph) (matche
|
||||||
return matches
|
return matches
|
||||||
}
|
}
|
||||||
|
|
||||||
func relevantL33tSubtable(password string) adjacency.AdjacencyGraph {
|
|
||||||
var releventSubs adjacency.AdjacencyGraph
|
func l33tMatch(password string) []match.Match {
|
||||||
for _, char := range password {
|
|
||||||
if len(L33T_TABLE.Graph[string(char)]) > 0 {
|
subsitutions := relevantL33tSubtable(password)
|
||||||
releventSubs.Graph[string(char)] = L33T_TABLE.Graph[string(char)]
|
|
||||||
|
permutations := getAllPermutationsOfLeetSubstitutions(password, subsitutions)
|
||||||
|
|
||||||
|
var matches []match.Match
|
||||||
|
|
||||||
|
for _, permutation := range permutations {
|
||||||
|
for _, mather := range DICTIONARY_MATCHERS {
|
||||||
|
matches = append(matches,mather(permutation)...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return releventSubs
|
for _, match := range matches {
|
||||||
|
match.Entropy += entropy.ExtraLeetEntropy(match, password)
|
||||||
|
match.DictionaryName = match.DictionaryName + "_3117"
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO yeah this is a little harder than i expect. . .
|
return matches
|
||||||
//func enumerateL33tSubs(table adjacency.AdjacencyGraph) []string {
|
}
|
||||||
// var subs [][]string
|
|
||||||
//
|
func getAllPermutationsOfLeetSubstitutions(password string, substitutionsMap map[string][]string) []string {
|
||||||
// dedup := func(subs []string) []string {
|
|
||||||
// deduped := mapset.NewSetFromSlice(subs)
|
var permutations []string
|
||||||
// return deduped.ToSlice()
|
|
||||||
// }
|
for index, char := range password {
|
||||||
//
|
for value, splice := range substitutionsMap {
|
||||||
// for i,v := range table.Graph {
|
for _, sub := range splice {
|
||||||
// var nextSubs []string
|
if string(char) == sub {
|
||||||
// for _, subChar := range v {
|
var permutation string
|
||||||
//
|
permutation = password[:index]+value+password[index+1:]
|
||||||
// }
|
|
||||||
//
|
permutations = append(permutations, permutation)
|
||||||
// }
|
if index < len(permutation) {
|
||||||
//}
|
tempPermutations := getAllPermutationsOfLeetSubstitutions(permutation[index + 1:], substitutionsMap)
|
||||||
|
for _, temp := range tempPermutations {
|
||||||
|
permutations = append(permutations, permutation[:index + 1] + temp)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return permutations
|
||||||
|
}
|
||||||
|
|
||||||
|
func relevantL33tSubtable(password string) map[string][]string {
|
||||||
|
relevantSubs := make(map[string][]string)
|
||||||
|
for key, values := range L33T_TABLE.Graph {
|
||||||
|
for _, value := range values {
|
||||||
|
if strings.Contains(password, value) {
|
||||||
|
relevantSubs[key] = append(relevantSubs[key], value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return relevantSubs
|
||||||
|
}
|
||||||
|
|
||||||
func RepeatMatch(password string) []match.Match {
|
func RepeatMatch(password string) []match.Match {
|
||||||
var matches []match.Match
|
var matches []match.Match
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"github.com/nbutton23/zxcvbn-go/match"
|
"github.com/nbutton23/zxcvbn-go/match"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
"fmt"
|
||||||
)
|
)
|
||||||
|
|
||||||
//DateSepMatch("1991-09-11jibjab11.9.1991")
|
//DateSepMatch("1991-09-11jibjab11.9.1991")
|
||||||
|
@ -120,3 +121,58 @@ func TestDateWithoutSepMatch(t *testing.T) {
|
||||||
matches := dateWithoutSepMatch("11091991")
|
matches := dateWithoutSepMatch("11091991")
|
||||||
assert.Len(t, matches, 1, "Lenght should be 1")
|
assert.Len(t, matches, 1, "Lenght should be 1")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//l33t
|
||||||
|
func TestLeetSubTable(t *testing.T){
|
||||||
|
subs := relevantL33tSubtable("password")
|
||||||
|
assert.Len(t, subs, 0, "password should produce no leet subs")
|
||||||
|
|
||||||
|
subs = relevantL33tSubtable("p4ssw0rd")
|
||||||
|
assert.Len(t, subs, 2, "p4ssw0rd should produce 2 subs")
|
||||||
|
|
||||||
|
subs = relevantL33tSubtable("1eet")
|
||||||
|
assert.Len(t, subs, 2, "1eet should produce 2 subs")
|
||||||
|
assert.Equal(t, subs["i"][0], "1")
|
||||||
|
assert.Equal(t, subs["l"][0], "1")
|
||||||
|
|
||||||
|
|
||||||
|
subs = relevantL33tSubtable("4pple@pple")
|
||||||
|
assert.Len(t, subs, 1, "4pple@pple should produce 1 subs")
|
||||||
|
assert.Len(t, subs["a"], 2)
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPermutationsOfLeetSubstitutions(t *testing.T){
|
||||||
|
password := "p4ssw0rd" //[passw0rd, password, p4ssword]
|
||||||
|
possibleSubs := relevantL33tSubtable(password)
|
||||||
|
|
||||||
|
permutations := getAllPermutationsOfLeetSubstitutions(password, possibleSubs)
|
||||||
|
|
||||||
|
assert.Len(t, permutations, 3, "There should be 3 permutations for "+password)
|
||||||
|
|
||||||
|
password = "p4$sw0rd" //[pa$sw0rd, passw0rd, password, pa$sword, p4ssw0rd, p4ssword, p4$sword]
|
||||||
|
possibleSubs = relevantL33tSubtable(password)
|
||||||
|
|
||||||
|
permutations = getAllPermutationsOfLeetSubstitutions(password, possibleSubs)
|
||||||
|
assert.Len(t, permutations, 7, "There should be 7 (? check my math) permutations for "+password)
|
||||||
|
|
||||||
|
password = "p4$$w0rd" //[pa$sw0rd, passw0rd, password, pa$sword, p4ssw0rd, p4ssword, p4$sword]
|
||||||
|
possibleSubs = relevantL33tSubtable(password)
|
||||||
|
|
||||||
|
permutations = getAllPermutationsOfLeetSubstitutions(password, possibleSubs)
|
||||||
|
assert.Len(t, permutations, 15, "Check my math 2*2*2*2 - 1 "+password)
|
||||||
|
|
||||||
|
|
||||||
|
password = "1337"
|
||||||
|
possibleSubs = relevantL33tSubtable(password)
|
||||||
|
permutations = getAllPermutationsOfLeetSubstitutions(password, possibleSubs)
|
||||||
|
assert.Len(t, permutations, 35, "check my math 3*2*2*3 -1 ")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLeet(t *testing.T){
|
||||||
|
password := "p4ssw0rd"
|
||||||
|
matches := l33tMatch(password)
|
||||||
|
|
||||||
|
fmt.Println(matches[0].J)
|
||||||
|
}
|
||||||
|
|
|
@ -3,18 +3,17 @@ package zxcvbn
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
"strconv"
|
"strconv"
|
||||||
"fmt"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Use these test to see how close to feature parity the library is.
|
Use these test to see how close to feature parity the library is.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
allowableError = float64(0.01)
|
allowableError = float64(0.05)
|
||||||
)
|
)
|
||||||
|
|
||||||
type failedTest struct {
|
type failedTest struct {
|
||||||
|
@ -22,7 +21,6 @@ type failedTest struct {
|
||||||
Expect float64
|
Expect float64
|
||||||
Actual float64
|
Actual float64
|
||||||
PError float64
|
PError float64
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var failedTests []failedTest
|
var failedTests []failedTest
|
||||||
|
|
Loading…
Reference in New Issue