.. index:: CryptContext; reference

.. module:: passlib.context
    :synopsis: CryptContext class, for managing multiple password hash schemes

.. _context-reference:

======================================================
:mod:`passlib.context` - CryptContext Hash Manager
======================================================
This page provides a complete reference of all the methods
and options supported by the :class:`!CryptContext` class
and helper utilities.

.. seealso::

    * :ref:`context-tutorial` --
      overview of this class and walkthrough of how to use it.

.. rst-class:: emphasize-children toc-always-open

The CryptContext Class
======================
.. class:: CryptContext(schemes=None, \*\*kwds)

    Helper for hashing passwords using different algorithms.

    At its base, this is a proxy object that makes it easy to use
    multiple :class:`~passlib.ifc.PasswordHash` objects at the same time.
    Instances of this class can be created by calling the constructor
    with the appropriate keywords, or by using one of the alternate
    constructors, which can load directly from a string or a local file.
    Since this class has so many options and methods, they have been broken
    out into subsections:

    * `Constructor Keywords`_ -- all the keywords this class accepts.
        - `Context Options`_ -- options affecting the Context itself.
        - `Algorithm Options`_ -- options controlling the wrapped hashes.
    * `Primary Methods`_ -- the primary methods most applications need.
    * `Hash Migration`_ -- methods for automatically replacing deprecated hashes.
    * `Alternate Constructors`_ -- creating instances from strings or files.
    * `Changing the Configuration`_ -- altering the configuration of an existing context.
    * `Examining the Configuration`_ -- programmatically examining the context's settings.
    * `Saving the Configuration`_ -- exporting the context's current configuration.
    * `Configuration Errors`_ -- overview of errors that may be thrown by :class:`!CryptContext` constructor

.. index:: CryptContext; keyword options

.. rst-class:: html-toggle expanded toc-always-open

Constructor Keywords
--------------------
The :class:`CryptContext` class accepts the following keywords,
all of which are optional.
The keywords are divided into two categories: `context options`_, which affect
the CryptContext itself; and `algorithm options`_, which place defaults
and limits on the algorithms used by the CryptContext.

.. _context-options:

Context Options
...............
Options which directly affect the behavior of the CryptContext instance:

.. _context-schemes-option:

``schemes``
    List of algorithms which the instance should support.

    The most important option in the constructor,
    This option controls what hashes can be used
    by the :meth:`~CryptContext.hash` method,
    which hashes will be recognized by :meth:`~CryptContext.verify`
    and :meth:`~CryptContext.identify`, and other effects
    throughout the instance.
    It should be a sequence of names,
    drawn from the hashes in :mod:`passlib.hash`.
    Listing an unknown name will cause a :exc:`ValueError`.
    You can use the :meth:`~CryptContext.schemes` method
    to get a list of the currently configured algorithms.
    As an example, the following creates a CryptContext instance
    which supports the :class:`~passlib.hash.sha256_crypt` and
    :class:`~passlib.hash.des_crypt` schemes::

        >>> from passlib.context import CryptContext
        >>> myctx = CryptContext(schemes=["sha256_crypt", "des_crypt"])
        >>> myctx.schemes()
        ("sha256_crypt", "des_crypt")


    .. note::

        The order of the schemes is sometimes important,
        as :meth:`~CryptContext.identify` will run
        through the schemes from first to last until an algorithm
        "claims" the hash. So plaintext algorithms and
        the like should be listed at the end.

    .. seealso:: the :ref:`context-basic-example` example in the tutorial.

.. _context-default-option:

``default``
    Specifies the name of the default scheme.

    This option controls which of the configured
    schemes will be used as the default when creating
    new hashes. This parameter is optional; if omitted,
    the first non-deprecated algorithm in ``schemes`` will be used.
    You can use the :meth:`~CryptContext.default_scheme` method
    to retrieve the name of the current default scheme.
    As an example, the following demonstrates the effect
    of this parameter on the :meth:`~CryptContext.hash`
    method::

        >>> from passlib.context import CryptContext
        >>> myctx = CryptContext(schemes=["sha256_crypt", "md5_crypt"])

        >>> # hash() uses the first scheme
        >>> myctx.default_scheme()
        'sha256_crypt'
        >>> myctx.hash("password")
        '$5$rounds=80000$R5ZIZRTNPgbdcWq5$fT/Oeqq/apMa/0fbx8YheYWS6Z3XLTxCzEtutsk2cJ1'

        >>> # but setting default causes the second scheme to be used.
        >>> myctx.update(default="md5_crypt")
        >>> myctx.default_scheme()
        'md5_crypt'
        >>> myctx.hash("password")
        '$1$Rr0C.KI8$Kvciy8pqfL9BQ2CJzEzfZ/'

    .. seealso:: the :ref:`context-basic-example` example in the tutorial.

.. _context-deprecated-option:

``deprecated``
    List of algorithms which should be considered "deprecated".

    This has the same format as ``schemes``, and should be
    a subset of those algorithms. The main purpose of this
    method is to flag schemes which need to be rehashed
    when the user next logs in. This has no effect
    on the `Primary Methods`_; but if the special `Hash Migration`_
    methods are passed a hash belonging to a deprecated scheme,
    they will flag it as needed to be rehashed using
    the ``default`` scheme.

    This may also contain a single special value,
    ``["auto"]``, which will configure the CryptContext instance
    to deprecate *all* supported schemes except for the default scheme.

    .. versionadded:: 1.6
        Added support for the ``["auto"]`` value.

    .. seealso:: :ref:`context-migration-example` in the tutorial

:samp:`truncate_error`

    By default, some algorithms will truncate large passwords
    (e.g. :class:`~passlib.hash.bcrypt` truncates ones larger than 72 bytes).
    Such hashes accept a ``truncate_error=True`` option to make them
    raise a :exc:`~passlib.exc.PasswordTruncateError` instead.

    This can also be set at the CryptContext level,
    and will passed to all hashes that support it.

    .. versionadded:: 1.7

.. _context-algorithm-options:

Algorithm Options
.................
All of the other options that can be passed to a :class:`CryptContext`
constructor affect individual hash algorithms.
All of the following keys have the form :samp:`{scheme}__{key}`,
where :samp:`{scheme}` is the name of one of the algorithms listed
in ``schemes``, and :samp:`{option}` one of the parameters below:

.. _context-default-rounds-option:

:samp:`{scheme}__rounds`

    Set the number of rounds required for this scheme
    when generating new hashes (using :meth:`~CryptContext.hash`).
    Existing hashes which have a different number of rounds will be marked
    as deprecated.

    This essentially sets ``default_rounds``, ``min_rounds``, and ``max_rounds`` all at once.
    If any of those options are also specified, they will override the value specified
    by ``rounds``.

    .. versionadded:: 1.7

        Previous releases of Passlib treated this as an alias for ``default_rounds``.

:samp:`{scheme}__default_rounds`

    Sets the default number of rounds to use with this scheme
    when generating new hashes (using :meth:`~CryptContext.hash`).

    If not set, this will fall back to the an algorithm-specific
    :attr:`~passlib.ifc.PasswordHash.default_rounds`.
    For hashes which do not support a rounds parameter, this option is ignored.
    As an example::

        >>> from passlib.context import CryptContext

        >>> # no explicit default_rounds set, so hash() uses sha256_crypt's default (80000)
        >>> myctx = CryptContext(["sha256_crypt"])
        >>> myctx.hash("fooey")
        '$5$rounds=80000$60Y7mpmAhUv6RDvj$AdseAOq6bKUZRDRTr/2QK1t38qm3P6sYeXhXKnBAmg0'
                   ^^^^^

        >>> # but if a default is specified, it will be used instead.
        >>> myctx = CryptContext(["sha256_crypt"], sha256_crypt__default_rounds=77123)
        >>> myctx.hash("fooey")
        '$5$rounds=77123$60Y7mpmAhUv6RDvj$AdseAOq6bKUZRDRTr/2QK1t38qm3P6sYeXhXKnBAmg0'
                   ^^^^^

    .. seealso:: the :ref:`context-default-settings-example` example in the tutorial.

:samp:`{scheme}__vary_rounds`

    .. deprecated:: 1.7

        This option has been deprecated as of Passlib 1.7, and will be removed in Passlib 2.0.
        The (very minimal) security benefit it provides was judged to not be worth code complexity
        it requires.

    Instead of using a fixed rounds value (such as specified by
    ``default_rounds``, above); this option will cause each call
    to :meth:`~CryptContext.hash` to vary the default rounds value
    by some amount.

    This can be an integer value, in which case each call will use a rounds
    value within the range ``default_rounds +/- vary_rounds``. It may
    also be a floating point value within the range 0.0 .. 1.0,
    in which case the range will be calculated as a proportion of the
    current default rounds (``default_rounds +/- default_rounds*vary_rounds``).
    A typical setting is ``0.1`` to ``0.2``.

    As an example of how this parameter operates::

        >>> # without vary_rounds set, hash() uses the same amount each time:
        >>> from passlib.context import CryptContext
        >>> myctx = CryptContext(schemes=["sha256_crypt"],
        ...                      sha256_crypt__default_rounds=80000)
        >>> myctx.hash("fooey")
        '$5$rounds=80000$60Y7mpmAhUv6RDvj$AdseAOq6bKUZRDRTr/2QK1t38qm3P6sYeXhXKnBAmg0'
        >>> myctx.hash("fooey")
        '$5$rounds=80000$60Y7mpmAhUv6RDvj$AdseAOq6bKUZRDRTr/2QK1t38qm3P6sYeXhXKnBAmg0'
                   ^^^^^

        >>> # but if vary_rounds is set, each one will be randomized
        >>> # (in this case, within the range 72000 .. 88000)
        >>> myctx = CryptContext(schemes=["sha256_crypt"],
        ...                      sha256_crypt__default_rounds=80000,
        ...                      sha256_crypt__vary_rounds=0.1)
        >>> myctx.hash("fooey")
        '$5$rounds=83966$bMpgQxN2hXo2kVr4$jL4Q3ov41UPgSbO7jYL0PdtsOg5koo4mCa.UEF3zan.'
        >>> myctx.hash("fooey")
        '$5$rounds=72109$43BBHC/hYPHzL69c$VYvVIdKn3Zdnvu0oJHVlo6rr0WjiMTGmlrZrrH.GxnA'
                   ^^^^^

    .. note::

        This is not a *needed* security measure, but it lets some of the less-significant
        digits of the rounds value act as extra salt bits; and helps foil
        any attacks targeted at a specific number of rounds of a hash.

.. _context-min-rounds-option:
.. _context-max-rounds-option:

:samp:`{scheme}__min_rounds`,
:samp:`{scheme}__max_rounds`

    These options place a limit on the number of rounds allowed for a particular
    scheme.

    For one, they limit what values are allowed for ``default_rounds``,
    and clip the effective range of the ``vary_rounds`` parameter.
    More importantly though, they proscribe a minimum strength for the hash,
    and any hashes which don't have sufficient rounds will be flagged as
    needing rehashing by the `Hash Migration`_ methods.

    .. note::

        These are configurable per-context limits.
        A warning will be issued if they exceed any hard limits
        set by the algorithm itself.

    .. seealso:: the :ref:`context-min-rounds-example` example in the tutorial.

.. _context-other-option:

:samp:`{scheme}__{other-option}`

    Finally, any other options are assumed to correspond to one of the
    that algorithm's :meth:`!hash` :attr:`settings <~passlib.ifc.PasswordHash.setting_kwds>`,
    such as setting a ``salt_size``.

    .. seealso:: the :ref:`context-default-settings-example` example in the tutorial.

Global Algorithm Options
........................
:samp:`all__{option}`

    The special scheme ``all`` permits you to set an option, and have
    it act as a global default for all the algorithms in the context.
    For instance, ``all__vary_rounds=0.1`` would set the ``vary_rounds``
    option for all the schemes where it was not overridden with an
    explicit :samp:`{scheme}__vary_rounds` option.

    .. deprecated:: 1.7

        This special scheme is deprecated as of Passlib 1.7, and will be removed in Passlib 2.0.
        It's only legitimate use was for ``vary_rounds``, which is also being removed in Passlib 2.0.

.. _user-categories:

.. rst-class:: html-toggle

User Categories
...............
:samp:`{category}__context__{option}`,
:samp:`{category}__{scheme}__{option}`

    Passing keys with this format to the :class:`CryptContext` constructor
    allows you to specify conditional context and algorithm options,
    controlled by the ``category`` parameter supported by most CryptContext
    methods.

    These options are conditional because they only take effect if
    the :samp:`{category}` prefix of the option matches the value of the ``category``
    parameter of the CryptContext method being invoked. In that case,
    they override any options specified without a category
    prefix (e.g. `admin__sha256_crypt__min_rounds` would override
    `sha256_crypt__min_rounds`).
    The category prefix and the value passed into the ``category`` parameter
    can be any string the application wishes to use, the only constraint
    is that ``None`` indicates the default category.

*Motivation:*
Policy limits such as default rounds values and deprecated schemes
generally have to be set globally. However, it's frequently desirable
to specify stronger options for certain accounts (such as admin accounts),
choosing to sacrifice longer hashing time for a more secure password.
The user categories system allows for this.
For example, a CryptContext could be set up as follows::

    >>> # A context object can be set up as follows:
    >>> from passlib.context import CryptContext
    >>> myctx = CryptContext(schemes=["sha256_crypt"],
    ...                      sha256_crypt__default_rounds=77000,
    ...                      staff__sha256_crypt__default_rounds=88000)

    >>> # In this case, calling hash() with ``category=None`` would result
    >>> # in a hash that used 77000 sha256-crypt rounds:
    >>> myctx.hash("password", category=None)
    '$5$rounds=77000$sj3XI0AbKlEydAKt$BhFvyh4.IoxaUeNlW6rvQ.O0w8BtgLQMYorkCOMzf84'
               ^^^^^

    >>> # But if the application passed in ``category="staff"`` when an administrative
    >>> # account set their password, 88000 rounds would be used:
    >>> myctx.hash("password", category="staff")
    '$5$rounds=88000$w7XIdKfTI9.YLwmA$MIzGvs6NU1QOQuuDHhICLmDsdW/t94Bbdfxdh/6NJl7'
               ^^^^^

.. rst-class:: html-toggle expanded

Primary Methods
---------------
The main interface to the CryptContext object deliberately mirrors
the :ref:`PasswordHash <password-hash-api>` interface, since its central
purpose is to act as a container for multiple password hashes.
Most applications will only need to make use two methods in a CryptContext
instance:

.. automethod:: CryptContext.hash
.. automethod:: CryptContext.encrypt
.. automethod:: CryptContext.verify
.. automethod:: CryptContext.identify
.. automethod:: CryptContext.dummy_verify

.. rst-class:: html-toggle

"crypt"-style methods
.....................
Additionally, the main interface offers wrappers for the two Unix "crypt"
style methods provided by all the :class:`~passlib.ifc.PasswordHash` objects:

.. automethod:: CryptContext.genhash
.. automethod:: CryptContext.genconfig

.. rst-class:: html-toggle expanded

Hash Migration
--------------
Applications which want to detect and regenerate deprecated
hashes will want to use one of the following methods:

.. automethod:: CryptContext.verify_and_update
.. automethod:: CryptContext.needs_update
.. automethod:: CryptContext.hash_needs_update

.. rst-class:: html-toggle expanded

.. _context-disabled-hashes:

Disabled Hash Managment
-----------------------
.. versionadded:: 1.7

It's frequently useful to disable a user's ability to login by
replacing their password hash with a standin that's guaranteed
to never verify, against *any* password.   CryptContext offers
some convenience methods for this through the following API.

.. automethod:: CryptContext.disable
.. automethod:: CryptContext.enable
.. automethod:: CryptContext.is_enabled

Alternate Constructors
----------------------
In addition to the main class constructor, which accepts a configuration
as a set of keywords, there are the following alternate constructors:

.. automethod:: CryptContext.from_string
.. automethod:: CryptContext.from_path
.. automethod:: CryptContext.copy

.. rst-class:: html-toggle expanded

Changing the Configuration
--------------------------
:class:`CryptContext` objects can have their configuration replaced or updated
on the fly, and from a variety of sources (keywords, strings, files).
This is done through three methods:

.. automethod:: CryptContext.update(\*\*kwds)
.. automethod:: CryptContext.load
.. automethod:: CryptContext.load_path

.. rst-class:: html-toggle expanded

Examining the Configuration
---------------------------
The CryptContext object also supports basic inspection of its
current configuration:

.. automethod:: CryptContext.schemes
.. automethod:: CryptContext.default_scheme
.. automethod:: CryptContext.handler
.. autoattribute:: CryptContext.context_kwds

.. rst-class:: html-toggle expanded

Saving the Configuration
------------------------
More detailed inspection can be done by exporting the configuration
using one of the serialization methods:

.. automethod:: CryptContext.to_dict
.. automethod:: CryptContext.to_string

Configuration Errors
--------------------
The following errors may be raised when creating a :class:`!CryptContext` instance
via any of its constructors, or when updating the configuration of an existing
instance:

:raises ValueError:

    * If a configuration option contains an invalid value
      (e.g. ``all__vary_rounds=-1``).

    * If the configuration contains valid but incompatible options
      (e.g. listing a scheme as both :ref:`default <context-default-option>`
      and :ref:`deprecated <context-deprecated-option>`).

:raises KeyError:

    * If the configuration contains an unknown or forbidden option
      (e.g. :samp:`{scheme}__salt`).

    * If the :ref:`schemes <context-schemes-option>`,
      :ref:`default <context-default-option>`, or
      :ref:`deprecated <context-deprecated-option>` options reference an unknown
      hash scheme (e.g. ``schemes=['xxx']``)

:raises TypeError:

    * If a configuration value has the wrong type (e.g. ``schemes=123``).

    Note that this error shouldn't occur when loading configurations
    from a file/string (e.g. using :meth:`CryptContext.from_string`).

Additionally, a :exc:`~passlib.exc.PasslibConfigWarning` may be issued
if any invalid-but-correctable values are encountered
(e.g. if :samp:`sha256_crypt__min_rounds` is set to less than
:class:`~passlib.hash.sha256_crypt` 's minimum of 1000).

.. versionchanged:: 1.6
    Previous releases used Python's builtin :exc:`UserWarning` instead
    of the more specific :exc:`!passlib.exc.PasslibConfigWarning`.

Other Helpers
=============
.. autoclass:: LazyCryptContext([schemes=None,] \*\*kwds [, onload=None])
