pbkdf2.py 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869
  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. import typing
  5. from cryptography import utils
  6. from cryptography.exceptions import (
  7. AlreadyFinalized,
  8. InvalidKey,
  9. UnsupportedAlgorithm,
  10. _Reasons,
  11. )
  12. from cryptography.hazmat.backends import _get_backend
  13. from cryptography.hazmat.backends.interfaces import Backend, PBKDF2HMACBackend
  14. from cryptography.hazmat.primitives import constant_time, hashes
  15. from cryptography.hazmat.primitives.kdf import KeyDerivationFunction
  16. class PBKDF2HMAC(KeyDerivationFunction):
  17. def __init__(
  18. self,
  19. algorithm: hashes.HashAlgorithm,
  20. length: int,
  21. salt: bytes,
  22. iterations: int,
  23. backend: typing.Optional[Backend] = None,
  24. ):
  25. backend = _get_backend(backend)
  26. if not isinstance(backend, PBKDF2HMACBackend):
  27. raise UnsupportedAlgorithm(
  28. "Backend object does not implement PBKDF2HMACBackend.",
  29. _Reasons.BACKEND_MISSING_INTERFACE,
  30. )
  31. if not backend.pbkdf2_hmac_supported(algorithm):
  32. raise UnsupportedAlgorithm(
  33. "{} is not supported for PBKDF2 by this backend.".format(
  34. algorithm.name
  35. ),
  36. _Reasons.UNSUPPORTED_HASH,
  37. )
  38. self._used = False
  39. self._algorithm = algorithm
  40. self._length = length
  41. utils._check_bytes("salt", salt)
  42. self._salt = salt
  43. self._iterations = iterations
  44. self._backend = backend
  45. def derive(self, key_material: bytes) -> bytes:
  46. if self._used:
  47. raise AlreadyFinalized("PBKDF2 instances can only be used once.")
  48. self._used = True
  49. utils._check_byteslike("key_material", key_material)
  50. return self._backend.derive_pbkdf2_hmac(
  51. self._algorithm,
  52. self._length,
  53. self._salt,
  54. self._iterations,
  55. key_material,
  56. )
  57. def verify(self, key_material: bytes, expected_key: bytes) -> None:
  58. derived_key = self.derive(key_material)
  59. if not constant_time.bytes_eq(derived_key, expected_key):
  60. raise InvalidKey("Keys do not match.")