/*
* crunchy - find common flaws in passwords
* Copyright (c) 2017-2018, Christian Muehlhaeuser <muesli@gmail.com>
*
* 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},
{"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 TestValidatePassword(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 {
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 BenchmarkValidatePassword(b *testing.B) {
v := NewValidator()
s := hashsum(strconv.Itoa(b.N), md5.New())
for n := 0; n < b.N; n++ {
v.Check(s)
}
}