-
-
Notifications
You must be signed in to change notification settings - Fork 19
/
Copy pathcrunchy_test.go
129 lines (112 loc) · 3.16 KB
/
crunchy_test.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
/*
* crunchy - find common flaws in passwords
* Copyright (c) 2017-2018, Christian Muehlhaeuser <[email protected]>
*
* For license see LICENSE
*/
package crunchy
import (
"crypto/md5"
"crypto/sha1"
"crypto/sha256"
"crypto/sha512"
"hash"
"strconv"
"testing"
)
var (
pws = []struct {
pw string
expected error
rating uint
}{
// valid passwords
{"d1924ce3d0510b2b2b4604c99453e2e1", nil, 100},
{"aCgIknPv", nil, 40},
{"1347902586", nil, 37},
{"aEc!1Edek?", nil, 71},
{"aEc!1Edek?f", nil, 77},
{"aEc!1Edek?f_", nil, 91},
{"aEc!1Edek?f_0", nil, 100},
// invalid passwords
{"", ErrEmpty, 0},
{" ", ErrEmpty, 0},
{"crunchy", ErrTooShort, 0},
{"aaaaaaaa", ErrTooFewChars, 0},
{"aabbccdd", ErrTooFewChars, 0},
{"aAbBcCdD", ErrTooFewChars, 0},
{"12345678", ErrTooSystematic, 0},
{"87654321", ErrTooSystematic, 0},
{"abcdefgh", ErrTooSystematic, 0},
{"hgfedcba", ErrTooSystematic, 0},
// haveibeenpwnd
{"Qwertyuiop", ErrFoundHIBP, 0},
{"password", ErrDictionary, 0},
{"intoxicate", ErrDictionary, 0},
{"p@ssw0rd", ErrMangledDictionary, 0}, // dictionary with mangling
{"!pass@word?", ErrMangledDictionary, 0}, // dictionary with mangling
{"drowssap", ErrMangledDictionary, 0}, // reversed dictionary
{"?drow@ssap!", ErrMangledDictionary, 0}, // reversed dictionary with mangling
// md5 dictionary lookup
{"5f4dcc3b5aa765d61d8327deb882cf99", ErrHashedDictionary, 0},
// sha1 dictionary lookup
{"5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8", ErrHashedDictionary, 0},
// sha256 dictionary lookup
{"5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8", ErrHashedDictionary, 0},
// sha512 dictionary lookup
{"b109f3bbbc244eb82441917ed06d618b9008dd09b3befd1b5e07394c706a8bb980b1d7785e5976ec049b46df5f1326af5a2ea6d103fd07c95385ffab0cacbc86", ErrHashedDictionary, 0},
}
)
func TestValidator(t *testing.T) {
v := NewValidator()
pw := "crunchy"
err := v.Check(pw)
if err == nil {
t.Errorf("Expected %v for password '%s', got nil", ErrTooShort, pw)
}
}
func TestRatePassword(t *testing.T) {
v := NewValidatorWithOpts(Options{
MinDist: -1,
Hashers: []hash.Hash{md5.New(), sha1.New(), sha256.New(), sha512.New()},
DictionaryPath: "/usr/share/dict",
})
for _, pw := range pws {
if pw.expected == ErrFoundHIBP {
continue
}
r, err := v.Rate(pw.pw)
if dicterr, ok := err.(*DictionaryError); ok {
err = dicterr.Err
} else if hasherr, ok := err.(*HashedDictionaryError); ok {
err = hasherr.Err
}
if r != pw.rating {
t.Errorf("Expected rating %d for password '%s', got %d", pw.rating, pw.pw, r)
}
if err != pw.expected {
t.Errorf("Expected %v for password '%s', got %v", pw.expected, pw.pw, err)
}
}
}
func TestCheckHIBP(t *testing.T) {
v := NewValidatorWithOpts(Options{
CheckHIBP: true,
})
for _, pw := range pws {
if pw.expected != ErrFoundHIBP {
continue
}
er := v.Check(pw.pw)
if er != pw.expected {
t.Errorf("Expected %v for password '%s', got %v", pw.expected, pw.pw, er)
}
}
}
func BenchmarkValidatePassword(b *testing.B) {
v := NewValidator()
s := hashsum(strconv.Itoa(b.N), md5.New())
for n := 0; n < b.N; n++ {
_ = v.Check(s)
}
}