diff options
Diffstat (limited to 'docs/password_hash_api.rst')
-rw-r--r-- | docs/password_hash_api.rst | 975 |
1 files changed, 519 insertions, 456 deletions
diff --git a/docs/password_hash_api.rst b/docs/password_hash_api.rst index c349992..e0ce49b 100644 --- a/docs/password_hash_api.rst +++ b/docs/password_hash_api.rst @@ -1,612 +1,675 @@ .. index:: - single: password hash api + single: PasswordHash interface single: custom hash handler; requirements -.. currentmodule:: passlib.hash +.. module:: passlib.ifc + :synopsis: abstract interfaces used by Passlib .. _password-hash-api: -================= -Password Hash API -================= +============================================= +Password Hash Interface +============================================= Overview ======== -All of the hashes supported by PassLib are implemented using classes [#otypes]_ -which support an identical interface; this document describes that -interface in terms of a non-existent abstract class called :class:`!PasswordHash`. -All of the supported password hashes [#supported]_ provide the following methods and attributes: +While the exact options and behavior will vary between algorithms, +all of the hashes provided by Passlib use the same interface, +defined by the following abstract base class: -:ref:`required-attributes` +.. class:: PasswordHash() - These consist of the attributes :attr:`~PasswordHash.name`, - :attr:`~PasswordHash.setting_kwds`, and :attr:`~PasswordHash.context_kwds`. - They permit users and applications to detect what features a specific :class:`!PasswordHash` - allows and/or requires. + This class provides an abstract interface for + an arbitrary password hashing algorithm. + While it offers a number of methods and attributes, + but most applications will only need the two primary methods: -:ref:`application-methods` + * :meth:`~PasswordHash.encrypt` - generate new salt, return hash of password. + * :meth:`~PasswordHash.verify` - verify password against existing hash. - This interface consists of the :meth:`~PasswordHash.encrypt`, - :meth:`~PasswordHash.identify`, and :meth:`~PasswordHash.verify` classmethods. - These are the methods most applications will need to make use of. + While not needed by most applications, the following methods + provide an interface that mimics the traditional Unix :func:`crypt` + function: -:ref:`crypt-methods` + * :meth:`~PasswordHash.genconfig` - create configuration string from salt & other options. + * :meth:`~PasswordHash.genhash` - hash password using existing hash or configuration string. - This interface consists of the :meth:`~PasswordHash.genconfig` - and :meth:`~PasswordHash.genhash` classmethods. - These methods mimic the standard unix crypt interface, - and are not usually needed by applications. + One additional support method is provided: -:ref:`optional-attributes` + * :meth:`~PasswordHash.identify` - check if hash belongs to this algorithm. - These attributes provide additional information - about the capabilities and limitations of certain password hash schemes. + Each hash algorithm also provides a number of :ref:`informational attributes <informational-attributes>`, + allowing programmatic inspection of it's options and parameter limits. -Usage -===== -While most uses of PassLib are done through a :class:`~passlib.context.CryptContext` class, -the various :class:`!PasswordHash` classes can be used directly to manipulate -passwords:: +.. _password-hash-examples: - >>> # for example, the SHA256-Crypt class: - >>> from passlib.hash import sha256_crypt as sc +Usage Examples +============== +The following code shows how to use the primary +methods of the :class:`~passlib.utils.handlers.PasswordHash` interface -- +:meth:`~PasswordHash.encrypt` and :meth:`~PasswordHash.verify` -- +using the :class:`~passlib.hash.sha256_crypt` hash as an example:: - >>> # using it to encrypt a password: - >>> h = sc.encrypt("password") - >>> h + >>> # import the handler class + >>> from passlib.hash import sha256_crypt + + >>> # hash a password using the default settings: + >>> hash = sha256_crypt.encrypt("password") + >>> hash '$5$rounds=40000$HIo6SCnVL9zqF8TK$y2sUnu13gp4cv0YgLQMW56PfQjWaTyiHjVbXTgleYG9' - >>> # subsequent calls to sc.encrypt() will generate a new salt: - >>> sc.encrypt("password") + >>> # note that each call to encrypt() generates a new salt, + >>> # and thus the contents of the hash will differ, despite using the same password: + >>> sha256_crypt.encrypt("password") '$5$rounds=40000$1JfxoiYM5Pxokyh8$ez8uV8jjXW7SjpaTg2vHJmx3Qn36uyZpjhyC9AfBi7B' - >>> # the same, but with an explict number of rounds: - >>> sc.encrypt("password", rounds=10000) - '$5$rounds=10000$UkvoKJb8BPrLnR.D$OrUnOdr.IJx74hmyyzuRdr5k9lSXdkFxKmr7bLQTty5' + >>> # if the hash supports a variable number of iterations (which sha256_crypt does), + >>> # you can override the default value via the 'rounds' keyword: + >>> sha256_crypt.encrypt("password", rounds=12345) + '$5$rounds=12345$UeVpHaN2YFDwBoeJ$NJN8DwVZ4UfQw6.ijJZNWoZtk1Ivi5YfKCDsI2HzSq2' - >>> #the identify method can be used to determine the format of an unknown hash: - >>> sc.identify(h) + >>> # on the other end of things, the verify() method takes care of + >>> # checking if a password matches an existing hash string: + >>> sha256_crypt.verify("password", hash) True - - >>> #check if some other hash is recognized (in this case, an MD5-Crypt hash) - >>> sc.identify('$1$3azHgidD$SrJPt7B.9rekpmwJwtON31') + >>> sha256_crypt.verify("letmeinplz", hash) False - >>> #the verify method encapsulates all hash comparison logic for a class: - >>> sc.verify("password", h) +.. note:: + + Whether a hash supports a particular configuration keywoard (such as ``rounds``) + can be determined from it's documentation page; but also programmatically from + it's :attr:`~PasswordHash.setting_kwds` attribute. + +That concludes the most basic example, but there are a few more +common use-cases, such as how to use the :meth:`~PasswordHash.identify` method:: + + >>> # attempting to call verify() with another algorithm's hash will result in a ValueError: + >>> from passlib.hash import sha256_crypt, md5_crypt + >>> other_hash = md5_crypt.encrypt("password") + >>> sha256_crypt.verify("password", other_hash) + Traceback (most recent call last): + <traceback omitted> + ValueError: not a valid sha256_crypt hash + + >>> # this can be prevented by using the identify method, + >>> # determines whether a hash belongs to a given algorithm: + >>> hash = sha256_crypt.encrypt("password") + >>> sha256_crypt.identify(hash) True - >>> sc.verify("wrongpassword", h) + >>> sha256_crypt.identify(other_hash) False -.. _required-attributes: +While the initial :meth:`~PasswordHash.encrypt` example works for most hashes, +a small number of algorithms require you provide external data +(such as a username) every time a hash is calculated. +An example of this is the :class:`~passlib.hash.oracle10` algorithm:: -Required Attributes -================================= -.. attribute:: PasswordHash.name + >>> # for oracle10, encrypt requires a username: + >>> from passlib.hash import oracle10 + >>> hash = oracle10.encrypt("secret", user="admin") + 'B858CE295C95193F' - A unique name used to identify - the particular scheme this class implements. + >>> # the difference between this and something like the rounds setting (above) + >>> # is that oracle10 also requires the username when verifying a hash: + >>> oracle10.verify("secret", hash, user="admin") + True - These names should consist only of lowercase a-z, the digits 0-9, and underscores. + >>> # if either the username OR password is wrong, verify() will fail: + >>> oracle10.verify("secret", hash, user="wronguser") + False + >>> oracle10.verify("wrongpassword", hash, user="admin") + False - .. note:: + >>> # forgetting to include the username when it's required will cause a TypeError: + >>> hash = oracle10.encrypt("password") + Traceback (most recent call last): + <traceback omitted> + TypeError: user must be unicode or bytes, not None - All handlers built into passlib are implemented as classes - located under :samp:`passlib.hash.{name}`, where :samp:`{name}` - is both the class name, and the value of the ``name`` attribute. - This is not a requirement, and may not be true for - externally-defined handlers. +.. note:: -.. attribute:: PasswordHash.setting_kwds + Whether a hash requires external parameters (such as ``user``) + can be determined from it's documentation page; but also programmatically from + it's :attr:`~PasswordHash.context_kwds` attribute. - If the scheme supports per-hash configuration - (such as salts, variable rounds, etc), this attribute - should contain a tuple of keywords corresponding - to each of those configuration options. - This should list all the main configuration keywords accepted - by :meth:`~PasswordHash.genconfig` and :meth:`~PasswordHash.encrypt`. - If no configuration options are supported, this attribute should be an empty tuple. +.. _primary-methods: - While each class may support a variety of options, each with their own meaning - and semantics, the following keywords should have the same behavior - across all schemes which use them: +Primary Methods +=============== +Most applications will only need to use two methods: +:meth:`~PasswordHash.encrypt` to generate new hashes, and :meth:`~PasswordHash.verify` +to check passwords against existing hashes. +These methods provide an easy interface for working with a password hash, +and abstract away details such as salt generation, hash normalization, +and hash comparison. - ``salt`` - If present, this means the algorithm contains some number of bits of salt - which should vary with every new hash created. +.. classmethod:: PasswordHash.encrypt(secret, \*\*kwds) - Additionally, this means - :meth:`~PasswordHash.genconfig` and :meth:`~PasswordHash.encrypt` - should both accept an optional ``salt`` keyword allowing the user - to specify a bare salt string. Note that this feature is rarely - needed, and the constraints on the size & content of this string - will vary for each algorithm. + Encrypt password, returning resulting hash string. - ``salt_size`` - Most algorithms which support ``salt`` will auto-generate a salt string - if none is provided. If this keyword is also present, it means it - can be used to select the size of the auto-generated salt. - If omitted, most algorithms will fall back to a default salt size. + :type secret: unicode or bytes + :arg secret: string containing the password to encode. - ``rounds`` - If present, this means the algorithm allows for a variable number of rounds - to be used, allowing the processor time required to be increased. + :param \*\*kwds: - Providing this as a keyword should allow the application to - override the class' default number of rounds. While this - must be a non-negative integer for all implementations, - additional constraints may be present for each algorith - (such as the cost varying on a linear or logarithmic scale). + All additional keywords are algorithm-specific, and will be listed + in that hash's documentation; though many of the more common keywords + are listed under :attr:`~PasswordHash.setting_kwds` + and :attr:`~PasswordHash.context_kwds`. + Examples of common keywords include ``salt`` and ``rounds``. - ``ident`` - If present, the class supports multiple formats for encoding - the same hash. The class's documentation will generally list - the allowed values, allowing alternate output formats to be selected. + :returns: + resulting hash, using an algorithm-specific format. - ``relaxed`` - If supported, ``relaxed=True`` will cause the handler to - be more forgiving about invalid input. Instead of immediately throwing - a :exc:`ValueError`, it will first attempt to correct the input, - and issue a :exc:`~passlib.exc.PasslibHashWarning` if successful. - This includes actions like clamping out-of-range rounds values, - and truncating salts that are too long. + this will use the native :class:`!str` type + (unicode under Python 3, ``ascii``-encoded bytes under Python 2). -.. attribute:: PasswordHash.context_kwds + :raises ValueError: - This attribute should contain a tuple of keywords - which should be passed into :func:`encrypt`, :func:`verify`, - and :func:`genhash` in order to encrypt a password. + * If a keyword's value is invalid (e.g. if a ``salt`` string + is too small, or a ``rounds`` value is out of range). - Some algorithms require external contextual information - in order to generate a checksum for a password. - An example of this is :doc:`Postgres' MD5 algorithm <lib/passlib.hash.postgres_md5>`, - which requires the username be provided when generating a hash - (see that class for an example of how this works in pratice). + * If the *secret* contains characters forbidden by the handler + (e.g. :class:`!des_crypt` forbids NULL characters). - Since most password hashes require no external information, - this tuple will usually be empty, and references - to context keywords can be ignored for all but a few classes. + :raises TypeError: - While each class may support a variety of options, each with their own meaning - and semantics, the following keywords should have the same behavior - across all schemes which use them: + * if :samp:`{secret}` is not unicode or bytes. + * if a keyword argument had an incorrect type. + * if a required keyword was not provided. - ``user`` + .. versionchanged:: 1.6 + Hashes now raise :exc:`TypeError` if a required keyword is missing, + rather than :exc:`ValueError` like in previous releases; in order + to conform with normal Python behavior. - If present, the class requires a username be specified whenever - performing a hash calculation (eg: postgres_md5 and oracle10). + .. versionchanged:: 1.6 + Passlib is now much stricter about input validation: for example, + out-of-range ``rounds`` values now cause an error instead of being + clipped (though applications may set ``relaxed=True`` to restore the old behavior). -.. _application-methods: +.. classmethod:: PasswordHash.verify(secret, hash, \*\*context_kwds) -Application Methods -=================== -The :meth:`~PasswordHash.encrypt`, :meth:`~PasswordHash.identify`, and :meth:`~PasswordHash.verify` methods are designed -to provide an easy interface for applications. They allow encrypt new passwords -without having to deal with details such as salt generation, verifying -passwords without having to deal with hash comparison rules, and determining -which scheme a hash belongs to when multiple schemes are in use. + Verify a secret using an existing hash. -.. classmethod:: PasswordHash.encrypt(secret, \*\*settings_and_context_kwds) + This checks if a secret matches against the one stored + inside the specified hash. - encrypt secret, returning resulting hash string. + :type secret: unicode or bytes + :param secret: + A string containing the password to check. - :arg secret: - A string containing the secret to encode. + :type secret: unicode or bytes + :param hash: + A string containing the hash to check against. - Unicode behavior is specified on a per-hash basis, - but the common case is to encode into utf-8 - before processing. + Hashes may be specified as :class:`!unicode` or + ``ascii``-encoded :class:`!bytes`. - :param \*\*settings_and_context_kwds: - All other keywords are algorithm-specified, - and should be listed in :attr:`~PasswordHash.setting_kwds` - and :attr:`~PasswordHash.context_kwds`. + :param \*\*kwds: + Very few hashes will have additional keywords. + + The ones that do typically require external contextual information + in order to calculate the digest. For these hashes, + the values must match the ones passed to the original + :meth:`~PasswordHash.encrypt` call when the hash was generated, + or the password will not verify. - Common settings keywords include ``salt`` and ``rounds``. + These additional keywords are algorithm-specific, and will be listed + in that hash's documentation; though the more common keywords + are listed under :attr:`~PasswordHash.context_kwds`. + Examples of common keywords include ``user``. + + :returns: + ``True`` if the secret matches, otherwise ``False``. + + :raises TypeError: + * if either *secret* or *hash* is not a unicode or bytes instance. + * if the hash requires additional keywords which are not provided, + or have the wrong type. :raises ValueError: + * if *hash* does not match this algorithm's format. + * if the secret contains forbidden characters (see + :meth:`~PasswordHash.encrypt`). + * if a configuration/salt string generated by :meth:`~PasswordHash.genconfig` + is passed in as the value for *hash* (these strings look + similar to a full hash, but typically lack the digest portion + needed to verify a password). - * If a keyword's value is invalid (e.g. if a ``salt`` string - is too small, or a ``rounds`` value is out of range). + .. versionchanged:: 1.6 + This function now raises :exc:`ValueError` if a ``None`` or config string is provided + instead of a proper hash; previous releases were inconsistent + in their handling of these cases. - * If the secret contains characters forbidden by the handler - (e.g. :class:`!des_crypt` forbids NULL characters). This should not - happen often, since most modern algorithms have no limitations on - the character values they accept. +.. _hash-unicode-behavior: - :raises TypeError: +.. note:: - * if :samp:`{secret}` is not a unicode or bytes instance. + Regarding unicode passwords & non-ASCII characters: - * if a required option (such as a context keyword) was not set. + For the majority of hash algorithms and use-cases, passwords should + be provided as either :class:`!unicode` or ``utf-8``-encoded :class:`!bytes`. + There are only two major exceptions: - :returns: - Hash string, using an algorithm-specific format. + * Some systems have legacy hashes that were generated using a different + character encoding. In this case, all :class:`!unicode` passwords + should be encoded using the correct encoding before they are hashed; + otherwise non-ASCII passwords may not :meth:`!verify` successfully. - .. versionchanged:: 1.6 + * For historical reasons, :class:`~passlib.hash.lmhash` uses ``cp437`` + as it's default encoding. It will handle :class:`!unicode` correctly, + but non-``ascii`` passwords provided as :class:`!bytes` must be encoded + using ``"cp437"``, or the correct encoding must be specified via :class:`!lmhash`'s + ``encoding`` keyword. - Previous versions of Passlib would raise :exc:`ValueError` if a - required keyword was missing; this has been changed to :exc:`TypeError` - in order to conform with normal Python behavior. +.. _crypt-methods: - Previous versions of Passlib would silently correct invalid settings - where possible (e.g. silently clamping out-of-range ``rounds``); as - of Passlib 1.6 the policy is to raise an explicit error. +Crypt Methods +============= +Taken together, the :meth:`~PasswordHash.genconfig` and :meth:`~PasswordHash.genhash` +are two tightly-coupled methods that mimic the standard Unix +"crypt" interface. The first method generates salt / configuration +strings from a set of settings, and the second hashes the password +using the provided configuration string. -.. classmethod:: PasswordHash.identify(hash) +.. seealso:: - Quickly identify if a hash string belongs to this algorithm. + Most applications will find :meth:`~PasswordHash.encrypt` much more useful, + as it combines the functionality of these two methods into one. + +.. classmethod:: PasswordHash.genconfig(\*\*setting_kwds) + + Returns a configuration string encoding settings for hash generation. - :arg hash: the candidate hash string to check + This function takes in all the same :attr:`~PasswordHash.setting_kwds` + as :meth:`~PasswordHash.encrypt`, fills in suitable defaults, + and encodes the settings into a single "configuration" string, + suitable passing to :meth:`~PasswordHash.genhash`. - :raises TypeError: if :samp:`{hash}` is not a unicode or bytes instance. + :param \*\*kwds: + All additional keywords are algorithm-specific, and will be listed + in that hash's documentation; though many of the more common keywords + are listed under :attr:`~PasswordHash.setting_kwds` + Examples of common keywords include ``salt`` and ``rounds``. :returns: - ``True`` if the input appears to be a hash or configuration string - which belongs to this algorithm, otherwise ``False``. + A configuration string (as :class:`!str`), or ``None`` if the scheme + does not support a separate configuration. + + :raises ValueError, TypeError: + This function raises exceptions for the same + reasons as :meth:`~PasswordHash.encrypt`. .. note:: - The goal of this method is positively identify the correct - handler for a given hash, and do it as efficiently as possible. - In order to accomplish this, many implementations perform only minimal - validation of the candidate hashes. Thus, they may return ``True`` - for hashes which are identifiable, but malformed enough that - a :exc:`ValueError` is raised when the string is passed to - :func:`~PasswordHash.verify` or :func:`~PasswordHash.genhash`. - Because of this, applications should rely on this method only for identification, - not confirmation that a hash is correctly formed. + This configuration string is typically the same as the full hash string, + except that it lacks the final portion containing the digested password. + This is sometimes referred to as a "salt" string, though it typically + contains much more than just the salt parameter. -.. classmethod:: PasswordHash.verify(secret, hash, \*\*context_kwds) +.. classmethod:: PasswordHash.genhash(secret, config, \*\*context_kwds) - verify a secret against an existing hash. + Encrypt secret using specified configuration string. - This checks if a secret matches against the one stored - inside the specified hash. + This takes in a password and a configuration string, + and returns a hash for that password. - :param secret: - A string containing the secret to check. - :param hash: - A string containing the hash to check against. + :type secret: unicode or bytes + :arg secret: + string containing the password to be encrypted. - :param \*\*context_kwds: - Any additional keywords will be passed to the encrypt - method. These should be limited to those listed - in :attr:`~PasswordHash.context_kwds`. + :type config: unicode or bytes or ``None`` + :arg config: + configuration string to use when encrypting secret. + this can either be an existing hash that was previously + returned by :meth:`~PasswordHash.genhash`, or a configuration string + that was previously created by :meth:`~PasswordHash.genconfig`. - :raises TypeError: + ``None`` is accepted *only* for the hashes which lack a configuration + string (for which :meth:`~PasswordHash.genconfig` always returns ``None``). - if either *secret* or *hash* is not a unicode or bytes instance. + :param \*\*kwds: + Very few hashes will have additional keywords. - :raises ValueError: - * the hash does not match this algorithm's hash format. - * if the secret contains forbidden characters (see - :meth:`~PasswordHash.encrypt`). - * if a configuration string from :meth:`~PasswordHash.genconfig` - is passed in as the value for *hash*. + The ones that do typically require external contextual information + in order to calculate the digest. For these hashes, + the values must match the ones passed to the original + :meth:`~PasswordHash.encrypt` call when the hash was generated, + or the password will not verify. + + These additional keywords are algorithm-specific, and will be listed + in that hash's documentation; though the more common keywords + are listed under ::attr:`~PasswordHash.context_kwds`. + Examples of common keywords include ``user``. :returns: - ``True`` if the secret matches, otherwise ``False``. + Encoded hash matching specified secret, config, and kwds. + This will always be a native :class:`!str` instance. -.. _crypt-methods: + :raises ValueError, TypeError: + This function raises exceptions for the same + reasons as :meth:`~PasswordHash.encrypt`. -Crypt Methods -============= -While the application methods are generally the most useful when integrating -password support into an application, those methods are for the most part -built on top of the crypt interface, which is somewhat simpler -for *implementing* new password schemes. It also happens to match -more closely with the crypt api of most Unix systems, -and consists of two functions: :meth:`~PasswordHash.genconfig` -and :meth:`~PasswordHash.genhash`. + .. warning:: -.. classmethod:: PasswordHash.genconfig(\*\*settings_kwds) + Traditionally, password verification using the "crypt" interface + was done by testing if ``hash == genhash(password, hash)``. + This test is only reliable for a handful of algorithms, + as various hash representation issues may cause false results. + Applications are strongly urged to use :meth:`~PasswordHash.verify` instead. - returns configuration string encoding settings for hash generation +.. _support-methods: - Many hashes have configuration options, and support a format - which encodes them into a single configuration string. - (This configuration string is usually an abbreviated version of their - encoded hash format, sans the actual checksum, and is commonly - referred to as a ``salt string``, though it may contain much more - than just a salt). +Support Methods +=============== +There is currently one additional support method, :meth:`~PasswordHash.identify`: - This function takes in configuration options specific to the handler, - validates the inputs, fills in defaults where appropriate, and returns - a configuration string. For algorithms which do not have any configuration - options, this function should always return ``None``. +.. classmethod:: PasswordHash.identify(hash) - :param \*\*settings_kwds: + Quickly identify if a hash string belongs to this algorithm. - While each algorithm may have it's own specific configuration options - (detailed in it's documentation), a list of common options can be - found in in :attr:`~PasswordHash.setting_kwds`. + :type hash: unicode or bytes + :arg hash: + the candidate hash string to check - commonly supported keywords include ``salt`` and ``rounds``. + :returns: + * ``True`` if the input is a configuration string or hash string + identifiable as belonging to this scheme (even if it's malformed). + * ``False`` if the input does *not* belong to this scheme. + * Hashes which lack a reliable method of identification may incorrectly + identify each-other's hashes (e.g. both :class:`~passlib.hash.lmhash` + and :class:`~passlib.hash.nthash` hash consist 32 hexidecimal characters). :raises TypeError: - if any required configuration options are omitted - (most options do not need to be specified; e.g. an appropriate - value for ``salt`` will be autogenerated for each call). + if :samp:`{hash}` is not a unicode or bytes instance. - :raises ValueError: - if any configuration options are invalid (and cannot - be corrected, if in relaxed parsing mode). + .. seealso:: - :returns: - the configuration string, or ``None`` if the algorithm does not support - any configuration options. + If you are considering using this method to select from multiple + algorithms in order to verify a password, you may be better served + by the :doc:`CryptContext </lib/passlib.context>` class. -.. classmethod:: PasswordHash.genhash(secret, config, \*\*context_kwds) +.. + the undocumented and experimental support methods currently include + parsehash() and bitsize() - encrypt secret to hash +.. _informational-attributes: - takes in a password, optional configuration string, - and any required contextual information the algorithm needs, - and returns the encoded hash strings. +Informational Attributes +======================== - :arg secret: string containing the password to be encrypted - :arg config: - configuration string to use when encrypting secret. - this can either be an existing hash that was previously - returned by :meth:`~PasswordHash.genhash`, or a configuration string - that was previously created by :meth:`~PasswordHash.genconfig`. +.. _general-attributes: - :param \*\*context_kwds: - All other keywords must be external contextual information - required by the algorithm to create the hash. If any, - these kwds must be specified in :attr:`~PasswordHash.context_kwds`. +General Information +------------------- +Each hash provides a handful of informational attributes, allowing +programs to dynamically adapt to the requirements of different +hash algorithms. The following attributes should be defined for all +the hashes in passlib: - :raises TypeError: - * if either *secret* or *config* is not a unicode or bytes instance. - * if required contextual keywords are not provided +.. attribute:: PasswordHash.name - :raises ValueError: - * if the configuration string is not in a recognized format. - * if the secret contains a forbidden character (rare, but some algorithms have limitations, eg: forbidding null characters) - * if the contextual information is invalid + Name uniquely identifying this hash. - :returns: - encoded hash matching specified secret, config, and context. + For the hashes built into Passlib, this will always match + the location where it was imported from — :samp:`passlib.hash.{name}` — + though externally defined hashes may not adhere to this. -.. _optional-attributes: + This should always be a :class:`!str` consisting of lowercase ``a-z``, + the digits ``0-9``, and the underscore character ``_``. -Optional Attributes -================================= -Many of the handlers expose the following informational -attributes (though their presence is not uniform or required -as of this version of Passlib). +.. attribute:: PasswordHash.setting_kwds -.. todo:: + Tuple listing the keywords supported by :meth:`~PasswordHash.encrypt` + and :meth:`~PasswordHash.genconfig` that control hash generation, and which will + be encoded into the resulting hash. - Consider making these attributes required for all hashes - which support the appropriate keyword in :attr:`~PasswordHash.setting_kwds`. + This list commonly includes keywords for controlling salt generation, + adjusting time-cost parameters, etc. Most of these settings are optional, + and suitable defaults will be chosen if they are omitted (e.g. salts + will be autogenerated). -.. _optional-rounds-attributes: + While the documentation for each hash should have a complete list of + the specific settings the hash uses, the following keywords should have + roughly the same behavior for all the hashes that support them: -Rounds Information ------------------- -For schemes which support a variable number of rounds (ie, ``'rounds' in PasswordHash.setting_kwds``), -the following attributes are usually exposed. -(Applications can test for this suites' presence by using :func:`~passlib.utils.has_rounds_info`) + ``salt`` + Specifies a fixed salt string to use, rather than randomly + generating one. -.. attribute:: PasswordHash.max_rounds + This option is supported by most of the hashes in Passlib, + though typically it isn't used, as random generation of a salt + is usually the desired behavior. - The maximum number of rounds the scheme allows. - Specifying values above this will generally result - in a warning, and :attr:`~!PasswordHash.max_rounds` will be used instead. - Must be a positive integer. + Hashes typically require this to be a :class:`!unicode` or + :class:`!bytes` instance, with additional constraints + appropriate to the algorithm. -.. attribute:: PasswordHash.min_rounds + ``salt_size`` - The minimum number of rounds the scheme allows. - Specifying values below this will generally result - in a warning, and :attr:`~!PasswordHash.min_rounds` will be used instead. - Must be within ``range(0, max_rounds+1)``. + Most algorithms which support the ``salt`` setting will + autogenerate a salt when none is provided. Many of those + will also offer this option, which allows the caller to specify + the size of salt which should be generated. If omitted, + the hash's default salt size will be used. -.. attribute:: PasswordHash.default_rounds + ``rounds`` + If present, this means the hash can vary the number + of internal rounds used in some part of it's algorithm, + allowing the calculation to take a variable amount of processor + time, for increased security. - The default number of rounds that will be used if not - explicitly set when calling :meth:`~PasswordHash.encrypt` or :meth:`~PasswordHash.genconfig`. - Must be within ``range(min_rounds, max_rounds+1)``. + While this is almost always a non-negative integer, + additional constraints may be present for each algorithm + (such as the cost varying on a linear or logarithmic scale). -.. attribute:: PasswordHash.rounds_cost + This value is typically omitted, in which case a default + value will be used. The defaults for all the hashes in Passlib + are periodically retuned to strike a balance between + security and responsiveness. - Specifies how the rounds value affects the amount of time taken. - Currently used values are: + ``ident`` + If present, the class supports multiple formats for encoding + the same hash. The class's documentation will generally list + the allowed values, allowing alternate output formats to be selected. - ``linear`` - time taken scales linearly with rounds value (eg: :class:`~passlib.hash.sha512_crypt`) + Note that these values will typically correspond to different + revision of the hash algorithm itself, and they may not all + offer the same level of security. - ``log2`` - time taken scales exponentially with rounds value (eg: :class:`~passlib.hash.bcrypt`) + ``relaxed`` + If supported, ``relaxed=True`` will cause the handler to + be more forgiving about invalid input. Instead of immediately throwing + a :exc:`ValueError`, it will first attempt to correct the input, + and issue a :exc:`~passlib.exc.PasslibHashWarning` if successful. + This includes actions like clamping out-of-range rounds values, + and truncating salts that are too long. + + Many of the hashes in Passlib support this option, even if it's not listed. + +.. attribute:: PasswordHash.context_kwds + + Tuple listing the keywords supported by :meth:`~PasswordHash.encrypt`, + :meth:`~PasswordHash.verify`, and :meth:`~PasswordHash.genhash` affect the hash, but are + not encoded within it, and thus must be provided each time + the hash is calculated. -.. _optional-salt-attributes: + This list commonly includes a user account, http realm identifier, + etc. Most of these keywords are required by the hashes which support them, + as they are frequently used in place of an embedded salt parameter. + This is typically an empty tuple for most of the hashes in passlib. + + While the documentation for each hash should have a complete list of + the specific context keywords the hash uses, + the following keywords should have roughly the same behavior + for all the hashes that support them: + + ``user`` + + If present, the class requires a username be specified whenever + performing a hash calculation (e.g. + :class:`~passlib.hash.postgres_md5` and + :class:`~passlib.hash.oracle10`). + + ``encoding`` + + Some hashes have poorly-defined or host-dependant unicode behavior, + and properly hashing a unique password requires providing + the correct encoding (e.g. :class:`~passlib.hash.lmhash`). + Hashes which provide this keyword will always expose + their default encoding programmatically via the + :attr:`~PasswordHash.default_encoding` attribute. + +.. _salt-attributes: Salt Information ---------------- -For schemes which support a salt (ie, ``'salt' in PasswordHash.setting_kwds``), -the following attributes are usually exposed. -(Applications can test for this suites' presence by using :func:`~passlib.utils.has_salt_info`) +For schemes which support a salt string, +``"salt"`` should be listed in their :attr:`~PasswordHash.setting_kwds`, +and the following attributes should be defined: .. attribute:: PasswordHash.max_salt_size - maximum number of characters which will be used - if a salt string is provided to :meth:`~PasswordHash.genconfig` or :meth:`~PasswordHash.encrypt`. - must be one of: - - * A positive integer - it should accept and silently truncate - any salt strings longer than this size. - - * ``None`` - the scheme should use all characters of a provided salt, - no matter how large. + The maximum number of bytes/characters allowed in the salt. + Should either be a positive integer, or ``None`` (indicating + the algorithm has no effective upper limit). .. attribute:: PasswordHash.min_salt_size - minimum number of characters required for any salt string - provided to :meth:`~PasswordHash.genconfig` or :meth:`~PasswordHash.encrypt`. - must be an integer within ``range(0,max_salt_size+1)``. + The minimum number of bytes/characters required for the salt. + Must be an integer between 0 or :attr:`~PasswordHash.max_salt_size`. .. attribute:: PasswordHash.default_salt_size - size of salts generated by genconfig - when no salt is provided by caller. - for most hashes, this defaults to :attr:`~PasswordHash.max_salt_size`. - this value must be within ``range(min_salt_size, max_salt_size+1)``. + The default salt size that will be used when generating a salt, + assuming ``salt_size`` is not set explicitly. This is typically + the same as :attr:`max_salt_size`, + or a sane default if ``max_salt_size=None``. .. attribute:: PasswordHash.salt_chars - string containing list of all characters which are allowed - to be specified in salt parameter. - for most :ref:`MCF <modular-crypt-format>` hashes, + A unicode string containing all the characters permitted + in a salt string. For most :ref:`MCF <modular-crypt-format>` hashes, this is equal to :data:`passlib.utils.HASH64_CHARS`. - this must be a :class:`!unicode` string if the salt is encoded, - or (rarely) :class:`!bytes` if the salt is manipulating as unencoded raw bytes. + For the rare hashes where the ``salt`` parameter must be specified + in bytes, this will be a placeholder :class:`!bytes` object containing + all 256 possible byte values. + +.. + not yet documentated, want to make sure this is how we want to do things: + + .. attribute:: PasswordHash.default_salt_chars + + sequence of characters used to generate new salts. + this is typically the same as :attr:`~PasswordHash.salt_chars`, but some + hashes accept a larger-than-useful range, and this will + contain only the "common" values used for generation. + +.. _rounds-attributes: + +Rounds Information +------------------ +For schemes which support a variable number of iterations to adjust their time-cost, +``"rounds"`` should be listed in :attr:`~PasswordHash.setting_kwds`, +and the following attributes should be defined: + +.. attribute:: PasswordHash.max_rounds + + The maximum number of rounds the scheme allows. + Specifying a value beyond this will result in a :exc:`ValueError`. + Will be a positive integer, or ``None`` (indicating + the algorithm has no effective upper limit). + +.. attribute:: PasswordHash.min_rounds + + The minimum number of rounds the scheme allows. + Specifying a value below this will result in a :exc:`ValueError`. + Will always be an integer between 0 and :attr:`~PasswordHash.max_rounds`. + +.. attribute:: PasswordHash.default_rounds + + The default number of rounds that will be used if none is explicitly + provided to :meth:`~PasswordHash.encrypt`. + This will always be an integer between :attr:`~PasswordHash.min_rounds` + and :attr:`~PasswordHash.max_rounds`. + +.. attribute:: PasswordHash.rounds_cost + + While the cost parameter ``rounds`` is an integer, how it corresponds + to the amount of time taken can vary between hashes. This attribute + indicates the scale used by the hash: + + * ``"linear"`` - time taken scales linearly with rounds value + (e.g. :class:`~passlib.hash.sha512_crypt`) + * ``"log2"`` - time taken scales exponentially with rounds value + (e.g. :class:`~passlib.hash.bcrypt`) .. todo:: - This section lists the behavior for handlers which accept - salt strings containing encoded characters. - Some handlers may instead expect raw bytes for their salt keyword, - and handle encoding / decoding them internally. - It should be documented how these attributes - behave in that situation. + Add notes about when/how the default rounds are retuned. + For the 1.6 release, all hashes were retuned to take ~250ms + on a single 3 ghz cpu core, or more rounds if that was felt + to not provide a minimum level of security. Also, there are + so many variables affecting relative system performance, + that this policy is more of an informed heuristic than a + rigid algorithm. .. - not yet documentated, want to make sure this is how we want to do things: + todo: haven't decided if this is how I want the api look before + formally publishing it in the documentation: - .. attribute:: PasswordHash.default_salt_chars + .. _password-hash-backends: - sequence of characters used to generated new salts - when no salt is provided by caller. - for most hashes, this is the same as :attr:`!PasswordHash.salt_chars`; - but some hashes accept a much larger range of values - than are typically used. This field allows - the full range to be accepted, while only - a select subset to be used for generation. + Multiple Backends + ================= + .. note:: - xxx: what about a bits_per_salt_char or some such, so effective salt strength - can be compared? + For the most part, applications will not need this interface, + outside of perhaps calling the :meth:`~PasswordHash.get_backend` + to determine which the active backend. -.. _hash-unicode-behavior: + Some hashes provided by Passlib have multiple backends which they + select from at runtime, to provide the fastest implementation available. + Algorithms which offer multiple backends will expose the following + methods and attributes: + + .. attribute:: PasswordHash.backends + + Tuple listing names of potential backends (which may or may not be available). + If this attribute is not present, the hash does not support + multiple backends. + + While the names of the backends are specific to the hash algorithm, + the following standard names may be present: + + * ``"os_crypt"`` - backend which uses stdlib's :mod:`!crypt` module. + this backend will not be available if the underlying host OS + does not support the particular hash algorithm. + + * ``"builtin"`` - backend using pure-python implementation built into + Passlib. All hashes will have this as their last backend, as a fallback. + + .. method:: PasswordHash.get_backend() + + This method should return the name of the currently active backend + that will be used by :meth:`!encrypt` and :meth:`!verify`. + + :raises passlib.exc.MissingBackendError: + in the rare case that *no* backends can be loaded. + + .. method:: PasswordHash.has_backend(backend) + + This method can be used to test if a specific backend is available. + Returns ``True`` or ``False``. + + .. method:: PasswordHash.set_backend(backend) + + This method can be used to select a specific backend. + The ``backend`` argument must be one of the backends listed + in :attr:`~PasswordHash.backends`, or the special value ``"default"``. -Unicode Behavior -================ - -.. versionadded:: 1.5 - -Quick summary -------------- -For the application developer in a hurry: - -* Passwords should be provided as :class:`unicode` if possible. - While they may be provided as :class:`bytes`, - in that case it is strongly suggested - they be encoded using ``utf-8`` or ``ascii``. - -* Passlib will always return hashes as native python strings. - This means :class:`unicode` under Python 3, - and ``ascii``-encoded :class:`bytes` under Python 2. - -* Applications should provide hashes as :class:`unicode` if possible. - However, ``ascii``-encoded :class:`bytes` are also accepted - under Python 2. - -The following sections detail the issues surrounding -encoding password hashes, and the behavior required -by handlers implementing this API. -It can be skipped by the uninterested. - -Passwords ---------- -Applications are strongly encouraged to provide passwords -as :class:`unicode`. Two situations where an application -might need to provide a password as :class:`bytes`: -the application isn't unicode aware (lots of python 2 apps), -or it needs to verify a password hash that used a specific encoding (eg ``latin-1``). -For either of these cases, application developers should consider -the following issues: - -* Most hashes in Passlib operate on a string of bytes. - For handlers implementing such hashes, - passwords provided as :class:`unicode` should be encoded to ``utf-8``, - and passwords provided as :class:`bytes` should be treated as opaque. - - A few of these hashes officially specify this behavior; - the rest have no preferred encoding at all, - so this was chosen as a sensible standard behavior. - Unless the underlying algorithm specifies an alternate policy, - handlers should always encode unicode to ``utf-8``. - -* Because of the above behavior for :class:`unicode` inputs, - applications which encode their passwords are urged - to use ``utf-8`` or ``ascii``, - so that hashes they generate with encoded bytes - will verify correctly if/when they start using unicode. - - Applications which need to verify existing hashes - using an alternate encoding such as ``latin-1`` - should be wary of this future "gotcha". - -* A few hashes operate on :class:`unicode` strings instead. - For handlers implementing such hashes: - passwords provided as :class:`unicode` should be handled as appropriate, - and passwords provided as :class:`bytes` should be treated as ``utf-8``, - and decoded. - - This behavior was chosen in order to be compatible with - the common case (above), combined with the fact - that applications should never need to use a specific - encoding with these hashes, as they are natively unicode. - - (Hashes like this include :class:`~passlib.hash.oracle10` and - :class:`~passlib.hash.nthash`) - -Hashes ------- -With the exception of plaintext passwords, -literally *all* of the hash formats surveyed by the Passlib authors -use only the characters found in 7-bit ``ascii``. -This has caused most password hashing code (in python and elsewhere) -to draw a very blurry line between :class:`unicode` and :class:`bytes`. -Because of that, the following behavior was dictated less -by design requirements, and more by compatibility -and ease of implementation issues: - -* Handlers should accept hashes as either :class:`unicode` or - as ``ascii``-encoded :class:`bytes`. - - This behavior allows applications to provide hashes - as unicode or as bytes, as they please; making - (among other things) migration to Python 3 easier. - - The primary exception to this is handlers implementing - plaintext passwords. The implementations in passlib generally - use ``utf-8`` to encode unicode passwords, - and reproduce existing passwords as opaque bytes. - -* Internally, it is recommended that handlers use - :class:`unicode` for parsing / formatting - purposes, and only use :class:`bytes` for decoded - binary data ready to be passed into their digest routines. - -* Handlers should return hashes as native python strings. - This means :class:`unicode` under Python 3, - and ``ascii``-encoded :class:`bytes` under Python 2. - - This behavior was chosen to fit with Python 3's - unicode-oriented philosophy, while retaining - backwards compatibility with Passlib 1.4 and earlier - under Python 2. - -.. rubric:: Footnotes - -.. [#otypes] While this specification is written referring to classes and classmethods, - password hash handlers can be any type of object (instance, module, etc), - so long as they offer attributes and functions with the required - signatures. For example, some of the handlers in Passlib are - instances of the :class:`~passlib.utils.handlers.PrefixWrapper` class. - -.. [#supported] all supported password hashes, whether builtin or registered - from an external source can be found in the :mod:`passlib.hash` module. + :raises passlib.exc.MissingBackendError: + if the specified backend is not available. |