Security guide
Client-side password generation with Web Crypto and rejection sampling
A technical whitepaper explaining PwdGen's browser-side password generation model, entropy boundaries, rejection sampling, and privacy limits.
Abstract
PwdGen uses a client-side reference generation method: browser or runtime Web Crypto provides random bytes, rejection sampling maps those bytes to unbiased bounded indices, and a Fisher-Yates shuffle distributes required character classes across the final password. The method is intentionally small, auditable, and reproducible across the web app, API adapter, CLI, and the prepared pwdgen-core package.
This document describes the engineering model. It is not a claim of a new cryptographic primitive, a formal standard, or an independent third-party audit.
Randomness source
The generator requests cryptographically strong random values through crypto.getRandomValues(). Web Crypto implementations are expected to use a cryptographically secure pseudo-random number generator seeded with high-quality entropy provided by the host environment. In practice, browsers delegate this responsibility to operating-system facilities and platform cryptographic providers.
PwdGen does not claim that every password-generation call directly samples a hardware noise source. The safer and more accurate statement is that the browser supplies CSPRNG output through the Web Crypto API, and that PwdGen avoids non-cryptographic pseudo-random interfaces.
Why not Math.random()
Math.random() is not specified for security-sensitive use. It is suitable for simulations, visual effects, and ordinary randomized UI behavior, but it does not provide the guarantees expected for passwords, reset codes, signing keys, or other credentials.
PwdGen treats insecure pseudo-random fallbacks as a failure state. If Web Crypto is unavailable, the generator should show a compatibility error rather than silently producing weak credentials.
Rejection sampling
Random bytes and integers are usually drawn from a power-of-two range. Password alphabets rarely have a size that divides that range exactly. A direct modulo operation can make some characters slightly more likely than others.
PwdGen uses rejection sampling:
- Draw a 32-bit unsigned integer.
- Compute the largest multiple of the alphabet size that fits inside the 32-bit range.
- Reject values above that boundary.
- Apply modulo only to the remaining complete range.
This keeps bounded character selection uniform without introducing measurable modulo bias.
Character coverage and entropy
For configured password policies, the generator first selects one character from each enabled class, fills the rest from the combined alphabet, and then shuffles the result. This helps satisfy destination password rules without putting a predictable class at a predictable position.
The theoretical entropy estimate is:
bits = length × log2(uniqueAlphabetSize)
That value is an upper bound for uniformly random choices from the configured alphabet. It does not account for password reuse, user-edited output, compromised devices, leaked passwords, or weak storage by the destination service.
Privacy boundary
In the browser tools, generated values remain in page memory and visible result fields until the user copies or exports them. The local generators do not send generated passwords to PwdGen servers, put them into URLs, or write them into analytics events.
This boundary does not protect against malicious browser extensions, clipboard managers, operating-system compromise, screen capture, phishing pages, or a user pasting a generated password into an unsafe destination.
Reproducible implementation
The public pwdgen-cli package and the prepared pwdgen-core package exist to keep the generation model inspectable outside the web page. Unit tests cover character-class inclusion, excluded characters, invalid configurations, entropy formulas, and the absence of insecure pseudo-random fallback code paths.
The goal is not to make PwdGen a private standard. The goal is to make the implementation small enough that developers can read, test, and replace it when their environment requires a different trust boundary.