API Reference

argon2_cffi comes with an high-level API and hopefully reasonable defaults for Argon2 parameters that result in a verification time of 40–50ms on recent-ish hardware.

Warning

The current memory requirement is set to rather conservative 100 MB. However, in memory constrained environments like Docker containers that can lead to problems. One possible non-obvious symptom are apparent freezes that are caused by swapping.

Please check Choosing Parameters for more details.

Unless you have any special needs, all you need to know is:

>>> from argon2 import PasswordHasher
>>> ph = PasswordHasher()
>>> hash = ph.hash("s3kr3tp4ssw0rd")
>>> hash  
'$argon2id$v=19$m=102400,t=2,p=8$tSm+JOWigOgPZx/g44K5fQ$WDyus6py50bVFIPkjA28lQ'
>>> ph.verify(hash, "s3kr3tp4ssw0rd")
True
>>> ph.check_needs_rehash(hash)
False
>>> ph.verify(hash, "t0t411ywr0ng")
Traceback (most recent call last):
  ...
argon2.exceptions.VerifyMismatchError: The password does not match the supplied hash

A login function could thus look like this:

import argon2


ph = argon2.PasswordHasher()


def login(db, user, password):
    hash = db.get_password_hash_for_user(user)

    # Verify password, raises exception if wrong.
    ph.verify(hash, password)

    # Now that we have the cleartext password,
    # check the hash's parameters and if outdated,
    # rehash the user's password in the database.
    if ph.check_needs_rehash(hash):
        db.set_password_hash_for_user(user, ph.hash(password))

While the PasswordHasher class has the aspiration to be good to use out of the box, it has all the parametrization you’ll need:

If you don’t specify any parameters, the following constants are used:

argon2.DEFAULT_RANDOM_SALT_LENGTH
argon2.DEFAULT_HASH_LENGTH
argon2.DEFAULT_TIME_COST
argon2.DEFAULT_MEMORY_COST
argon2.DEFAULT_PARALLELISM

You can see their values in PasswordHasher.

Exceptions

exception argon2.exceptions.VerificationError

Verification failed.

You can find the original error message from Argon2 in args[0].

exception argon2.exceptions.VerifyMismatchError

The secret does not match the hash.

Subclass of argon2.exceptions.VerificationError.

New in version 16.1.0.

exception argon2.exceptions.HashingError

Raised if hashing failed.

You can find the original error message from Argon2 in args[0].

exception argon2.exceptions.InvalidHash

Raised if the hash is invalid before passing it to Argon2.

New in version 18.2.0.

Utilities

Low Level

>>> import argon2
>>> argon2.low_level.hash_secret(
...     b"secret", b"somesalt",
...     time_cost=1, memory_cost=8, parallelism=1, hash_len=64, type=argon2.low_level.Type.D
... )
b'$argon2d$v=19$m=8,t=1,p=1$c29tZXNhbHQ$ba2qC75j0+JAunZZ/L0hZdQgCv+tOieBuKKXSrQiWm7nlkRcK+YqWr0i0m0WABJKelU8qHJp0SZzH0b1Z+ITvQ'

The raw hash can also be computed:

>>> argon2.low_level.hash_secret_raw(
...     b"secret", b"somesalt",
...     time_cost=1, memory_cost=8, parallelism=1, hash_len=8, type=argon2.low_level.Type.D
... )
b'\xe4n\xf5\xc8|\xa3>\x1d'

The super low-level argon2_core() function is exposed too if you need access to very specific options:

In order to use core(), you need access to argon2_cffi’s FFI objects. Therefore it is OK to use argon2.low_level.ffi and argon2.low_level.lib when working with it:

>>> from argon2.low_level import ARGON2_VERSION, Type, core, ffi, lib
>>> pwd = b"secret"
>>> salt = b"12345678"
>>> hash_len = 8
>>> # Make sure you keep FFI objects alive until *after* the core call!
>>> cout = ffi.new("uint8_t[]", hash_len)
>>> cpwd = ffi.new("uint8_t[]", pwd)
>>> csalt = ffi.new("uint8_t[]", salt)
>>> ctx = ffi.new(
...     "argon2_context *", dict(
...         version=ARGON2_VERSION,
...         out=cout, outlen=hash_len,
...         pwd=cpwd, pwdlen=len(pwd),
...         salt=csalt, saltlen=len(salt),
...         secret=ffi.NULL, secretlen=0,
...         ad=ffi.NULL, adlen=0,
...         t_cost=1,
...         m_cost=8,
...         lanes=1, threads=1,
...         allocate_cbk=ffi.NULL, free_cbk=ffi.NULL,
...         flags=lib.ARGON2_DEFAULT_FLAGS,
...     )
... )
>>> ctx
<cdata 'struct Argon2_Context *' owning 120 bytes>
>>> core(ctx, Type.D.value)
0
>>> out = bytes(ffi.buffer(ctx.out, ctx.outlen))
>>> out
b'\xb4\xe2HjO\x14d\x9b'
>>> out == argon2.low_level.hash_secret_raw(pwd, salt, 1, 8, 1, 8, Type.D)
True

All constants and types on argon2.low_level.lib are guaranteed to stay as long they are not altered by Argon2 itself.

Deprecated APIs

These APIs are from the first release of argon2_cffi and proved to live in an unfortunate mid-level. On one hand they have defaults and check parameters but on the other hand they only consume byte strings.

Therefore the decision has been made to replace them by a high-level (argon2.PasswordHasher) and a low-level (argon2.low_level) solution. There are no immediate plans to remove them though.