[cryptography] pypass, a HMAC-based passphrase generator

travis+ml-rbcryptography at subspacefield.org travis+ml-rbcryptography at subspacefield.org
Wed Sep 29 19:33:30 EDT 2010


Oh drat, forgot to attach script to last email.
-- 
I find your ideas intriguing and would like to subscribe to your newsletter.
My emails do not have attachments; it's a digital signature that your mail
program doesn't understand. | http://www.subspacefield.org/~travis/ 
If you are a spammer, please email john at subspacefield.org to get blacklisted.
-------------- next part --------------
#! /usr/bin/env python
# -*- mode:python -*-
# $Id:$

"""
pypass - a tool to generate passphrases for web sites

Right now it only outputs in base64; one day I'll expand for all the
sets of forseeable retardation.
"""

import hashlib
import hmac
import base64

def hashphrase(master_pass_phrase):
    """Convert low-entropy-density pass phrase to uniformly-random secret"""
    # SHA-512 because I don't wanna hear no bitchin' from people who
    # don't know preimage resistance from collision resistance.
    return hashlib.sha512(master_pass_phrase).digest()

def genpass(master_key, domain_name, generation=0):
    """Generate a passphrase for a particular site, or based on a hint"""
    return hmac.new(master_key,
                    domain_name + chr(0) + str(generation),
                    hashlib.sha512).digest()

def doit(master_pass_phrase, domain_name, generation="0"):
    master_key = hashphrase(master_pass_phrase)
    gen_int = int(generation)
    passblob = genpass(master_key, domain_name, gen_int)
    return base64.b64encode(passblob)

def print_pass(chars, *args):
    my_pass = doit(*args)
    if (chars != 0):
        my_pass = my_pass[:chars]
    print(my_pass)

if __name__ == '__main__':

    # Parse command-line options.
    import getopt, sys

    usage = "Usage: %s [-g generation] [-c chars] [master_pass] domain_name\n" \
            "-g generation is numeric, defaults to zero\n" \
            "-c chars is how many chars to output, zero is all\n" \
            "only specify master pass on command line if single user machine" \
            % sys.argv[0]
    # TODO: Use argparse.
    try:
        opts, args = getopt.getopt(sys.argv[1:], "hg:c:", [ "help", "generation=", "chars=" ])
    except getopt.GetoptError:
        sys.stderr.write(usage)
        sys.exit(1)

    # "I've got three points to make.  Point zero..." - Dijkstra
    generation = "0"
    chars = 0 # unlimited
    for o, a in opts:
        if o in ("-h", "--help"):
            print usage
            sys.exit(0)
        elif o in ("-g", "--generation"):
            generation = a
        elif o in ("-c", "--chars"):
            chars = int(a)
        else:
            assert False, "Unhandled command line option"

    if len(args) > 2:
        assert False, "Too many arguments"
    elif len(args) == 2:
        # Master pass is first so we can keep it on command line when doing this for
        # many domain names (a/k/a hints)
        (master_pass, domain_name) = args
    else: # 1 or 2
        import getpass
        # TODO: For moderately long master passphrases, lack of any echo is super-annoying.
        master_pass = getpass.getpass("Master Passphrase: ")
        if len(args) == 0:
            domain_name = getpass.getpass("Domain name or hint: ")
        else:
            domain_name = args[0]

    print_pass(chars, master_pass, domain_name, generation)

    sys.exit(0)
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 833 bytes
Desc: not available
URL: <http://lists.randombit.net/pipermail/cryptography/attachments/20100929/01fee290/attachment.asc>


More information about the cryptography mailing list