rusty-pwgen 0.2.0

Generate pronounceable or random passwords from the OS CSPRNG — a Rust port of Theodore Ts'o's `pwgen` with strict-compat mode, deterministic `-H` reproducible mode (SHA256 + ChaCha20), and a typed library API.
Documentation

rusty-pwgen

Generate pronounceable or random passwords from the OS CSPRNG. Rust port of Theodore Ts'o's pwgen 2.08.

crates.io docs.rs CI MSRV license: MIT OR Apache-2.0

Default mode adds --help, --version, completions, & parse-time conflict detection. Strict mode reverts every observable surface to byte-equal pwgen 2.08 (including last-wins flag resolution). The -H reproducible-mode chain is locked at SHA256 + ChaCha20Rng so seed files keep producing the same password.

Part of the Rusty portfolio.

Install

cargo install rusty-pwgen
# or, with prebuilt binaries:
cargo binstall rusty-pwgen
# or, download directly from GitHub Releases:
# https://github.com/jsh562/rusty-pwgen/releases

To also install a pwgen binary alias (argv[0] auto-detect routes into Strict mode):

cargo install rusty-pwgen --features pwgen-alias

Usage

# Default 8-char pronounceable, columnar TTY output
rusty-pwgen

# One 12-char pronounceable password (easy to type, lower entropy)
rusty-pwgen 12 1

# One 16-char cryptographically random password (higher entropy, harder to type)
rusty-pwgen -s 16 1

# 20-char random with symbols (passwords that need to resist offline cracking)
rusty-pwgen -s -y 20 1

# Five passwords with ambiguous chars (0/O, 1/l/I) removed (good for verbal handoff)
rusty-pwgen -B 12 5

# Reproducible mode: same seed file + same pin produce the same password
rusty-pwgen -H ~/.seed#mypin 12 1

# Strict pwgen-compat mode (drop-in pwgen 2.08 replacement, last-wins flag resolution)
rusty-pwgen --strict 12 1
RUSTY_PWGEN_STRICT=1 rusty-pwgen 12 1
pwgen 12 1                                # via pwgen-alias feature or argv[0] symlink

# Shell completions
rusty-pwgen completions bash               # > ~/.bash_completion.d/rusty-pwgen
rusty-pwgen completions zsh                # > ~/.zfunc/_rusty-pwgen
rusty-pwgen completions fish               # > ~/.config/fish/completions/rusty-pwgen.fish
rusty-pwgen completions powershell

Library API

The library exposes pronounceable & secure modes without subprocesses, TTY detection, or CLI parsing. Those live behind the cli feature.

use rusty_pwgen::{PwgenBuilder, CompatibilityMode};

let mut pwgen = PwgenBuilder::new()
    .length(16)
    .secure(true)
    .symbols(true)
    .build()?;

let password: String = pwgen.generate_one();
let batch: Vec<String> = pwgen.generate_n(10);
let streaming = pwgen.iter().take(1_000_000).count();
# Ok::<(), rusty_pwgen::Error>(())

For library-only consumers without CLI deps see the Cargo Features section.

Cargo Features

default enables full, which (for this single-capability port) resolves to the cli umbrella. pwgen-classic reproduces v0.1.x bare-port behavior matching upstream pwgen 2.08 1:1. To strip the CLI surface use default-features = false or --no-default-features & add the features you want.

rusty-pwgen is a single-capability port: its one documented job is "generate pronounceable or random passwords from the OS CSPRNG". No optional feature leaves are carved beyond the required umbrellas; see docs/feature-layout.md for why.

Feature matrix

Feature Description Umbrella(s)
cli All CLI-only dependencies (clap, clap_complete, anyhow, terminal_size) and the binary entry point, mode resolver, output formatter, seed-input resolver, and Strict-mode pre-scanner. Library consumers strip via default-features = false. full, pwgen-classic, pwgen-minimal, pwgen-alias
pwgen-alias Installs an additional pwgen binary alongside rusty-pwgen. Both share source; argv[0] auto-detect routes pwgen invocations into Strict mode. PATH-collision behavior with upstream pwgen is documented in Compatibility below. (standalone, implies cli)
bench Pulls criterion and enables benches/throughput.rs. Dev-tooling only; outside the convention's leaf surface. Name preserved verbatim from v0.1.x. (standalone)

Preset bundles

Bundle Composition Use case
pwgen-classic cli Drop-in upstream pwgen 2.08 replacement. Strict mode is invoked via --strict, RUSTY_PWGEN_STRICT, or pwgen-alias argv[0] auto-detect.
pwgen-minimal cli Explicit minimal-CLI alias for users who prefer the <port>-minimal naming convention seen across other portfolio ports. Identical composition to pwgen-classic.

Keep-list workaround (Cargo features are union-only)

Cargo features cannot subtract from default. To get "everything except a specific feature," disable defaults & enumerate the features you want:

cargo install rusty-pwgen --no-default-features --features "cli"
# → bare CLI with no pwgen alias, no bench tooling.

cargo install rusty-pwgen --no-default-features --features "cli pwgen-alias"
# → CLI + the pwgen alias binary.

For the common cases the named preset bundles are usually sufficient.

Library-only consumers

[dependencies]
rusty-pwgen = { version = "0.2", default-features = false }

This strips clap, clap_complete, anyhow, & terminal_size. The resulting build pulls only rand, rand_chacha, sha2, & thiserror (all required by the always-on library API: OS CSPRNG sourcing, ChaCha20 seeded source for -H, SHA256 hashing for seed input, & error types).

Convention authority

This layout follows the portfolio-wide Cargo Features Convention. The "why" lives in ADR-0006; the "what" lives in project-instructions.md §Cargo Feature Surface. Every Rusty port from v0.2 onward exposes the same umbrella set (default / full / cli / <port>-classic), per-port leaves named in kebab-case, & 2 to 4 preset bundles.

Compatibility

rusty-pwgen has two modes:

  • Default mode. clap-styled flag parser. --help, --version, & the completions subcommand are all available. Conflicting flag pairs (-c -A, -n -0, -1 -C) MUST be rejected at parse time with a clear error.
  • Strict mode (activated by --strict, RUSTY_PWGEN_STRICT=1, or invoking the binary as pwgen). Byte-equal stdout, stderr, & exit codes against pwgen 2.08 (Debian stable 2026-05). Last-wins flag resolution preserved. --help, --version, & completions MUST be rejected.

Cryptographic safety

rusty-pwgen uses rand::rngs::OsRng, which wraps getrandom(2) / BCryptGenRandom / CCRandomGenerateBytes. This is appropriate for general-purpose passwords. It MUST NOT be treated as a substitute for dedicated crypto libraries when generating long-lived key material.

Entropy guidance

Pronounceable mode trades entropy for memorability. At default settings (length 8, capitals + numerals on, no symbols), pronounceable passwords carry around 30-32 bits of entropy vs around 48 bits for -s (secure) mode at the same length. Use -s when memorability isn't required.

Documented intentional divergences

  1. Default-mode conflict rejection. Upstream pwgen accepts conflicting flag pairs via last-wins; rusty-pwgen Default rejects at parse time. Strict mode preserves upstream last-wins.
  2. -H uses SHA256 -> 32-byte ChaCha20 seed, not SHA1. ChaCha20Rng wants 32 bytes natively, so SHA256 fits without padding. The chain is locked at v0.1.0; any change is a MAJOR bump.
  3. -H reproducible mode is not cryptographically appropriate for high-value secrets. Output is deterministic; an attacker with the same seed file produces the same password.
  4. Unknown-flag stderr in Strict. Emits only the first unknown-flag error. Upstream's Getopt::Long iterates per character; we don't replicate that.
  5. No -a/--alt-phonics (legacy no-op upstream; omitted entirely).
  6. No "naughty word" filter. Upstream has an optional compile-time substring blocklist; v0.1.0 omits it. Forward-review candidate.
  7. No --secure-source. Upstream's flag toggling /dev/random vs /dev/urandom is Linux-only & meaningless on modern kernels; rusty-pwgen always uses OsRng.

See docs/COMPATIBILITY.md for the full per-flag matrix.

pwgen-alias PATH-collision warning

Building with --features pwgen-alias installs a second binary named pwgen alongside rusty-pwgen. If upstream pwgen is also on the same PATH, whichever directory comes first wins. Invoke rusty-pwgen (always unambiguous) or omit the pwgen-alias feature when upstream pwgen is also present.

What's not shipped

  • -a/--alt-phonics. Legacy no-op upstream; omitted entirely.
  • "Naughty word" substring blocklist. Upstream has an optional compile-time list; v0.1.0 omits it. Forward-review candidate.
  • --secure-source flag. Linux-only & meaningless on modern kernels; rusty-pwgen always uses OsRng.

MSRV

Rust 1.85 (edition 2024 floor; std::io::IsTerminal stable since 1.70).

License

Dual-licensed under MIT or Apache-2.0 at your option.