summaryrefslogtreecommitdiff
path: root/docs/password_hash_api.rst
blob: c34999200a9fdcd9f665e3738a2034ac4dc80318 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
.. index::
    single: password hash api
    single: custom hash handler; requirements

.. currentmodule:: passlib.hash

.. _password-hash-api:

=================
Password Hash API
=================

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:

:ref:`required-attributes`

  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.

:ref:`application-methods`

  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.

:ref:`crypt-methods`

  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.

:ref:`optional-attributes`

  These attributes provide additional information
  about the capabilities and limitations of certain password hash schemes.

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::

    >>> # for example, the SHA256-Crypt class:
    >>> from passlib.hash import sha256_crypt as sc

    >>> # using it to encrypt a password:
    >>> h = sc.encrypt("password")
    >>> h
    '$5$rounds=40000$HIo6SCnVL9zqF8TK$y2sUnu13gp4cv0YgLQMW56PfQjWaTyiHjVbXTgleYG9'

    >>> # subsequent calls to sc.encrypt() will generate a new salt:
    >>> sc.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'

    >>> #the identify method can be used to determine the format of an unknown hash:
    >>> sc.identify(h)
    True

    >>> #check if some other hash is recognized (in this case, an MD5-Crypt hash)
    >>> sc.identify('$1$3azHgidD$SrJPt7B.9rekpmwJwtON31')
    False

    >>> #the verify method encapsulates all hash comparison logic for a class:
    >>> sc.verify("password", h)
    True
    >>> sc.verify("wrongpassword", h)
    False

.. _required-attributes:

Required Attributes
=================================
.. attribute:: PasswordHash.name

    A unique name used to identify
    the particular scheme this class implements.

    These names should consist only of lowercase a-z, the digits 0-9, and underscores.

    .. note::

        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.

.. attribute:: PasswordHash.setting_kwds

    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.

    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:

    ``salt``
        If present, this means the algorithm contains some number of bits of salt
        which should vary with every new hash created.

        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.

    ``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.

    ``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.

        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).

    ``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.

    ``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.

.. attribute:: PasswordHash.context_kwds

    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.

    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).

    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.

    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:

    ``user``

        If present, the class requires a username be specified whenever
        performing a hash calculation (eg: postgres_md5 and oracle10).

.. _application-methods:

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.

.. classmethod:: PasswordHash.encrypt(secret, \*\*settings_and_context_kwds)

    encrypt secret, returning resulting hash string.

    :arg secret:
        A string containing the secret to encode.

        Unicode behavior is specified on a per-hash basis,
        but the common case is to encode into utf-8
        before processing.

    :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`.

        Common settings keywords include ``salt`` and ``rounds``.

    :raises ValueError:

        * If a keyword's value is invalid (e.g. if a ``salt`` string
          is too small, or a ``rounds`` value is out of range).

        * 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.

    :raises TypeError:

        * if :samp:`{secret}` is not a unicode or bytes instance.

        * if a required option (such as a context keyword) was not set.

    :returns:
        Hash string, using an algorithm-specific format.

    .. versionchanged:: 1.6

        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.

        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.

.. classmethod:: PasswordHash.identify(hash)

    Quickly identify if a hash string belongs to this algorithm.

    :arg hash: the candidate hash string to check

    :raises TypeError: if :samp:`{hash}` is not a unicode or bytes instance.

    :returns:
        ``True`` if the input appears to be a hash or configuration string
        which belongs to this algorithm, otherwise ``False``.

    .. 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.

.. classmethod:: PasswordHash.verify(secret, hash, \*\*context_kwds)

    verify a secret against an existing hash.

    This checks if a secret matches against the one stored
    inside the specified hash.

    :param secret:
        A string containing the secret to check.
    :param hash:
        A string containing the hash to check against.

    :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`.

    :raises TypeError:

        if either *secret* or *hash* is not a unicode or bytes instance.

    :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*.

    :returns:
        ``True`` if the secret matches, otherwise ``False``.

.. _crypt-methods:

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`.

.. classmethod:: PasswordHash.genconfig(\*\*settings_kwds)

    returns configuration string encoding settings for hash generation

    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).

    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``.

    :param \*\*settings_kwds:

        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`.

        commonly supported keywords include ``salt`` and ``rounds``.

    :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).

    :raises ValueError:
        if any configuration options are invalid (and cannot
        be corrected, if in relaxed parsing mode).

    :returns:
        the configuration string, or ``None`` if the algorithm does not support
        any configuration options.

.. classmethod:: PasswordHash.genhash(secret, config, \*\*context_kwds)

    encrypt secret to hash

    takes in a password, optional configuration string,
    and any required contextual information the algorithm needs,
    and returns the encoded hash strings.

    :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`.

    :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`.

    :raises TypeError:
        * if either *secret* or *config* is not a unicode or bytes instance.
        * if required contextual keywords are not provided

    :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

    :returns:
        encoded hash matching specified secret, config, and context.

.. _optional-attributes:

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).

.. todo::

    Consider making these attributes required for all hashes
    which support the appropriate keyword in :attr:`~PasswordHash.setting_kwds`.

.. _optional-rounds-attributes:

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`)

.. attribute:: PasswordHash.max_rounds

    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.

.. attribute:: PasswordHash.min_rounds

    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)``.

.. attribute:: PasswordHash.default_rounds

    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)``.

.. attribute:: PasswordHash.rounds_cost

    Specifies how the rounds value affects the amount of time taken.
    Currently used values are:

    ``linear``
        time taken scales linearly with rounds value (eg: :class:`~passlib.hash.sha512_crypt`)

    ``log2``
        time taken scales exponentially with rounds value (eg: :class:`~passlib.hash.bcrypt`)

.. _optional-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`)

.. 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.

.. 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)``.

.. 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)``.

.. 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,
    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.

.. 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.

..
    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 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.

    xxx: what about a bits_per_salt_char or some such, so effective salt strength
    can be compared?

.. _hash-unicode-behavior:

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.