pbkdf2.py 2.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667
  1. # This file is dual licensed under the terms of the Apache License, Version
  2. # 2.0, and the BSD License. See the LICENSE file in the root of this repository
  3. # for complete details.
  4. from cryptography import utils
  5. from cryptography.exceptions import (
  6. AlreadyFinalized,
  7. InvalidKey,
  8. UnsupportedAlgorithm,
  9. _Reasons,
  10. )
  11. from cryptography.hazmat.backends import _get_backend
  12. from cryptography.hazmat.backends.interfaces import PBKDF2HMACBackend
  13. from cryptography.hazmat.primitives import constant_time, hashes
  14. from cryptography.hazmat.primitives.kdf import KeyDerivationFunction
  15. class PBKDF2HMAC(KeyDerivationFunction):
  16. def __init__(
  17. self,
  18. algorithm: hashes.HashAlgorithm,
  19. length: int,
  20. salt: bytes,
  21. iterations: int,
  22. backend=None,
  23. ):
  24. backend = _get_backend(backend)
  25. if not isinstance(backend, PBKDF2HMACBackend):
  26. raise UnsupportedAlgorithm(
  27. "Backend object does not implement PBKDF2HMACBackend.",
  28. _Reasons.BACKEND_MISSING_INTERFACE,
  29. )
  30. if not backend.pbkdf2_hmac_supported(algorithm):
  31. raise UnsupportedAlgorithm(
  32. "{} is not supported for PBKDF2 by this backend.".format(
  33. algorithm.name
  34. ),
  35. _Reasons.UNSUPPORTED_HASH,
  36. )
  37. self._used = False
  38. self._algorithm = algorithm
  39. self._length = length
  40. utils._check_bytes("salt", salt)
  41. self._salt = salt
  42. self._iterations = iterations
  43. self._backend = backend
  44. def derive(self, key_material: bytes) -> bytes:
  45. if self._used:
  46. raise AlreadyFinalized("PBKDF2 instances can only be used once.")
  47. self._used = True
  48. utils._check_byteslike("key_material", key_material)
  49. return self._backend.derive_pbkdf2_hmac(
  50. self._algorithm,
  51. self._length,
  52. self._salt,
  53. self._iterations,
  54. key_material,
  55. )
  56. def verify(self, key_material: bytes, expected_key: bytes) -> None:
  57. derived_key = self.derive(key_material)
  58. if not constant_time.bytes_eq(derived_key, expected_key):
  59. raise InvalidKey("Keys do not match.")