You are looking at historical revision 22312 of this page. It may differ significantly from its current revision.
This egg provides functions for generating secure password hashes.
This is done by providing Chicken bindings for the Unix crypt() function. It will attempt to use the system's crypt() for all available types, and supplies fallbacks when the native crypt does not implement a common scheme like Niels Provos' bcrypt() or Ulrich Drepper's SHA-2 based crypt().
Basic usage is extremely simple (just like Unix crypt()):
Generating a new password hash
(use crypt) (crypt "password") => "$2a$12$eeOD.RHX7kex47wGOu3ZVu2JhRyQBBOyORhd/mTWjQghMWbrxGNCy"
This will automatically use the hashing mechanism currently deemed most secure. At the moment that is the Blowfish hashing scheme with 2^12 rounds. A new random salt is automatically generated each time this procedure is invoked with only one argument.
Checking whether a password matches a hash
This is done just like Unix crypt() by checking whether the generated hash matches the input hash:
(use crypt) (define h "$2a$12$eeOD.RHX7kex47wGOu3ZVu2JhRyQBBOyORhd/mTWjQghMWbrxGNCy") (string=? (crypt "password" h) h) => #t (string=? (crypt "wrong" h) h) => #f
Why use crypt()?
The advantage of Unix crypt() over other password hashing schemes is that crypt() provides a way to upgrade the hashing mechanism to a more secure one without having to rehash all passwords; hashes are stored with a prefix code which indicates the hashing mechanism used to generate that hash, so they continue to work using the old algorithm while newly generated hashes are hashed using the stronger algorithm.
Other languages might include just a library specifically for bcrypt(), but this egg's author thinks it is silly to provide a separate library with a dedicated API, precisely because crypt() is designed to transparently upgrade to stronger algorithms as time progresses. bcrypt(), because it is adaptive for CPU speed improvements, will provide good security for the foreseeable future as long as no weaknesses are discovered in the algorithm itself. Once that happens (or a substantially better scheme is developed, etc) you would need to replace all calls to that library with a new one (or change bcrypt() to include whatevercrypt() code).
Crypt hashes come in three basic flavors:
rEK1ecacw.7.c (salt: rE)
This is just a raw base64-encoded DES password hash. The first two characters encode the salt, the rest is the hashed password.
Extended DES uses a variable number of encryption rounds and 24 bits of salt rather than 12 bits.
_J9..K0AyUubDrfOgO4s (prefix: _J9.. salt: K0Ay)
The leading underscore indicates we're using the extended DES scheme here. The first four characters after the underscore indicate the number of iterations to run the encryption algorithm, the next four represent the salt and the final eleven are the hashed password.
Modern, modular format
This looks like the following:
$1$O3JMY.Tw$AdLnLjQ/5jXF9.MTp3gHv/ (prefix: $1$ salt: O3JMY.Tw)
For more examples of hashes, see the OpenWall/John the Ripper community wiki page with sample hashes
The ALG encodes the algorithm used for generating the hash, the ALGSPECIFIC is usually the salt followed by the hash. Some schemes store some additional settings before the salt, and some separate the salt from the hash with a dollar sign.
Currently, the following values for ALG are standardized:
- Paul Hennig-Kamp's MD5 scheme. This is a very baroque system, introduced in FreeBSD, which runs MD5 for a large but fixed number of iterations on the password.
- Niels Provos' Blowfish scheme. This is an adaptable scheme introduced in OpenBSD, which allows the system administrator to determine the number of rounds to run the algorithm. As hardware speed improves, this number can be increased to compensate.
- Ulrich Drepper's SHA-256 scheme. This is also an adaptable scheme, introduced in glibc.
- Ulrich Drepper's SHA-512 scheme. Same as the above, except with hashes of double the size :)
There are also some less common values:
- Identical to $1$. This prefix is generated by the Apache Portable Runtime library (used by htpasswd, for example)
- SHA-1 hash, also used by the Apache Portable Runtime library. (yes, this is not compatible with the standard dollar-sign prefix. Apparently these guys like being completely incompatible to the rest of the world)
- MD5-based hash used by PHPass - the Portable PHP password hashing framework
- Same as above, but used by PHPbb because, well, they're PHP developers. (I wonder if these developers are somehow related to the people working on APR...)
All code in this egg is explicitly placed in the public domain. You may do whatever you want with it.
This egg contains code written by the following people:
- Peter Bex (Chicken glue code, MD5 and DES crypt implementation)
- Colin Plumb (MD5 code)
- Ulrich Drepper (SHA-2 implementation)
- "Solar Designer" (Blowfish implementation, salt generation code)
- Phil Karn (DES code)
- Shiro Kawai, "Blowfish password hashing"
- Thomas Ptacek, "Enough With The Rainbow Tables: What You Need To Know About Secure Password Schemes"
- Coda Hale, "How to safely store a password"
- Niels Provos and David Mazières, "A Future-Adaptable Password Scheme"
- Philip Leong and Chris Tham, "Unix Password Encryption Considered Insecure"
- J. Orlin Grabbe, "The DES Algorithm Illustrated"