Coverage for /var/srv/projects/api.amasfac.comuna18.com/tmp/venv/lib/python3.9/site-packages/django/utils/crypto.py: 84%

30 statements  

« prev     ^ index     » next       coverage.py v6.4.4, created at 2023-07-17 14:22 -0600

1""" 

2Django's standard crypto functions and utilities. 

3""" 

4import hashlib 

5import hmac 

6import secrets 

7 

8from django.conf import settings 

9from django.utils.encoding import force_bytes 

10 

11 

12class InvalidAlgorithm(ValueError): 

13 """Algorithm is not supported by hashlib.""" 

14 

15 pass 

16 

17 

18def salted_hmac(key_salt, value, secret=None, *, algorithm="sha1"): 

19 """ 

20 Return the HMAC of 'value', using a key generated from key_salt and a 

21 secret (which defaults to settings.SECRET_KEY). Default algorithm is SHA1, 

22 but any algorithm name supported by hashlib can be passed. 

23 

24 A different key_salt should be passed in for every application of HMAC. 

25 """ 

26 if secret is None: 26 ↛ 27line 26 didn't jump to line 27, because the condition on line 26 was never true

27 secret = settings.SECRET_KEY 

28 

29 key_salt = force_bytes(key_salt) 

30 secret = force_bytes(secret) 

31 try: 

32 hasher = getattr(hashlib, algorithm) 

33 except AttributeError as e: 

34 raise InvalidAlgorithm( 

35 "%r is not an algorithm accepted by the hashlib module." % algorithm 

36 ) from e 

37 # We need to generate a derived key from our base key. We can do this by 

38 # passing the key_salt and our base key through a pseudo-random function. 

39 key = hasher(key_salt + secret).digest() 

40 # If len(key_salt + secret) > block size of the hash algorithm, the above 

41 # line is redundant and could be replaced by key = key_salt + secret, since 

42 # the hmac module does the same thing for keys longer than the block size. 

43 # However, we need to ensure that we *always* do this. 

44 return hmac.new(key, msg=force_bytes(value), digestmod=hasher) 

45 

46 

47RANDOM_STRING_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" 

48 

49 

50def get_random_string(length, allowed_chars=RANDOM_STRING_CHARS): 

51 """ 

52 Return a securely generated random string. 

53 

54 The bit length of the returned value can be calculated with the formula: 

55 log_2(len(allowed_chars)^length) 

56 

57 For example, with default `allowed_chars` (26+26+10), this gives: 

58 * length: 12, bit length =~ 71 bits 

59 * length: 22, bit length =~ 131 bits 

60 """ 

61 return "".join(secrets.choice(allowed_chars) for i in range(length)) 

62 

63 

64def constant_time_compare(val1, val2): 

65 """Return True if the two strings are equal, False otherwise.""" 

66 return secrets.compare_digest(force_bytes(val1), force_bytes(val2)) 

67 

68 

69def pbkdf2(password, salt, iterations, dklen=0, digest=None): 

70 """Return the hash of password using pbkdf2.""" 

71 if digest is None: 71 ↛ 72line 71 didn't jump to line 72, because the condition on line 71 was never true

72 digest = hashlib.sha256 

73 dklen = dklen or None 

74 password = force_bytes(password) 

75 salt = force_bytes(salt) 

76 return hashlib.pbkdf2_hmac(digest().name, password, salt, iterations, dklen)