Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Increase default PBKDF2 iterations

Increases the default PBKDF2 iterations, since computers have gotten
faster since 2011. In the future, we plan to increment by 10% per
major version.
  • Loading branch information...
commit a075e2ad0dcce65cb5cf4cb654ac8a6839db0baf 1 parent 59a34c4
Paul McMillan authored September 19, 2013
4  django/contrib/auth/hashers.py
@@ -231,12 +231,12 @@ class PBKDF2PasswordHasher(BasePasswordHasher):
231 231
     """
232 232
     Secure password hashing using the PBKDF2 algorithm (recommended)
233 233
 
234  
-    Configured to use PBKDF2 + HMAC + SHA256 with 10000 iterations.
  234
+    Configured to use PBKDF2 + HMAC + SHA256 with 12000 iterations.
235 235
     The result is a 64 byte binary string.  Iterations may be changed
236 236
     safely but you must rename the algorithm if you change SHA256.
237 237
     """
238 238
     algorithm = "pbkdf2_sha256"
239  
-    iterations = 10000
  239
+    iterations = 12000
240 240
     digest = hashlib.sha256
241 241
 
242 242
     @password_max_length(MAXIMUM_PASSWORD_LENGTH)
10  django/contrib/auth/tests/test_hashers.py
@@ -52,7 +52,7 @@ def test_simple(self):
52 52
     def test_pkbdf2(self):
53 53
         encoded = make_password('lètmein', 'seasalt', 'pbkdf2_sha256')
54 54
         self.assertEqual(encoded,
55  
-            'pbkdf2_sha256$10000$seasalt$CWWFdHOWwPnki7HvkcqN9iA2T3KLW1cf2uZ5kvArtVY=')
  55
+            'pbkdf2_sha256$12000$seasalt$Ybw8zsFxqja97tY/o6G+Fy1ksY4U/Hw3DRrGED6Up4s=')
56 56
         self.assertTrue(is_password_usable(encoded))
57 57
         self.assertTrue(check_password('lètmein', encoded))
58 58
         self.assertFalse(check_password('lètmeinz', encoded))
@@ -284,16 +284,16 @@ def encode(s, password, salt):
284 284
 
285 285
     def test_low_level_pkbdf2(self):
286 286
         hasher = PBKDF2PasswordHasher()
287  
-        encoded = hasher.encode('lètmein', 'seasalt')
  287
+        encoded = hasher.encode('lètmein', 'seasalt2')
288 288
         self.assertEqual(encoded,
289  
-            'pbkdf2_sha256$10000$seasalt$CWWFdHOWwPnki7HvkcqN9iA2T3KLW1cf2uZ5kvArtVY=')
  289
+            'pbkdf2_sha256$12000$seasalt2$hlDLKsxgkgb1aeOppkM5atCYw5rPzAjCNQZ4NYyUROw=')
290 290
         self.assertTrue(hasher.verify('lètmein', encoded))
291 291
 
292 292
     def test_low_level_pbkdf2_sha1(self):
293 293
         hasher = PBKDF2SHA1PasswordHasher()
294  
-        encoded = hasher.encode('lètmein', 'seasalt')
  294
+        encoded = hasher.encode('lètmein', 'seasalt2')
295 295
         self.assertEqual(encoded,
296  
-            'pbkdf2_sha1$10000$seasalt$oAfF6vgs95ncksAhGXOWf4Okq7o=')
  296
+            'pbkdf2_sha1$12000$seasalt2$JeMRVfjjgtWw3/HzlnlfqBnQ6CA=')
297 297
         self.assertTrue(hasher.verify('lètmein', encoded))
298 298
 
299 299
     def test_upgrade(self):
11  django/utils/crypto.py
@@ -139,11 +139,12 @@ def pbkdf2(password, salt, iterations, dklen=0, digest=None):
139 139
 
140 140
     HMAC+SHA256 is used as the default pseudo random function.
141 141
 
142  
-    Right now 10,000 iterations is the recommended default which takes
143  
-    100ms on a 2.2Ghz Core 2 Duo.  This is probably the bare minimum
144  
-    for security given 1000 iterations was recommended in 2001. This
145  
-    code is very well optimized for CPython and is only four times
146  
-    slower than openssl's implementation.
  142
+    As of 2011, 10,000 iterations was the recommended default which
  143
+    took 100ms on a 2.2Ghz Core 2 Duo. This is probably the bare
  144
+    minimum for security given 1000 iterations was recommended in
  145
+    2001. This code is very well optimized for CPython and is only
  146
+    four times slower than openssl's implementation. Look in
  147
+    django.contrib.auth.hashers for the present default.
147 148
     """
148 149
     assert iterations > 0
149 150
     if not digest:
7  docs/internals/howto-release-django.txt
@@ -89,6 +89,13 @@ any time leading up to the actual release:
89 89
    key you'll use for the release, and should include patches for each issue
90 90
    being fixed.
91 91
 
  92
+#. If this is a major release, make sure the tests pass, then increase
  93
+   the default PBKDF2 iterations in
  94
+   ``django.contrib.auth.hashers.PBKDF2PasswordHasher`` by about 10%
  95
+   (pick a round number). Run the tests, and update the 3 failing
  96
+   hasher tests with the new values. Make sure this gets noted in the
  97
+   release notes (see release notes on 1.6 for an example).
  98
+
92 99
 #. As the release approaches, watch Trac to make sure no release blockers
93 100
    are left for the upcoming release.
94 101
 
7  docs/releases/1.6.txt
@@ -365,6 +365,13 @@ Minor features
365 365
   a list (except on SQLite). This has long been possible (but not officially
366 366
   supported) on MySQL and PostgreSQL, and is now also available on Oracle.
367 367
 
  368
+* The default iteration count for the PBKDF2 password hasher has been
  369
+  increased by 20%. This backwards compatible change will not affect
  370
+  existing passwords or users who have subclassed
  371
+  `django.contrib.auth.hashers.PBKDF2PasswordHasher`` to change the
  372
+  default value.
  373
+
  374
+
368 375
 Backwards incompatible changes in 1.6
369 376
 =====================================
370 377
 

0 notes on commit a075e2a

Please sign in to comment.
Something went wrong with that request. Please try again.