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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
/*!
# Passwords
This crate provides useful tools to generate multiple readable passwords, as well as analyze and score them.

## Generator

`PasswordGenerator` can be used for generating passwords which consist optional numbers, lowercase letters, uppercase letters, symbols and spaces.

```rust
use passwords::PasswordGenerator;

let pg = PasswordGenerator {
       length: 8,
       numbers: true,
       lowercase_letters: true,
       uppercase_letters: true,
       symbols: true,
       spaces: true,
       exclude_similar_characters: false,
       strict: true,
   };

println!("{}", pg.generate_one().unwrap());
println!("{:?}", pg.generate(5).unwrap());
```

It also has a fluent interface.

```rust
use passwords::PasswordGenerator;

let pg = PasswordGenerator::new().length(8).numbers(true).lowercase_letters(true).uppercase_letters(true).symbols(true).spaces(true).exclude_similar_characters(true).strict(true);

println!("{}", pg.generate_one().unwrap());
println!("{:?}", pg.generate(5).unwrap());
```

The `generate` method has been optimized for multiple generation. Don't reuse the `generate_one` method to generate multiple passwords. If the count of passwords can't be determined, use the `try_iter` method to create a `PasswordGeneratorIter` instance which implements the `Iterator` trait and can re-generate passwords more efficiently.

```rust
use passwords::PasswordGenerator;

let pgi = PasswordGenerator::new().try_iter().unwrap();

println!("{}", pgi.generate_one());
println!("{:?}", pgi.generate(5));
```

```rust
use passwords::PasswordGenerator;

let mut pgi = PasswordGenerator::new().try_iter().unwrap();

println!("{}", pgi.next().unwrap());
println!("{}", pgi.next().unwrap());
```

## Hasher

To enable hashing functions, you need to enable the **crypto** feature.

```toml
[dependencies.passwords]
version = "*"
features = ["crypto"]
```

Then, `bcrypt`, `identify_bcrypt`, `bcrypt_format`, `identify_bcrypt_format`, `get_password_with_null_terminated_byte` and `gen_salt` functions in the `hasher` module are available.

```rust
# #[cfg(feature = "crypto")]
# {
use passwords::hasher;

let salt = hasher::gen_salt();

let hashed = hasher::bcrypt(10, &salt, "password\0").unwrap();
assert!(unsafe { hasher::identify_bcrypt(10, &salt, "password\0", &hashed) });

let mcf = hasher::bcrypt_format(10, &salt, "password\0").unwrap();
assert!(unsafe { hasher::identify_bcrypt_format("password\0", mcf) });
# }
```

## Analyzer

The `analyze` function in the `analyzer` module can be used to create a `AnalyzedPassword` instance which contains some information about the input password.

Typically, we don't want our readable password to contain control characters like BS, LF, CR, etc.
Before the analyzer analyzes a password, it filters the password in order to remove its control characters. And after analyzing, the analyzer will return the filtered password.
Therefore, you can use this analyzer as a password guard before you store the input password (or generally hash it first and then store) to your database.

```rust
use passwords::analyzer;

let password = "ZYX[$BCkQB中文}%A_3456]  H(\rg";

let analyzed = analyzer::analyze(password);

assert_eq!("ZYX[$BCkQB中文}%A_3456]  H(g", analyzed.password()); // "\r" was filtered
assert_eq!(26, analyzed.length()); // Characters' length, instead of that of UTF-8 bytes
assert_eq!(2, analyzed.spaces_count()); // Two spaces between "]" and "H"
assert_eq!(4, analyzed.numbers_count()); // Numbers are "3456"
assert_eq!(2, analyzed.lowercase_letters_count()); // Lowercase letters are "k" and "g"
assert_eq!(9, analyzed.uppercase_letters_count()); // Uppercase letters are "ZYX", "BC", "QB", "A" and "H"
assert_eq!(7, analyzed.symbols_count()); // Symbols are "[$", "}%", "_", "]" and "("
assert_eq!(2, analyzed.other_characters_count()); // Other characters are "中文". These characters are usually not included on the rainbow table.
assert_eq!(2, analyzed.consecutive_count()); // Consecutive repeated characters are "  " (two spaces)
assert_eq!(2, analyzed.non_consecutive_count()); // Non-consecutive repeated characters are "B" (appears twice)
assert_eq!(7, analyzed.progressive_count()); // Progressive characters are "ZYX" and "3456". "BC" is not counted, because its length is only 2, not three or more.
```

You can also check whether a password is too simple and dangerous to use, by looking up a *common passwords table*.
If you want to do that, you need to enable the **common-password** feature.

```toml
[dependencies.passwords]
version = "*"
features = ["common-password"]
```
Then, the `is_common_password` function in `analyzer` module and the `is_common` method of a `AnalyzedPassword` instance are available.

You should notice that after you enable the **common-password** feature, the time for compiling increases dramatically, because the *common passwords table* will be compiled into the executable binary file as a hardcode array.


## Scorer

After analyzing a password, you can use the `score` function in the `scorer` module to score it.

```rust
use passwords::analyzer;
use passwords::scorer;

assert_eq!(62f64, scorer::score(&analyzer::analyze("kq4zpz13")));
assert_eq!(100f64, scorer::score(&analyzer::analyze("ZYX[$BCkQB中文}%A_3456]  H(\rg")));

if cfg!(feature = "common-password") {
    assert_eq!(11.2f64, scorer::score(&analyzer::analyze("feelings"))); // "feelings" is common, so the score is punitively the original divided by 5
} else {
    assert_eq!(56f64, scorer::score(&analyzer::analyze("feelings")));
}
```

A password whose score is,

* 0 ~ 20 is very dangerous (may be cracked within few seconds)
* 20 ~ 40 is dangerous
* 40 ~ 60 is very weak
* 60 ~ 80 is weak
* 80 ~ 90 is good
* 90 ~ 95 is strong
* 95 ~ 99 is very strong
* 99 ~ 100 is invulnerable
*/

/// Analyze passwords.
pub mod analyzer;
mod generator;
#[cfg(feature = "crypto")]
/// Hash passwords.
pub mod hasher;
/// Score passwords.
pub mod scorer;

pub use analyzer::AnalyzedPassword;
pub use generator::PasswordGenerator;