How I should have done password crypto for DWiki
DWiki (the software behind WanderingThoughts) uses cryptography for the traditional web application things, namely login passwords and login cookies; it stores hashed versions of login passwords, and it signs its login cookies. I had very little idea what I was doing when I wrote that code, so DWiki's current use of cryptography is better off not discussed in polite company; instead, let's discuss how it should work.
(I was so stupid that I didn't use HMAC, despite it being in the Python library, because I thought it was too complicated and I preferred something simpler that I could fully understand. Well, the joke's on me.)
First, you need to store encrypted passwords. The basic minimum
requirement is to generate a unique per-password salt with os.urandom()
,
do hmac.new(salt, passwd, hashlib.sha1)
, and store both the HMAC
output and the salt. Per Matasano Chargen,
using bcrypt is much better; however, there is no Python module for
it in the standard library, so if you're that worried you'd need
to build the bcrypt module from pypi. As far as I know, there is
no standard library support for better (ie significantly slower)
hashes than SHA1.
(You might ask why not SHA512? According to openssl speed
, it's only
two to three times slower than SHA1, ie still pretty fast, and it
means you have very large password hashes. If you're worried that much
about security, go with bcrypt. Also, I lack enough crypto knowledge
to know if repeatedly SHA1-ing the HMAC digest result will damage
your security. If it doesn't, adding some extra SHA1 rounds will at
least vaguely mimic some of bcrypt's advantages and completely erase
SHA512's.)
To sign and authenticate cookies, use HMAC (with SHA1) on anything you
need to authenticate plus a global secret key (any random value will do;
I got DWiki's from /dev/urandom
), and put in the login cookie both
the plaintext and the authenticator digest. If you don't care about how
long people have valid cookies, you can just sign the login name; if you
do care, you need to sign both the login name and the expiry time. Make
sure to sign exactly what you put in the login cookie (minus the
signature, obviously).
(By now I am sufficiently paranoid that I would include the delimiter between the plaintext and the signature in what I sign, just in case.)
(Disclaimer: this may turn out to be horribly naive in N years, just like the last time around.)
|
|