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
|
.. 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 by Django:
* :class:`django_salted_sha1` - simple salted SHA1 digest, currently Django'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.
* :class:`hex_md5` - historical format used by old Django versions.
.. warning::
All of these hashes are suceptible to brute-force attacks;
even the strongest of these (:class:`django_salted_sha1`)
is a simple single-round salted digest.
They should not be used for any purpose
besides manipulating existing Django password hashes.
.. seealso::
* :data:`passlib.apps.django_context` - a premade Django context
which 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.
Salted Hashes
=============
Usage
-----
These classes can be used directly as follows::
>>> from passlib.hash import django_salted_sha1 as dss
>>> #encrypt password
>>> h = dss.encrypt("password")
>>> h
'sha1$c6218$161d1ac8ab38979c5a31cbaba4a67378e7e60845'
>>> lms.identify(h) #check if hash is recognized
True
>>> lms.identify('JQMuyS6H.AGMo') #check if some other hash is recognized
False
>>> lms.verify("password", h) #verify correct password
True
>>> lms.verify("secret", h) #verify incorrect password
False
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 hexidecimal digits (``f8793`` in the example).
* :samp:`{checksum}` is lowercase hexidecimal 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 hexidecimal.
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 hexidecimal 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
=========
.. 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 hexidecimal 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::
Older versions of Django may also have
passwords encoded using :class:`~passlib.hash.hex_md5`,
though this has been deprecated by Django.
|