This commit is contained in:
Hynek Schlawack 2023-06-02 14:06:10 +02:00
parent 50c946537a
commit 4fb3ca32e3
No known key found for this signature in database
GPG Key ID: AE2536227F69F181
11 changed files with 249 additions and 267 deletions

61
docs/argon2.md Normal file
View File

@ -0,0 +1,61 @@
# What is Argon2?
:::{note}
**TL;DR**: Use {class}`argon2.PasswordHasher` with its default parameters to securely hash your passwords.
You do **not** need to read or understand anything below this box.
:::
Argon2 is a secure password hashing algorithm.
It is designed to have both a configurable runtime as well as memory consumption.
This means that you can decide how long it takes to hash a password and how much memory is required.
In September 2021, Argon2 has been standardized by the IETF in {rfc}`9106`.
Argon2 comes in three variants: Argon2**d**, Argon2**i**, and Argon2**id**.
Argon2**d**'s strength is the resistance against [timememory trade-offs], while Argon2**i**'s focus is on resistance against [side-channel attacks].
Accordingly, Argon2**i** was originally considered the correct choice for password hashing and password-based key derivation.
In practice it turned out that a *combination* of d and i -- that combines their strenghts -- is the better choice.
And so Argon2**id** was born and is now considered the *main variant* (and the only variant required by the RFC to be implemented).
## Why “just use bcrypt” Is Not the Best Answer (Anymore)
The current workhorses of password hashing are unquestionably [*bcrypt*] and [PBKDF2].
And while they're still fine to use, the password cracking community embraced new technologies like [GPU]s and [ASIC]s to crack password in a highly parallel fashion.
An effective measure against extreme parallelism proved making computation of password hashes also *memory* hard.
The best known implementation of that approach is to date [*scrypt*].
However according to the [Argon2 paper] [^outdated], page 2:
> \[…\] the existence of a trivial time-memory tradeoff allows compact implementations with the same energy cost.
Therefore a new algorithm was needed.
This time future-proof and with committee-vetting instead of single implementors.
[^outdated]: Please note that the paper is in some parts outdated.
For instance it predates the genesis of Argon2**id**.
Generally please refer to {rfc}`9106` instead.
## Password Hashing Competition
The [Password Hashing Competition] took place between 2012 and 2015 to find a new, secure, and future-proof password hashing algorithm.
Previously the NIST was in charge but after certain events and [revelations] their integrity has been put into question by the general public.
So a group of independent cryptographers and security researchers came together.
In the end, Argon2 was [announced] as the winner.
[announced]: https://groups.google.com/forum/#!topic/crypto-competitions/3QNdmwBS98o
[argon2 paper]: https://www.password-hashing.net/argon2-specs.pdf
[asic]: https://en.wikipedia.org/wiki/Application-specific_integrated_circuit
[*bcrypt*]: https://en.wikipedia.org/wiki/Bcrypt
[gpu]: https://hashcat.net/hashcat/
[password hashing competition]: https://www.password-hashing.net/
[pbkdf2]: https://en.wikipedia.org/wiki/PBKDF2
[revelations]: https://en.wikipedia.org/wiki/Dual_EC_DRBG
[*scrypt*]: https://en.wikipedia.org/wiki/Scrypt
[side-channel attacks]: https://en.wikipedia.org/wiki/Side-channel_attack
[timememory trade-offs]: https://en.wikipedia.org/wiki/Spacetime_tradeoff

View File

@ -1,66 +0,0 @@
What is Argon2?
===============
.. note::
**TL;DR**: Use :class:`argon2.PasswordHasher` with its default parameters to securely hash your passwords.
You do **not** need to read or understand anything below this box.
Argon2 is a secure password hashing algorithm.
It is designed to have both a configurable runtime as well as memory consumption.
This means that you can decide how long it takes to hash a password and how much memory is required.
In September 2021, Argon2 has been standardized by the IETF in :rfc:`9106`.
Argon2 comes in three variants: Argon2\ **d**, Argon2\ **i**, and Argon2\ **id**.
Argon2\ **d**'s strength is the resistance against `timememory trade-offs`_, while Argon2\ **i**'s focus is on resistance against `side-channel attacks`_.
Accordingly, Argon2\ **i** was originally considered the correct choice for password hashing and password-based key derivation.
In practice it turned out that a *combination* of d and i -- that combines their strenghts -- is the better choice.
And so Argon2\ **id** was born and is now considered the *main variant* (and the only variant required by the RFC to be implemented).
.. _`timememory trade-offs`: https://en.wikipedia.org/wiki/Spacetime_tradeoff
.. _`side-channel attacks`: https://en.wikipedia.org/wiki/Side-channel_attack
Why “just use bcrypt” Is Not the Best Answer (Anymore)
------------------------------------------------------
The current workhorses of password hashing are unquestionably bcrypt_ and PBKDF2_.
And while they're still fine to use, the password cracking community embraced new technologies like GPU_\ s and ASIC_\ s to crack password in a highly parallel fashion.
An effective measure against extreme parallelism proved making computation of password hashes also *memory* hard.
The best known implementation of that approach is to date scrypt_.
However according to the `Argon2 paper`_ [#outdated]_, page 2:
[…] the existence of a trivial time-memory tradeoff allows compact implementations with the same energy cost.
Therefore a new algorithm was needed.
This time future-proof and with committee-vetting instead of single implementors.
.. [#outdated] Please note that the paper is in some parts outdated.
For instance it predates the genesis of Argon2\ **id**.
Generally please refer to :rfc:`9106` instead.
.. _bcrypt: https://en.wikipedia.org/wiki/Bcrypt
.. _PBKDF2: https://en.wikipedia.org/wiki/PBKDF2
.. _GPU: https://hashcat.net/hashcat/
.. _ASIC: https://en.wikipedia.org/wiki/Application-specific_integrated_circuit
.. _scrypt: https://en.wikipedia.org/wiki/Scrypt
.. _Argon2 paper: https://www.password-hashing.net/argon2-specs.pdf
Password Hashing Competition
----------------------------
The `Password Hashing Competition`_ took place between 2012 and 2015 to find a new, secure, and future-proof password hashing algorithm.
Previously the NIST was in charge but after certain events and revelations_ their integrity has been put into question by the general public.
So a group of independent cryptographers and security researchers came together.
In the end, Argon2 was announced_ as the winner.
.. _Password Hashing Competition: https://www.password-hashing.net/
.. _revelations: https://en.wikipedia.org/wiki/Dual_EC_DRBG
.. _announced: https://groups.google.com/forum/#!topic/crypto-competitions/3QNdmwBS98o

24
docs/cli.md Normal file
View File

@ -0,0 +1,24 @@
# CLI
To aid you with finding the parameters, *argon2-cffi* offers a CLI interface that can be accessed using `python -m argon2`.
It will benchmark Argon2's password *verification* in the current environment:
```console
$ python -m argon2
Running Argon2id 100 times with:
hash_len: 32 bytes
memory_cost: 65536 KiB
parallelism: 4 threads
time_cost: 3 iterations
Measuring...
45.7ms per password verification
```
You can use command line arguments to set hashing parameters.
Either by setting them one by one (`-t` for time, `-m` for memory, `-p` for parallelism, `-l` for hash length), or by passing `--profile` followed by one of the names from {mod}`argon2.profiles`.
In that case, the other parameters are ignored.
If you don't pass any arguments as above, it runs with {class}`argon2.PasswordHasher`'s default values.
This should make it much easier to determine the right parameters for your use case and your environment.

View File

@ -1,25 +0,0 @@
CLI
===
To aid you with finding the parameters, *argon2-cffi* offers a CLI interface that can be accessed using ``python -m argon2``.
It will benchmark Argon2's password *verification* in the current environment:
.. code-block:: console
$ python -m argon2
Running Argon2id 100 times with:
hash_len: 32 bytes
memory_cost: 65536 KiB
parallelism: 4 threads
time_cost: 3 iterations
Measuring...
45.7ms per password verification
You can use command line arguments to set hashing parameters.
Either by setting them one by one (``-t`` for time, ``-m`` for memory, ``-p`` for parallelism, ``-l`` for hash length), or by passing ``--profile`` followed by one of the names from :mod:`argon2.profiles`.
In that case, the other parameters are ignored.
If you don't pass any arguments as above, it runs with :class:`argon2.PasswordHasher`'s default values.
This should make it much easier to determine the right parameters for your use case and your environment.

View File

@ -16,9 +16,7 @@ extensions = [
"sphinx.ext.todo",
]
myst_enable_extensions = [
"deflist",
]
myst_enable_extensions = ["deflist", "colon_fence"]
# Add any paths that contain templates here, relative to this directory.
templates_path = ["_templates"]

36
docs/index.md Normal file
View File

@ -0,0 +1,36 @@
# *argon2-cffi*: Argon2 for Python
Release **{sub-ref}`release`** ([What's new?](changelog))
```{include} ../README.md
:end-before: <!-- end-short -->
:start-after: <!-- begin-short -->
```
## User's Guide
```{toctree}
:maxdepth: 1
argon2
installation
api
parameters
cli
faq
changelog
```
## Project Information
```{include} ../README.md
:start-after: '## Project Information'
```
## Indices and tables
- {ref}`genindex`
- {ref}`search`

View File

@ -1,41 +0,0 @@
================================
*argon2-cffi*: Argon2 for Python
================================
Release v\ |release| (:doc:`What's new? <changelog>`)
.. include:: ../README.md
:parser: myst_parser.sphinx_
:start-after: <!-- begin-short -->
:end-before: <!-- end-short -->
User's Guide
============
.. toctree::
:maxdepth: 1
argon2
installation
api
parameters
cli
faq
changelog
Project Information
===================
.. include:: ../README.md
:parser: myst_parser.sphinx_
:start-after: ## Project Information
Indices and tables
==================
* :ref:`genindex`
* :ref:`search`

73
docs/installation.md Normal file
View File

@ -0,0 +1,73 @@
# Installation
## Using a Vendored Argon2
```console
$ python -Im pip install argon2-cffi
```
should be all it takes.
But since *argon2-cffi* depends on [argon2-cffi-bindings] that vendors Argon2's C code by default, it can lead to complications depending on the platform.
The C code is known to compile and work on all common platforms (including x86, ARM, and PPC).
On x86, an [SSE2]-optimized version is used.
If something goes wrong, please try to update your *cffi*, *pip* and *setuptools* packages first:
```console
$ python -Im pip install -U cffi pip setuptools
```
Overall this should be the safest bet because *argon2-cffi* has been specifically tested against the vendored version.
### Wheels
Binary [wheels](https://pythonwheels.com) for macOS, Windows, and Linux are provided on [PyPI] by [argon2-cffi-bindings].
With a recent-enough *pip* and *setuptools*, they should be used automatically.
### Source Distribution
A working C compiler and [CFFI environment] are required to build the [argon2-cffi-bindings] dependency.
If you've been able to compile Python CFFI extensions before, *argon2-cffi* should install without any problems.
## Using a System-wide Installation of Argon2
If you set `ARGON2_CFFI_USE_SYSTEM` to `1` (and *only* `1`), *argon2-cffi-bindings* will not build its bindings.
However binary wheels are preferred by *pip* and Argon2 gets installed along with *argon2-cffi* anyway.
Therefore you also have to instruct *pip* to use a source distribution of [argon2-cffi-bindings]:
```console
$ env ARGON2_CFFI_USE_SYSTEM=1 \
python -m pip install --no-binary=argon2-cffi-bindings argon2-cffi
```
This approach can lead to problems around your build chain and you can run into incompatibilities between Argon2 and *argon2-cffi* if the latter has been tested against a different version.
**It is your own responsibility to deal with these risks if you choose this path.**
Available since version 18.1.0.
The `--no-binary` option value changed in 21.2.0 due to the outsourcing of the binary bindings.
## Override Automatic SSE2 Detection
Usually the build process tries to guess whether or not it should use [SSE2]-optimized code.
Despite our best efforts, this can go wrong.
Therefore you can use the `ARGON2_CFFI_USE_SSE2` environment variable to control the process:
- If you set it to `1`, *argon2-cffi* will build **with** SSE2 support.
- If you set it to `0`, *argon2-cffi* will build **without** SSE2 support.
- If you set it to anything else, it will be ignored and *argon2-cffi* will try to guess.
Available since version 20.1.0.
[argon2-cffi-bindings]: https://github.com/hynek/argon2-cffi-bindings
[cffi environment]: https://cffi.readthedocs.io/en/latest/installation.html
[pypi]: https://pypi.org/project/argon2-cffi-bindings/
[sse2]: https://en.wikipedia.org/wiki/SSE2

View File

@ -1,81 +0,0 @@
Installation
============
Using a Vendored Argon2
-----------------------
.. code-block:: bash
python -m pip install argon2-cffi
should be all it takes.
But since *argon2-cffi* depends on `argon2-cffi-bindings`_ that vendors Argon2's C code by default, it can lead to complications depending on the platform.
The C code is known to compile and work on all common platforms (including x86, ARM, and PPC).
On x86, an SSE2_-optimized version is used.
If something goes wrong, please try to update your *cffi*, *pip* and *setuptools* packages first:
.. code-block:: bash
python -m pip install -U cffi pip setuptools
Overall this should be the safest bet because *argon2-cffi* has been specifically tested against the vendored version.
Wheels
^^^^^^
Binary `wheels <https://pythonwheels.com>`_ for macOS, Windows, and Linux are provided on PyPI_ by `argon2-cffi-bindings`_.
With a recent-enough *pip* and *setuptools*, they should be used automatically.
Source Distribution
^^^^^^^^^^^^^^^^^^^
A working C compiler and `CFFI environment`_ are required to build the `argon2-cffi-bindings`_ dependency.
If you've been able to compile Python CFFI extensions before, *argon2-cffi* should install without any problems.
Using a System-wide Installation of Argon2
------------------------------------------
If you set ``ARGON2_CFFI_USE_SYSTEM`` to ``1`` (and *only* ``1``), *argon2-cffi-bindings* will not build its bindings.
However binary wheels are preferred by *pip* and Argon2 gets installed along with *argon2-cffi* anyway.
Therefore you also have to instruct *pip* to use a source distribution of `argon2-cffi-bindings`_:
.. code-block:: bash
env ARGON2_CFFI_USE_SYSTEM=1 \
python -m pip install --no-binary=argon2-cffi-bindings argon2-cffi
This approach can lead to problems around your build chain and you can run into incompatibilities between Argon2 and *argon2-cffi* if the latter has been tested against a different version.
**It is your own responsibility to deal with these risks if you choose this path.**
Available since version 18.1.0.
The ``--no-binary`` option value changed in 21.2.0 due to the outsourcing of the binary bindings.
Override Automatic SSE2 Detection
---------------------------------
Usually the build process tries to guess whether or not it should use SSE2_-optimized code.
Despite our best efforts, this can go wrong.
Therefore you can use the ``ARGON2_CFFI_USE_SSE2`` environment variable to control the process:
- If you set it to ``1``, *argon2-cffi* will build **with** SSE2 support.
- If you set it to ``0``, *argon2-cffi* will build **without** SSE2 support.
- If you set it to anything else, it will be ignored and *argon2-cffi* will try to guess.
Available since version 20.1.0.
.. _SSE2: https://en.wikipedia.org/wiki/SSE2
.. _PyPI: https://pypi.org/project/argon2-cffi-bindings/
.. _CFFI environment: https://cffi.readthedocs.io/en/latest/installation.html
.. _`argon2-cffi-bindings`: https://github.com/hynek/argon2-cffi-bindings

54
docs/parameters.md Normal file
View File

@ -0,0 +1,54 @@
# Choosing Parameters
:::{note}
You can probably just use {class}`argon2.PasswordHasher` with its default values and be fine.
But it's good to double check using *argon2-cffi*'s {doc}`cli` client, whether its defaults are too slow or too fast for your use case.
:::
Finding the right parameters for a password hashing algorithm is a daunting task.
As of September 2021, we have the official Internet standard [RFC 9106] to help use with it.
It comes with two recommendations in [section 4](https://www.rfc-editor.org/rfc/rfc9106.html#section-4), that (as of *argon2-cffi* 21.2.0) you can load directly from the {mod}`argon2.profiles` module: {data}`argon2.profiles.RFC_9106_HIGH_MEMORY` (called "FIRST RECOMMENDED") and {data}`argon2.profiles.RFC_9106_LOW_MEMORY` ("SECOND RECOMMENDED") into {meth}`argon2.PasswordHasher.from_parameters()`.
Please use the {doc}`cli` interface together with its `--profile` argument to see if they work for you.
______________________________________________________________________
If you need finer tuning, the current recommended best practice is as follow:
1. Choose whether you want Argon2i, Argon2d, or Argon2id (`type`).
If you don't know what that means, choose Argon2id ({attr}`argon2.Type.ID`).
2. Figure out how many threads can be used on each call to Argon2 (`parallelism`, called "lanes" in the RFC).
They recommend 4 threads.
3. Figure out how much memory each call can afford (`memory_cost`).
The APIs use [Kibibytes] (1024 bytes) as base unit.
4. Select the salt length.
16 bytes is sufficient for all applications, but can be reduced to 8 bytes in the case of space constraints.
5. Choose a hash length (`hash_len`, called "tag length" in the documentation).
16 bytes is sufficient for password verification.
6. Figure out how long each call can take.
One [recommendation](https://web.archive.org/web/20160304024620/https://www.nccgroup.trust/us/about-us/newsroom-and-events/blog/2015/march/enough-with-the-salts-updates-on-secure-password-schemes/) for concurrent user logins is to keep it under 0.5 ms.
The RFC used to recommend under 500 ms.
The truth is somewhere between those two values: more is more secure, less is a better user experience.
*argon2-cffi*'s current defaults land with ~50ms somewhere in the middle, but the actual time depends on your hardware.
Please note though, that even a verification time of 1 second won't protect you against bad passwords from the "top 10,000 passwords" lists that you can find online.
7. Measure the time for hashing using your chosen parameters.
Start with `time_cost=1` and measure the time it takes.
Raise `time_cost` until it is within your accounted time.
If `time_cost=1` takes too long, lower `memory_cost`.
*argon2-cffi*'s {doc}`cli` will help you with this process.
:::{note}
Alternatively, you can also refer to the [OWASP cheatsheet](https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html#argon2id).
:::
[kibibytes]: https://en.wikipedia.org/wiki/Kibibyte
[rfc 9106]: https://www.rfc-editor.org/rfc/rfc9106.html

View File

@ -1,51 +0,0 @@
Choosing Parameters
===================
.. note::
You can probably just use :class:`argon2.PasswordHasher` with its default values and be fine.
But it's good to double check using *argon2-cffi*'s :doc:`cli` client, whether its defaults are too slow or too fast for your use case.
Finding the right parameters for a password hashing algorithm is a daunting task.
As of September 2021, we have the official Internet standard `RFC 9106`_ to help use with it.
It comes with two recommendations in `section 4 <https://www.rfc-editor.org/rfc/rfc9106.html#section-4>`_, that (as of *argon2-cffi* 21.2.0) you can load directly from the :mod:`argon2.profiles` module: :data:`argon2.profiles.RFC_9106_HIGH_MEMORY` (called "FIRST RECOMMENDED") and :data:`argon2.profiles.RFC_9106_LOW_MEMORY` ("SECOND RECOMMENDED") into :meth:`argon2.PasswordHasher.from_parameters()`.
Please use the :doc:`cli` interface together with its ``--profile`` argument to see if they work for you.
----
If you need finer tuning, the current recommended best practice is as follow:
#. Choose whether you want Argon2i, Argon2d, or Argon2id (``type``).
If you don't know what that means, choose Argon2id (:attr:`argon2.Type.ID`).
#. Figure out how many threads can be used on each call to Argon2 (``parallelism``, called "lanes" in the RFC).
They recommend 4 threads.
#. Figure out how much memory each call can afford (``memory_cost``).
The APIs use Kibibytes_ (1024 bytes) as base unit.
#. Select the salt length.
16 bytes is sufficient for all applications, but can be reduced to 8 bytes in the case of space constraints.
#. Choose a hash length (``hash_len``, called "tag length" in the documentation).
16 bytes is sufficient for password verification.
#. Figure out how long each call can take.
One `recommendation <https://web.archive.org/web/20160304024620/https://www.nccgroup.trust/us/about-us/newsroom-and-events/blog/2015/march/enough-with-the-salts-updates-on-secure-password-schemes/>`_ for concurrent user logins is to keep it under 0.5 ms.
The RFC used to recommend under 500 ms.
The truth is somewhere between those two values: more is more secure, less is a better user experience.
*argon2-cffi*'s current defaults land with ~50ms somewhere in the middle, but the actual time depends on your hardware.
Please note though, that even a verification time of 1 second won't protect you against bad passwords from the "top 10,000 passwords" lists that you can find online.
#. Measure the time for hashing using your chosen parameters.
Start with ``time_cost=1`` and measure the time it takes.
Raise ``time_cost`` until it is within your accounted time.
If ``time_cost=1`` takes too long, lower ``memory_cost``.
*argon2-cffi*'s :doc:`cli` will help you with this process.
.. note::
Alternatively, you can also refer to the `OWASP cheatsheet <https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html#argon2id>`_.
.. _`RFC 9106`: https://www.rfc-editor.org/rfc/rfc9106.html
.. _kibibytes: https://en.wikipedia.org/wiki/Kibibyte