passwords 3.1.16

This crate provides useful tools to generate multiple readable passwords, as well as analyze and score them.
Documentation
Passwords
====================

[![CI](https://github.com/magiclen/passwords/actions/workflows/ci.yml/badge.svg)](https://github.com/magiclen/passwords/actions/workflows/ci.yml)

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
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

## Crates.io

https://crates.io/crates/passwords

## Documentation

https://docs.rs/passwords

## License

[MIT](LICENSE)