cl-bcrypt
is a Common Lisp system for generating, parsing and
verification of bcrypt password hashes.
Clone the cl-bcrypt repo in your Quicklisp local-projects directory.
git clone https://github.com/dnaeon/cl-bcrypt.git
Load the system.
CL-USER> (ql:quickload :cl-bcrypt)
The supported hash algorithm identifiers are 2a
and 2b
.
The following section provides some examples to get you started with the cl-bcrypt system.
The functions discussed here are availabe in the CL-BCRYPT
(and its
nickname BCRYPT
) package.
In order to create a new bcrypt password you need to use the
BCRYPT:MAKE-PASSWORD
function, e.g.
CL-USER> (defparameter *password*
(bcrypt:make-password "my-secret-password"))
*PASSWORD*
BCRYPT:MAKE-PASSWORD
accepts keyword parameters, which allow you to
specify a different salt (e.g. obtained by BCRYPT:GENERATE-SALT
),
different cost factor than the default, and a different algorithm
identifier than the default (e.g. 2a
).
If you don't specify explicitely a salt, a random one will be
generated for you by the BCRYPT:GENERATE-SALT
function.
This example specifies a cost factor of 16
and a hash algorithm
identifier 2a
.
CL-USER> (defparameter *password*
(bcrypt:make-password "my-secret-password" :cost 16 :identifier "2a"))
*PASSWORD*
You can use the BCRYPT:ALGORITHM-IDENTIFIER
, BCRYPT:COST-FACTOR
,
BCRYPT:SALT
and BCRYPT:PASSWORD-HASH
readers to inspect the
returned BCRYPT:PASSWORD
instance from the BCRYPT:MAKE-PASSWORD
function, e.g.
CL-USER> (bcrypt:algorithm-identifier *password*)
"2a"
CL-USER> (bcrypt:cost-factor *password*)
16
CL-USER> (bcrypt:salt *password*)
#(18 117 245 59 29 97 63 72 199 11 254 164 52 87 213 169)
CL-USER> (bcrypt:password-hash *password*)
#(94 0 171 116 90 235 30 220 57 45 147 214 210 77 244 223 63 14 153 13 140 213 183)
The BCRYPT:SALT
and BCRYPT:PASSWORD-HASH
readers return the raw
bytes of the salt and the password hash respectively.
In order to encode a BCRYPT:PASSWORD
instance into its text
representation you need to use the BCRYPT:ENCODE
function.
CL-USER> (bcrypt:encode *password*)
"$2a$16$ClVzMvzfNyhFA94iLDdToOVeApbDppFru3JXNUyi1y1x6MkO0KzZa"
A bcrypt password hash can be decoded using the BCRYPT:DECODE
function,
which will return a new instance of BCRYPT:PASSWORD
, e.g.
CL-USER> (bcrypt:decode "$2a$16$ClVzMvzfNyhFA94iLDdToOVeApbDppFru3JXNUyi1y1x6MkO0KzZa")
#<CL-BCRYPT:PASSWORD {1002207AD3}>
If you encode back the returned instance you should get the same hash string as the one that was decoded.
The BCRYPT:PARSE-HASH
function returns a property list of the
parts that comprise the bcrypt hash string.
CL-USER> (bcrypt:parse-hash "$2a$16$ClVzMvzfNyhFA94iLDdToOVeApbDppFru3JXNUyi1y1x6MkO0KzZa")
(:ALGORITHM-IDENTIFIER "2a"
:COST-FACTOR "16"
:SALT "ClVzMvzfNyhFA94iLDdToO"
:PASSWORD-HASH "VeApbDppFru3JXNUyi1y1x6MkO0KzZa")
When you need to test whether a given bcrypt hash matches a given
password you can use the BCRYPT:PASSWORD=
predicate, e.g.
CL-USER> (bcrypt:password= "my-secret-password"
"$2a$16$ClVzMvzfNyhFA94iLDdToOVeApbDppFru3JXNUyi1y1x6MkO0KzZa")
T
Tests are provided as part of the cl-bcrypt.test
system.
In order to run the tests you can evaluate the following expressions.
CL-USER> (ql:quickload :cl-bcrypt.test)
CL-USER> (asdf:test-system :cl-bcrypt.test)
Or you can run the tests in a Docker container instead.
First, build the Docker image.
docker build -t cl-bcrypt .
Run the tests.
docker run --rm cl-bcrypt
cl-bcrypt
is hosted on Github. Please contribute by
reporting issues, suggesting features or by sending patches using pull
requests.
- Marin Atanasov Nikolov ([email protected])
This project is Open Source and licensed under the BSD License.