summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul McMillan <paul.mcmillan@nebula.com>2013-09-19 17:39:43 +0100
committerPaul McMillan <paul.mcmillan@nebula.com>2013-09-19 18:02:25 +0100
commita075e2ad0dcce65cb5cf4cb654ac8a6839db0baf (patch)
tree5116a0aade0ddaa229de4b99e84a49f73202b37c
parent59a34c43a8c3d62eaa400d48a9c26ed5400fc647 (diff)
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.
-rw-r--r--django/contrib/auth/hashers.py4
-rw-r--r--django/contrib/auth/tests/test_hashers.py10
-rw-r--r--django/utils/crypto.py11
-rw-r--r--docs/internals/howto-release-django.txt7
-rw-r--r--docs/releases/1.6.txt7
5 files changed, 27 insertions, 12 deletions
diff --git a/django/contrib/auth/hashers.py b/django/contrib/auth/hashers.py
index fdf3b1b3b4..5c41b0240c 100644
--- a/django/contrib/auth/hashers.py
+++ b/django/contrib/auth/hashers.py
@@ -231,12 +231,12 @@ class PBKDF2PasswordHasher(BasePasswordHasher):
"""
Secure password hashing using the PBKDF2 algorithm (recommended)
- Configured to use PBKDF2 + HMAC + SHA256 with 10000 iterations.
+ Configured to use PBKDF2 + HMAC + SHA256 with 12000 iterations.
The result is a 64 byte binary string. Iterations may be changed
safely but you must rename the algorithm if you change SHA256.
"""
algorithm = "pbkdf2_sha256"
- iterations = 10000
+ iterations = 12000
digest = hashlib.sha256
@password_max_length(MAXIMUM_PASSWORD_LENGTH)
diff --git a/django/contrib/auth/tests/test_hashers.py b/django/contrib/auth/tests/test_hashers.py
index 51cb0b277b..324559de45 100644
--- a/django/contrib/auth/tests/test_hashers.py
+++ b/django/contrib/auth/tests/test_hashers.py
@@ -52,7 +52,7 @@ class TestUtilsHashPass(unittest.TestCase):
def test_pkbdf2(self):
encoded = make_password('lètmein', 'seasalt', 'pbkdf2_sha256')
self.assertEqual(encoded,
- 'pbkdf2_sha256$10000$seasalt$CWWFdHOWwPnki7HvkcqN9iA2T3KLW1cf2uZ5kvArtVY=')
+ 'pbkdf2_sha256$12000$seasalt$Ybw8zsFxqja97tY/o6G+Fy1ksY4U/Hw3DRrGED6Up4s=')
self.assertTrue(is_password_usable(encoded))
self.assertTrue(check_password('lètmein', encoded))
self.assertFalse(check_password('lètmeinz', encoded))
@@ -284,16 +284,16 @@ class TestUtilsHashPass(unittest.TestCase):
def test_low_level_pkbdf2(self):
hasher = PBKDF2PasswordHasher()
- encoded = hasher.encode('lètmein', 'seasalt')
+ encoded = hasher.encode('lètmein', 'seasalt2')
self.assertEqual(encoded,
- 'pbkdf2_sha256$10000$seasalt$CWWFdHOWwPnki7HvkcqN9iA2T3KLW1cf2uZ5kvArtVY=')
+ 'pbkdf2_sha256$12000$seasalt2$hlDLKsxgkgb1aeOppkM5atCYw5rPzAjCNQZ4NYyUROw=')
self.assertTrue(hasher.verify('lètmein', encoded))
def test_low_level_pbkdf2_sha1(self):
hasher = PBKDF2SHA1PasswordHasher()
- encoded = hasher.encode('lètmein', 'seasalt')
+ encoded = hasher.encode('lètmein', 'seasalt2')
self.assertEqual(encoded,
- 'pbkdf2_sha1$10000$seasalt$oAfF6vgs95ncksAhGXOWf4Okq7o=')
+ 'pbkdf2_sha1$12000$seasalt2$JeMRVfjjgtWw3/HzlnlfqBnQ6CA=')
self.assertTrue(hasher.verify('lètmein', encoded))
def test_upgrade(self):
diff --git a/django/utils/crypto.py b/django/utils/crypto.py
index 3c15b8b35b..3331424cb7 100644
--- a/django/utils/crypto.py
+++ b/django/utils/crypto.py
@@ -139,11 +139,12 @@ def pbkdf2(password, salt, iterations, dklen=0, digest=None):
HMAC+SHA256 is used as the default pseudo random function.
- Right now 10,000 iterations is the recommended default which takes
- 100ms on a 2.2Ghz Core 2 Duo. This is probably the bare minimum
- for security given 1000 iterations was recommended in 2001. This
- code is very well optimized for CPython and is only four times
- slower than openssl's implementation.
+ As of 2011, 10,000 iterations was the recommended default which
+ took 100ms on a 2.2Ghz Core 2 Duo. This is probably the bare
+ minimum for security given 1000 iterations was recommended in
+ 2001. This code is very well optimized for CPython and is only
+ four times slower than openssl's implementation. Look in
+ django.contrib.auth.hashers for the present default.
"""
assert iterations > 0
if not digest:
diff --git a/docs/internals/howto-release-django.txt b/docs/internals/howto-release-django.txt
index a926de27ab..03b543bd5e 100644
--- a/docs/internals/howto-release-django.txt
+++ b/docs/internals/howto-release-django.txt
@@ -89,6 +89,13 @@ any time leading up to the actual release:
key you'll use for the release, and should include patches for each issue
being fixed.
+#. If this is a major release, make sure the tests pass, then increase
+ the default PBKDF2 iterations in
+ ``django.contrib.auth.hashers.PBKDF2PasswordHasher`` by about 10%
+ (pick a round number). Run the tests, and update the 3 failing
+ hasher tests with the new values. Make sure this gets noted in the
+ release notes (see release notes on 1.6 for an example).
+
#. As the release approaches, watch Trac to make sure no release blockers
are left for the upcoming release.
diff --git a/docs/releases/1.6.txt b/docs/releases/1.6.txt
index b665d8cec5..7cded8c544 100644
--- a/docs/releases/1.6.txt
+++ b/docs/releases/1.6.txt
@@ -365,6 +365,13 @@ Minor features
a list (except on SQLite). This has long been possible (but not officially
supported) on MySQL and PostgreSQL, and is now also available on Oracle.
+* The default iteration count for the PBKDF2 password hasher has been
+ increased by 20%. This backwards compatible change will not affect
+ existing passwords or users who have subclassed
+ `django.contrib.auth.hashers.PBKDF2PasswordHasher`` to change the
+ default value.
+
+
Backwards incompatible changes in 1.6
=====================================