Crypto.KDF.BCrypt

cryptonite-0.30: Cryptography Primitives sink

Safe Haskell | Safe-Inferred
Language | Haskell2010

Crypto.KDF.BCrypt

Description

Password encoding and validation using bcrypt.

Example usage:

    >>> import Crypto.KDF.BCrypt (hashPassword, validatePassword)
    >>> import qualified Data.ByteString.Char8 as B
    >>>
    >>> let bcryptHash = B.pack "$2a$10$MJJifxfaqQmbx1Mhsq3oq.YmMmfNhkyW4s/MS3K5rIMVfB7w0Q/OW"
    >>> let password = B.pack "password"
    >>> validatePassword password bcryptHash
    >>> True
    >>> let otherPassword = B.pack "otherpassword"
    >>> otherHash <- hashPassword 12 otherPassword :: IO B.ByteString
    >>> validatePassword otherPassword otherHash
    >>> True

See https://www.usenix.org/conference/1999-usenix-annual-technical-conference/future-adaptable-password-scheme for details of the original algorithm.

The functions `hashPassword` and `validatePassword` should be all that most users need.

Hashes are strings of the form `$2a$10$MJJifxfaqQmbx1Mhsq3oq.YmMmfNhkyW4sMS3K5rIMVfB7w0QOW` which encode a version number, an integer cost parameter and the concatenated salt and hash bytes (each separately Base64 encoded. Incrementing the cost parameter approximately doubles the time taken to calculate the hash.

The different version numbers evolved to account for bugs in the standard C implementations. They don't represent different versions of the algorithm itself and in most cases should produce identical results. The most up to date version is `2b` and this implementation uses the `2b` version prefix, but will also attempt to validate against hashes with versions `2a` and `2y`. Version `2` or `2x` will be rejected. No attempt is made to differentiate between the different versions when validating a password, but in practice this shouldn't cause any problems if passwords are UTF-8 encoded (which they should be) and less than 256 characters long.

The cost parameter can be between 4 and 31 inclusive, but anything less than 10 is probably not strong enough. High values may be prohibitively slow depending on your hardware. Choose the highest value you can without having an unacceptable impact on your users. The cost parameter can also be varied depending on the account, since it is unique to an individual hash.

Synopsis

- hashPassword :: (MonadRandom m, ByteArray password, ByteArray hash) => Int -> password -> m hash
- validatePassword :: (ByteArray password, ByteArray hash) => password -> hash -> Bool
- validatePasswordEither :: (ByteArray password, ByteArray hash) => password -> hash -> Either String Bool
- bcrypt :: (ByteArray salt, ByteArray password, ByteArray output) => Int -> salt -> password -> output

# Documentation

hashPassword #

Arguments

:: (MonadRandom m, ByteArray password, ByteArray hash) |
=> Int | The cost parameter. Should be between 4 and 31 (inclusive). Values which lie outside this range will be adjusted accordingly.
-> password | The password. Should be the UTF-8 encoded bytes of the password text.
-> m hash | The bcrypt hash in standard format.

Create a bcrypt hash for a password with a provided cost value. Typically used to create a hash when a new user account is registered or when a user changes their password.

Each increment of the cost approximately doubles the time taken. The 16 bytes of random salt will be generated internally.

validatePassword :: (ByteArray password, ByteArray hash) => password -> hash -> Bool #

Check a password against a stored bcrypt hash when authenticating a user.

Returns `False` if the password doesn't match the hash, or if the hash is invalid or an unsupported version.

validatePasswordEither :: (ByteArray password, ByteArray hash) => password -> hash -> Either String Bool #

Check a password against a bcrypt hash

As for `validatePassword` but will provide error information if the hash is invalid or an unsupported version.

bcrypt #

Arguments

:: (ByteArray salt, ByteArray password, ByteArray output) |
=> Int | The cost parameter. Should be between 4 and 31 (inclusive). Values which lie outside this range will be adjusted accordingly.
-> salt | The salt. Must be 16 bytes in length or an error will be raised.
-> password | The password. Should be the UTF-8 encoded bytes of the password text.
-> output | The bcrypt hash in standard format.

Create a bcrypt hash for a password with a provided cost value and salt.

Cost value under 4 will be automatically adjusted back to 10 for safety reason.