Funktionierender Prototyp des Serious Games zur Vermittlung von Wissen zu Software-Engineering-Arbeitsmodellen.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

crypto.py 3.2KB

1 year ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. """
  2. Django's standard crypto functions and utilities.
  3. """
  4. import hashlib
  5. import hmac
  6. import secrets
  7. from django.conf import settings
  8. from django.utils.encoding import force_bytes
  9. from django.utils.inspect import func_supports_parameter
  10. class InvalidAlgorithm(ValueError):
  11. """Algorithm is not supported by hashlib."""
  12. pass
  13. def salted_hmac(key_salt, value, secret=None, *, algorithm="sha1"):
  14. """
  15. Return the HMAC of 'value', using a key generated from key_salt and a
  16. secret (which defaults to settings.SECRET_KEY). Default algorithm is SHA1,
  17. but any algorithm name supported by hashlib can be passed.
  18. A different key_salt should be passed in for every application of HMAC.
  19. """
  20. if secret is None:
  21. secret = settings.SECRET_KEY
  22. key_salt = force_bytes(key_salt)
  23. secret = force_bytes(secret)
  24. try:
  25. hasher = getattr(hashlib, algorithm)
  26. except AttributeError as e:
  27. raise InvalidAlgorithm(
  28. "%r is not an algorithm accepted by the hashlib module." % algorithm
  29. ) from e
  30. # We need to generate a derived key from our base key. We can do this by
  31. # passing the key_salt and our base key through a pseudo-random function.
  32. key = hasher(key_salt + secret).digest()
  33. # If len(key_salt + secret) > block size of the hash algorithm, the above
  34. # line is redundant and could be replaced by key = key_salt + secret, since
  35. # the hmac module does the same thing for keys longer than the block size.
  36. # However, we need to ensure that we *always* do this.
  37. return hmac.new(key, msg=force_bytes(value), digestmod=hasher)
  38. RANDOM_STRING_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
  39. def get_random_string(length, allowed_chars=RANDOM_STRING_CHARS):
  40. """
  41. Return a securely generated random string.
  42. The bit length of the returned value can be calculated with the formula:
  43. log_2(len(allowed_chars)^length)
  44. For example, with default `allowed_chars` (26+26+10), this gives:
  45. * length: 12, bit length =~ 71 bits
  46. * length: 22, bit length =~ 131 bits
  47. """
  48. return "".join(secrets.choice(allowed_chars) for i in range(length))
  49. def constant_time_compare(val1, val2):
  50. """Return True if the two strings are equal, False otherwise."""
  51. return secrets.compare_digest(force_bytes(val1), force_bytes(val2))
  52. def pbkdf2(password, salt, iterations, dklen=0, digest=None):
  53. """Return the hash of password using pbkdf2."""
  54. if digest is None:
  55. digest = hashlib.sha256
  56. dklen = dklen or None
  57. password = force_bytes(password)
  58. salt = force_bytes(salt)
  59. return hashlib.pbkdf2_hmac(digest().name, password, salt, iterations, dklen)
  60. # TODO: Remove when dropping support for PY38. inspect.signature() is used to
  61. # detect whether the usedforsecurity argument is available as this fix may also
  62. # have been applied by downstream package maintainers to other versions in
  63. # their repositories.
  64. if func_supports_parameter(hashlib.md5, "usedforsecurity"):
  65. md5 = hashlib.md5
  66. new_hash = hashlib.new
  67. else:
  68. def md5(data=b"", *, usedforsecurity=True):
  69. return hashlib.md5(data)
  70. def new_hash(hash_algorithm, *, usedforsecurity=True):
  71. return hashlib.new(hash_algorithm)