From 4fb3ca32e3e21e524f541dfaa4f0651fb12a990e Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Fri, 2 Jun 2023 14:06:10 +0200 Subject: [PATCH] MyST --- docs/argon2.md | 61 ++++++++++++++++++++++++++++++++ docs/argon2.rst | 66 ----------------------------------- docs/cli.md | 24 +++++++++++++ docs/cli.rst | 25 ------------- docs/conf.py | 4 +-- docs/index.md | 36 +++++++++++++++++++ docs/index.rst | 41 ---------------------- docs/installation.md | 73 ++++++++++++++++++++++++++++++++++++++ docs/installation.rst | 81 ------------------------------------------- docs/parameters.md | 54 +++++++++++++++++++++++++++++ docs/parameters.rst | 51 --------------------------- 11 files changed, 249 insertions(+), 267 deletions(-) create mode 100644 docs/argon2.md delete mode 100644 docs/argon2.rst create mode 100644 docs/cli.md delete mode 100644 docs/cli.rst create mode 100644 docs/index.md delete mode 100644 docs/index.rst create mode 100644 docs/installation.md delete mode 100644 docs/installation.rst create mode 100644 docs/parameters.md delete mode 100644 docs/parameters.rst diff --git a/docs/argon2.md b/docs/argon2.md new file mode 100644 index 0000000..b58886a --- /dev/null +++ b/docs/argon2.md @@ -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 [time–memory 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 +[time–memory trade-offs]: https://en.wikipedia.org/wiki/Space–time_tradeoff diff --git a/docs/argon2.rst b/docs/argon2.rst deleted file mode 100644 index f9f132c..0000000 --- a/docs/argon2.rst +++ /dev/null @@ -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 `time–memory 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). - -.. _`time–memory trade-offs`: https://en.wikipedia.org/wiki/Space–time_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 diff --git a/docs/cli.md b/docs/cli.md new file mode 100644 index 0000000..536d59d --- /dev/null +++ b/docs/cli.md @@ -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. diff --git a/docs/cli.rst b/docs/cli.rst deleted file mode 100644 index 57be673..0000000 --- a/docs/cli.rst +++ /dev/null @@ -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. diff --git a/docs/conf.py b/docs/conf.py index aaba18a..5d0ebbc 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -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"] diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..ab74406 --- /dev/null +++ b/docs/index.md @@ -0,0 +1,36 @@ +# *argon2-cffi*: Argon2 for Python + +Release **{sub-ref}`release`** ([What's new?](changelog)) + +```{include} ../README.md +:end-before: +:start-after: +``` + + +## 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` diff --git a/docs/index.rst b/docs/index.rst deleted file mode 100644 index 4fc7a02..0000000 --- a/docs/index.rst +++ /dev/null @@ -1,41 +0,0 @@ -================================ -*argon2-cffi*: Argon2 for Python -================================ - -Release v\ |release| (:doc:`What's new? `) - - -.. include:: ../README.md - :parser: myst_parser.sphinx_ - :start-after: - :end-before: - - -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` diff --git a/docs/installation.md b/docs/installation.md new file mode 100644 index 0000000..27e9f89 --- /dev/null +++ b/docs/installation.md @@ -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 diff --git a/docs/installation.rst b/docs/installation.rst deleted file mode 100644 index 75e7861..0000000 --- a/docs/installation.rst +++ /dev/null @@ -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 `_ 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 diff --git a/docs/parameters.md b/docs/parameters.md new file mode 100644 index 0000000..d25ea0d --- /dev/null +++ b/docs/parameters.md @@ -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 diff --git a/docs/parameters.rst b/docs/parameters.rst deleted file mode 100644 index 91ccd68..0000000 --- a/docs/parameters.rst +++ /dev/null @@ -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 `_, 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 `_ 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 `_. - - -.. _`RFC 9106`: https://www.rfc-editor.org/rfc/rfc9106.html -.. _kibibytes: https://en.wikipedia.org/wiki/Kibibyte