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
|
.. index:: Django; hash formats
=============================================================
:samp:`passlib.hash.django_{digest}` - Django-specific Hashes
=============================================================
.. currentmodule:: passlib.hash
The `Django <http://www.djangoproject.com>`_ web framework
provides a module for storing user accounts and passwords
(:mod:`!django.contrib.auth`).
This module's password hashing code supports a few simple salted digests,
stored using the format :samp:`{id}${salt}${checksum}` (where :samp:`{id}`
is an identifier assigned by Django).
Passlib provides support for all the hashes used up to and including
Django 1.10.
..
.. seealso::
* :ref:`passlib.apps.django_context <django-contexts>` -
a set of premade contexts which mimic Django's builtin hashing policy,
and can read all of the formats listed below.
* :mod:`passlib.ext.django` - a plugin that
updates Django to use a stronger hashing scheme,
and migrates existing hashes as users log in.
Django 1.10 Hashes
==================
Argon2
------
Django 1.10 added a wrapper for Argon2:
.. class:: django_argon2
This class implements Django 1.10's Argon2 wrapper, and follows the :ref:`password-hash-api`.
This is identical to :class:`!argon2` itself, but with
the Django-specific prefix ``"argon2"`` prepended.
See :doc:`argon2 </lib/passlib.hash.argon2>` for more details,
the usage and behavior is identical.
This should be compatible with the hashes generated by
Django 1.10's :class:`!Argon2PasswordHasher` class.
.. versionadded:: 1.7
This hash has the exact same structure as :mod:`passlib.hash.argon2`,
except that it has the prefix ``argon2`` added. For example,
the django_argon2 hash...::
argon2$argon2i$v=19$m=256,t=1,p=1$c29tZXNhbHQ$AJFIsNZTMKTAewB4+ETN1A
...corresponds to the argon2 hash::
argon2i$v=19$m=256,t=1,p=1$c29tZXNhbHQ$AJFIsNZTMKTAewB4+ETN1A
Django 1.6 Hashes
=================
Django 1.6 added one new hash:
Bcrypt SHA256
-------------
.. autoclass:: django_bcrypt_sha256
This hash has the exact same structure as :class:`~passlib.hash.bcrypt`,
except that it has the prefix ``bcrypt$`` added. For example,
the django_bcrypt_sha256 hash...::
bcrypt_sha256$$2a$06$/3OeRpbOf8/l6nPPRdZPp.nRiyYqPobEZGdNRBWihQhiFDh1ws1tu
...has the same structure as the bcrypt hash.::
$2a$06$/3OeRpbOf8/l6nPPRdZPp.nRiyYqPobEZGdNRBWihQhiFDh1ws1tu
That said, the hash is calculated slightly differently... the password
is run through sha256(), the result encoded to lowercase hexadecimal,
and then handed to bcrypt proper. This very similar to passlib's
:class:`~passlib.hash.bcrypt_sha256`, and addresses the same set of issues.
.. _django-1.4-hashes:
Django 1.4 Hashes
=================
Django 1.4 introduced a new "hashers" framework, as well as
three new modern large-salt variable-cost hash algorithms:
* :class:`django_pbkdf2_sha256` - a PBKDF2-HMAC-SHA256 based hash.
* :class:`django_pbkdf2_sha1` - a PBKDF2-HMAC-SHA1 based hash.
* :class:`django_bcrypt` - a wrapper around :class:`~passlib.hash.bcrypt`.
These classes can be used directly as follows::
>>> from passlib.hash import django_pbkdf2_sha256 as handler
>>> # hash password
>>> h = handler.hash("password")
>>> h
'pbkdf2_sha256$10000$s1w0UXDd00XB$+4ORmyvVWAQvoAEWlDgN34vlaJx1ZTZpa1pCSRey2Yk='
>>> # verify password
>>> handler.verify("password", h)
True
>>> handler.verify("eville", h)
False
.. seealso:: the generic :ref:`PasswordHash usage examples <password-hash-examples>`
Interface
---------
.. autoclass:: django_pbkdf2_sha256()
.. autoclass:: django_pbkdf2_sha1()
.. data:: django_bcrypt()
This class implements Django 1.4's BCrypt wrapper, and follows the :ref:`password-hash-api`.
This is identical to :class:`!bcrypt` itself, but with
the Django-specific prefix ``"bcrypt$"`` prepended.
See :doc:`/lib/passlib.hash.bcrypt` for more details,
the usage and behavior is identical.
This should be compatible with the hashes generated by
Django 1.4's :class:`!BCryptPasswordHasher` class.
.. versionadded:: 1.6
Format
------
An example :class:`!django_pbkdf2_sha256` hash (of ``password``) is:
``pbkdf2_sha256$10000$s1w0UXDd00XB$+4ORmyvVWAQvoAEWlDgN34vlaJx1ZTZpa1pCSRey2Yk=``
Both of Django's PBKDF2 hashes have the same basic format,
:samp:`{ident}${rounds}${salt}${checksum}`, where:
* :samp:`{ident}` is an identifier (``pbkdf2_sha256`` in the case of the example).
* :samp:`{rounds}` is a variable cost parameter encoded in decimal.
* :samp:`{salt}` consists of (usually 12) alphanumeric digits
(``s1w0UXDd00XB`` in the example).
* :samp:`{checksum}` is the base64 encoding the PBKDF2 digest.
The digest portion is generated by passing the ``utf-8`` encoded password,
the ``ascii``-encoded salt string, and the number of rounds into
PBKDF2 using the HMAC-SHA256 prf; and generated a 32 byte checksum,
which is then encoding using base64.
The other PBKDF2 wrapper functions similarly.
Django 1.0 Hashes
=================
.. warning::
All of the following hashes are very susceptible to brute-force attacks;
since they are simple single-round salted digests.
They should not be used for any purpose
besides manipulating existing Django password hashes.
Django 1.0 supports some basic salted digests, as well as some
legacy hashes:
* :class:`django_salted_sha1` - simple salted SHA1 digest, Django 1.0-1.3's default.
* :class:`django_salted_md5` - simple salted MD5 digest.
* :class:`django_des_crypt` - support for legacy :class:`des_crypt` hashes,
shoehorned into Django's hash format.
These classes can be used directly as follows::
>>> from passlib.hash import django_salted_sha1 as handler
>>> # hash password
>>> h = handler.hash("password")
>>> h
'sha1$c6218$161d1ac8ab38979c5a31cbaba4a67378e7e60845'
>>> # verify password
>>> handler.verify("password", h)
True
>>> handler.verify("eville", h)
False
.. seealso:: the generic :ref:`PasswordHash usage examples <password-hash-examples>`
Interface
---------
.. autoclass:: django_salted_md5()
.. autoclass:: django_salted_sha1()
Format
------
An example :class:`!django_salted_sha1` hash (of ``password``) is:
``sha1$f8793$c4cd18eb02375a037885706d414d68d521ca18c7``
Both of Django's salted hashes have the same basic format,
:samp:`{ident}${salt}${checksum}`, where:
* :samp:`{ident}` is an identifier (``sha1`` in the case of the example,
``md5`` for :class:`!django_salted_md5`).
* :samp:`{salt}` consists of (usually 5) lowercase hexadecimal digits (``f8793`` in the example).
* :samp:`{checksum}` is lowercase hexadecimal encoding of the checksum.
The checksum is generated by concatenating the salt digits followed
by the password, and hashing them using the specified digest (MD5 or SHA-1).
The digest is then encoded to hexadecimal.
If the password is unicode, it is converted to ``utf-8`` first.
Security Issues
---------------
Django's salted hashes should not be considered very secure.
* They use only a single round of digests with known collision
and pre-image attacks (SHA1 & MD5).
* While it could be increased, they currently use only 20 bits
of entropy in their salt, which is borderline insufficient to defeat
rainbow tables.
* They digest the encoded hexadecimal salt, not the raw bytes,
increasing the odds that a particular salt+password string
will be present in a pre-computed tables of ascii digests.
Des Crypt Wrapper
=================
.. autoclass:: django_des_crypt()
Format
------
An example :class:`!django_des_crypt` hash (of ``password``) is
``crypt$cd1a4$cdlRbNJGImptk``; the general format is the same
as the salted hashes: :samp:`{ident}${salt}${checksum}`, where:
* :samp:`{ident}` is the identifier ``crypt``.
* :samp:`{salt}` is 5 lowercase hexadecimal digits (``cd1a4`` in the example).
* :samp:`{checksum}` is a :class:`!des_crypt` hash (``cdlRbNJGImptk`` in the example).
It should be noted that this class essentially just shoe-horns
:class:`des_crypt` into a format compatible with the Django salted hashes (above).
It has a few quirks, such as the fact that only the first two characters
of the salt are used by :class:`!des_crypt`, and they are in turn
duplicated as the first two characters of the checksum.
For security issues relating to :class:`!django_des_crypt`,
see :class:`des_crypt`.
Other Hashes
============
.. autoclass:: django_disabled()
.. note::
Some older (pre-1.0) versions of Django encoded
passwords using :class:`~passlib.hash.hex_md5`,
though this has been deprecated by Django,
and should become increasingly rare.
|