Comeonin password hashing library

I’ve just released version 3 of Comeonin, a password hashing library.

The following small changes have been made:

  • changes to the NIF code to make it more scheduler-friendly
  • more information about Argon2, the winner of the 2015 Password Hashing Competition, in the documentation
  • now using elixir_make as the compiler

If you have any questions / issues, just let me know.


Do we still need the C++ tools in Windows?

1 Like

Yes - you still need to compile C code

Hi all,

I have just released version 4.0.0-rc.0 of Comeonin. There are quite a few changes in how it is organized, but upgrading should be quite straightforward.

The first big change is that all of the password hashing algorithms are now optional dependencies of Comeonin, so the first thing you need to do is decide which algorithm you want to use and also include that as a dependency. It is also possible to use the dependency libraries directly, without installing Comeonin.

The second major change is that there is now support for Argon2, the winner of the 2015 Password Hashing Competition. That means that the supported algorithms are Argon2, Bcrypt and Pbkdf2.

There are also a couple of helper functions - add_hash and check_pass, which should reduce the amount of code you write when adding password hashes to the database and / or check a user’s password (by comparing it with a stored hash).

To use this version, add the following to the deps section in your mix.exs file:

{:comeonin, "~> 4.0-rc"},
{:argon2_elixir, "~> 1.2"},

If you are using Bcrypt, use {:bcrypt_elixir, "~> 0.11"}, and if you are using Pbkdf2, add {:pbkdf2_elixir, "0.11"}.

Here is the full changelog:

  • Enhancements
    • Added support for Argon2 (as an optional dependency – argon2_elixir)
    • Added higher-level helper functions to each algorithm’s module
      • These functions accept / return maps and should reduce code use when adding password hashes / checking passwords
    • Improved the statistics function in each module – report
    • Added sha256 support and django format support to Pbkdf2
  • Changes
    • Made all the hashing algorithms optional dependencies
    • Moved the configuration to the separate dependency libraries
    • Removed support for one-time passwords

If you have any questions / comments, please let me know.


Cool! Since all the modules are now external, do you plan to add a feature to Comeonin that would be able to determine which module to use given a password hash? This would be useful if you have started out with bcrypt and then decide to move to Argon2 for new passwords.


I haven’t really considered having Comeonin determine which module in that way, but I have tried to make the apis for all the algorithms as close as possible (the only differences are in the opts for hashpwsalt, which are algorithm-specific), so changing the algorithm mainly involves changing the module name – from Comeonin.Bcrypt to Comeonin.Argon2 – and then deciding how to configure the new algorithm (how many rounds, etc.).

1 Like

If your concern is that you will have a mixed set of hashes in the database, and you want some way to determine which module should be used, then I’ll definitely consider that.

1 Like

I suppose one could also easily implement it for the individual application especially since Bcrypt and Argon2 explicitly prefixes all hashes:

case hash do
  "$2b$" <> _ = hash -> Bcrypt.verify_pass(password, hash)
  "$argon2" <> _ = hash -> Argon2.verify_pass(password, hash)

On reflection, I would prefer to handle this use case by adding some information about it in the wiki, rather than making changes to the Comeonin api. As you mention, you can pattern match on the hash to work out which algorithm it is, and that should work out fine.

1 Like

It seems like dialyxer does not work well with the new rc.

I’ve the following function:

@spec authenticate(String.t, String.t) :: {:ok, User.t} | {:error, term}
def authenticate(email, password) when is_binary(email) and is_binary(password) do
  |> Repo.get_by(email: email)
  |> check_pass(password)
def authenticate(_, _), do: {:error, "Incorrect arguments."}

But calling it like this does trigger warnings:

with {:ok, user} <- Authentication.authenticate(email, pass) do
The pattern {'ok', _@4} can never match the type 
{'error',{'error',_} | 
#{'__struct__':='Elixir.Ecto.Changeset', […]}}

And hints what could throw it off here? Not checking the password and returning correct tuples seems to work.

I’m probably going to add dialyxir to each dependency algorithm. I know that otherwise it will give errors for the ‘dummy check’ function. I hope to get that done within the next few days.


Released version 4.0.0.

The current versions of the different algorithms are as follows:

  • argon2_elixir - 1.2.2
  • bcrypt_elixir - 0.12.0
  • pbkdf2_elixir - 0.12.0

At the moment, there is a problem with building argon2_elixir on Windows, but that should be solved within the next few days.

Finally, one of the goals of Comeonin is that the documentation is very good. If you feel that any of the documentation is unclear or incomplete, please open an issue / pull request.


I have just updated bcrypt_elixir to version 1.0.

This now has dirty scheduler support, which should make it more scheduler-friendly. For this version, you need Erlang 20 installed, or you need to build Erlang with dirty scheduler support.


If possible by any means, I do not think you should drop non-dirty thus fast. There may be reasons to not update or self-compile OTP while wanting to update a security relevant library as fast as possible.

I should have made it clearer that I’m not dropping support for the non-dirty scheduler version.

Version 1.0 supports dirty schedulers.

Version 0.12 is the ‘old’ version, which is still maintained and works fine, so if someone doesn’t want to update to Erlang 20, they can stay on the pre-1.0 version.

1 Like

How long will you provide security backports to pre 1.0? Until OTP 19 fades from main distributions repositories?

It reads as quite a large jump… 0.12 to 1.0

If the library is following Semantic Versioning, a jump from 0.x to 1.x indicates that the APIs are not compatible which is indeed the case here.

Yupp, I am aware of that. And it is unclear how long at least security relevant patches will flow back to 0.12.

I’m just asking for a rough estimate of 0.12s end-of-life.

0.12 will be maintained for the foreseeable future, and it is very stable. It is just that it is not quite as scheduler friendly as the new version.

Making the new version 1.0 is meant to prevent developers updating to the new version by accident.

If you have any further questions, please feel free to ask.


A little explanation of some of the changes that came with version 4 of Comeonin –