Last active
September 19, 2019 10:45
-
-
Save yaunj/ab420e8358350c4ed39a476bf97a79c3 to your computer and use it in GitHub Desktop.
xkcd style password generator
This file contains 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/env python | |
"""Generate a password in similar vein to XKCD 936""" | |
from __future__ import print_function, unicode_literals | |
import random | |
import string | |
class XKCDPasswordGenerator: | |
"""Generate a password in similar vein to XKCD 936""" | |
def __init__(self, dictionary_file='/usr/share/dict/words'): | |
self.dictionary = get_dict(dictionary_file) | |
def get_dictword(self, length): | |
"""Return a random dictionary word of required length""" | |
return random.choice(list(word.strip() for word in self.dictionary if len(word) > length)) | |
def genpass(self, words, digits): | |
"""Generate a random XKCD 936 password""" | |
wordcount, wordlength = words | |
padding = random.choice(string.punctuation) * 2 | |
separator = random.choice(string.punctuation) | |
pwparts = [padding, get_digits(digits), separator] | |
for i in range(wordcount): | |
if i % 2 == 0: | |
case = str.lower | |
else: | |
case = str.upper | |
pwparts.append(case(self.get_dictword(wordlength))) | |
pwparts.append(separator) | |
pwparts.append(get_digits(digits)) | |
pwparts.append(padding) | |
return ''.join(map(str, pwparts)) | |
def get_digits(digits): | |
"""Return a random number with required number of digits""" | |
return random.randint(10 ** (digits - 1), (10 ** digits) - 1) | |
def get_dict(filename='/usr/share/dict/words'): | |
"""Get sanitized words from a dictionary file""" | |
words = [] | |
with open(filename) as dictfile: | |
for word in dictfile: | |
word = word.strip() | |
if all(c in string.ascii_letters for c in word): | |
words.append(word) | |
return words | |
def main(): | |
"""Main entry point""" | |
import argparse | |
parser = argparse.ArgumentParser() | |
parser.add_argument('-w', '--words', help='number of words', type=int, default=3) | |
parser.add_argument('-W', '--word-length', help='minimum word length', type=int, default=4) | |
parser.add_argument('-d', '--digits', help='number of digits', type=int, default=2) | |
parser.add_argument('-n', '--num-passwords', help='number of passwords to generate', type=int, default=1) | |
args = parser.parse_args() | |
generator = XKCDPasswordGenerator() | |
for _ in range(args.num_passwords): | |
print(generator.genpass((args.words, args.word_length), args.digits)) | |
if __name__ == '__main__': | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment