295 lines
12 KiB
ReStructuredText
295 lines
12 KiB
ReStructuredText
|
|
||
|
.. _pbkdf:
|
||
|
|
||
|
Password Based Key Derivation
|
||
|
========================================
|
||
|
|
||
|
Often one needs to convert a human readable password into a cryptographic
|
||
|
key. It is useful to slow down the computation of these computations in order to
|
||
|
reduce the speed of brute force search, thus they are parameterized in some
|
||
|
way which allows their required computation to be tuned.
|
||
|
|
||
|
PasswordHash
|
||
|
--------------
|
||
|
|
||
|
.. versionadded:: 2.8.0
|
||
|
|
||
|
This API, declared in ``pwdhash.h``, has two classes, ``PasswordHashFamily``
|
||
|
representing the general algorithm, such as "PBKDF2(SHA-256)", or "Scrypt", and
|
||
|
``PasswordHash`` representing a specific instance of the problem which is fully
|
||
|
specified with all parameters (say "Scrypt" with ``N`` = 8192, ``r`` = 64, and
|
||
|
``p`` = 8) and which can be used to derive keys.
|
||
|
|
||
|
.. cpp:class:: PasswordHash
|
||
|
|
||
|
.. cpp:function:: void hash(std::span<uint8_t> out, \
|
||
|
std::string_view password, \
|
||
|
std::span<uint8> salt)
|
||
|
|
||
|
Derive a key from the specified *password* and *salt*, placing it into *out*.
|
||
|
|
||
|
.. cpp:function:: void hash(std::span<uint8_t> out, \
|
||
|
std::string_view password, \
|
||
|
std::span<const uint8> salt, \
|
||
|
std::span<const uint8> ad, \
|
||
|
std::span<const uint8> key)
|
||
|
|
||
|
Derive a key from the specified *password*, *salt*, associated data (*ad*), and
|
||
|
secret *key*, placing it into *out*. The *ad* and *key* are both allowed
|
||
|
to be empty. Currently non-empty AD/key is only supported with Argon2.
|
||
|
|
||
|
.. cpp:function:: void derive_key(uint8_t out[], size_t out_len, \
|
||
|
const char* password, const size_t password_len, \
|
||
|
const uint8_t salt[], size_t salt_len) const
|
||
|
|
||
|
Same functionality as the 3 argument variant of :cpp:func:`PasswordHash::hash`.
|
||
|
|
||
|
.. cpp:function:: void derive_key(uint8_t out[], size_t out_len, \
|
||
|
const char* password, const size_t password_len, \
|
||
|
const uint8_t salt[], size_t salt_len, \
|
||
|
const uint8_t ad[], size_t ad_len, \
|
||
|
const uint8_t key[], size_t key_len) const
|
||
|
|
||
|
Same functionality as the 5 argument variant of :cpp:func:`PasswordHash::hash`.
|
||
|
|
||
|
.. cpp:function:: std::string to_string() const
|
||
|
|
||
|
Return a descriptive string including the parameters (iteration count, etc)
|
||
|
|
||
|
.. cpp:function:: size_t iterations() const
|
||
|
|
||
|
Return the iteration parameter
|
||
|
|
||
|
.. cpp:function:: size_t memory_param() const
|
||
|
|
||
|
Return the memory usage parameter, or 0 if the algorithm does not offer
|
||
|
a memory usage option.
|
||
|
|
||
|
.. cpp:function:: size_t parallelism() const
|
||
|
|
||
|
Returns the parallelism parameter, or 0 if the algorithm does not offer a
|
||
|
parallelism option.
|
||
|
|
||
|
.. cpp:function:: size_t total_memory_usage() const
|
||
|
|
||
|
Return a guesstimate of the total number of bytes of memory consumed when
|
||
|
running this algorithm. If the function is not intended to be memory-hard
|
||
|
and uses an effictively fixed amount of memory when running, this function
|
||
|
returns 0.
|
||
|
|
||
|
.. cpp:function:: bool supports_keyed_operation() const
|
||
|
|
||
|
Returns true if this password hash supports supplying a secret key
|
||
|
to :cpp:func:`PasswordHash::hash`.
|
||
|
|
||
|
.. cpp:function:: bool supports_associated_data() const
|
||
|
|
||
|
Returns true if this password hash supports supplying associated data
|
||
|
to :cpp:func:`PasswordHash::hash`.
|
||
|
|
||
|
The ``PasswordHashFamily`` creates specific instances of ``PasswordHash``:
|
||
|
|
||
|
.. cpp:class:: PasswordHashFamily
|
||
|
|
||
|
.. cpp:function:: static std::unique_ptr<PasswordHashFamily> create(const std::string& what)
|
||
|
|
||
|
For example "PBKDF2(SHA-256)", "Scrypt", "Argon2id". Returns null if the
|
||
|
algorithm is not available.
|
||
|
|
||
|
.. cpp:function:: std::unique_ptr<PasswordHash> default_params() const
|
||
|
|
||
|
Create a default instance of the password hashing algorithm. Be warned the
|
||
|
value returned here may change from release to release.
|
||
|
|
||
|
.. cpp:function:: std::unique_ptr<PasswordHash> tune( \
|
||
|
size_t output_len, \
|
||
|
std::chrono::milliseconds msec, \
|
||
|
size_t max_memory_usage_mb = 0, \
|
||
|
std::chrono::milliseconds tuning_msec = std::chrono::milliseconds(10)) const
|
||
|
|
||
|
Return a password hash instance tuned to run for approximately ``msec``
|
||
|
milliseconds when producing an output of length ``output_len``. (Accuracy
|
||
|
may vary, use the command line utility ``botan pbkdf_tune`` to check.)
|
||
|
|
||
|
The parameters will be selected to use at most *max_memory_usage_mb* megabytes
|
||
|
of memory, or if left as zero any size is allowed.
|
||
|
|
||
|
This function works by runing a short tuning loop to estimate the
|
||
|
performance of the algorithm, then scaling the parameters appropriately to
|
||
|
hit the target size. The length of time the tuning loop runs can be
|
||
|
controlled using the *tuning_msec* parameter.
|
||
|
|
||
|
.. cpp:function:: std::unique_ptr<PasswordHash> from_params( \
|
||
|
size_t i1, size_t i2 = 0, size_t i3 = 0) const
|
||
|
|
||
|
Create a password hash using some scheme specific format. Parameters are as follows:
|
||
|
|
||
|
* For PBKDF2, PGP-S2K, and Bcrypt-PBKDF, ``i1`` is iterations
|
||
|
* Scrypt uses ``i1`` == ``N``, ``i2`` == ``r``, and ``i3`` == ``p``
|
||
|
* Argon2 family uses ``i1`` == ``M``, ``i2`` == ``t``, and ``i3`` == ``p``
|
||
|
|
||
|
All unneeded parameters should be set to 0 or left blank.
|
||
|
|
||
|
Code Example
|
||
|
------------
|
||
|
|
||
|
An example demonstrating using the API to hash a password using Argon2i:
|
||
|
|
||
|
.. literalinclude:: /../src/examples/pwdhash.cpp
|
||
|
:language: cpp
|
||
|
|
||
|
Available Schemes
|
||
|
----------------------
|
||
|
|
||
|
General Recommendations
|
||
|
^^^^^^^^^^^^^^^^^^^^^^^^^
|
||
|
|
||
|
If you need wide interoperability use PBKDF2 with HMAC-SHA256 and at least 50K
|
||
|
iterations. If you don't, use Argon2id with p=1, t=3 and M as large as you
|
||
|
can reasonably set (say 1 gigabyte).
|
||
|
|
||
|
You can test how long a particular PBKDF takes to execute using the cli tool
|
||
|
``pbkdf_tune``::
|
||
|
|
||
|
$ ./botan pbkdf_tune --algo=Argon2id 500 --max-mem=192 --check
|
||
|
For 500 ms selected Argon2id(196608,3,1) using 192 MiB took 413.159 msec to compute
|
||
|
|
||
|
This returns the parameters chosen by the fast auto-tuning algorithm, and
|
||
|
because ``--check`` was supplied the hash is also executed with the full set of
|
||
|
parameters and timed.
|
||
|
|
||
|
PBKDF2
|
||
|
^^^^^^^^^^^^
|
||
|
|
||
|
PBKDF2 is the "standard" password derivation scheme, widely implemented in many
|
||
|
different libraries. It uses HMAC internally and requires choosing a hash
|
||
|
function to use. (If in doubt use SHA-256 or SHA-512). It also requires choosing
|
||
|
an iteration count, which makes brute force attacks more expensive. Use *at
|
||
|
least* 50000 and preferably much more. Using 250,000 would not be unreasonable.
|
||
|
|
||
|
Scrypt
|
||
|
^^^^^^^^^^
|
||
|
|
||
|
.. versionadded:: 2.7.0
|
||
|
|
||
|
Scrypt is a relatively newer design which is "memory hard" - in
|
||
|
addition to requiring large amounts of CPU power it uses a large block
|
||
|
of memory to compute the hash. This makes brute force attacks using
|
||
|
ASICs substantially more expensive.
|
||
|
|
||
|
Scrypt has three parameters, usually termed ``N``, ``r``, and ``p``. ``N`` is
|
||
|
the primary control of the workfactor, and must be a power of 2. For interactive
|
||
|
logins use 32768, for protection of secret keys or backups use 1048576.
|
||
|
|
||
|
The ``r`` parameter controls how 'wide' the internal hashing operation is. It
|
||
|
also increases the amount of memory that is used. Values from 1 to 8 are
|
||
|
reasonable.
|
||
|
|
||
|
Setting ``p`` parameter to greater than 1 splits up the work in a way that up
|
||
|
to p processors can work in parallel.
|
||
|
|
||
|
As a general recommendation, use ``N`` = 32768, ``r`` = 8, ``p`` = 1
|
||
|
|
||
|
Argon2
|
||
|
^^^^^^^^^^
|
||
|
|
||
|
.. versionadded:: 2.11.0
|
||
|
|
||
|
Argon2 is the winner of the PHC (Password Hashing Competition) and
|
||
|
provides a tunable memory hard PBKDF. There are three minor variants
|
||
|
of Argon2 - Argon2d, Argon2i, and Argon2id. All three are implemented.
|
||
|
|
||
|
Bcrypt
|
||
|
^^^^^^^^^^^^
|
||
|
|
||
|
.. versionadded:: 2.11.0
|
||
|
|
||
|
Bcrypt-PBKDF is a variant of the well known ``bcrypt`` password hashing
|
||
|
function. Like ``bcrypt`` it is based around using Blowfish for the key
|
||
|
expansion, which requires 4 KiB of fast random access memory, making hardware
|
||
|
based attacks more expensive. Unlike Argon2 or Scrypt, the memory usage is not
|
||
|
tunable.
|
||
|
|
||
|
This function is relatively obscure but is used for example in OpenSSH.
|
||
|
Prefer Argon2 or Scrypt in new systems.
|
||
|
|
||
|
OpenPGP S2K
|
||
|
^^^^^^^^^^^^
|
||
|
|
||
|
.. warning::
|
||
|
|
||
|
The OpenPGP algorithm is weak and strange, and should be avoided unless
|
||
|
implementing OpenPGP.
|
||
|
|
||
|
There are some oddities about OpenPGP's S2K algorithms that are documented
|
||
|
here. For one thing, it uses the iteration count in a strange manner; instead of
|
||
|
specifying how many times to iterate the hash, it tells how many *bytes* should
|
||
|
be hashed in total (including the salt). So the exact iteration count will
|
||
|
depend on the size of the salt (which is fixed at 8 bytes by the OpenPGP
|
||
|
standard, though the implementation will allow any salt size) and the size of
|
||
|
the passphrase.
|
||
|
|
||
|
To get what OpenPGP calls "Simple S2K", set iterations to 0, and do not specify
|
||
|
a salt. To get "Salted S2K", again leave the iteration count at 0, but give an
|
||
|
8-byte salt. "Salted and Iterated S2K" requires an 8-byte salt and some
|
||
|
iteration count (this should be significantly larger than the size of the
|
||
|
longest passphrase that might reasonably be used; somewhere from 1024 to 65536
|
||
|
would probably be about right). Using both a reasonably sized salt and a large
|
||
|
iteration count is highly recommended to prevent password guessing attempts.
|
||
|
|
||
|
PBKDF
|
||
|
---------
|
||
|
|
||
|
:cpp:class:`PBKDF` is the older API for this functionality, presented in header
|
||
|
``pbkdf.h``. It only supports PBKDF2 and the PGP S2K algorithm, not
|
||
|
Scrypt, Argon2, or bcrypt. This interface is deprecated and will be removed
|
||
|
in a future major release.
|
||
|
|
||
|
In addition, this API requires the passphrase be entered as a
|
||
|
``std::string``, which means the secret will be stored in memory that
|
||
|
will not be zeroed.
|
||
|
|
||
|
.. cpp:class:: PBKDF
|
||
|
|
||
|
.. cpp:function:: static std::unique_ptr<PBKDF> create(const std::string& algo_spec, \
|
||
|
const std::string& provider = "")
|
||
|
|
||
|
Return a newly created PBKDF object. The name should be in the
|
||
|
format "PBKDF2(HASHNAME)", "PBKDF2(HMAC(HASHNAME))", or
|
||
|
"OpenPGP-S2K". Returns null if the algorithm is not available.
|
||
|
|
||
|
.. cpp:function:: void pbkdf_iterations(uint8_t out[], size_t out_len, \
|
||
|
const std::string& passphrase, \
|
||
|
const uint8_t salt[], size_t salt_len, \
|
||
|
size_t iterations) const
|
||
|
|
||
|
Run the PBKDF algorithm for the specified number of iterations,
|
||
|
with the given salt, and write output to the buffer.
|
||
|
|
||
|
.. cpp:function:: void pbkdf_timed(uint8_t out[], size_t out_len, \
|
||
|
const std::string& passphrase, \
|
||
|
const uint8_t salt[], size_t salt_len, \
|
||
|
std::chrono::milliseconds msec, \
|
||
|
size_t& iterations) const
|
||
|
|
||
|
Choose (via short run-time benchmark) how many iterations to perform
|
||
|
in order to run for roughly msec milliseconds. Writes the number
|
||
|
of iterations used to reference argument.
|
||
|
|
||
|
.. cpp:function:: OctetString derive_key( \
|
||
|
size_t output_len, const std::string& passphrase, \
|
||
|
const uint8_t* salt, size_t salt_len, \
|
||
|
size_t iterations) const
|
||
|
|
||
|
Computes a key from *passphrase* and the *salt* (of length
|
||
|
*salt_len* bytes) using an algorithm-specific interpretation of
|
||
|
*iterations*, producing a key of length *output_len*.
|
||
|
|
||
|
Use an iteration count of at least 10000. The salt should be
|
||
|
randomly chosen by a good random number generator (see
|
||
|
:ref:`random_number_generators` for how), or at the very least
|
||
|
unique to this usage of the passphrase.
|
||
|
|
||
|
If you call this function again with the same parameters, you will
|
||
|
get the same key.
|