mirror of
https://github.com/status-im/zxcvbn-go.git
synced 2025-02-21 15:38:22 +00:00
Implemented repeating match. Started with l33t check
This commit is contained in:
parent
e63b91de56
commit
0270356a60
51
adjacency/L33t.json
Normal file
51
adjacency/L33t.json
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
{
|
||||||
|
"graph": {
|
||||||
|
"a": [
|
||||||
|
"4",
|
||||||
|
"@"
|
||||||
|
],
|
||||||
|
"b": [
|
||||||
|
"8"
|
||||||
|
],
|
||||||
|
"c": [
|
||||||
|
"(",
|
||||||
|
"{",
|
||||||
|
"[",
|
||||||
|
"<"
|
||||||
|
],
|
||||||
|
"e": [
|
||||||
|
"3"
|
||||||
|
],
|
||||||
|
"g": [
|
||||||
|
"6",
|
||||||
|
"9"
|
||||||
|
],
|
||||||
|
"i": [
|
||||||
|
"1",
|
||||||
|
"!",
|
||||||
|
"|"
|
||||||
|
],
|
||||||
|
"l": [
|
||||||
|
"1",
|
||||||
|
"|",
|
||||||
|
"7"
|
||||||
|
],
|
||||||
|
"o": [
|
||||||
|
"0"
|
||||||
|
],
|
||||||
|
"s": [
|
||||||
|
"$",
|
||||||
|
"5"
|
||||||
|
],
|
||||||
|
"t": [
|
||||||
|
"+",
|
||||||
|
"7"
|
||||||
|
],
|
||||||
|
"x": [
|
||||||
|
"%"
|
||||||
|
],
|
||||||
|
"z": [
|
||||||
|
"2"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
@ -9,7 +9,7 @@ import (
|
|||||||
|
|
||||||
|
|
||||||
type AdjacencyGraph struct {
|
type AdjacencyGraph struct {
|
||||||
Graph map[string][6]string
|
Graph map[string][]string
|
||||||
averageDegree float64
|
averageDegree float64
|
||||||
Name string
|
Name string
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,7 @@ type Match struct {
|
|||||||
Turns int
|
Turns int
|
||||||
ShiftedCount int
|
ShiftedCount int
|
||||||
Entropy float64
|
Entropy float64
|
||||||
|
RepeatedChar string
|
||||||
}
|
}
|
||||||
|
|
||||||
type DateMatch struct {
|
type DateMatch struct {
|
||||||
|
@ -8,6 +8,7 @@ import (
|
|||||||
"zxcvbn-go/adjacency"
|
"zxcvbn-go/adjacency"
|
||||||
"zxcvbn-go/match"
|
"zxcvbn-go/match"
|
||||||
"sort"
|
"sort"
|
||||||
|
// "github.com/deckarep/golang-set"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -18,6 +19,7 @@ var (
|
|||||||
KEYBOARD_AVG_DEGREE float64
|
KEYBOARD_AVG_DEGREE float64
|
||||||
KEYPAD_STARTING_POSITIONS int
|
KEYPAD_STARTING_POSITIONS int
|
||||||
KEYPAD_AVG_DEGREE float64
|
KEYPAD_AVG_DEGREE float64
|
||||||
|
L33T_TABLE adjacency.AdjacencyGraph
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -82,8 +84,13 @@ func loadFrequencyList() {
|
|||||||
ADJACENCY_GRAPHS = append(ADJACENCY_GRAPHS, keypadGraph)
|
ADJACENCY_GRAPHS = append(ADJACENCY_GRAPHS, keypadGraph)
|
||||||
ADJACENCY_GRAPHS = append(ADJACENCY_GRAPHS, adjacency.GetAdjancencyGraphFromFile(macKeypadfilePath, "macKepad"))
|
ADJACENCY_GRAPHS = append(ADJACENCY_GRAPHS, adjacency.GetAdjancencyGraphFromFile(macKeypadfilePath, "macKepad"))
|
||||||
|
|
||||||
|
l33tFilePath, _ := filepath.Abs("adjacency/L33t.json")
|
||||||
|
L33T_TABLE = adjacency.GetAdjancencyGraphFromFile(l33tFilePath, "l33t")
|
||||||
|
|
||||||
MATCHERS = append(MATCHERS, DICTIONARY_MATCHERS...)
|
MATCHERS = append(MATCHERS, DICTIONARY_MATCHERS...)
|
||||||
MATCHERS = append(MATCHERS, SpatialMatch)
|
MATCHERS = append(MATCHERS, spatialMatch)
|
||||||
|
MATCHERS = append(MATCHERS, repeatMatch)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -246,7 +253,7 @@ func buildDateMatchCandidateTwo(day, month byte, year string, i, j int) match.Da
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func SpatialMatch(password string) (matches []match.Match) {
|
func spatialMatch(password string) (matches []match.Match) {
|
||||||
for _, graph := range ADJACENCY_GRAPHS {
|
for _, graph := range ADJACENCY_GRAPHS {
|
||||||
matches = append(matches, spatialMatchHelper(password, graph)...)
|
matches = append(matches, spatialMatchHelper(password, graph)...)
|
||||||
}
|
}
|
||||||
@ -299,7 +306,6 @@ func spatialMatchHelper(password string, graph adjacency.AdjacencyGraph) (matche
|
|||||||
j += 1
|
j += 1
|
||||||
} else {
|
} else {
|
||||||
// otherwise push the pattern discovered so far, if any...
|
// otherwise push the pattern discovered so far, if any...
|
||||||
|
|
||||||
// don't consider length 1 or 2 chains.
|
// don't consider length 1 or 2 chains.
|
||||||
if j - i > 2 {
|
if j - i > 2 {
|
||||||
matches = append(matches, match.Match{Pattern:"spatial", I:i, J:j - 1, Token:password[i:j], DictionaryName:graph.Name, Turns:turns, ShiftedCount:shiftedCount })
|
matches = append(matches, match.Match{Pattern:"spatial", I:i, J:j - 1, Token:password[i:j], DictionaryName:graph.Name, Turns:turns, ShiftedCount:shiftedCount })
|
||||||
@ -313,3 +319,80 @@ func spatialMatchHelper(password string, graph adjacency.AdjacencyGraph) (matche
|
|||||||
}
|
}
|
||||||
return matches
|
return matches
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func relevantL33tSubtable(password string) adjacency.AdjacencyGraph {
|
||||||
|
var releventSubs adjacency.AdjacencyGraph
|
||||||
|
for _, char := range password {
|
||||||
|
if len(L33T_TABLE.Graph[string(char)]) > 0 {
|
||||||
|
releventSubs.Graph[string(char)] = L33T_TABLE.Graph[string(char)]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return releventSubs
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO yeah this is a little harder than i expect. . .
|
||||||
|
//func enumerateL33tSubs(table adjacency.AdjacencyGraph) []string {
|
||||||
|
// var subs [][]string
|
||||||
|
//
|
||||||
|
// dedup := func(subs []string) []string {
|
||||||
|
// deduped := mapset.NewSetFromSlice(subs)
|
||||||
|
// return deduped.ToSlice()
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// for i,v := range table.Graph {
|
||||||
|
// var nextSubs []string
|
||||||
|
// for _, subChar := range v {
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
|
func repeatMatch(password string) []match.Match {
|
||||||
|
var matches []match.Match
|
||||||
|
|
||||||
|
//Loop through password. if current == prev currentStreak++ else if currentStreak > 2 {buildMatch; currentStreak = 1} prev = current
|
||||||
|
var current, prev string
|
||||||
|
currentStreak := 1
|
||||||
|
var i int
|
||||||
|
var char rune
|
||||||
|
for i, char = range password {
|
||||||
|
current = string(char)
|
||||||
|
if i == 0 {
|
||||||
|
prev = current
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if current == prev {
|
||||||
|
currentStreak++
|
||||||
|
|
||||||
|
} else if currentStreak > 2 {
|
||||||
|
iPos := i-currentStreak
|
||||||
|
jPos := i-1
|
||||||
|
matches = append(matches, match.Match{
|
||||||
|
Pattern:"repeat",
|
||||||
|
I:iPos,
|
||||||
|
J:jPos,
|
||||||
|
Token:password[iPos:jPos+1],
|
||||||
|
RepeatedChar:prev})
|
||||||
|
currentStreak = 1
|
||||||
|
} else {
|
||||||
|
currentStreak = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
prev = current
|
||||||
|
}
|
||||||
|
|
||||||
|
if currentStreak > 2 {
|
||||||
|
iPos := i - currentStreak+1
|
||||||
|
jPos := i
|
||||||
|
matches = append(matches, match.Match{
|
||||||
|
Pattern:"repeat",
|
||||||
|
I:iPos,
|
||||||
|
J:jPos,
|
||||||
|
Token:password[iPos:jPos + 1],
|
||||||
|
RepeatedChar:prev})
|
||||||
|
}
|
||||||
|
return matches
|
||||||
|
}
|
@ -15,9 +15,16 @@ const (
|
|||||||
START_UPPER string = `^[A-Z][^A-Z]+$`
|
START_UPPER string = `^[A-Z][^A-Z]+$`
|
||||||
END_UPPER string = `^[^A-Z]+[A-Z]$'`
|
END_UPPER string = `^[^A-Z]+[A-Z]$'`
|
||||||
ALL_UPPER string = `^[A-Z]+$`
|
ALL_UPPER string = `^[A-Z]+$`
|
||||||
|
|
||||||
|
//for a hash function like bcrypt/scrypt/PBKDF2, 10ms per guess is a safe lower bound.
|
||||||
|
//(usually a guess would take longer -- this assumes fast hardware and a small work factor.)
|
||||||
|
//adjust for your site accordingly if you use another hash function, possibly by
|
||||||
|
//several orders of magnitude!
|
||||||
SINGLE_GUESS float64 = 0.010
|
SINGLE_GUESS float64 = 0.010
|
||||||
NUM_ATTACKERS float64 = 100
|
NUM_ATTACKERS float64 = 100 //Cores used to make guesses
|
||||||
SECONDS_PER_GUESS float64 = SINGLE_GUESS / NUM_ATTACKERS
|
SECONDS_PER_GUESS float64 = SINGLE_GUESS / NUM_ATTACKERS
|
||||||
|
|
||||||
|
|
||||||
)
|
)
|
||||||
type MinEntropyMatch struct {
|
type MinEntropyMatch struct {
|
||||||
Password string
|
Password string
|
||||||
@ -126,18 +133,18 @@ func get(a []float64, i int) float64 {
|
|||||||
|
|
||||||
return a[i]
|
return a[i]
|
||||||
}
|
}
|
||||||
func calcBruteforceCardinality(password string) int {
|
func calcBruteforceCardinality(password string) float64 {
|
||||||
lower, upper, digits, symbols := 0, 0, 0, 0
|
lower, upper, digits, symbols := float64(0), float64(0), float64(0), float64(0)
|
||||||
|
|
||||||
for _, char := range password {
|
for _, char := range password {
|
||||||
if unicode.IsLower(char) {
|
if unicode.IsLower(char) {
|
||||||
lower = 26
|
lower = float64(26)
|
||||||
} else if unicode.IsDigit(char) {
|
} else if unicode.IsDigit(char) {
|
||||||
digits = 10
|
digits = float64(10)
|
||||||
} else if unicode.IsUpper(char) {
|
} else if unicode.IsUpper(char) {
|
||||||
upper = 26
|
upper = float64(26)
|
||||||
} else {
|
} else {
|
||||||
symbols = 33
|
symbols = float64(33)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -155,6 +162,8 @@ func calcEntropy(match match.Match) float64 {
|
|||||||
entropy = dictionaryEntropy(match)
|
entropy = dictionaryEntropy(match)
|
||||||
} else if match.Pattern == "spatial" {
|
} else if match.Pattern == "spatial" {
|
||||||
entropy = spatialEntropy(match)
|
entropy = spatialEntropy(match)
|
||||||
|
} else if match.Pattern == "repeat" {
|
||||||
|
entropy = repeatEntropy(match)
|
||||||
}
|
}
|
||||||
|
|
||||||
match.Entropy = entropy
|
match.Entropy = entropy
|
||||||
@ -264,6 +273,13 @@ func extraUpperCaseEntropy(match match.Match) float64 {
|
|||||||
return float64(math.Log2(possibililities))
|
return float64(math.Log2(possibililities))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func repeatEntropy(match match.Match) float64 {
|
||||||
|
cardinality := calcBruteforceCardinality(match.Token)
|
||||||
|
entropy := math.Log2(cardinality * float64(len(match.Token)))
|
||||||
|
|
||||||
|
return entropy
|
||||||
|
}
|
||||||
|
|
||||||
func entropyToCrackTime(entropy float64) float64 {
|
func entropyToCrackTime(entropy float64) float64 {
|
||||||
crackTime := (0.5 * math.Pow(float64(2), entropy)) * SECONDS_PER_GUESS
|
crackTime := (0.5 * math.Pow(float64(2), entropy)) * SECONDS_PER_GUESS
|
||||||
|
|
||||||
@ -275,7 +291,7 @@ func roundToXDigits(number float64, digits int) float64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func displayTime(seconds float64) string {
|
func displayTime(seconds float64) string {
|
||||||
formater := "%d %s"
|
formater := "%.1f %s"
|
||||||
minute := float64(60)
|
minute := float64(60)
|
||||||
hour := minute * float64(60)
|
hour := minute * float64(60)
|
||||||
day := hour * float64(24)
|
day := hour * float64(24)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user