def supported_by_hashlib_pbkdf2(self): """helper to detect if hash is supported by hashlib.pbkdf2_hmac()""" if not _stdlib_pbkdf2_hmac: return None try: _stdlib_pbkdf2_hmac(self.name, b"p", b"s", 1) return True except ValueError: # "unsupported hash type" return False
def supported_by_hashlib_pbkdf2(self): if not _stdlib_pbkdf2_hmac: return try: _stdlib_pbkdf2_hmac(self.name, 'p', 's', 1) return True except ValueError: return False return
def pbkdf2_hmac(digest, secret, salt, rounds, keylen=None): secret = to_bytes(secret, param='secret') salt = to_bytes(salt, param='salt') digest_info = lookup_hash(digest) digest_size = digest_info.digest_size if not isinstance(rounds, int_types): raise exc.ExpectedTypeError(rounds, 'int', 'rounds') if rounds < 1: raise ValueError('rounds must be at least 1') if keylen is None: keylen = digest_size else: if not isinstance(keylen, int_types): raise exc.ExpectedTypeError(keylen, 'int or None', 'keylen') else: if keylen < 1: raise ValueError('keylen must be at least 1') block_count = (keylen + digest_size - 1) // digest_size if block_count > MAX_UINT32: raise OverflowError('keylen too long for digest') if digest_info.supported_by_fastpbkdf2: return _fast_pbkdf2_hmac(digest_info.name, secret, salt, rounds, keylen) if digest_info.supported_by_hashlib_pbkdf2: return _stdlib_pbkdf2_hmac(digest_info.name, secret, salt, rounds, keylen) keyed_hmac = compile_hmac(digest, secret) calc_block = _get_pbkdf2_looper(digest_size) return join_bytes( calc_block(keyed_hmac, keyed_hmac(salt + _pack_uint32(i)), rounds) for i in irange(1, block_count + 1))[:keylen]
def pbkdf2_hmac(digest, secret, salt, rounds, keylen=None): """pkcs#5 password-based key derivation v2.0 using HMAC + arbitrary digest. :arg digest: digest name or constructor. :arg secret: passphrase to use to generate key. may be :class:`!bytes` or :class:`unicode` (encoded using UTF-8). :arg salt: salt string to use when generating key. may be :class:`!bytes` or :class:`unicode` (encoded using UTF-8). :param rounds: number of rounds to use to generate key. :arg keylen: number of bytes to generate. if omitted / ``None``, will use digest's native output size. :returns: raw bytes of generated key .. versionchanged:: 1.7 This function will use the first available of the following backends: * `fastpbk2 <https://pypi.python.org/pypi/fastpbkdf2>`_ * :func:`hashlib.pbkdf2_hmac` (only available in py2 >= 2.7.8, and py3 >= 3.4) * builtin pure-python backend See :data:`passlib.crypto.digest.PBKDF2_BACKENDS` to determine which backend(s) are in use. """ # validate secret & salt secret = to_bytes(secret, param="secret") salt = to_bytes(salt, param="salt") # resolve digest digest_info = lookup_hash(digest) digest_size = digest_info.digest_size # validate rounds if not isinstance(rounds, int_types): raise exc.ExpectedTypeError(rounds, "int", "rounds") if rounds < 1: raise ValueError("rounds must be at least 1") # validate keylen if keylen is None: keylen = digest_size elif not isinstance(keylen, int_types): raise exc.ExpectedTypeError(keylen, "int or None", "keylen") elif keylen < 1: # XXX: could allow keylen=0, but want to be compat w/ stdlib raise ValueError("keylen must be at least 1") # find smallest block count s.t. keylen <= block_count * digest_size; # make sure block count won't overflow (per pbkdf2 spec) # this corresponds to throwing error if keylen > digest_size * MAX_UINT32 # NOTE: stdlib will throw error at lower bound (keylen > MAX_SINT32) # NOTE: have do this before other backends checked, since fastpbkdf2 raises wrong error # (InvocationError, not OverflowError) block_count = (keylen + digest_size - 1) // digest_size if block_count > MAX_UINT32: raise OverflowError("keylen too long for digest") # # check for various high-speed backends # # ~3x faster than pure-python backend # NOTE: have to do this after above guards since fastpbkdf2 lacks bounds checks. if digest_info.supported_by_fastpbkdf2: return _fast_pbkdf2_hmac(digest_info.name, secret, salt, rounds, keylen) # ~1.4x faster than pure-python backend # NOTE: have to do this after fastpbkdf2 since hashlib-ssl is slower, # will support larger number of hashes. if digest_info.supported_by_hashlib_pbkdf2: return _stdlib_pbkdf2_hmac(digest_info.name, secret, salt, rounds, keylen) # # otherwise use our own implementation # # generated keyed hmac keyed_hmac = compile_hmac(digest, secret) # get helper to calculate pbkdf2 inner loop efficiently calc_block = _get_pbkdf2_looper(digest_size) # assemble & return result return join_bytes( calc_block(keyed_hmac, keyed_hmac(salt + _pack_uint32(i)), rounds) for i in irange(1, block_count + 1))[:keylen]
def pbkdf2_hmac(digest, secret, salt, rounds, keylen=None): """pkcs#5 password-based key derivation v2.0 using HMAC + arbitrary digest. :arg digest: digest name or constructor. :arg secret: passphrase to use to generate key. may be :class:`!bytes` or :class:`unicode` (encoded using UTF-8). :arg salt: salt string to use when generating key. may be :class:`!bytes` or :class:`unicode` (encoded using UTF-8). :param rounds: number of rounds to use to generate key. :arg keylen: number of bytes to generate. if omitted / ``None``, will use digest's native output size. :returns: raw bytes of generated key .. versionchanged:: 1.7 This function will use the first available of the following backends: * `fastpbk2 <https://pypi.python.org/pypi/fastpbkdf2>`_ * :func:`hashlib.pbkdf2_hmac` (only available in py2 >= 2.7.8, and py3 >= 3.4) * builtin pure-python backend See :data:`passlib.crypto.digest.PBKDF2_BACKENDS` to determine which backend(s) are in use. """ # validate secret & salt secret = to_bytes(secret, param="secret") salt = to_bytes(salt, param="salt") # resolve digest digest_info = lookup_hash(digest) digest_size = digest_info.digest_size # validate rounds if not isinstance(rounds, int_types): raise exc.ExpectedTypeError(rounds, "int", "rounds") if rounds < 1: raise ValueError("rounds must be at least 1") # validate keylen if keylen is None: keylen = digest_size elif not isinstance(keylen, int_types): raise exc.ExpectedTypeError(keylen, "int or None", "keylen") elif keylen < 1: # XXX: could allow keylen=0, but want to be compat w/ stdlib raise ValueError("keylen must be at least 1") # find smallest block count s.t. keylen <= block_count * digest_size; # make sure block count won't overflow (per pbkdf2 spec) # this corresponds to throwing error if keylen > digest_size * MAX_UINT32 # NOTE: stdlib will throw error at lower bound (keylen > MAX_SINT32) # NOTE: have do this before other backends checked, since fastpbkdf2 raises wrong error # (InvocationError, not OverflowError) block_count = (keylen + digest_size - 1) // digest_size if block_count > MAX_UINT32: raise OverflowError("keylen too long for digest") # # check for various high-speed backends # # ~3x faster than pure-python backend # NOTE: have to do this after above guards since fastpbkdf2 lacks bounds checks. if digest_info.supported_by_fastpbkdf2: return _fast_pbkdf2_hmac(digest_info.name, secret, salt, rounds, keylen) # ~1.4x faster than pure-python backend # NOTE: have to do this after fastpbkdf2 since hashlib-ssl is slower, # will support larger number of hashes. if digest_info.supported_by_hashlib_pbkdf2: return _stdlib_pbkdf2_hmac(digest_info.name, secret, salt, rounds, keylen) # # otherwise use our own implementation # # generated keyed hmac keyed_hmac = compile_hmac(digest, secret) # get helper to calculate pbkdf2 inner loop efficiently calc_block = _get_pbkdf2_looper(digest_size) # assemble & return result return join_bytes( calc_block(keyed_hmac, keyed_hmac(salt + _pack_uint32(i)), rounds) for i in irange(1, block_count + 1) )[:keylen]