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 7import sys 8 9from cryptography import utils 10from cryptography.exceptions import ( 11 AlreadyFinalized, 12 InvalidKey, 13 UnsupportedAlgorithm, 14 _Reasons, 15) 16from cryptography.hazmat.backends import _get_backend 17from cryptography.hazmat.backends.interfaces import ScryptBackend 18from cryptography.hazmat.primitives import constant_time 19from cryptography.hazmat.primitives.kdf import KeyDerivationFunction 20 21 22# This is used by the scrypt tests to skip tests that require more memory 23# than the MEM_LIMIT 24_MEM_LIMIT = sys.maxsize // 2 25 26 27@utils.register_interface(KeyDerivationFunction) 28class Scrypt(object): 29 def __init__(self, salt, length, n, r, p, backend=None): 30 backend = _get_backend(backend) 31 if not isinstance(backend, ScryptBackend): 32 raise UnsupportedAlgorithm( 33 "Backend object does not implement ScryptBackend.", 34 _Reasons.BACKEND_MISSING_INTERFACE, 35 ) 36 37 self._length = length 38 utils._check_bytes("salt", salt) 39 if n < 2 or (n & (n - 1)) != 0: 40 raise ValueError("n must be greater than 1 and be a power of 2.") 41 42 if r < 1: 43 raise ValueError("r must be greater than or equal to 1.") 44 45 if p < 1: 46 raise ValueError("p must be greater than or equal to 1.") 47 48 self._used = False 49 self._salt = salt 50 self._n = n 51 self._r = r 52 self._p = p 53 self._backend = backend 54 55 def derive(self, key_material): 56 if self._used: 57 raise AlreadyFinalized("Scrypt instances can only be used once.") 58 self._used = True 59 60 utils._check_byteslike("key_material", key_material) 61 return self._backend.derive_scrypt( 62 key_material, self._salt, self._length, self._n, self._r, self._p 63 ) 64 65 def verify(self, key_material, expected_key): 66 derived_key = self.derive(key_material) 67 if not constant_time.bytes_eq(derived_key, expected_key): 68 raise InvalidKey("Keys do not match.") 69