Last active
February 7, 2024 09:04
-
-
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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