Online password generators are a bad idea: you trust a website with your fresh credential, and the site’s JavaScript may log or transmit what it generates. Strong password generation should happen locally, with cryptographically secure randomness, in tools you can inspect.
The Problem with Web-Based Generators
- Run JavaScript you cannot easily audit
- May transmit generated passwords via analytics
- Poorly written ones use
Math.random()— not cryptographically secure - Subject to supply chain attacks (CDN compromise, npm injection)
Command-Line Generators
Using /dev/urandom
# 24-character alphanumeric
cat /dev/urandom | tr -dc 'A-Za-z0-9' | head -c 24; echo
# With special characters
cat /dev/urandom | tr -dc 'A-Za-z0-9!@#$%^&*()-_=+' | head -c 32; echo
# Hex (useful for API keys)
openssl rand -hex 32
# Base64 (more compact, good for tokens)
openssl rand -base64 32
Python (secrets module — CSPRNG)
# Simple secure password
python3 -c "import secrets, string; \
chars = string.ascii_letters + string.digits + '!@#\$%^&*()'; \
print(''.join(secrets.choice(chars) for _ in range(32)))"
# URL-safe token
python3 -c "import secrets; print(secrets.token_urlsafe(32))"
# Diceware passphrase from system wordlist
python3 -c "
import secrets
words = open('/usr/share/dict/words').read().splitlines()
words = [w for w in words if w.isalpha() and 4 <= len(w) <= 8]
passphrase = ' '.join(secrets.choice(words) for _ in range(6))
print(passphrase)
"
pwgen
sudo apt install pwgen
# 20-char secure random password
pwgen -s 20 1
# 10 passwords of 32 chars with special chars
pwgen -sy 32 10
KeePassXC CLI
sudo apt install keepassxc
keepassxc-cli generate --length 32 --upper --lower --numbers --special
Diceware — Maximum Trust
Diceware passphrases use physical dice, removing all digital entropy concerns:
# EFF wordlist (7,776 words)
curl -o eff_large_wordlist.txt \
https://www.eff.org/files/2016/07/18/eff_large_wordlist.txt
python3 -c "
import secrets
words = {}
with open('eff_large_wordlist.txt') as f:
for line in f:
parts = line.strip().split()
if len(parts) == 2:
words[parts[0]] = parts[1]
def roll(n=5):
return ''.join(str(secrets.randbelow(6) + 1) for _ in range(n))
passphrase = ' '.join(words[roll()] for _ in range(6))
print(passphrase)
"
6 EFF words = ~77.5 bits of entropy. Use 7-8 words for master passwords.
Entropy Comparison
| Method | Length | Entropy |
|---|---|---|
| All lowercase | 12 chars | ~56 bits |
| Alphanumeric | 20 chars | ~119 bits |
| Full charset | 16 chars | ~104 bits |
| 6 EFF words | ~30 chars | ~77 bits |
| 8 EFF words | ~40 chars | ~103 bits |
| openssl rand -base64 32 | 44 chars | 256 bits |
Shell Script Password Generator
#!/bin/bash
# passgen.sh
usage() {
echo "Usage: $0 [-l length] [-t type] [-n count]"
echo " -t: alpha, alnum, full, hex, b64"
exit 1
}
LENGTH=24; TYPE="full"; COUNT=1
while getopts "l:t:n:h" opt; do
case $opt in
l) LENGTH=$OPTARG ;;
t) TYPE=$OPTARG ;;
n) COUNT=$OPTARG ;;
h) usage ;;
esac
done
for _ in $(seq 1 $COUNT); do
case $TYPE in
alpha) python3 -c "import secrets, string; print(''.join(secrets.choice(string.ascii_letters) for _ in range($LENGTH)))" ;;
alnum) python3 -c "import secrets, string; print(''.join(secrets.choice(string.ascii_letters+string.digits) for _ in range($LENGTH)))" ;;
full) python3 -c "import secrets, string; a=string.ascii_letters+string.digits+'!@#\$%^&*()'; print(''.join(secrets.choice(a) for _ in range($LENGTH)))" ;;
hex) openssl rand -hex $(( LENGTH / 2 )) ;;
b64) openssl rand -base64 $LENGTH | head -c $LENGTH; echo ;;
*) usage ;;
esac
done
chmod +x passgen.sh
./passgen.sh -l 32 -t full -n 5
Entropy Deep Dive: Why Diceware Wins
Entropy is measured in bits. Assuming an attacker can try 1 trillion guesses/second:
- 56 bits of entropy: 2 days to crack
- 77 bits of entropy: 400 years
- 103 bits of entropy: 1 trillion years
- 128 bits of entropy: Cryptographically unbreakable in foreseeable future
Method: cat /dev/urandom | tr -dc 'A-Za-z0-9' | head -c 12
- Entropy: ~71 bits (26 lowercase + 26 uppercase + 10 numbers = 62 charset)
- Time to crack: ~10 years
Method: 6 EFF Diceware words
- Entropy: ~77 bits (log2(7776^6) = 77.5)
- Time to crack: ~400 years
- Passphrase: “correct-horse-battery-staple”
The diceware approach is superior because:
- Human-memorable words are easier to type correctly
- Distributed across word boundaries (less pattern fatigue)
- Mathematically equivalent to random character strings
- No special characters that websites reject
For user accounts: Use 5-6 EFF words (70-80 bits). For root/admin: Use 7-8 words (100+ bits).
Password Reuse: The Catastrophic Mistake
One compromised service exposes a password that works on multiple sites. This is the #1 cause of account takeover.
Consequence of password reuse:
- LinkedIn breach: 700 million passwords
- Attacker cracks a few passwords
- Tests those passwords on Gmail, Twitter, Banking sites
- Gains access to 40% of accounts
Solution: Unique password per site, generated locally.
# Store passwords in KeePassXC (encrypted local database)
# Generate passwords with KeePassXC's built-in generator
# Configure to 32 characters, all character types
# Or use a local password store with GPG encryption:
pip3 install pass
pass init your-gpg-key
# Generate and store
pass generate Banking/Checking 32
# Stores: Banking/Checking.gpg (encrypted with your GPG key)
# Retrieve
pass Banking/Checking
Never use online password managers that sync to the cloud (LastPass, 1Password cloud) if you want local control.
Master Password Strategy
If using KeePassXC or local password manager:
Master password: 8 EFF words (128 bits)
Diceware passphrase: "seven-autumn-pencil-gravity-nephew-orange-rocket-system"
Write this down and store it in a physical safe. It’s your master key to all other passwords. If you forget it, all passwords are lost forever.
Alternative: Split the master password using Shamir’s Secret Sharing
pip3 install pyminizip
# Create encrypted password database
pass init your-gpg-key
# Your master password, split into 3 shares (need 2 to recover)
# Requires external tool: https://www.ssss.readthedocs.io/
# This is advanced and rarely necessary
For most users: One strong master password in a safe location is sufficient.
Avoiding Common Password Generation Mistakes
Mistakes to avoid:
- Using website “random password generators”: They’re logging what they generate
- Using
Math.random()in JavaScript: Not cryptographically secure - Patterns (“Password2024!”, “Winter2025!”): Attackers specifically test these
- Reusing a base: “Gmail123”, “Gmail456” on multiple sites
- Birthdate or personal info: Easily guessable supplementary data
- Weak special characters: “!” “?” “@” are guessed first
- Keyboard patterns: “qwerty”, “12345”, “!@#$%”
Correct approach:
# Using openssl (cryptographically secure randomness)
openssl rand -base64 32 | cut -c 1-32
# Output: aB4kDpLx+8yZcQwErTuIsH/VjNmKoP
# Using /dev/urandom (pure randomness)
head -c 32 /dev/urandom | base64
# Output: x9Zm2L5vQWaE8+3pKnJbRs4MvTyU7F
Both are cryptographically secure and not guessable.
API Key Generation Strategy
For API keys and tokens (longer-lived secrets), use even stronger entropy:
# OAuth token (128 bits minimum)
openssl rand -base64 48 | cut -c 1-64
# AWS access key format (simulate)
python3 -c "
import secrets, string
# AWS format: 20 base32 chars
key = ''.join(secrets.choice(string.ascii_uppercase + '234567') for _ in range(20))
print('AKIA' + key) # AKIA prefix for real AWS keys
"
# API key with mixed alphabet and numbers
python3 -c "
import secrets
chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
api_key = 'sk_' + ''.join(secrets.choice(chars) for _ in range(48))
print(api_key)
"
Use 256-bit entropy (43 base64 characters) for API keys that authenticate applications.
Secure Password Storage After Generation
After generating a password:
- Copy to password manager immediately: Never store in plaintext on disk
- Clear clipboard after pasting:
xclip -selection clipboard < /dev/null - Use browser’s built-in password saver (or password manager plugin)
- Never email the password to yourself: Email is transmitted in plaintext
For shared team credentials (AWS accounts, SSH keys):
- Use a shared password manager (Bitwarden Business, 1Password Teams)
- Rotate credentials quarterly
- Audit access logs
- Never share via chat or email
Testing Your Generator
Verify your password generator is actually cryptographically secure:
# Generate 1000 passwords and check for patterns
for i in {1..1000}; do
openssl rand -hex 16 | cut -c 1-16
done | sort | uniq -d | wc -l
# Should be 0 (no duplicates in 1000 samples means good randomness)
# Statistical test (NIST)
pip3 install randomness-tester
# Tests distribution of random bytes
If you see any duplicates or patterns in 1000+ samples, your generator is flawed.
Related Reading
- How to Use BorgBackup for Encrypted Backups
- How to Remove Metadata from PDF Files
- Privacy-Focused Cloud Email Providers Compared
- Best Password Generator Strategy 2026: A Developer’s Guide
- AI Coding Assistant Session Data Lifecycle
- Claude vs ChatGPT for Drafting Gdpr Compliant Privacy
Built by theluckystrike — More at zovo.one