import "github.com/klauspost/password"
Dictionary Password Validation for Go
For usage and examples see: https://github.com/klauspost/password (or open the README.md)
This library will help you import a password dictionary and will allow you to validate new/changed passwords against the dictionary.
You are able to use your own database and password dictionary. Currently the package supports importing dictionaries similar to CrackStation's Password Cracking Dictionary: https://crackstation.net/buy-crackstation-wordlist-password-cracking-dictionary.htm
It and has "drivers" for various backends, see the "drivers" directory, where there are implementations and a test framework that will help you test your own drivers.
var BulkMax = 1000
BulkMax is the maximum number of passwords sent at once to the writer. You can change this before starting an import.
ErrInvalidString is returned by the default sanitizer if the string contains an invalid utf8 character sequence.
ErrPasswordInDB is returedn by Check, if the password is in the database.
ErrSanitizeTooShort is returned by the default sanitizer, if the input password is less than 8 runes.
Logger used for output during Import. This can be exchanged with your own.
Check a password against the database. It will return an error if:
- Sanitazition fails. - DB lookup returns an error - Password is in database (ErrPasswordInDB)
If nil is passed as Sanitizer, DefaultSanitizer will be used.
Import will populate a database with common passwords.
You must supply a Tokenizer (see tokenizer package for default tokenizers) that will deliver the passwords, a DbWriter, where the passwords will be sent, and finally a Sanitizer to clean up the passwords - - if you send nil DefaultSanitizer will be used.
Code:
r, err := os.Open("./testdata/testdata.txt.gz") if err != nil { panic("cannot open file") } // Create a database to write to mem := testdb.NewMemDBBulk() // The input is gzipped text file with // one input per line, so we choose a tokenizer // that matches. in, err := tokenizer.NewGzLine(r) if err != nil { panic(err) } // Import using the default sanitizer err = Import(in, mem, nil) if err != nil { panic(err) } // Data is now imported, let's do a check // Check a password that is in the sample data err = Check("tl1992rell", mem, nil) fmt.Println(err)
Output:
password found in database
Open a xz compressed archive and import it. Uses the "xi2.org/x/xz" package to read xz files.
Code:
r, err := os.Open("rockyou.txt.xz")
if err != nil {
// Fake it
fmt.Println("Imported", 9341543, "items")
return
}
xzr, err := xz.NewReader(r, 0)
if err != nil {
panic(err)
}
mem := testdb.NewMemDBBulk()
in := tokenizer.NewLine(xzr)
err = Import(in, mem, nil)
if err != nil {
panic(err)
}
fmt.Println("Imported", len(*mem), "items")
Output:
Imported 9341543 items
Sanitize will sanitize a password, useful before hashing and storing it.
If the sanitizer is nil, DefaultSanitizer will be used.
SanitizeOK can be used to check if a password passes the sanitizer.
If the sanitizer is nil, DefaultSanitizer will be used.
If your DbWriter implements this, input will be sent in batches instead of using Add.
A DB should check the database for the supplied password. The password sent to the interface has always been sanitized.
A DbWriter is used for adding passwords to a database. Items sent to Add has always been sanitized, however the same passwords can be sent multiple times.
A Sanitizer should prepare a password, and check the basic properties that should be satisfied. For an example, see DefaultSanitizer
DefaultSanitizer should be used for adding passwords to the database. Assumes input is UTF8.
DefaultSanitizer performs the following sanitazion:
- Trim space, tab and newlines from start+end of input - Check that there is at least 8 runes. Return ErrSanitizeTooShort if not. - Check that the input is valid utf8. Return ErrInvalidString if not. - Normalize input using Unicode Normalization Form KD
If input is less than 8 runes ErrSanitizeTooShort is returned.
This example shows how to create a custom sanitizer that checks if the password matches the username or email.
CustomSanitizer is defined as:
type CustomSanitizer struct { email string username string } func (c CustomSanitizer) Sanitize(s string) (string, error) { s, err := DefaultSanitizer.Sanitize(s) if err != nil { return "", err } if strings.EqualFold(s, c.email) { return "", errors.New("password cannot be the same as email") } if strings.EqualFold(s, c.username) { return "", errors.New("password cannot be the same as user name") } return s, nil }
Code:
// Create a custom sanitizer. san := CustomSanitizer{email: "john@doe.com", username: "johndoe73"} // Check some passwords err := SanitizeOK("john@doe.com", san) fmt.Println(err) err = SanitizeOK("JohnDoe73", san) fmt.Println(err) err = SanitizeOK("MyP/|$$W0rd", san) fmt.Println(err)
Output:
password cannot be the same as email password cannot be the same as user name <nil>
Tokenizer delivers input tokens (passwords). Calling Next() should return the next password, and when finished io.EOF should be returned.
It is ok for the Tokenizer to send empty strings and duplicate values.
Path | Synopsis |
---|---|
drivers | Provides a standard test library for drivers. |
drivers/bloompw | A bitset Bloom filter for a reduced memory password representation. |
drivers/boltpw | Driver for BoltDB |
drivers/cassandra | Package cassandra is a driver for Apache Cassandra |
drivers/mgopw | Driver for MongoDB |
drivers/sqlpw | Wrapper for an SQL database backend |
drivers/testdb | An in-memory database for testing |
tokenizer | Tokenizers for various formats, that satisfies the password.Tokenizer interface. |
Package password imports 8 packages (graph) and is imported by 1 packages. Updated 2016-07-21. Refresh now. Tools for package owners.