[cryptography] pypass, a HMAC-based passphrase generator

Marsh Ray marsh at extendedsubset.com
Wed Sep 29 20:46:30 EDT 2010

On 09/29/2010 06:31 PM, travis+ml-rbcryptography at subspacefield.org wrote:
> Basic idea:
> master_secret = hash(master_pass)
> passphrase = HMAC(master_secret, hint)
> Details in the source.
> Not as secure as a password safe,

Only to the extent you're counting on the attacker not having your 
encrypted password file. But if you're going to assume that, you could 
just store them plain text. (FWIW, I have been told that my 
black-and-white view of these things is not universally held).

  --- Password safe:

Bad guy gets your encrypted file (laptop stolen and drive sold on ebay)
-> bad guy can now attack your master password offline.

Bad guy gets your encrypted file when he installed the keylogger with 
which he got your master password
-> bad guy gets all your passwords.

  --- HMAC generated passwords:

Bad guy gets two or three plaintext passwords which you submitted to 
unencrypted or otherwise pwned websites
-> bad guy can attack your master password offline.

Bad guy gets your master password
-> bad guy gets all your passwords.

So using this system does make it even more critical to pick a 
super-strong master password and keep it secret. Ideally, you'd run this 
on an old PDA or something and never type the master password into a 
networked computer at all. Keyloggers are the bad guy's tool of choice 
these days.

> but doesn't require any replication
> or backups - just remember your master pass and be able to get this
> script.
> Generation count is there for sites that make you change it.
> Output is in base64, currently.

That may be something you want to change. Some sites will to choke on 
the special characters, others will require them.

> $ ./pypass.py -h
> Usage: ./pypass.py [-g generation] [-c chars] [master_pass] domain_name
> -g generation is numeric, defaults to zero
> -c chars is how many chars to output, zero is all

> only specify master pass on command line if single user machine

Don't even allow the option to supply the master password as a 
command-line argument. Take it on stdin, or even as an env variable.

> $ ./pypass.py foo foo
> SCo4YqL0WoD+rmmo5zWBpE3H/qEMdjvzc5op5LOcQimH8Vea5ZemgdJoeXl3MSk6gg+ltBp4NkwMci/SwAiwzQ==
> $ ./pypass.py my_master_pass foo
> /dM6HO2sBcVc4pNIJvfZBozW24vFuxXxWDrD07bl/V+Dre0CcFzBiWVgXXe3icZmZkf1PFMqYoJyapHC3Epy5w==

Have a more reasonable default length, like 12. Unless you're trying to 
find buffer overflows on the server or something.

Occasionally, you'll generate a password without any digits or special 
characters if required by the server. Should your app prevent that somehow?

> $ ./pypass.py -c 5 my_master_pass foo
> /dM6H
> $ ./pypass.py
> Master Passphrase:
> Domain name or hint:
> /dM6HO2sBcVc4pNIJvfZBozW24vFuxXxWDrD07bl/V+Dre0CcFzBiWVgXXe3icZmZkf1PFMqYoJyapHC3Epy5w==
> Script attached.
> Comments?

It looks useful, as far as password authentication goes, that is.

I use a little app 'pwgen' for making passwords. I has an option to take 
a seed file, which could be the master password I suppose.

You might look at all its options to get more ideas.

One thing I don't like about pwgen is that it tries to detect if it's 
being invoked from a terminal or a script and behaves differently.

> Should I use PBKDF2 instead of hashing master pass?

Consuming millions of additional cycles for each lookup helps resist 
offline attacks. The OpenBSD bcrypt paper has a good description of this 
issue. You might look into that algorithm.

Personally, I'm a fan of picking long random passwords and writing them 
down on blank business cards which I then handle carefully. The whole 
"one password to rule them all" thing scares me a little.

- Marsh

More information about the cryptography mailing list