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.
Install
# or, no toolchain required:
Usage
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 ;
let mut pwgen = new
.length
.secure
.symbols
.build?;
let password: String = pwgen.generate_one;
let batch: = pwgen.generate_n;
let streaming = pwgen.iter.take.count;
# Ok::
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:
- 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). -Huses 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.-Hreproducible mode is NOT cryptographically appropriate for high-value secrets. Output is deterministic; an attacker with the same seed file produces the same password.- Unknown-flag stderr format in Strict mode emits ONLY the first unknown-flag error (option A pattern). Upstream's
Getopt::Longiterates per character; we don't replicate that. - No
-a/--alt-phonics(legacy no-op in upstream; we omit entirely). - No "naughty word" filter — upstream has an optional compile-time substring blocklist; v0.1.0 omits it. Forward-review candidate.
- No
--secure-source— upstream's flag toggling/dev/randomvs/dev/urandomis Linux-only and meaningless on modern kernels; we always useOsRng.
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.