Skip to content

Instantly share code, notes, and snippets.

@arubdesu
Last active March 1, 2023 17:42
Show Gist options
  • Save arubdesu/a3d0087438da6d0f77ab to your computer and use it in GitHub Desktop.
Save arubdesu/a3d0087438da6d0f77ab to your computer and use it in GitHub Desktop.
much thanks to pudquick for figuring out the mapping and pulling list comprehension magic out of his pocket
#!/usr/bin/python
"""Returns a 'memorable' password to facilitate typing off another computers screen
Originally designed for making long/semi-complex, but easier to type passwords
"""
import optparse
import gzip
from random import randrange, choice
def chunkstring(string, length):
"""list the comprehendo, my friendo"""
return (string[0+i:length+i] for i in range(0, len(string), length))
# Read in a range of the same words Password Assistant uses, much thanks to frogor
def words_in_range(short, loong):
"""Given a low and high length, return a list of words provided on OS X"""
words_path = '/System/Library/Frameworks/SecurityInterface.framework/Resources/pwa_dict_en.gz'
words_file = gzip.open(words_path, 'rb')
# seek(essentially) to the second 'table' of data that tells you beginning/ends of words
#pylint: disable=unused-variable
ignore = words_file.read(512)
# build our word length counts with the 64 sections as indexes, with the values
# represented in the file as hex - ergo the '16', which int converts
word_counts = dict()
for num_of_letters_index in range(64):
word_counts[num_of_letters_index] = int(words_file.read(8).strip(), 16)
keys = sorted(word_counts.keys())
results = []
for counts in keys:
this_count = word_counts[counts]
if this_count > 0:
# Only look for words if word count is more than 0
# read (the number of words * word length) bytes
raw_words = words_file.read(this_count*counts)
# chunk them up by word length
words = chunkstring(raw_words, counts)
for word in words:
if len(word) >= short and len(word) <= loong:
try:
word.decode('ascii')
results.append(word)
#pylint: disable=bare-except
except:
pass
words_file.close()
return results
def main():
"""gimme some main"""
#pylint: disable=invalid-name
p = optparse.OptionParser()
p.set_usage("""Usage: %prog [options]""")
p.add_option('--shortest', '-s', dest='shortest_number', default=6, type=int,
help="""(Integer) Number of letters in shortest words to randomly choose.""")
p.add_option('--longest', '-l', dest='longest_number', default=10, type=int,
help="""(Integer) Number of letters in longest words to randomly choose.""")
p.add_option('--total', '-t', dest='total_length', default=22, type=int,
help="""(Integer) Total number of letters in final password.""")
#pylint: disable=unused-variable
options, arguments = p.parse_args()
scoped_words = words_in_range(options.shortest_number, options.longest_number)
full_len = len(scoped_words)
front, back = (scoped_words[randrange(0, full_len)], scoped_words[randrange(0, full_len)])
diff_string = ''
if len(front + back) < options.total_length:
difference = options.total_length - len(front + back)
while difference > 4:
#pylint: disable=anomalous-backslash-in-string
diff_string += choice('!@#$%&*+=-<>?/\:')
difference -= 1
#pylint: disable=unused-variable
for diff in range(difference):
diff_string += str(randrange(5, 10, 2))
final_password = ''.join([front, diff_string, back])
print final_password
if __name__ == '__main__':
main()
@gregneagle
Copy link

There's a definite pattern to the generated digits between the words: 7s and 5s only:

% python memorable_passworder.py 
impanels:5575banters
% python memorable_passworder.py
snappiest75symbiotic
% python memorable_passworder.py
farmland:!5757jammer
% python memorable_passworder.py
fusileers55oxidizers
% python memorable_passworder.py
nickel@7555Brunswick

Is that intended?

@arubdesu
Copy link
Author

Darn those 'up to but not including' cases! Fixed, thanks. You are truly the snappiest75symbiotic

@cschutzman
Copy link

The real questions is… who is going to snag nickel@7555Brunswick as their next AppleID.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment