Code

Ticket #5787: django-bcrypt.diff

File django-bcrypt.diff, 6.7 KB (added by ekarulf, 7 years ago)

First revision of django-bcrypt patch

Line 
1Index: django/conf/global_settings.py
2===================================================================
3--- django/conf/global_settings.py      (revision 6573)
4+++ django/conf/global_settings.py      (working copy)
5@@ -333,6 +333,15 @@
6 
7 LOGIN_REDIRECT_URL = '/accounts/profile/'
8 
9+# The preferred hash algorithm for storing passwords
10+# Acceptable values are 'crypt', 'md5', 'sha1', and 'bcrypt'
11+# NOTE : 'crypt' and 'md5' are provided only for legacy integration
12+PREFERRED_HASH = 'sha1'
13+
14+# The number of rounds determines the complexity of the bcrypt alg.
15+# The work factor is 2**log_rounds, and the default is 12
16+BCRYPT_LOG_ROUNDS = 12
17+
18 ###########
19 # TESTING #
20 ###########
21Index: django/contrib/auth/models.py
22===================================================================
23--- django/contrib/auth/models.py       (revision 6573)
24+++ django/contrib/auth/models.py       (working copy)
25@@ -46,13 +46,49 @@
26             return hashlib.sha1(salt + raw_password).hexdigest()
27     raise ValueError("Got unknown password algorithm type in password.")
28 
29+def hash_password(raw_password, enc_password):
30+    """
31+    Returns a formatted hash of the user's password.
32+    """
33+    if enc_password in ('crypt', 'md5', 'sha1', 'bcrypt'):
34+        validating = False
35+        algo = enc_password
36+        algo_args = ''
37+        hsh = ''
38+    else:
39+        validating = True
40+        if enc_password[0] == '$':
41+            algo, algo_args, hsh = enc_password[1:].split('$')
42+        else:
43+            algo, algo_args, hsh = enc_password.split('$')
44+    if algo == 'bcrypt' or algo == '2' or algo == '2a':
45+        try:
46+            import bcrypt
47+            if validating:
48+                # If we are validating, use the hash in the provided password
49+                salt = enc_password
50+            else:
51+                # If we are generating a new hash, we need to generate a salt
52+                from django.conf import settings
53+                salt = bcrypt.gensalt(settings.BCRYPT_LOG_ROUNDS)
54+            return bcrypt.hashpw(raw_password, salt)
55+        except ImportError:
56+            raise ValueError('"bcrypt" password algorithm not supported in this environment')
57+    else:
58+        if validating:
59+            salt = algo_args
60+        else:
61+            import random
62+            salt = get_hexdigest(algo, str(random.random()), str(random.random()))[:5]
63+        hsh = get_hexdigest(algo, salt, raw_password)
64+        return '%s$%s$%s' % (algo, salt, hsh)
65+
66 def check_password(raw_password, enc_password):
67     """
68     Returns a boolean of whether the raw_password was correct. Handles
69     encryption formats behind the scenes.
70     """
71-    algo, salt, hsh = enc_password.split('$')
72-    return hsh == get_hexdigest(algo, salt, raw_password)
73+    return enc_password == hash_password(raw_password, enc_password)
74 
75 class SiteProfileNotAvailable(Exception):
76     pass
77@@ -181,11 +217,13 @@
78         return full_name.strip()
79 
80     def set_password(self, raw_password):
81-        import random
82-        algo = 'sha1'
83-        salt = get_hexdigest(algo, str(random.random()), str(random.random()))[:5]
84-        hsh = get_hexdigest(algo, salt, raw_password)
85-        self.password = '%s$%s$%s' % (algo, salt, hsh)
86+        """
87+        Sets the users's password hash to a hash of raw_password. Handles
88+        encryption formats behind the scenes.
89+        """
90+        from django.conf import settings
91+        algo = settings.PREFERRED_HASH
92+        self.password = hash_password(raw_password, algo)
93 
94     def check_password(self, raw_password):
95         """
96Index: docs/settings.txt
97===================================================================
98--- docs/settings.txt   (revision 6573)
99+++ docs/settings.txt   (working copy)
100@@ -225,6 +225,16 @@
101 ``CommonMiddleware`` is installed (see the `middleware docs`_). See also
102 ``PREPEND_WWW``.
103 
104+BCRYPT_LOG_ROUNDS
105+-------------
106+
107+**New in Django development version**
108+
109+Default: ``12``
110+
111+The number of rounds determines the complexity of the ``bcrypt`` password
112+hashing algorithm. The work factor is 2**BCRYPT_LOG_ROUNDS.
113+
114 CACHE_BACKEND
115 -------------
116 
117@@ -678,6 +688,27 @@
118 See `allowed date format strings`_. See also ``DATE_FORMAT``,
119 ``DATETIME_FORMAT``, ``TIME_FORMAT`` and ``YEAR_MONTH_FORMAT``.
120 
121+PREFERRED_HASH
122+----------
123+
124+**New in Django development version**
125+
126+Default: ``'sha1'``
127+
128+The default hash to use when saving new passwords. The hashtype is either
129+``sha1`` (default), ``md5``, ``crypt`` or ``bcrypt`` -- the algorithm used to
130+perform a one-way hash of the password.
131+
132+Note that the ``crypt`` method is only supported on platforms that have the
133+standard Python ``crypt`` module available, and ``crypt`` support is only
134+available in the Django development version. Likewise the ``bcrypt`` algorithm
135+is supported only on platforms that have the standard Python ``bcrypt`` module
136+available, and like ``crypt`` it is only supported in the development version.
137+
138+**Important Note** : ``md5`` and ``crypt`` are both deprecated algorithms that
139+are maintained for legacy integration. New applications are recommended to use
140+stronger algorithms like ``sha1`` (default) or ``bcrypt``.
141+
142 PREPEND_WWW
143 -----------
144 
145Index: docs/authentication.txt
146===================================================================
147--- docs/authentication.txt     (revision 6573)
148+++ docs/authentication.txt     (working copy)
149@@ -218,13 +218,20 @@
150 
151 That's hashtype, salt and hash, separated by the dollar-sign character.
152 
153-Hashtype is either ``sha1`` (default), ``md5`` or ``crypt`` -- the algorithm
154-used to perform a one-way hash of the password. Salt is a random string used
155-to salt the raw password to create the hash. Note that the ``crypt`` method is
156-only supported on platforms that have the standard Python ``crypt`` module
157-available, and ``crypt`` support is only available in the Django development
158-version.
159+Hashtype is either ``sha1`` (default), ``md5``, ``crypt`` or ``bcrypt`` -- the
160+algorithm used to perform a one-way hash of the password. Salt is a random
161+string used to salt the raw password to create the hash. Note that the ``crypt``
162+method is only supported on platforms that have the standard Python ``crypt``
163+module available, and ``crypt`` support is only available in the Django
164+development version. Likewise the ``bcrypt`` algorithm is supported only on
165+platforms that have the standard Python ``bcrypt`` module available, and like
166+``crypt`` it is only supported in the development version.
167 
168+You may change the default hash algorithm by changing the PREFERRED_HASH
169+setting. Please note that ``md5`` and ``crypt`` are both deprecated algorithms
170+that are maintained for legacy integration. New applications are recommended to
171+use stronger algorithms like ``sha1`` (default) or ``bcrypt``.
172+
173 For example::
174 
175     sha1$a1976$a36cc8cbf81742a8fb52e221aaeab48ed7f58ab4