Safe Haskell | None |
---|---|
Language | Haskell2010 |
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 otherPasssword :: 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 have evolved because of bugs in the standard
C implementations. The most up to date version is 2b
and this
implementation 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).
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.
- 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
:: (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 Source #
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 Source #
Check a password against a bcrypt hash
As for validatePassword
but will provide error information if the hash is invalid or
an unsupported version.
:: (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.