pbkdf2.py 1.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162
  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 __future__ import annotations
  5. import typing
  6. from cryptography import utils
  7. from cryptography.exceptions import (
  8. AlreadyFinalized,
  9. InvalidKey,
  10. UnsupportedAlgorithm,
  11. _Reasons,
  12. )
  13. from cryptography.hazmat.bindings._rust import openssl as rust_openssl
  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.Any = None,
  24. ):
  25. from cryptography.hazmat.backends.openssl.backend import (
  26. backend as ossl,
  27. )
  28. if not ossl.pbkdf2_hmac_supported(algorithm):
  29. raise UnsupportedAlgorithm(
  30. f"{algorithm.name} is not supported for PBKDF2.",
  31. _Reasons.UNSUPPORTED_HASH,
  32. )
  33. self._used = False
  34. self._algorithm = algorithm
  35. self._length = length
  36. utils._check_bytes("salt", salt)
  37. self._salt = salt
  38. self._iterations = iterations
  39. def derive(self, key_material: bytes) -> bytes:
  40. if self._used:
  41. raise AlreadyFinalized("PBKDF2 instances can only be used once.")
  42. self._used = True
  43. return rust_openssl.kdf.derive_pbkdf2_hmac(
  44. key_material,
  45. self._algorithm,
  46. self._salt,
  47. self._iterations,
  48. self._length,
  49. )
  50. def verify(self, key_material: bytes, expected_key: bytes) -> None:
  51. derived_key = self.derive(key_material)
  52. if not constant_time.bytes_eq(derived_key, expected_key):
  53. raise InvalidKey("Keys do not match.")