secret_generator.py 2.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. import hashlib
  2. import os
  3. from .secret_properties import secret_properties
  4. class secret_generator(metaclass = secret_properties):
  5. def __init__(self, password: str):
  6. self.__password = password
  7. self.__secret = None
  8. @property
  9. def password(self) -> str:
  10. return self.__password
  11. def validate(self, secret: str) -> bool:
  12. if not self.__check_secret(secret):
  13. return False
  14. hashed, salt = self.__split_secret(secret)
  15. target_hashed, second_salt = self.__generate_hashed(salt)
  16. return hashed == target_hashed
  17. def __check_secret(self, secret: str) -> bool:
  18. properties = self.__class__
  19. hash_length = properties.hash_hex_length
  20. salt_length = properties.salt_hex_length
  21. separator = properties.salt_separator
  22. if secret.find(separator) != hash_length:
  23. return False
  24. if len(secret) != hash_length + salt_length + len(separator):
  25. return False
  26. return True
  27. def __split_secret(self, secret: str) -> [bytes, bytes]:
  28. properties = self.__class__
  29. separator = properties.salt_separator
  30. splited = secret.split(separator)
  31. hashed = bytes.fromhex(splited[0])
  32. salt = bytes.fromhex(splited[-1])
  33. return hashed, salt
  34. def __generate_hashed(self, salt: bytes | None = None) -> str:
  35. properties = self.__class__
  36. rounds = properties.hash_rounds
  37. algorithm = properties.hash_algorithm
  38. password = self.password.encode("UTF-8")
  39. if salt is None:
  40. random_size = properties.salt_length
  41. salt = os.urandom(random_size)
  42. hashed = hashlib.pbkdf2_hmac(
  43. algorithm,
  44. password,
  45. salt,
  46. rounds
  47. )
  48. return hashed, salt
  49. @property
  50. def secret(self) -> str:
  51. if self.__secret is not None:
  52. return self.__secret
  53. hashed, salt = self.__generate_hashed()
  54. self.__secret = self.__create_secret(hashed, salt)
  55. return self.secret
  56. def __create_secret(self, hashed: bytes, salt: bytes) -> str:
  57. properties = self.__class__
  58. separator = properties.salt_separator
  59. result = hashed.hex() + separator + salt.hex()
  60. if not self.__check_secret(result):
  61. raise Exception("Can not create secret. Check secret settings!")
  62. return result