<s> from __future__ import absolute_import , division , print_function <EOL> import six <EOL> from cryptography import utils <EOL> from cryptography . exceptions import ( <EOL> AlreadyFinalized , InvalidKey , UnsupportedAlgorithm , _Reasons <EOL> ) <EOL> from cryptography . hazmat . backends . interfaces import HMACBackend <EOL> from cryptography . hazmat . primitives import constant_time , hmac <EOL> from cryptography . hazmat . primitives . kdf import KeyDerivationFunction <EOL> @ utils . register_interface ( KeyDerivationFunction ) <EOL> class HKDF ( object ) : <EOL> def __init__ ( self , algorithm , length , salt , info , backend ) : <EOL> if not isinstance ( backend , HMACBackend ) : <EOL> raise UnsupportedAlgorithm ( <EOL> "<STR_LIT>" , <EOL> _Reasons . BACKEND_MISSING_INTERFACE <EOL> ) <EOL> self . _algorithm = algorithm <EOL> if not ( salt is None or isinstance ( salt , bytes ) ) : <EOL> raise TypeError ( "<STR_LIT>" ) <EOL> if salt is None : <EOL> salt = b"<STR_LIT:\x00>" * ( self . _algorithm . digest_size // <NUM_LIT:8> ) <EOL> self . _salt = salt <EOL> self . _backend = backend <EOL> self . _hkdf_expand = HKDFExpand ( self . _algorithm , length , info , backend ) <EOL> def _extract ( self , key_material ) : <EOL> h = hmac . HMAC ( self . _salt , self . _algorithm , backend = self . _backend ) <EOL> h . update ( key_material ) <EOL> return h . finalize ( ) <EOL> def derive ( self , key_material ) : <EOL> if not isinstance ( key_material , bytes ) : <EOL> raise TypeError ( "<STR_LIT>" ) <EOL> return self . _hkdf_expand . derive ( self . _extract ( key_material ) ) <EOL> def verify ( self , key_material , expected_key ) : <EOL> if not constant_time . bytes_eq ( self . derive ( key_material ) , expected_key ) : <EOL> raise InvalidKey <EOL> @ utils . register_interface ( KeyDerivationFunction ) <EOL> class HKDFExpand ( object ) : <EOL> def __init__ ( self , algorithm , length , info , backend ) : <EOL> if not isinstance ( backend , HMACBackend ) : <EOL> raise UnsupportedAlgorithm ( <EOL> "<STR_LIT>" , <EOL> _Reasons . BACKEND_MISSING_INTERFACE <EOL> ) <EOL> self . _algorithm = algorithm <EOL> self . _backend = backend <EOL> max_length = <NUM_LIT:255> * ( algorithm . digest_size // <NUM_LIT:8> ) <EOL> if length > max_length : <EOL> raise ValueError ( <EOL> "<STR_LIT>" . format ( <EOL> max_length <EOL> ) ) <EOL> self . _length = length <EOL> if not ( info is None or isinstance ( info , bytes ) ) : <EOL> raise TypeError ( "<STR_LIT>" ) <EOL> if info is None : <EOL> info = b"<STR_LIT>" <EOL> self . _info = info <EOL> self . _used = False <EOL> def _expand ( self , key_material ) : <EOL> output = [ b"<STR_LIT>" ] <EOL> counter = <NUM_LIT:1> <EOL> while ( self . _algorithm . digest_size // <NUM_LIT:8> ) * len ( output ) < self . _length : <EOL> h = hmac . HMAC ( key_material , self . _algorithm , backend = self . _backend ) <EOL> h . update ( output [ - <NUM_LIT:1> ] ) <EOL> h . update ( self . _info ) <EOL> h . update ( six . int2byte ( counter ) ) <EOL> output . append ( h . finalize ( ) ) <EOL> counter += <NUM_LIT:1> <EOL> return b"<STR_LIT>" . join ( output ) [ : self . _length ] <EOL> def derive ( self , key_material ) : <EOL> if not isinstance ( key_material , bytes ) : <EOL> raise TypeError ( "<STR_LIT>" ) <EOL> if self . _used : <EOL> raise AlreadyFinalized <EOL> self . _used = True <EOL> return self . _expand ( key_material ) <EOL> def verify ( self , key_material , expected_key ) : <EOL> if not constant_time . bytes_eq ( self . derive ( key_material ) , expected_key ) : <EOL> raise InvalidKey </s>
