security.py 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. # ---------------------------
  2. #Fichier : security.py
  3. #Date : 14.10.2020
  4. #But :
  5. #Remarque :
  6. #------------------------------
  7. import random, string, base64, hmac, re
  8. SCRYPT_N = 65536
  9. SCRYPT_SALT_LEN = 16
  10. API_ID_LEN = 24
  11. def implode(pw_hash, salt):
  12. """
  13. Implodes the given hash and its arguments into a string
  14. :param pw_hash: password hash
  15. :param salt: hash salt
  16. :returns: hash string with arguments in order (salt,hash)
  17. """
  18. return '$' + salt + '$' + pw_hash
  19. def explode(hashstr):
  20. """
  21. Explodes a hash string whose values are separated by '$' into an array
  22. :param hashstr: hash string to explode
  23. :returns: elements of the given hash string as an array
  24. """
  25. return hashstr.split('$')
  26. def pw_complexity(password):
  27. """
  28. Checks the password complexity before using it
  29. :param password: password to verify complexity
  30. :returns: true if the password is complex enoughs, false otherwise
  31. """
  32. # Dans le cas d'un mot de passe inférieur à 8 caractères
  33. if (len(password) < 8):
  34. return False
  35. # Dans le cas d'un mot de passe sans chiffre
  36. if (re.search(r"\d", password) is None):
  37. return False
  38. # Dans le cas d'un mot de passe sans majuscule
  39. if (re.search(r"[A-Z]", password) is None):
  40. return False
  41. # Dans le cas d'un mot de passe sans minuscule
  42. if (re.search(r"[a-z]", password) is None):
  43. return False
  44. return True
  45. def hash_pw(password):
  46. """
  47. Hashes the given password using scrypt and a random salt
  48. :param password: password to hash
  49. :returns: hashed password with arguments
  50. """
  51. salt = gen_rand_string()
  52. pw_hash = base64.b64encode(
  53. hmac.new(
  54. key=salt.encode('utf8'),
  55. msg=password.encode('utf8'),
  56. digestmod='SHA256'
  57. ).digest()
  58. ).decode('utf8')
  59. return implode(pw_hash, salt)
  60. def check_pw(password, pw_hash):
  61. """
  62. Checks whether the specified password and parameters match the given hash
  63. :param password: password to check
  64. :param pw_hash: hash string to compare with
  65. :returns: True if the password is correct, else False
  66. """
  67. hashvars = explode(pw_hash)
  68. mac = base64.b64decode(pw_hash)
  69. return hmac.compare_digest(hashvars[2].encode('utf8'), base64.b64encode(hmac.new(
  70. key=hashvars[1].encode('utf8'),
  71. msg=password.encode('utf8'),
  72. digestmod='SHA256'
  73. ).digest()))
  74. def gen_rand_string(prefix=None):
  75. """
  76. Generates a random string of 24 characters (alphanumeric case-sensitive)
  77. :param prefix: prefix to append to the random string
  78. :returns: random string of 24 alphanumeric characters (case-sensitive)
  79. """
  80. return (prefix + '_' if prefix != None else '') + ''.join(
  81. random.SystemRandom().choice(
  82. string.ascii_letters + string.digits
  83. ) for _ in range(API_ID_LEN)
  84. )