rusty-pwgen 0.1.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

A Rust port of Theodore Ts'o's pwgen utility: generate pronounceable or random passwords from the OS CSPRNG. Static binaries on Linux, macOS, and Windows; works with or without a Rust toolchain via cargo install or cargo binstall. Default mode adds quality-of-life niceties upstream pwgen doesn't have (--help, --version, completions, parse-time conflict detection); Strict mode reverts every observable surface to byte-identical pwgen 2.08 behavior for drop-in migration.

Part of the Rusty portfolio — a collection of small Rust ports of utilities missing from the Rust ecosystem.

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

Install

cargo install rusty-pwgen
# or, no toolchain required:
cargo binstall rusty-pwgen

Usage

rusty-pwgen                   # 8-char pronounceable, columnar TTY output
rusty-pwgen 12 1              # one 12-char pronounceable password
rusty-pwgen -s 16 1           # one 16-char cryptographically random
rusty-pwgen -s -y 20 1        # 20-char random with symbols
rusty-pwgen -B 12 5           # 5 passwords with ambiguous chars removed
rusty-pwgen -H ~/.seed#mypin 12 1   # reproducible: same seed file → same password

Cargo Features

Feature Default Includes
cli clap, clap_complete, anyhow, terminal_size; the rusty-pwgen binary
pwgen-alias also produces a second pwgen binary (auto-Strict via argv[0])
bench criterion harness
default-features = false n/a library-only: rand + rand_chacha + sha2 + thiserror only

Library API

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

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

Compatibility statement (vs upstream pwgen)

Pinned upstream version: pwgen 2.08 (Debian stable 2026-05).

Cryptographic safety: rusty-pwgen uses rand::rngs::OsRng (which wraps getrandom, pulling from getrandom(2) / BCryptGenRandom / CCRandomGenerateBytes) for non-deterministic generation. This is appropriate for general-purpose passwords. It is NOT 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 ≈30-32 bits of entropy vs ≈48 bits for -s (secure) mode at the same length. Use -s when memorability isn't required.

Documented intentional divergences from upstream pwgen:

  1. Default-mode conflict rejection — upstream pwgen accepts conflicting flag pairs (-c -A, -n -0, -1 -C) via last-wins; rusty-pwgen Default rejects them at parse time with a clear error. Strict mode preserves upstream last-wins (FR-014/015).
  2. -H uses SHA256 → 32-byte ChaCha20 seed, not SHA1. ChaCha20Rng wants 32 bytes natively, so SHA256 fits without padding (Clarification Q1). 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 format in Strict mode emits ONLY the first unknown-flag error (option A pattern). Upstream's Getopt::Long iterates per character; we don't replicate that.
  5. No -a/--alt-phonics (legacy no-op in upstream; we omit 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 and meaningless on modern kernels; we always use OsRng.

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.

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

Stability (lockstep SemVer)

Library and binary share a single crate version. The -H reproducible-mode contract (SHA256 + ChaCha20Rng chain) is locked at v0.1.0 — any change is a MAJOR bump because consumers may have stored seed files expecting specific passwords back. Pronounceable-algorithm output changes are MINOR bumps. All public enums and structs are #[non_exhaustive].

MSRV

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

License

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