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