cryptonite-0.29: Cryptography Primitives sink
Safe HaskellNone
LanguageHaskell2010

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

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.