Skip to content

Instantly share code, notes, and snippets.

@0x9900
Created July 12, 2026 16:54
Show Gist options
  • Select an option

  • Save 0x9900/405d5099c6d44813757967cb823b2a06 to your computer and use it in GitHub Desktop.

Select an option

Save 0x9900/405d5099c6d44813757967cb823b2a06 to your computer and use it in GitHub Desktop.
Yet another password generator
#!/usr/bin/env python3
# vim:fenc=utf-8
#
# Copyright © 2026 fred <github-fred@hidzz.com>
#
# Distributed under terms of the BSD 3-Clause license.
import os
import secrets
import sys
from functools import lru_cache
from pathlib import Path
from typing import List
DICT_FILE = Path('/usr/share/dict/words')
# Most common word with a length of 3 to 6 characters.
# https://gist.github.com/deekayen/4148741
COMMON_WORDS = [
"that", "have", "with", "this", "from", "they", "will", "would", "there",
"their", "what", "about", "which", "when", "make", "like", "time", "just",
"know", "take", "people", "into", "year", "your", "good", "some", "could",
"them", "other", "than", "then", "look", "only", "come", "over", "think",
"also", "back", "after", "work", "first", "well", "even", "want", "these",
"give", "most",
]
# Secure random for shuffling
_RANDOM = secrets.SystemRandom()
@lru_cache(maxsize=1)
def all_words() -> List[str]:
words = set()
if not DICT_FILE.exists():
print(f'The dictionnary file "{DICT_FILE}" does not exists')
sys.exit(os.EX_OSFILE)
with DICT_FILE.open('r', encoding='utf-8', errors='replace') as fd:
for word in fd:
word = word.strip().lower()
if word in COMMON_WORDS:
continue
# Remove words with accents because they might be challenging to type
# with some keyboards.
if "'" in word or not word.isascii():
continue
if 3 < len(word) < 6:
words.add(word)
print(f'=== {len(words)} selected ===')
return list(words)
def _maybe_transform(word: str) -> str:
"""Optionally transform a word with leetspeak substitutions."""
# Use a consistent mapping
leet_map = {'i': '!', 'e': '3', 'o': '0', 'a': '@', 's': '$'}
# Transform 40% of transformable characters
transformed = []
chances = 50
for char in word:
if char in leet_map and secrets.randbelow(100) < chances:
transformed.append(leet_map[char])
chances = chances - 5 if chances > 0 else chances
else:
transformed.append(char)
return ''.join(transformed)
def make_password(length: int = 4, leet_chance: float = 0.4) -> str:
if length < 1:
raise ValueError('Length must be at least 1')
words = all_words()
if not words:
raise RuntimeError('No words available for password generation')
password = [secrets.choice(words) for _ in range(length)]
# Apply leetspeak substitution to random words
for i in range(length):
if secrets.randbelow(100) < leet_chance * 100:
password[i] = _maybe_transform(password[i])
_RANDOM.shuffle(password)
return '-'.join(password)
def main():
for _ in range(6):
password = make_password(4)
print(f'{len(password)} = {password}')
if __name__ == "__main__":
main()
#
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment