Permalink
Browse files

Refs #23919 -- Removed obsolete compare_digest() and pbkdf2() impleme…

…ntations.
  • Loading branch information...
timgraham committed Jan 19, 2017
1 parent 9695b14 commit d4bb37593ed1cc0831404b6c5e8581e628d00f3b
Showing with 12 additions and 112 deletions.
  1. +12 −112 django/utils/crypto.py
View
@@ -1,11 +1,9 @@
"""
Django's standard crypto functions and utilities.
"""
-import binascii
import hashlib
import hmac
import random
-import struct
import time
from django.conf import settings
@@ -73,115 +71,17 @@ def get_random_string(length=12,
return ''.join(random.choice(allowed_chars) for i in range(length))
-if hasattr(hmac, "compare_digest"):
- # Prefer the stdlib implementation, when available.
- def constant_time_compare(val1, val2):
- return hmac.compare_digest(force_bytes(val1), force_bytes(val2))
-else:
- def constant_time_compare(val1, val2):
- """
- Returns True if the two strings are equal, False otherwise.
+def constant_time_compare(val1, val2):
+ """Return True if the two strings are equal, False otherwise."""
+ return hmac.compare_digest(force_bytes(val1), force_bytes(val2))
- The time taken is independent of the number of characters that match.
- For the sake of simplicity, this function executes in constant time only
- when the two strings have the same length. It short-circuits when they
- have different lengths. Since Django only uses it to compare hashes of
- known expected length, this is acceptable.
- """
- if len(val1) != len(val2):
- return False
- result = 0
- if isinstance(val1, bytes) and isinstance(val2, bytes):
- for x, y in zip(val1, val2):
- result |= x ^ y
- else:
- for x, y in zip(val1, val2):
- result |= ord(x) ^ ord(y)
- return result == 0
-
-
-def _bin_to_long(x):
- """
- Convert a binary string into a long integer
-
- This is a clever optimization for fast xor vector math
- """
- return int(binascii.hexlify(x), 16)
-
-
-def _long_to_bin(x, hex_format_string):
- """
- Convert a long integer into a binary string.
- hex_format_string is like "%020x" for padding 10 characters.
- """
- return binascii.unhexlify((hex_format_string % x).encode('ascii'))
-
-
-if hasattr(hashlib, "pbkdf2_hmac"):
- def pbkdf2(password, salt, iterations, dklen=0, digest=None):
- """
- Implements PBKDF2 with the same API as Django's existing
- implementation, using the stdlib.
-
- This is used in Python 2.7.8+ and 3.4+.
- """
- if digest is None:
- digest = hashlib.sha256
- if not dklen:
- dklen = None
- password = force_bytes(password)
- salt = force_bytes(salt)
- return hashlib.pbkdf2_hmac(
- digest().name, password, salt, iterations, dklen)
-else:
- def pbkdf2(password, salt, iterations, dklen=0, digest=None):
- """
- Implements PBKDF2 as defined in RFC 2898, section 5.2
-
- HMAC+SHA256 is used as the default pseudo random function.
-
- As of 2014, 100,000 iterations was the recommended default which took
- 100ms on a 2.7Ghz Intel i7 with an optimized implementation. 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 about five times slower than OpenSSL's implementation. Look in
- django.contrib.auth.hashers for the present default, it is lower than
- the recommended 100,000 because of the performance difference between
- this and an optimized implementation.
- """
- assert iterations > 0
- if not digest:
- digest = hashlib.sha256
- password = force_bytes(password)
- salt = force_bytes(salt)
- hlen = digest().digest_size
- if not dklen:
- dklen = hlen
- if dklen > (2 ** 32 - 1) * hlen:
- raise OverflowError('dklen too big')
- L = -(-dklen // hlen)
- r = dklen - (L - 1) * hlen
-
- hex_format_string = "%%0%ix" % (hlen * 2)
-
- inner, outer = digest(), digest()
- if len(password) > inner.block_size:
- password = digest(password).digest()
- password += b'\x00' * (inner.block_size - len(password))
- inner.update(password.translate(hmac.trans_36))
- outer.update(password.translate(hmac.trans_5C))
-
- def F(i):
- u = salt + struct.pack(b'>I', i)
- result = 0
- for j in range(int(iterations)):
- dig1, dig2 = inner.copy(), outer.copy()
- dig1.update(u)
- dig2.update(dig1.digest())
- u = dig2.digest()
- result ^= _bin_to_long(u)
- return _long_to_bin(result, hex_format_string)
-
- T = [F(x) for x in range(1, L)]
- return b''.join(T) + F(L)[:r]
+def pbkdf2(password, salt, iterations, dklen=0, digest=None):
+ """Return the hash of password using pbkdf2."""
+ if digest is None:
+ digest = hashlib.sha256
+ if not dklen:
+ dklen = None
+ password = force_bytes(password)
+ salt = force_bytes(salt)
+ return hashlib.pbkdf2_hmac(digest().name, password, salt, iterations, dklen)

0 comments on commit d4bb375

Please sign in to comment.