Identifier search

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().

If you need to forcefully override what native crypt() features are available (for example when you're cross-compiling to another platform), you can set the FORCE_CRYPT_HASHTYPES environment variable when invoking chicken-install. This should be a space-separated list of hash types. The allowed names are the same as the ones accepted by the crypt-gensalt procedure for the type argument (see below). If in doubt, set the variable to an empty string. This will force usage of all procedures provided by the egg only.

If you are cross-compiling from or to OpenBSD or some other system which has crypt() as part of libc (as opposed to being in libcrypt), you may additionally need to set the FORCE_CRYPT_USE_LIBCRYPT environment variable to TRUE/YES/1 or FALSE/NO/0 depending on whether the target system uses a separate libcrypt or not.

This will automatically use the hashing mechanism currently deemed most secure. At the moment that is the Blowfish hashing scheme ("bcrypt") with 2^12 rounds. A new random salt is automatically generated each time this procedure is invoked with only one argument.

If you want to create a crypt hash using a specific algorithm, you need to a little more work:

First and foremost, crypt() is safe. Lots of thought has gone into the modern flavors of crypt. The UNIX family of operating systems have been using crypt() since 1976 and the algorithms used by crypt() have been constantly improved over time to keep up with improvements in password cracking. It provides stretching, salting and defeats parallel cracking by using a unique salt for each password which is then automatically added to the hash.

The main advantage of Unix crypt() over other safe 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. It's still up to you to implement an update strategy and decide if and when to expire hashes that are no longer deemed secure enough, though!

Modern flavors of crypt() allow you to tweak the cost of generating a hash (the stretching factor), to compensate for Moore's law so that as computers get faster, you can make it more expensive to generate a hash. This thwarts even highly optimized password cracking tools. Remember: slower is better for password hashing schemes! Of course, this too can be done without rehashing older passwords.

Other languages might include just a library specifically for bcrypt(), but this egg's author thinks it is a bit silly to provide a separate library with a dedicated API, since 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 so that the name is no longer descriptive. This defeats the point of having a modular hash syntax in the first place.

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.

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:

$1$

Paul Hennig-Kamp's MD5 scheme. This is a very baroque system, introduced in FreeBSD, which runs a convoluted series of MD5 calls for a large but fixed number of iterations.

$2a$

Niels Provos' Blowfish scheme, aka bcrypt. 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.

$5$

Ulrich Drepper's SHA-256 scheme. This is also an adaptable scheme, introduced in glibc.

$6$

Ulrich Drepper's SHA-512 scheme. Same as the above, except with hashes of double the size :)

There are also some less common values:

$apr1$

Identical to $1$. This prefix is generated by the Apache Portable Runtime library (used by htpasswd, for example)

{SHA}

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)

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...)

$2x$

"compatibility" option for OpenWall's bcrypt implementation (used as fallback for bcrypt in this egg) to trigger old buggy behavior that has a known vulnerability, only to be used when comparing values produced by the old version.

$2y$

"force correct algorithm" option for OpenWall's bcrypt implementation. When passed $2a$ normally bcrypt will sometimes fall back to the buggy algorithm, but in this egg it acts like $2y was passed. This is done to ensure compatibility with the BSD implementation, which dictates the standard. Currently there is no way to pass $2x$ or $2y$ to crypt even if the OpenWall version is used internally. If you really need this, please contact me and I'll try to figure out a way to do it.

The full API consists of two main procedures with some helpers and several algorithm-specific salt generation procedures. It's recommended you use only the algorithm-specific salt generation procedures when you have very specific needs. In the future these extra procedures might be dropped.

This procedure returns the hashed version of the string plaintext-password based on the settings provided by the string salt-or-hash (typically this argument is called "setting" in most POSIX documentation). If salt-or-hash is not provided or #f, a salt will automatically be generated by calling (crypt-gensalt) with no arguments.

This means this procedure can be used in two ways: the first is to generate a hash for a new password and the second is to validate a password against a previously generated hash.

The return value of this procedure can be stored and later used as a salt-or-hash value in subsequent calls to this procedure to validate a user-supplied password; it is a string that contains the salt and algorithm specifications as a prefix of the hash. For more info about why this works, see the "Background Info" section.

This procedure can be used to obtain a string you can pass to the crypt procedure as the salt-or-hash argument. The string generally starts with a dollar-sign followed by an algorithm specifier, followed by the salt. For more specific info about the format of this string, see the "Background Info" section.

The type argument selects the algorithm type to use. It can currently be one of the following symbols: blowfish, sha512, sha256, md5, des-extended or des. If not supplied or #f, the value of (crypt-default-implementation) is used.

The random argument can be used to supply a stronger randomization procedure. It should be a procedure that accepts two integers (a minimum and a maximum) and returns an u8vector with random values. The u8vector must have a length between the minimum and the maximum, both inclusive. The maximum can be #f when there is no upper bound. If random is not supplied or #f, the value of (crypt-default-random-u8vector) is used.

The default implementation specifier to put in newly generated salt strings. Can be any symbol accepted by crypt-gensalt. It will always default to the strongest algorithm that was current at the time the egg was last updated. Currently that is blowfish.

The default implementation to use by crypt-gensalt as a source of randomly-filled u8vectors. This procedure should accept two integer arguments; a minimum and a maximum length for the u8vector to return. The maximum may also be #f if there is no upper bound.

Defaults to crypt-maximum-random-u8vector. If security is very important, you should probably override it, because the default random procedure provided by Chicken is not very strong, and is even extremely weak on some platforms.

The initial value of crypt-default-random-u8vector. This procedure simply calls Chicken's built-in random to get enough values between 0 and 255 to fill the u8vector. It will use the maximum length if available, otherwise the minimum length (this may change later).

You should only use these when you have specific needs for a particular type of algorithm. The defaults are supposed to be good enough for general use. If you disagree, please let me know so I can change this.

The default value for crypt-blowfish-gensalt's logrounds argument. This is the 2-based logarithm of the number of rounds, so the number 10 indicates 1024 iterations of the blowfish encryption algorithm should be run.

Currently it is set to 12 by default, but this value should grow as computing power grows.

Generates a salt string for the extended DES-based crypt() implementation as introduced by BSDi.

rounds is the number of iterations to run the DES algorithm. If not specified or #f it defaults to the value of crypt-des-extended-default-rounds. Important note: DES has specific weaknesses that makes it easier to detect weak keys when it is run for an even number of rounds, so it's important to specify an odd number here.

Generates a salt string for the original UNIX DES-based crypt() implementation. random is a procedure that returns a randomly filled u8vector. See the documentation on crypt-default-random-u8vector and crypt-gensalt for more information.

Philip Leong and Chris Tham, "Unix Password Encryption Considered Insecure", proceedings of the 1991 USENIX Winter conference. (there used to be a link to the paper here, but it's dead by now. Let me know if you find a copy)