def __init__(self, operation, request_originator_keys, contract, **kwargs): if not self.__ops__[operation]: raise ValueError('invalid operation') self.operation = operation self.contract_id = contract.contract_id self.creator_id = contract.creator_id self.enclave_service = kwargs.get('enclave_service') if self.enclave_service == 'random': enclave_id = random.choice(list(contract.enclave_map.keys())) try: #use the eservice database to get the client einfo = eservice_db.get_by_enclave_id(enclave_id) self.enclave_service = einfo.client except Exception as e: raise Exception( 'failed to get enclave client using database: %s', str(e)) self.encrypted_state_encryption_key = contract.get_state_encryption_key( self.enclave_service.enclave_id) self.originator_keys = request_originator_keys self.make_channel_keys() self.session_key = crypto.SKENC_GenerateKey() self.contract_code = contract.contract_code self.contract_state = contract.contract_state self.message = ContractMessage(self.originator_keys, self.channel_id, **kwargs) self.replication_params = contract.replication_params self.request_number = ContractRequest.__request_number__ ContractRequest.__request_number__ += 1
def __init__(self, operation, request_originator_keys, contract, **kwargs) : super().__init__(request_originator_keys, contract, **kwargs) if not self.__ops__[operation] : raise ValueError('invalid operation') self.operation = operation self.contract_code = contract.contract_code self.contract_state = contract.contract_state self.message = ContractMessage(self.originator_keys, self.channel_id, **kwargs)
def __init__(self, operation, request_originator_keys, enclave_service, contract, **kwargs) : if not self.__ops__[operation] : raise ValueError('invalid operation') self.operation = operation self.contract_id = contract.contract_id self.creator_id = contract.creator_id self.encrypted_state_encryption_key = contract.get_state_encryption_key(enclave_service.enclave_id) self.enclave_service = enclave_service self.originator_keys = request_originator_keys self.channel_keys = keys.TransactionKeys() self.session_key = crypto.SKENC_GenerateKey() self.contract_code = contract.contract_code self.contract_state = contract.contract_state self.message = ContractMessage(self.originator_keys, self.channel_keys, **kwargs)
class ContractRequest(object): __ops__ = {'initialize': True, 'update': True} def __init__(self, operation, request_originator_keys, enclave_service, contract, **kwargs): if not self.__ops__[operation]: raise ValueError('invalid operation') self.operation = operation self.contract_id = contract.contract_id self.creator_id = contract.creator_id self.encrypted_state_encryption_key = contract.get_state_encryption_key( enclave_service.enclave_id) self.enclave_service = enclave_service self.originator_keys = request_originator_keys self.channel_keys = keys.TransactionKeys() self.session_key = crypto.SKENC_GenerateKey() self.contract_code = contract.contract_code self.contract_state = contract.contract_state self.message = ContractMessage(self.originator_keys, self.channel_keys, **kwargs) @property def enclave_keys(self): return self.enclave_service.enclave_keys def __serialize_for_encryption(self): result = dict() result['Operation'] = self.operation result['ContractID'] = self.contract_id result['CreatorID'] = self.creator_id result[ 'EncryptedStateEncryptionKey'] = self.encrypted_state_encryption_key result['ContractState'] = self.contract_state.serializeForInvokation() result['ContractCode'] = self.contract_code.serialize() result['ContractMessage'] = self.message.serialize() return json.dumps(result) def __encrypt_session_key(self): encrypted_key = self.enclave_keys.encrypt(self.session_key) return crypto.byte_array_to_base64(encrypted_key) # response -- base64 encode, response encrypted with session key def __decrypt_response(self, response): decoded_response = crypto.base64_to_byte_array(response) return crypto.SKENC_DecryptMessage(self.session_key, decoded_response) # enclave_service -- enclave service wrapper object def evaluate(self): encrypted_session_key = self.__encrypt_session_key() # Encrypt the request serialized_byte_array = crypto.string_to_byte_array( self.__serialize_for_encryption()) encrypted_request_raw = crypto.SKENC_EncryptMessage( self.session_key, serialized_byte_array) encrypted_request = crypto.byte_array_to_base64(encrypted_request_raw) try: # Check and conditionally put the encrypted state into the block store if it is non-empty state_hash_b64 = self.contract_state.getStateHash(encoding='b64') if state_hash_b64: block_store_len = self.enclave_service.block_store_head( state_hash_b64) if block_store_len <= 0: # This block wasn't present in the block store of this enclave service - need to send it logger.debug( "Block store did not contain block '%s' - sending it", state_hash_b64) ret = self.enclave_service.block_store_put( state_hash_b64, self.contract_state.encrypted_state) if ret != True: logger.exception("block_store_put failed for key %s", state_hash_b64) raise encoded_encrypted_response = self.enclave_service.send_to_contract( encrypted_session_key, encrypted_request) if encoded_encrypted_response == None: logger.exception( "send_to_contract failed but no exception was thrown") raise logger.debug("raw response from enclave: %s", encoded_encrypted_response) except: logger.exception('contract invocation failed') raise try: decrypted_response = self.__decrypt_response( encoded_encrypted_response) response_string = crypto.byte_array_to_string(decrypted_response) response_parsed = json.loads(response_string[0:-1]) logger.debug("parsed response: %s", response_parsed) contract_response = ContractResponse(self, response_parsed) except Exception as e: logger.exception('contract response is invalid: ' + str(e)) raise return contract_response
class ContractRequest(object): __ops__ = {'initialize': True, 'update': True} def __init__(self, operation, request_originator_keys, enclave_service, contract, **kwargs): if not self.__ops__[operation]: raise ValueError('invalid operation') self.operation = operation self.contract_id = contract.contract_id self.creator_id = contract.creator_id self.encrypted_state_encryption_key = contract.get_state_encryption_key( enclave_service.enclave_id) self.enclave_service = enclave_service self.originator_keys = request_originator_keys self.channel_keys = keys.TransactionKeys() self.session_key = crypto.SKENC_GenerateKey() self.contract_code = contract.contract_code self.contract_state = contract.contract_state self.message = ContractMessage(self.originator_keys, self.channel_keys, **kwargs) @property def enclave_keys(self): return self.enclave_service.enclave_keys @property def session_iv(self): return crypto.SKENC_GenerateIV(self.enclave_keys.identity) def __serialize_for_encryption(self): result = dict() result['Operation'] = self.operation result['ContractID'] = self.contract_id result['CreatorID'] = self.creator_id result[ 'EncryptedStateEncryptionKey'] = self.encrypted_state_encryption_key result['ContractState'] = self.contract_state.serialize() result['ContractCode'] = self.contract_code.serialize() result['ContractMessage'] = self.message.serialize() return json.dumps(result) def __encrypt_session_key(self): encrypted_key = self.enclave_keys.encrypt(self.session_key) return crypto.byte_array_to_base64(encrypted_key) def __encrypt_request(self): serialized_byte_array = crypto.string_to_byte_array( self.__serialize_for_encryption()) encrypted_request = crypto.SKENC_EncryptMessage( self.session_key, self.session_iv, serialized_byte_array) return crypto.byte_array_to_base64(encrypted_request) # response -- base64 encode, response encrypted with session key def __decrypt_response(self, response): decoded_response = crypto.base64_to_byte_array(response) return crypto.SKENC_DecryptMessage(self.session_key, self.session_iv, decoded_response) # enclave_service -- enclave service wrapper object def evaluate(self): encrypted_session_key = self.__encrypt_session_key() encrypted_request = self.__encrypt_request() try: encoded_encrypted_response = self.enclave_service.send_to_contract( encrypted_session_key, encrypted_request) assert encoded_encrypted_response logger.debug("raw response from enclave: %s", encoded_encrypted_response) except: logger.exception('contract invocation failed') raise try: decrypted_response = self.__decrypt_response( encoded_encrypted_response) response_string = crypto.byte_array_to_string(decrypted_response) response_parsed = json.loads(response_string[0:-1]) logger.debug("parsed response: %s", response_parsed) contract_response = ContractResponse(self, response_parsed) except: logger.exception('contract response is invalid') raise return contract_response
class UpdateStateRequest(ContractRequest) : # ------------------------------------------------------- def __init__(self, operation, request_originator_keys, contract, **kwargs) : super().__init__(request_originator_keys, contract, **kwargs) if not self.__ops__[operation] : raise ValueError('invalid operation') self.operation = operation self.contract_code = contract.contract_code self.contract_state = contract.contract_state self.message = ContractMessage(self.originator_keys, self.channel_id, **kwargs) # ------------------------------------------------------- def __serialize_for_encryption(self) : result = dict() result['ContractID'] = self.contract_id result['CreatorID'] = self.creator_id result['EncryptedStateEncryptionKey'] = self.encrypted_state_encryption_key result['ContractCodeHash'] = self.contract_code.compute_hash(encoding='b64') result['ContractStateHash'] = self.contract_state.get_state_hash(encoding='b64') result['ContractMessage'] = self.message.serialize() return json.dumps(result) # ------------------------------------------------------- def evaluate(self) : """ evaluate the request using the enclave service """ assert self.operation == 'update' # Encrypt the request serialized_byte_array = crypto.string_to_byte_array(self.__serialize_for_encryption()) encrypted_request = bytes(crypto.SKENC_EncryptMessage(self.session_key, serialized_byte_array)) encrypted_key = bytes(self.enclave_keys.encrypt(self.session_key)) try : self.contract_state.push_state_to_eservice(self.enclave_service) encrypted_response = self.enclave_service.send_to_contract(encrypted_key, encrypted_request) except Exception as e: logger.warn('contract invocation failed; %s', str(e)) raise InvocationException('contract invocation failed') from e try : decrypted_response = crypto.SKENC_DecryptMessage(self.session_key, encrypted_response) except Exception as e: logger.exception('failed to decrypt response; %s', encrypted_response) raise InvocationException('contract response cannot be decrypted') try : response_string = crypto.byte_array_to_string(decrypted_response) response_parsed = json.loads(response_string[0:-1]) logger.debug("parsed response: %s", response_parsed) except Exception as e: logger.exception('contract response is invalid; %s', str(e)) raise InvocationException('failed to parse contract response') from e # if response_parsed['Status'] is False : # raise InvocationException(response_parsed['InvocationResponse']) try : if response_parsed['Status'] and response_parsed['StateChanged'] : contract_response = UpdateStateResponse(self, response_parsed) else : contract_response = ContractResponse(self, response_parsed) except Exception as e: logger.exception('contract response is invalid; %s', str(e)) raise InvocationException('contract response is invalid') from e return contract_response
class ContractRequest(object) : __ops__ = { 'initialize' : True, 'update' : True } # ------------------------------------------------------- def __init__(self, operation, request_originator_keys, enclave_service, contract, **kwargs) : if not self.__ops__[operation] : raise ValueError('invalid operation') self.operation = operation self.contract_id = contract.contract_id self.creator_id = contract.creator_id self.encrypted_state_encryption_key = contract.get_state_encryption_key(enclave_service.enclave_id) self.enclave_service = enclave_service self.originator_keys = request_originator_keys self.channel_keys = keys.TransactionKeys() self.session_key = crypto.SKENC_GenerateKey() self.contract_code = contract.contract_code self.contract_state = contract.contract_state self.message = ContractMessage(self.originator_keys, self.channel_keys, **kwargs) # ------------------------------------------------------- @property def enclave_keys(self) : return self.enclave_service.enclave_keys # ------------------------------------------------------- def __serialize_for_encryption(self) : result = dict() result['Operation'] = self.operation result['ContractID'] = self.contract_id result['CreatorID'] = self.creator_id result['EncryptedStateEncryptionKey'] = self.encrypted_state_encryption_key result['ContractState'] = self.contract_state.serialize_for_invocation() result['ContractCode'] = self.contract_code.serialize() result['ContractMessage'] = self.message.serialize() return json.dumps(result) # ------------------------------------------------------- def __encrypt_session_key(self) : encrypted_key = self.enclave_keys.encrypt(self.session_key) return crypto.byte_array_to_base64(encrypted_key) # ------------------------------------------------------- def __decrypt_response(self, response) : """ decrypt the response using the session key :param response string: base64 encoded, encrypted with session key """ decoded_response = crypto.base64_to_byte_array(response) return crypto.SKENC_DecryptMessage(self.session_key, decoded_response) # ------------------------------------------------------- def evaluate(self) : """ evaluate the request using the enclave service """ encrypted_session_key = self.__encrypt_session_key() # Encrypt the request serialized_byte_array = crypto.string_to_byte_array(self.__serialize_for_encryption()) encrypted_request_raw = crypto.SKENC_EncryptMessage(self.session_key, serialized_byte_array) encrypted_request = crypto.byte_array_to_base64(encrypted_request_raw) try : self.contract_state.push_state_to_eservice(self.enclave_service) encoded_encrypted_response = self.enclave_service.send_to_contract(encrypted_session_key, encrypted_request) logger.debug("raw response from enclave: %s", encoded_encrypted_response) except Exception as e: logger.warn('contract invocation failed; %s', str(e)) raise InvocationException('contract invocation failed') from e try : decrypted_response = self.__decrypt_response(encoded_encrypted_response) response_string = crypto.byte_array_to_string(decrypted_response) response_parsed = json.loads(response_string[0:-1]) logger.debug("parsed response: %s", response_parsed) contract_response = ContractResponse(self, response_parsed) except Exception as e: logger.warn('contract response is invalid; %s', str(e)) raise InvocationException('contract response is invalid') from e return contract_response
class ContractRequest(object): __ops__ = {'initialize': True, 'update': True} # a monotonic counter used locally by the client to identify all its # requests. every (contract_id, statehash) pair maps to a unique # request_number. the converse is not true (if the request failed) __request_number__ = 0 # ------------------------------------------------------- def __init__(self, operation, request_originator_keys, contract, **kwargs): if not self.__ops__[operation]: raise ValueError('invalid operation') self.operation = operation self.contract_id = contract.contract_id self.creator_id = contract.creator_id self.enclave_service = kwargs.get('enclave_service') if self.enclave_service == 'random': enclave_id = random.choice(list(contract.enclave_map.keys())) try: #use the eservice database to get the client einfo = eservice_db.get_by_enclave_id(enclave_id) self.enclave_service = einfo.client except Exception as e: raise Exception( 'failed to get enclave client using database: %s', str(e)) self.encrypted_state_encryption_key = contract.get_state_encryption_key( self.enclave_service.enclave_id) self.originator_keys = request_originator_keys self.make_channel_keys() self.session_key = crypto.SKENC_GenerateKey() self.contract_code = contract.contract_code self.contract_state = contract.contract_state self.message = ContractMessage(self.originator_keys, self.channel_id, **kwargs) self.replication_params = contract.replication_params self.request_number = ContractRequest.__request_number__ ContractRequest.__request_number__ += 1 # ------------------------------------------------------- def make_channel_keys(self, ledger_type=os.environ.get('PDO_LEDGER_TYPE')): if ledger_type == 'sawtooth': self.channel_keys = keys.TransactionKeys() self.channel_id = self.channel_keys.txn_public elif ledger_type == 'ccf': self.channel_keys = crypto.random_bit_string(64) # byte array self.channel_id = crypto.byte_array_to_base64( crypto.compute_message_hash(self.channel_keys)) else: raise Exception( "Invalid Ledger Type. Must be either sawtooth or ccf.") # ------------------------------------------------------- @property def enclave_keys(self): return self.enclave_service.enclave_keys # ------------------------------------------------------- def __serialize_for_encryption(self): result = dict() result['Operation'] = self.operation result['ContractID'] = self.contract_id result['CreatorID'] = self.creator_id result[ 'EncryptedStateEncryptionKey'] = self.encrypted_state_encryption_key if self.operation == 'initialize': result['ContractCode'] = self.contract_code.serialize() else: result['ContractCodeHash'] = self.contract_code.compute_hash( encoding='b64') result['ContractStateHash'] = self.contract_state.get_state_hash( encoding='b64') result['ContractMessage'] = self.message.serialize() return json.dumps(result) # ------------------------------------------------------- def evaluate(self): """ evaluate the request using the enclave service """ # Encrypt the request serialized_byte_array = crypto.string_to_byte_array( self.__serialize_for_encryption()) encrypted_request = bytes( crypto.SKENC_EncryptMessage(self.session_key, serialized_byte_array)) encrypted_key = bytes(self.enclave_keys.encrypt(self.session_key)) try: self.contract_state.push_state_to_eservice(self.enclave_service) encrypted_response = self.enclave_service.send_to_contract( encrypted_key, encrypted_request) except Exception as e: logger.warn('contract invocation failed; %s', str(e)) raise InvocationException('contract invocation failed') from e try: decrypted_response = crypto.SKENC_DecryptMessage( self.session_key, encrypted_response) except Exception as e: logger.exception('failed to decrypt response; %s', encrypted_response) raise InvocationException('contract response cannot be decrypted') try: response_string = crypto.byte_array_to_string(decrypted_response) response_parsed = json.loads(response_string[0:-1]) logger.debug("parsed response: %s", response_parsed) contract_response = ContractResponse(self, response_parsed) except Exception as e: logger.exception('contract response is invalid; %s', str(e)) raise InvocationException('contract response is invalid') from e return contract_response