Skip to main content
{/}codefunc
Web & APIJuly 23, 2026 · 7 min read

Password Generators and Entropy: Character Sets, CSPRNG, and What Not to Hash

How password entropy works, why character sets matter, when browser CSPRNG is enough, and why generated passwords are not a substitute for proper password storage hashing.

By codefunc

passwordentropycsprngsecurityweb-crypto

Generated passwords fail for two opposite reasons: they look strong but come from a weak random source, or they are strong but then get stored with a fast hash as if that were "encryption." Frontend tools make generation easy; the security property still depends on entropy, character set, and where the secret goes next.

Bottom line: Use a cryptographically secure PRNG (crypto.getRandomValues), pick a character set that matches the system that will accept the password, and aim for enough entropy (typically 80+ bits for important accounts). Never use SHA-256 of a password as storage. Generators create secrets; password KDFs (Argon2, bcrypt, scrypt) protect them at rest.

Who this guide is for

Frontend and full-stack developers building signup flows, local secret helpers, or test credentials — and anyone choosing between a browser password tool and a password manager. If you only need unique IDs, use a UUID generator; passwords are for authentication secrets, not identifiers.

Entropy in plain language

Entropy measures how hard a value is to guess, usually in bits. Roughly: each extra bit doubles the search space.

For a password drawn uniformly from a set of size N with length L:

entropy_bits ≈ L × log2(N)
Character set Approx. N Length 12 Length 16 Length 20
Digits only 10 ~40 bits ~53 bits ~66 bits
Lowercase 26 ~56 bits ~75 bits ~94 bits
Lower + upper + digits 62 ~71 bits ~95 bits ~119 bits
Above + symbols (~95 printable) ~95 ~79 bits ~105 bits ~131 bits

Rules of thumb used in practice:

Use case Target entropy
Low-value throwaway account ~64 bits
Normal user / API password 80–100 bits
High-value master or vault secret 128+ bits

A long passphrase of random words can also hit these targets; the math is the same — count the size of the word list and the number of words.

Length and alphabet size both matter. Password1! is long enough on paper but fails because it is not drawn uniformly from a large space — attackers try common patterns first.

Character sets: match the consumer

Generators often offer toggles: uppercase, lowercase, digits, symbols, and "exclude ambiguous" (0/O, 1/l/I).

Option When to use Risk
Alphanumeric only Legacy systems that reject symbols Need more length for same entropy
Full printable ASCII Modern password managers / APIs Copy-paste into shells may need quoting
Exclude ambiguous Human typing from a screen Slightly smaller N — compensate with length
No look-alikes + no symbols Some bank / console UIs Easy to under-estimate strength

Always generate against the actual policy of the target system. A 20-character symbol-rich password that a vendor silently truncates to 12 characters is weaker than a 16-character alphanumeric password that is stored in full.

Test candidates with a Password Generator that runs in the browser so you can iterate on length and charset without sending secrets to a server.

Browser CSPRNG vs Math.random

Password generation must use a cryptographically secure random source.

Source Suitable for passwords? Notes
crypto.getRandomValues Yes Web Crypto; available in browsers and modern Node
crypto.subtle (for keys) Yes (key generation) Prefer for cryptographic keys
Math.random() No Not a CSPRNG; predictable enough to reject
Timestamp / UUID v1 style No Not uniform secret material
function randomPassword(length, alphabet) {
  const bytes = new Uint8Array(length);
  crypto.getRandomValues(bytes);
  let out = "";
  // Rejection sampling avoids modulo bias when alphabet.length is not a power of 2
  const maxUnbiased = Math.floor(256 / alphabet.length) * alphabet.length;
  let i = 0;
  while (out.length < length) {
    if (i === bytes.length) {
      crypto.getRandomValues(bytes);
      i = 0;
    }
    const v = bytes[i++];
    if (v < maxUnbiased) {
      out += alphabet[v % alphabet.length];
    }
  }
  return out;
}

Naive bytes[i] % alphabet.length introduces a small bias when the alphabet size does not divide 256 evenly. For short passwords the bias is minor; for high-assurance generators, use rejection sampling as above or a well-reviewed library.

codefunc's Password Generator is built for this workflow: configure charset and length, generate locally, copy once. No data leaves your machine.

Passwords vs UUIDs vs hashes

These tools solve different problems and get mixed up in tickets.

Artifact Purpose Tool
Random password Human or machine secret for login / Basic Auth Password Generator
UUID / ULID Unique identifier, not a secret by default UUID Generator
SHA-256 digest Integrity fingerprint of known data Hash Generator

A UUID is unique; it is not automatically a high-entropy password in the sense of a user-chosen secret with a charset policy — though a 128-bit random UUID can serve as an API token if the system treats it as opaque random bytes. Do not "strengthen" a password by hashing it in the client and sending the hash as the password unless the protocol is designed for that (it usually is not).

Why not for password storage hashing

Generating a strong password and storing passwords are separate layers.

Step Correct approach Wrong approach
Create a secret CSPRNG password / passphrase Math.random, dictionary words alone
Transmit TLS; prefer password managers Paste into public pastebins
Store at rest (server) Argon2id / scrypt / bcrypt with unique salt SHA-256(password), MD5(password)
Verify Same KDF with stored salt and params Compare against a bare SHA digest table

A Hash Generator is excellent for checksums and debugging digests. It is the wrong tool for deciding how to store user passwords. Fast hashes let stolen databases be cracked at GPU speed. OWASP and NIST guidance converge on memory-hard or intentionally slow password hashing — not a single SHA-256 pass.

If you are designing signup:

  1. Generate or accept a high-entropy secret.
  2. Send it only over HTTPS.
  3. On the server, run a password KDF with per-user salt and adequate parameters.
  4. Never log the plaintext password.

Practical workflow for developers

  1. Decide minimum entropy for the environment (API key vs human login).
  2. Pick a charset the consumer accepts; add length until bits are enough.
  3. Generate with crypto.getRandomValues or a client-side Password Generator.
  4. Store in a password manager or secrets vault — not in git, screenshots, or chat.
  5. For machine tokens, consider random bytes encoded as hex/Base64 instead of "pronounceable" passwords.
  6. For IDs in URLs and databases, use UUID Generator — keep auth secrets separate.

Common mistakes

  • Memorable patterns — keyboard walks and SeasonYear! look complex and fall to rules-based attacks.
  • Reuse across systems — one breach unlocks many accounts.
  • Truncation — silent max-length on the server destroys entropy you thought you had.
  • Client-only "hashing" as security — hashing in the browser before send does not replace TLS or server-side KDFs.
  • Uploading secrets to online generators — prefer tools that run entirely in your browser.

Practical takeaway

Treat password generation as sampling from a known alphabet with a CSPRNG until you reach a clear entropy target. Match character sets to real system limits, and compensate with length when the alphabet shrinks. Use codefunc's Password Generator for local generation, UUID Generator for identifiers, and Hash Generator for digests — never as a password-storage strategy. Storage belongs to Argon2/bcrypt/scrypt on the server.

Sources

Try it on codefunc

Related articles

3

Search tools

Find a developer tool