Skip to content

Instantly share code, notes, and snippets.

@zvoase
Created December 6, 2008 15:00
Show Gist options
  • Save zvoase/32886 to your computer and use it in GitHub Desktop.
Save zvoase/32886 to your computer and use it in GitHub Desktop.
#!/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