• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
5from __future__ import absolute_import, division, print_function
6
7from cryptography import utils
8from cryptography.exceptions import (
9    AlreadyFinalized,
10    InvalidKey,
11    UnsupportedAlgorithm,
12    _Reasons,
13)
14from cryptography.hazmat.backends import _get_backend
15from cryptography.hazmat.backends.interfaces import PBKDF2HMACBackend
16from cryptography.hazmat.primitives import constant_time
17from cryptography.hazmat.primitives.kdf import KeyDerivationFunction
18
19
20@utils.register_interface(KeyDerivationFunction)
21class PBKDF2HMAC(object):
22    def __init__(self, algorithm, length, salt, iterations, backend=None):
23        backend = _get_backend(backend)
24        if not isinstance(backend, PBKDF2HMACBackend):
25            raise UnsupportedAlgorithm(
26                "Backend object does not implement PBKDF2HMACBackend.",
27                _Reasons.BACKEND_MISSING_INTERFACE,
28            )
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
45    def derive(self, key_material):
46        if self._used:
47            raise AlreadyFinalized("PBKDF2 instances can only be used once.")
48        self._used = True
49
50        utils._check_byteslike("key_material", key_material)
51        return self._backend.derive_pbkdf2_hmac(
52            self._algorithm,
53            self._length,
54            self._salt,
55            self._iterations,
56            key_material,
57        )
58
59    def verify(self, key_material, expected_key):
60        derived_key = self.derive(key_material)
61        if not constant_time.bytes_eq(derived_key, expected_key):
62            raise InvalidKey("Keys do not match.")
63