Skip to content

Instantly share code, notes, and snippets.

@tzarskyz
Forked from dcolish/passwordmaker.py
Created September 7, 2013 11:13
Show Gist options
  • Save tzarskyz/6474745 to your computer and use it in GitHub Desktop.
Save tzarskyz/6474745 to your computer and use it in GitHub Desktop.
"""
Will either compute a passwordmaker style key from `sha256(mp + site +
username)` or open a symmetrically keyed gpg file and lookup a specific
site-key for the username and password. The keyfile must follow the following
format::
foobar.com:
username: johnuser
password: megaleet
"""
from argparse import ArgumentParser
import getpass
import hashlib
import math
import gnupg
import yaml
CHARSET = ("ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789`~!@#$%^&*()_-+={}|[]\\:\";\'<>?,./")
# `copy_url` from lodgeit.py
# :license: 3-Clause BSD
# :authors: 2007-2008 Georg Brandl <[email protected]>,
# 2006 Armin Ronacher <[email protected]>,
# 2006 Matt Good <[email protected]>,
# 2005 Raphael Slinckx <[email protected]>
def clipboard_copy(item):
"""Copy the item into the clipboard."""
# try windows first
try:
import win32clipboard
except ImportError:
# then give pbcopy a try. do that before gtk because
# gtk might be installed on os x but nobody is interested
# in the X11 clipboard there.
from subprocess import Popen, PIPE
for prog in 'pbcopy', 'xclip':
try:
client = Popen([prog], stdin=PIPE)
except OSError:
continue
else:
client.stdin.write(item)
client.stdin.close()
client.wait()
break
else:
try:
import pygtk
pygtk.require('2.0')
import gtk
import gobject
except ImportError:
return
gtk.clipboard_get(gtk.gdk.SELECTION_CLIPBOARD).set_text(item)
gobject.idle_add(gtk.main_quit)
gtk.main()
else:
win32clipboard.OpenClipboard()
win32clipboard.EmptyClipboard()
win32clipboard.SetClipboardText(item)
win32clipboard.CloseClipboard()
def rstr2any(input, encoding, trim=True):
"""Convert a raw string to an arbitrary string encoding. Set trim
to false for keeping leading zeros
"""
divisor = len(encoding)
remainders = []
# Convert to an array of 16-bit big-endian values, forming the dividend
dividend = []
# pad this
while len(dividend) < math.ceil(len(input) / 2):
dividend.append(0)
for i in range(len(dividend)):
dividend[i] = (ord(input[i * 2]) << 8) | ord(input[i * 2 + 1])
# Repeatedly perform a long division. The binary array forms the dividend,
# the length of the encoding is the divisor. Once computed, the quotient
# forms the dividend for the next step. We stop when the dividend is zero.
# All remainders are stored for later use.
while len(dividend) > 0:
quotient = []
x = 0
for i in range(len(dividend)):
x = (int(x) << 16) + dividend[i]
q = math.floor(x / divisor)
x -= q * divisor
if len(quotient) > 0 or q > 0:
quotient.append(q)
remainders.append(x)
dividend = quotient
# Convert the remainders to the output string
output = ""
for i in range(len(remainders) - 1, 0, -1):
output += encoding[int(remainders[i])]
return output
def main():
parser = ArgumentParser()
parser.add_argument('-f', '--file',
help='GPG file to use for looking up keys',
type=file)
parser.add_argument('-u', '--user',
help='Username default',
default=getpass.getuser())
mutex_group = parser.add_mutually_exclusive_group()
mutex_group.add_argument('-l', '--list', action='store_true')
mutex_group.add_argument('-g', '--generate')
mutex_group.add_argument('-s', '--select')
namespace = parser.parse_args()
if namespace.list or namespace.select:
symmetric_phrase = getpass.getpass('passphrase: ')
gpg = gnupg.GPG()
crypt = gpg.decrypt_file(namespace.file, passphrase=symmetric_phrase)
key_data = yaml.load(crypt.data)
if namespace.list:
print key_data.keys()
return
elif namespace.select:
# TODO:dc: check for the key in key_data
username = key_data[namespace.select].get('username', '')
pass_ = key_data[namespace.select].get('password', '')
else:
mp = getpass.getpass('master key: ')
site = raw_input('site: ')
username = namespace.user
hash_ = hashlib.sha256(mp + site + username).digest()
pass_ = rstr2any(hash_, CHARSET)[:20]
clipboard_copy(pass_)
print username
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment