Skip to content

Instantly share code, notes, and snippets.

@nathants nathants/new-password.py
Last active Jun 3, 2018

Embed
What would you like to do?
#!/usr/bin/env python3.6
import secrets
import string
import sys
import tty
import termios
import functools
import math
import operator
def getch():
fd = sys.stdin.fileno()
old = termios.tcgetattr(fd)
try:
tty.setraw(fd)
val = sys.stdin.read(1).lower()
print(val, end=' ', file=sys.stderr, flush=True)
return val
finally:
termios.tcsetattr(fd, termios.TCSADRAIN, old)
if __name__ == '__main__':
print('https://xkcd.com/936/\n', file=sys.stderr)
# print a guide to password size and strength, from: https://stackoverflow.com/a/42804456
size = len(open('/usr/share/dict/words').readlines())
print('number of word choices: {:,}'.format(size), file=sys.stderr)
print('\nnumber of possible passwords of word length:', file=sys.stderr)
for num_words in 4, 6, 8, 12, 24:
print('', num_words, '->', '{:,}'.format(functools.reduce(operator.mul, range(size - num_words + 1, size + 1)) // math.factorial(num_words)), file=sys.stderr)
print('', file=sys.stderr)
# make a new password
print('how many words would you like? ', file=sys.stderr)
num_words = int(input())
all_words = open('/usr/share/dict/words', encoding='utf-8').read().splitlines()
size = len(all_words)
offsets = dict(zip(string.ascii_lowercase, (secrets.randbelow(size) for _ in range(len(string.ascii_lowercase)))))
print('collecting entropy. press a random key for each word requested to randomize offsets:', end=' ', file=sys.stderr, flush=True)
words = [all_words[(secrets.randbelow(size) + offsets[getch()]) % size] for _ in range(num_words)]
print('', file=sys.stderr, flush=True)
phrase = ' '.join([x.lower().split("'")[0] for x in words])
print(phrase)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.