Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
The Erlang code is subject to this license:
The Erlang code, native wrappers, and tests are subject to this license:

%% Copyright (c) 2011 Hunter Morris <hunter.morris@smarkets.com>
%% Copyright (c) 2026 Marc Worrell <marc@worrell.nl>

%% Permission to use, copy, modify, and distribute this software for any
%% purpose with or without fee is hereby granted, provided that the above
Expand Down Expand Up @@ -54,6 +55,7 @@ The underlying bcrypt (hashing) code is derived from OpenBSD libc and is
subject to the following license:

/*
* Copyright (c) 2026 Marc Worrell <marc@worrell.nl>
* Copyright (c) 2014 Ted Unangst <tedu@openbsd.org>
* Copyright (c) 1997 Niels Provos <provos@umich.edu>
*
Expand Down
190 changes: 105 additions & 85 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ erlang-bcrypt is on Hex:

```erlang
{deps, [
{bcrypt, "1.1.3"}
{bcrypt, "~> 2.0"}
]}.
```

Expand All @@ -53,31 +53,32 @@ Basic build instructions
make
```

2. Run it (simple way, starting sasl, crypto and bcrypt):
2. Run it (simple way, starting sasl, crypto, poolboy and bcrypt):

```shell
$ ./rebar3 shell
===> Verifying dependencies...
===> Compiling bcrypt
make: Nothing to be done for `all'.
Erlang/OTP 23 [erts-11.0] [source] [64-bit] [smp:12:12] [ds:12:12:10] [async-threads:1] [hipe]
Erlang/OTP 28 [erts-16.4] [source] [64-bit] [smp:10:10] [ds:10:10:10] [async-threads:1] [jit]

Eshell V11.0 (abort with ^G)
Eshell V16.4 (press Ctrl+G to abort, type help(). for help)
1> application:ensure_all_started(bcrypt).
{ok,[bcrypt]}
{ok,[poolboy,bcrypt]
2>
```


Basic usage instructions
------------------------

Hash a password using a salt with the default number of rounds:

```erlang
1> {ok, Salt} = bcrypt:gen_salt().
{ok,"$2b$12$sSS8Eg.ovVzaHzi1nUHYK."}
{ok,"$2b$12$JrJ8HaRoDZaCALBL08XAie"}
2> {ok, Hash} = bcrypt:hashpw("foo", Salt).
{ok,"$2b$12$sSS8Eg.ovVzaHzi1nUHYK.HbUIOdlQI0iS22Q5rd5z.JVVYH6sfm6"}
{ok,"$2b$12$JrJ8HaRoDZaCALBL08XAie1PQi.8QII9K0f05qhVSaHGOW56jnYW2"}
```

Verify the password:
Expand All @@ -89,6 +90,17 @@ true
false
```

Generate a PHP-compatible `$2y$` hash using `gen_salt/2`:

```erlang
{ok, PhpSalt} = bcrypt:gen_salt(12, '2y'),
{ok, PhpHash} = bcrypt:hashpw(<<"password">>, PhpSalt).
```

Store `PhpHash` as the password hash; PHP can verify it with
`password_verify()`.


Configuration
-------------

Expand All @@ -100,92 +112,25 @@ application's environment:
hash function. Defaults to `12`.

`mechanism`
Specifies whether to use the NIF implementation (`'nif'`) or a
pool of port programs (`'port'`). Defaults to `'nif'`.

`Note: hashing runs on OTP dirty CPU schedulers, not normal scheduler threads.`
Selects `nif` (the default) or `port`. The NIF hashes inside the Erlang VM
on OTP dirty CPU schedulers. The port backend hashes in a pool of external
OS processes. Set this option before starting bcrypt; restart the bcrypt
application after changing it.

`pool_size`
Specifies the size of the port program pool. Defaults to `4`.
Sets the maximum number of port workers when using `port`. Defaults to `4`.

`nif_pool_size`
Specifies the size of the nif program pool. Defaults to `4`.
Sets the number of Erlang workers in the NIF pool when using `nif`.
Defaults to `4`. This does not set the number of OTP dirty CPU schedulers.

`nif_pool_max_overflow`
Specifies the max workers to overflow of the nif program pool. Defaults to `10`.
Sets the maximum number of additional temporary NIF pool workers when
the regular workers are busy. Defaults to `10`.

Run tests
---------

To run the eunit and proper tests use:

```shell
make tests
```

To test all exported function of a module use:

```shell
$ ./rebar3 as test shell
===> Verifying dependencies...
===> Compiling bcrypt
make: Nothing to be done for all.
Erlang/OTP 23 [erts-11.0] [source] [64-bit] [smp:12:12] [ds:12:12:10] [async-threads:1] [hipe]

Eshell V11.0 (abort with ^G)
1> application:ensure_all_started(bcrypt).
{ok,[bcrypt]}
2>proper:check_specs(bcrypt).
Testing bcrypt:gen_salt/0
....................................................................................................
OK: Passed 100 test(s).

Testing bcrypt:hashpw/2
....................................................................................................
OK: Passed 100 test(s).

Testing bcrypt:gen_salt/1
....................................................................................................
OK: Passed 100 test(s).

Testing bcrypt:mechanism/0
....................................................................................................
OK: Passed 100 test(s).

[]
4>
```

## Documentation generation

### Edoc

#### Generate public API
```
rebar3 edoc
```

#### Generate private API
```
rebar3 as edoc_private edoc
```

### ExDoc

```
rebar3 ex_doc --output edoc
```


Both the _port_ and the _NIF_ version of bcrypt are tested.
All tests should pass.

Original authors
----------------

Hunter Morris & [Mrinal Wadhwa](https://github.com/mrinalwadhwa).

## Password compatibility and native safety
Password compatibility and native safety
----------------------------------------

New salts use `$2b$`. Hashing uses at most the first 72 password bytes,
following OpenBSD bcrypt. Passwords up to 1,024 bytes are accepted; longer
Expand Down Expand Up @@ -243,3 +188,78 @@ Run `make security-test` for native boundary checks under ASan/UBSan. Run
`rebar3 as test eunit` for compatibility, malformed-input, and lifecycle tests.
The lifecycle regression can also be run with `ERL_FLAGS="+S 1"` to verify
that owner exit does not block the sole normal scheduler.


Run tests
---------

To run the eunit and proper tests use:

```shell
make test
```

To test all exported function of a module use:

```shell
$ ./rebar3 as test shell
===> Verifying dependencies...
===> Analyzing applications...
===> Compiling bcrypt
make: Nothing to be done for all.
Erlang/OTP 28 [erts-16.4] [source] [64-bit] [smp:10:10] [ds:10:10:10] [async-threads:1] [jit]

Eshell V16.4 (press Ctrl+G to abort, type help(). for help)
1> application:ensure_all_started(bcrypt).
{ok,[poolboy,bcrypt]}
2> proper:check_specs(bcrypt).
Testing bcrypt:gen_salt/0
....................................................................................................
OK: Passed 100 test(s).

Testing bcrypt:is_worker_available/0
....................................................................................................
OK: Passed 100 test(s).

Testing bcrypt:gen_salt/2
....................................................................................................
OK: Passed 100 test(s).

Testing bcrypt:hashpw/2
....................................................................................................
OK: Passed 100 test(s).

Testing bcrypt:gen_salt/1
....................................................................................................
OK: Passed 100 test(s).

Testing bcrypt:mechanism/0
....................................................................................................
OK: Passed 100 test(s).

[]
4>
```

## Documentation generation

### Edoc for public API
```
rebar3 edoc
```

### Edoc for private API
```
rebar3 as edoc_private edoc
```

### ExDoc

```
rebar3 ex_doc --output edoc
```

Original authors
----------------

Hunter Morris & [Mrinal Wadhwa](https://github.com/mrinalwadhwa).
1 change: 1 addition & 0 deletions c_src/bcrypt.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/* $OpenBSD: bcrypt.c,v 1.58 2020/07/06 13:33:05 pirofti Exp $ */

/*
* Copyright (c) 2026 Marc Worrell <marc@worrell.nl>
* Copyright (c) 2014 Ted Unangst <tedu@openbsd.org>
* Copyright (c) 1997 Niels Provos <provos@umich.edu>
*
Expand Down
4 changes: 4 additions & 0 deletions c_src/bcrypt.h
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
/* Copyright (c) 2026 Marc Worrell <marc@worrell.nl>
* See LICENSE for license terms.
*/

#ifndef ERLANG_BCRYPT_H
#define ERLANG_BCRYPT_H

Expand Down
1 change: 1 addition & 0 deletions c_src/bcrypt_nif.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
/*
* Copyright (c) 2026 Marc Worrell <marc@worrell.nl>
* Copyright (c) 2011-2012 Hunter Morris <hunter.morris@smarkets.com>
*
* Permission to use, copy, modify, and distribute this software for any
Expand Down
1 change: 1 addition & 0 deletions c_src/bcrypt_port.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
/*
* Copyright (c) 2026 Marc Worrell <marc@worrell.nl>
* Copyright (c) 2011 Hunter Morris <hunter.morris@smarkets.com>
*
* Permission to use, copy, modify, and distribute this software for any
Expand Down
1 change: 1 addition & 0 deletions src/bcrypt.erl
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
%% Copyright (c) 2011 Hunter Morris
%% Copyright (c) 2026 Marc Worrell <marc@worrell.nl>
%% Distributed under the MIT license; see LICENSE for details.
%% @doc The OpenBSD Blowfish password hashing algorithm wrapper module.
-module(bcrypt).
Expand Down
2 changes: 1 addition & 1 deletion src/bcrypt_nif.erl
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
%% @author Hunter Morris <hunter.morris@smarkets.com>
%% @copyright 2011 Hunter Morris
%% @copyright 2011 Hunter Morris, 2026 Marc Worrell
%%
%% @doc Bcrypt Erlang wrapper. <div>The wrapper around the OpenBSD Blowfish password hashing algorithm, as
%% described in: [http://www.openbsd.org/papers/bcrypt-paper.ps "A Future-Adaptable Password Scheme"]
Expand Down
2 changes: 1 addition & 1 deletion src/bcrypt_nif_worker.erl
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
%% @copyright 2011 Hunter Morris.
%% @copyright 2011 Hunter Morris, 2026 Marc Worrell
%% @doc Implementation of `gen_server' behaviour.
%% @end
%% Distributed under the MIT license; see LICENSE for details.
Expand Down
2 changes: 1 addition & 1 deletion src/bcrypt_pool.erl
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
%% @copyright 2011 Hunter Morris
%% @copyright 2011 Hunter Morris, 2026 Marc Worrell
%% @doc Implementation of `gen_server' behaviour.
%% @end
%% Distributed under the MIT license; see LICENSE for details.
Expand Down
4 changes: 4 additions & 0 deletions test/bcrypt_native_tests.c
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
/* Copyright (c) 2026 Marc Worrell <marc@worrell.nl>
* See LICENSE for license terms.
*/

/* Run under ASan/UBSan with `make security-test`. */
#include <assert.h>
#include <string.h>
Expand Down
3 changes: 3 additions & 0 deletions test/bcrypt_security_tests.erl
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
%% Copyright (c) 2026 Marc Worrell <marc@worrell.nl>
%% See LICENSE for license terms.

-module(bcrypt_security_tests).
-include_lib("eunit/include/eunit.hrl").

Expand Down
3 changes: 3 additions & 0 deletions test/bcrypt_tests.erl
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
%% Copyright (c) 2026 Marc Worrell <marc@worrell.nl>
%% See LICENSE for license terms.

-module(bcrypt_tests).
-include_lib("eunit/include/eunit.hrl").

Expand Down
3 changes: 3 additions & 0 deletions test/prop_bcrypt.erl
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
%% Copyright (c) 2026 Marc Worrell <marc@worrell.nl>
%% See LICENSE for license terms.

-module(prop_bcrypt).

-include_lib("proper/include/proper.hrl").
Expand Down
Loading