Skip to content

Instantly share code, notes, and snippets.

@Raniz85
Last active February 7, 2024 09:04
Show Gist options
  • Save Raniz85/1209eb09fa8e5cedc0106787aa0888cd to your computer and use it in GitHub Desktop.
Save Raniz85/1209eb09fa8e5cedc0106787aa0888cd to your computer and use it in GitHub Desktop.
Short Python script to generate a passphrase with capitals, numbers and special characters using aspell as the source for the wordlist. Perfect for generating rememberable passwords that also pass common password requirements. Make sure you have aspell and at least one dictionary installed and change the default language on row 18 as you see fit.
#!/usr/bin/python3
import subprocess
import secrets
import argparse
parser = argparse.ArgumentParser(
description="Generate a passphrase.\n"
"The phrase will consist of a configurable number of words separated by numbers or special characters. One of the "
"words will be capitalized."
)
parser.add_argument("-n", "--num-words", type=int, default=3)
parser.add_argument("--min-length", type=int, default=4, help="Minimum length of words")
parser.add_argument(
"--max-length", type=int, default=10, help="Maximum length of words"
)
parser.add_argument(
"-l", "--language", default="sv", help="Language to use for wordlist"
)
parser.add_argument("-p", action="store_true", help="Print the length of the wordlist before printing the passphrase")
args = parser.parse_args()
def shuffle(source):
stack = source[:]
shuffled = []
while len(stack) > 0:
index = secrets.randbelow(len(stack))
shuffled.append(stack[index])
del stack[index]
return shuffled
def remove_ownership_suffix(word):
if args.language == "en" and word.endswith("'s"):
return word[:-2]
else:
return word
words = list(
filter(
lambda w: len(w) >= args.min_length and len(w) <= args.max_length,
map(
lambda w: remove_ownership_suffix(w.lower()),
subprocess.check_output(
f"aspell -d {args.language} dump master | aspell -l {args.language} expand",
shell=True,
)
.decode()
.splitlines(),
),
)
)
if args.p:
print(len(words))
words = [secrets.choice(words) for _ in range(args.num_words)]
cap_index = secrets.randbelow(len(words) - 1)
words[cap_index] = words[cap_index].capitalize()
special_chars = list("!@#$%^&*")
numbers = list(str(i) for i in range(0, 10))
separators = []
for i in range(args.num_words - 1):
if i == 0:
separator = secrets.choice(special_chars)
elif i == 1:
separator = secrets.choice(numbers)
else:
separator = secrets.choice(special_chars + numbers)
separators.append(separator)
separators = shuffle(separators)
separators.append("")
phrase = "".join(e for pair in zip(words, separators) for e in pair)
print(phrase)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment