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.gitLoad 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") TTests 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-bcryptcl-bcrypt is hosted on Github. Please contribute by reporting issues, suggesting features or by sending patches using pull requests.
- Marin Atanasov Nikolov (dnaeon@gmail.com)
This project is Open Source and licensed under the BSD License.