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