mirror of
				https://github.com/django/django.git
				synced 2025-10-31 09:41:08 +00:00 
			
		
		
		
	Refs #23919 -- Removed obsolete compare_digest() and pbkdf2() implementations.
This commit is contained in:
		| @@ -1,11 +1,9 @@ | |||||||
| """ | """ | ||||||
| Django's standard crypto functions and utilities. | Django's standard crypto functions and utilities. | ||||||
| """ | """ | ||||||
| import binascii |  | ||||||
| import hashlib | import hashlib | ||||||
| import hmac | import hmac | ||||||
| import random | import random | ||||||
| import struct |  | ||||||
| import time | import time | ||||||
|  |  | ||||||
| from django.conf import settings | 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)) |     return ''.join(random.choice(allowed_chars) for i in range(length)) | ||||||
|  |  | ||||||
|  |  | ||||||
| if hasattr(hmac, "compare_digest"): | def constant_time_compare(val1, val2): | ||||||
|     # Prefer the stdlib implementation, when available. |     """Return True if the two strings are equal, False otherwise.""" | ||||||
|     def constant_time_compare(val1, val2): |     return hmac.compare_digest(force_bytes(val1), force_bytes(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. |  | ||||||
|  |  | ||||||
|         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): | def pbkdf2(password, salt, iterations, dklen=0, digest=None): | ||||||
|     """ |     """Return the hash of password using pbkdf2.""" | ||||||
|     Convert a binary string into a long integer |     if digest is None: | ||||||
|  |         digest = hashlib.sha256 | ||||||
|     This is a clever optimization for fast xor vector math |     if not dklen: | ||||||
|     """ |         dklen = None | ||||||
|     return int(binascii.hexlify(x), 16) |     password = force_bytes(password) | ||||||
|  |     salt = force_bytes(salt) | ||||||
|  |     return hashlib.pbkdf2_hmac(digest().name, password, salt, iterations, dklen) | ||||||
| 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] |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user