Created
December 6, 2008 15:00
-
-
Save zvoase/32886 to your computer and use it in GitHub Desktop.
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/env python | |
# -*- coding: utf-8 -*- | |
# | |
# phopass.py - Generate phonemic passwords. | |
# | |
##### LICENSE ################################################################ | |
# Copyright (c) 2008 Zachary Voase | |
# | |
# Permission is hereby granted, free of charge, to any person | |
# obtaining a copy of this software and associated documentation | |
# files (the "Software"), to deal in the Software without | |
# restriction, including without limitation the rights to use, | |
# copy, modify, merge, publish, distribute, sublicense, and/or sell | |
# copies of the Software, and to permit persons to whom the | |
# Software is furnished to do so, subject to the following | |
# conditions: | |
# | |
# The above copyright notice and this permission notice shall be | |
# included in all copies or substantial portions of the Software. | |
# | |
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | |
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES | |
# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | |
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT | |
# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, | |
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | |
# OTHER DEALINGS IN THE SOFTWARE. | |
############################################################################## | |
# This program was inspired/copied/stolen from the PhonemicPassword plugin for | |
# Ruby on Rails. The original (Ruby) version was written by Obie Fernandez, | |
# and is available here: | |
# | |
# http://obiefernandez.com/svn/plugins/phonemic_passwords | |
# | |
############################################################################## | |
""" | |
phopass.py - Generate phonemic passwords. | |
To generate a phonemic password, call ``generate_password()`` with an optional | |
integer keyword argument ``length``. It will return a string containing the | |
generated password. The length of the returned password will default to 8 | |
characters. | |
This file may also be run as a script from the command line. In this case, the | |
default password length is 8, but an additional integer argument may be given | |
which will yield a different length. | |
This program was inspired/copied/stolen from the PhonemicPassword plugin for | |
Ruby on Rails. The original (Ruby) version was written by Obie Fernandez, and | |
is available at his website_. | |
.. _website: http://obiefernandez.com/svn/plugins/phonemic_passwords | |
""" | |
import os | |
import random | |
import sys | |
################# | |
# Phoneme flags # | |
################# | |
CONSONANT = 1 | |
VOWEL = 1 << 1 | |
DIPHTHONG = 1 << 2 | |
NOT_FIRST = 1 << 3 | |
NOT_LAST = 1 << 4 | |
RARE = 1 << 5 | |
################ | |
# Phoneme data # | |
################ | |
PHONEMES = { | |
'a': '010000', | |
'ae': '011111', | |
'ah': '011000', | |
'ai': '011000', | |
'ao': '011000', | |
'au': '011000', | |
'aw': '011000', | |
'ay': '011100', | |
'b': '100000', | |
'bl': '101010', | |
'br': '101010', | |
'c': '100010', | |
'ch': '101000', | |
'ck': '101100', | |
'cl': '101010', | |
'cr': '101010', | |
'd': '100000', | |
'dr': '101010', | |
'e': '010000', | |
'ea': '011000', | |
'ee': '011100', | |
'ei': '011110', | |
'eo': '011110', | |
'eu': '011000', | |
'ew': '011100', | |
'f': '100010', | |
'ff': '100100', | |
'fl': '100010', | |
'fr': '100010', | |
'g': '100000', | |
'gg': '101101', | |
'gh': '101100', | |
'gl': '101010', | |
'h': '100010', | |
'i': '010000', | |
'ia': '011000', | |
'ie': '011110', | |
'j': '100011', | |
'k': '100011', | |
'kl': '100011', | |
'kr': '100011', | |
'l': '100000', | |
'ld': '101100', | |
'll': '101101', | |
'lt': '101100', | |
'ly': '101100', | |
'm': '100000', | |
'mp': '101100', | |
'n': '100000', | |
'ng': '101100', | |
'nt': '101100', | |
'o': '010000', | |
'oh': '011000', | |
'oo': '011001', | |
'ough': '011101', | |
'ow': '011000', | |
'p': '100000', | |
'ph': '101011', | |
'pl': '101011', | |
'pr': '101010', | |
'qu': '101011', | |
'r': '100000', | |
'rt': '101000', | |
's': '100000', | |
'sch': '101000', | |
'sh': '101000', | |
'sk': '101000', | |
'st': '101000', | |
't': '100000', | |
'th': '101000', | |
'tr': '101010', | |
'ts': '101100', | |
'tt': '100111', | |
'tw': '101010', | |
'u': '010000', | |
'ui': '010111', | |
'v': '100010', | |
'w': '100010', | |
'wh': '100010', | |
'x': '100001', | |
'y': '100000', | |
'z': '100001', | |
} | |
for key, value in PHONEMES.items(): | |
PHONEMES[key] = int(value, 2) | |
############################ | |
# Password-generation code # | |
############################ | |
def generate_password(length=8): | |
password, first, last, previous = '', True, False, (None, None) | |
desired = CONSONANT if random.randint(0, 4) else VOWEL | |
while len(password) < length: | |
phoneme = random.choice(list(PHONEMES.keys())) | |
phoneme_signature = PHONEMES[phoneme] | |
phoneme_flags = [ | |
phoneme_signature & CONSONANT, | |
phoneme_signature & VOWEL, | |
phoneme_signature & DIPHTHONG, | |
phoneme_signature & NOT_FIRST, | |
phoneme_signature & NOT_LAST, | |
phoneme_signature & RARE] | |
if ((desired not in phoneme_flags) or | |
(first and (NOT_FIRST in phoneme_flags)) or | |
(last and (NOT_LAST in phoneme_flags)) or | |
(len(phoneme) > (length - len(password))) or | |
( | |
(CONSONANT in phoneme_flags) and | |
(DIPHTHONG in phoneme_flags) and | |
(phoneme in password)) or | |
(previous[0] and ( | |
(phoneme in previous[0]) or | |
(previous[0] in phoneme))) or | |
((DIPHTHONG in phoneme_flags) and (not random.randint(0, 3))) or | |
((RARE in phoneme_flags) and random.randint(0, 7))): | |
continue | |
password += phoneme | |
last = (length - len(password)) <= 2 | |
if len(password) >= length: | |
return password | |
desired = VOWEL if (desired == CONSONANT) else CONSONANT | |
previous = (phoneme, phoneme_flags) | |
if first: | |
first = False | |
#################################### | |
# This can be run as a script, too # | |
#################################### | |
if __name__ == '__main__': | |
if sys.argv[1:]: | |
length = int(sys.argv[1]) | |
else: | |
length = 8 | |
sys.stdout.write(generate_password(length) + os.linesep) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment