README.md
1crunchy
2=======
3
4[![Latest Release](https://img.shields.io/github/release/muesli/crunchy.svg)](https://github.com/muesli/crunchy/releases)
5[![GoDoc](https://godoc.org/github.com/golang/gddo?status.svg)](https://godoc.org/github.com/muesli/crunchy)
6[![Build Status](https://travis-ci.org/muesli/crunchy.svg?branch=master)](https://travis-ci.org/muesli/crunchy)
7[![Coverage Status](https://coveralls.io/repos/github/muesli/crunchy/badge.svg?branch=master)](https://coveralls.io/github/muesli/crunchy?branch=master)
8[![Go ReportCard](http://goreportcard.com/badge/muesli/crunchy)](http://goreportcard.com/report/muesli/crunchy)
9
10Finds common flaws in passwords. Like cracklib, but written in Go.
11
12Detects:
13 - `ErrEmpty`: Empty passwords
14 - `ErrTooShort`: Too short passwords
15 - `ErrTooFewChars`: Too few different characters, like "aabbccdd"
16 - `ErrTooSystematic`: Systematic passwords, like "abcdefgh" or "87654321"
17 - `ErrDictionary`: Passwords from a dictionary / wordlist
18 - `ErrMangledDictionary`: Mangled / reversed passwords, like "p@ssw0rd" or "drowssap"
19 - `ErrHashedDictionary`: Hashed dictionary words, like "5f4dcc3b5aa765d61d8327deb882cf99" (the md5sum of "password")
20 - `ErrFoundHIBP`: Optional hash checks against the haveibeenpwned.com database
21
22Your system dictionaries from `/usr/share/dict` will be indexed. If no dictionaries were found, crunchy only relies on
23the regular sanity checks (`ErrEmpty`, `ErrTooShort`, `ErrTooFewChars` and `ErrTooSystematic`). On Ubuntu it is
24recommended to install the wordlists distributed with `cracklib-runtime`, on macOS you can install `cracklib-words` from
25brew. You could also install various other language dictionaries or wordlists, e.g. from skullsecurity.org.
26
27crunchy uses the WagnerFischer algorithm to find mangled passwords in your dictionaries.
28
29## Installation
30
31Make sure you have a working Go environment (Go 1.2 or higher is required).
32See the [install instructions](http://golang.org/doc/install.html).
33
34To install crunchy, simply run:
35
36 go get github.com/muesli/crunchy
37
38## Example
39
40```go
41package main
42
43import (
44 "github.com/muesli/crunchy"
45 "fmt"
46)
47
48func main() {
49 validator := crunchy.NewValidator()
50
51 err := validator.Check("12345678")
52 if err != nil {
53 fmt.Printf("The password '12345678' is considered unsafe: %v\n", err)
54 }
55
56 err = validator.Check("p@ssw0rd")
57 if dicterr, ok := err.(*crunchy.DictionaryError); ok {
58 fmt.Printf("The password 'p@ssw0rd' is too similar to dictionary word '%s' (distance %d)\n",
59 dicterr.Word, dicterr.Distance)
60 }
61
62 err = validator.Check("d1924ce3d0510b2b2b4604c99453e2e1")
63 if err == nil {
64 // Password is considered acceptable
65 ...
66 }
67}
68```
69
70## Custom Options
71
72```go
73package main
74
75import (
76 "github.com/muesli/crunchy"
77 "fmt"
78)
79
80func main() {
81 validator := crunchy.NewValidatorWithOpts(crunchy.Options{
82 // MinLength is the minimum length required for a valid password
83 // (must be >= 1, default is 8)
84 MinLength: 10,
85
86 // MinDiff is the minimum amount of unique characters required for a valid password
87 // (must be >= 1, default is 5)
88 MinDiff: 8,
89
90 // MinDist is the minimum WagnerFischer distance for mangled password dictionary lookups
91 // (must be >= 0, default is 3)
92 MinDist: 4,
93
94 // Hashers will be used to find hashed passwords in dictionaries
95 Hashers: []hash.Hash{md5.New(), sha1.New(), sha256.New(), sha512.New()},
96
97 // DictionaryPath contains all the dictionaries that will be parsed
98 // (default is /usr/share/dict)
99 DictionaryPath: "/var/my/own/dicts",
100
101 // Check haveibeenpwned.com database
102 // Default is false
103 CheckHIBP: true,
104 })
105 ...
106}
107```
108