That was a problem of mine couple of weeks ago.
We were deploying a large MIS project to 975 different geographical locations where our own user credential store will be used as an authenticator for different set of already implemented and in-use applications. We already provided both REST and SOAP based authentication service but customer insisted to be able to reach the user credential store from other applications with just a a DB connection to read-only view of related table or view. Sigh... (this highly coupled bad design decision is a subject of another question).
That forced us to sit and convert our salted and iteratively hashed password storage scheme to a specification and provide some different language implementations for easy integration.
We called it Fairly Secure Hashed Passwords or FSHP in short.
Implemented it in Python, Ruby, PHP5 and released it to Public Domain. Available to be consumed, forked, flamed or spit on GitHub at http://github.com/bdd/fshp
FSHP is a salted, iteratively hashed password hashing implementation.
Design principle is similar with PBKDF1 specification in RFC 2898
(a.k.a: PKCS #5: Password-Based Cryptography Specification Version 2.0.)
FSHP allows choosing the salt length, number of iterations and the
underlying cryptographic hash function among SHA-1 and SHA-2 (256, 384, 512).
Self defining meta prefix at the beginning of every output makes it portable while letting the consumer to choose its own password storage security baseline.
SECURITY:
Default FSHP1 uses 8 byte salts, with 4096 iterations of SHA-256 hashing.
- 8 byte salt renders rainbow table attacks impractical by multiplying the
required space with 2^64.
- 4096 iterations causes brute force attacks to be fairly expensive.
- There are no known attacks against SHA-256 to find collisions with
a computational effort of fewer than 2^128 operations at the time of
this release.
IMPLEMENTATIONS:
- Python: Tested with 2.3.5 (w/ hashlib), 2.5.1, 2.6.1
- Ruby : Tested with 1.8.6
- PHP5 : Tested with 5.2.6
Everyone is more than welcome to create missing language implementations or
polish the current ones.
BASIC OPERATION (with Python):
>>> fsh = fshp.crypt('OrpheanBeholderScryDoubt')
>>> print fsh
{FSHP1|8|4096}GVSUFDAjdh0vBosn1GUhzGLHP7BmkbCZVH/3TQqGIjADXpc+6NCg3g==
>>> fshp.validate('OrpheanBeholderScryDoubt', fsh)
True
CUSTOMIZING THE CRYPT:
Let's weaken our password hashing scheme.
- Decrease the salt length from default 8 to 2.
- Decrease the iteration round from default 4096 to 10.
- Select FSHP0 with SHA-1 as the underlying hash algorithm.
>>> fsh = fshp.crypt('ExecuteOrder66', saltlen=2, rounds=10, variant=0)
>>> print fsh
{FSHP0|2|10}Nge7yRT/vueEGVFPIxcDjiaHQGFQaQ==