def __init__(self, request, response, **kwargs): super().__init__(request, response, **kwargs) self.state_changed = True self.request_number = request.request_number self.operation = 'initialize' self.metadata_hash = crypto.base64_to_byte_array( response['MetadataHash']) self.signature = response['Signature'] # save the information we will need for the transaction state_hash_b64 = response['StateHash'] self.new_state_hash = crypto.base64_to_byte_array(state_hash_b64) message = self.serialize_for_signing() if not self.verify_enclave_signature(message, request.enclave_keys): raise InvocationException('failed to verify enclave signature') self.raw_state = self.enclave_service.get_block(state_hash_b64) self.new_state_object = ContractState(self.contract_id, self.raw_state) self.new_state_object.pull_state_from_eservice(self.enclave_service) # compute ids of blocks in the change set (used for replication) self.new_state_object.compute_ids_of_newblocks( request.contract_state.component_block_ids) self.replication_params = request.replication_params
def compute_pdo_ccl_signature(private_key, enclave_id, enclave_signature, channel_id, contract_id, creator_public_key_pem, contract_code_hash, message_hash, current_state_hash, previous_state_hash, dependency_list): k = crypto.SIG_PrivateKey(private_key) message_byte_array = crypto.string_to_byte_array(enclave_id) message_byte_array += crypto.base64_to_byte_array(enclave_signature) message_byte_array += crypto.string_to_byte_array(channel_id) message_byte_array += crypto.string_to_byte_array(contract_id) message_byte_array += crypto.string_to_byte_array(creator_public_key_pem) message_byte_array += crypto.base64_to_byte_array(contract_code_hash) message_byte_array += crypto.base64_to_byte_array(message_hash) message_byte_array += crypto.base64_to_byte_array(current_state_hash) #in ccl initialize, previous state hash and dependencies are supposed to be empty if previous_state_hash: message_byte_array += crypto.base64_to_byte_array(previous_state_hash) for d in dependency_list: message_byte_array += crypto.string_to_byte_array(d.contract_id) message_byte_array += crypto.string_to_byte_array(d.state_hash) signature = k.SignMessage(message_byte_array) encoded_signature = crypto.byte_array_to_base64(signature) logger.debug("signed message string: " + crypto.byte_array_to_base64(message_byte_array)) logger.debug("signed message hash: " + crypto.byte_array_to_hex( crypto.compute_message_hash(message_byte_array))) logger.debug("signature: %s", encoded_signature) return encoded_signature
def ccl_update(self, channel_keys, contract_enclave_id, enclave_signature, contract_id, message_hash, current_state_hash, previous_state_hash, dependency_list, **extra_params): tx_method = "ccl_update" dependencies = [] for dependency in dependency_list: temp = dict() temp['contract_id'] = dependency['contract_id'] temp['state_hash'] = crypto.base64_to_byte_array( dependency['state_hash']) temp['state_hash_for_sign'] = dependency['state_hash'] dependencies.append(temp) tx_params = PayloadBuilder.build_update_contract_state_transaction_from_data( channel_keys, contract_enclave_id, crypto.base64_to_byte_array(enclave_signature), contract_id, current_state_hash, previous_state_hash, message_hash, dependencies) try: response = self.ccf_client.submit_rpc(tx_method, tx_params) if response.result: # result will be True for successful init transaction return tx_params['nonce'] else: raise Exception(response.error) except Exception as e: raise
def ccl_initialize( self, channel_keys, contract_enclave_id, enclave_signature, contract_id, contract_code_hash, # not used by CCF message_hash, initial_state_hash, contract_metadata_hash, **extra_params): tx_method = "ccl_initialize" tx_params = PayloadBuilder.build_initialize_contract_state_transaction_from_data( channel_keys, contract_enclave_id, crypto.base64_to_byte_array(enclave_signature), contract_id, message_hash, initial_state_hash, contract_metadata_hash, self.pdo_signer.signing_key) try: response = self.ccf_client.submit_rpc(tx_method, tx_params) if response.result: # result will be True for successful init transaction return tx_params['nonce'] else: raise Exception(response.error) except Exception as e: raise
def verify(self, message, encoded_signature, encoding='hex'): """ verify the signature of a message from the agent :param message: the message for verification, no encoding :param signature: encoded signature :param encoding: the encoding used for the signature; one of raw, hex, b64 """ logger.debug("signature for verification: %s", encoded_signature) if type(message) is bytes: message_byte_array = message elif type(message) is tuple: message_byte_array = message else: message_byte_array = bytes(message, 'ascii') if encoding == 'raw': decoded_signature = encoded_signature elif encoding == 'hex': decoded_signature = crypto.hex_to_byte_array(encoded_signature) elif encoding == 'b64': decoded_signature = crypto.base64_to_byte_array(encoded_signature) else: raise ValueError('unknown encoding; {0}'.format(encoding)) result = self._verifying_key.VerifySignature(message_byte_array, decoded_signature) if result < 0: raise Error('malformed signature') return
def safe_filename(b64name): """the base64 encoding we use for contract_id and state_hash make them very poor file names; convert to hex for better behavior """ decoded = crypto.base64_to_byte_array(b64name) encoded = crypto.byte_array_to_hex(decoded) return encoded[16:]
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 __init__(self, request, response) : """ Initialize a contract response object :param request: the ContractRequest object corresponding to the response :param response: diction containing the response from the enclave """ self.status = response['Status'] self.invocation_response_raw = response['InvocationResponse'] self.invocation_response = invocation_response(response['InvocationResponse']) self.state_changed = response['StateChanged'] self.new_state_object = request.contract_state #if the new state is same as the old state, then change set is empty self.new_state_object.changed_block_ids=[] self.request_number = request.request_number self.operation = request.operation if self.status and self.state_changed : self.signature = response['Signature'] state_hash_b64 = response['StateHash'] # we have another mismatch between the field names in the enclave # and the field names expected in the transaction; this needs to # be fixed at some point self.dependencies = [] for dependency in response['Dependencies'] : contract_id = dependency['ContractID'] state_hash = dependency['StateHash'] self.dependencies.append({'contract_id' : contract_id, 'state_hash' : state_hash}) # save the information we will need for the transaction self.channel_keys = request.channel_keys self.channel_id = request.channel_id self.contract_id = request.contract_id self.creator_id = request.creator_id self.code_hash = request.contract_code.compute_hash() self.message_hash = request.message.compute_hash() self.new_state_hash = crypto.base64_to_byte_array(state_hash_b64) self.originator_keys = request.originator_keys self.enclave_service = request.enclave_service self.old_state_hash = () if request.operation != 'initialize' : self.old_state_hash = ContractState.compute_hash(request.contract_state.raw_state) if not self.__verify_enclave_signature(request.enclave_keys) : raise Exception('failed to verify enclave signature') self.raw_state = self.enclave_service.get_block(state_hash_b64) self.new_state_object = ContractState(self.contract_id, self.raw_state) self.new_state_object.pull_state_from_eservice(self.enclave_service) # compute ids of blocks in the change set (used for replication) self.new_state_object.compute_ids_of_newblocks(request.contract_state.component_block_ids) self.replication_params = request.replication_params
def verify_ledger_signature(cls, message, signature): """ Verify ledger signature. sign is base64 encoded. document is a string""" message_byte_array = bytes(message, 'ascii') decoded_signature = crypto.base64_to_byte_array(signature) result = cls.ccf_signature_verifyer.VerifySignature(message_byte_array, decoded_signature) if result < 0 : raise Exception('malformed signature'); return result
def update_state(self, encrypted_state) : self.encrypted_state = encrypted_state self.component_block_ids = [] if self.encrypted_state : b64_decoded_byte_array = crypto.base64_to_byte_array(self.encrypted_state) b64_decoded_string = crypto.byte_array_to_string(b64_decoded_byte_array).rstrip('\0') json_main_state_block = json.loads(b64_decoded_string) self.component_block_ids = json_main_state_block['BlockIds']
def compute_hash(encrypted_state, encoding='raw'): """ compute the hash of the encrypted state """ state_byte_array = crypto.base64_to_byte_array(encrypted_state) state_hash = crypto.compute_message_hash(state_byte_array) if encoding == 'raw': return state_hash elif encoding == 'b64': return crypto.byte_array_to_base64(state_hash) elif encoding == 'hex': return crypto.byte_array_to_hex(state_hash) raise ValueError('unknown encoding; {}'.format(encoding))
def __init__(self, request, response) : """ Initialize a contract response object :param request: the ContractRequest object corresponding to the response :param response: diction containing the response from the enclave """ self.status = response['Status'] self.result = response['Result'] self.state_changed = response['StateChanged'] if self.status and self.state_changed : self.signature = response['Signature'] state_hash_b64 = response['StateHash'] # we have another mismatch between the field names in the enclave # and the field names expected in the transaction; this needs to # be fixed at some point self.dependencies = [] for dependency in response['Dependencies'] : contract_id = dependency['ContractID'] state_hash = dependency['StateHash'] self.dependencies.append({'contract_id' : contract_id, 'state_hash' : state_hash}) # save the information we will need for the transaction self.channel_keys = request.channel_keys self.contract_id = request.contract_id self.creator_id = request.creator_id self.code_hash = request.contract_code.compute_hash() self.message_hash = request.message.compute_hash() self.new_state_hash = crypto.base64_to_byte_array(state_hash_b64) self.originator_keys = request.originator_keys self.enclave_service = request.enclave_service self.old_state_hash = () if request.operation != 'initialize' : self.old_state_hash = ContractState.compute_hash(request.contract_state.encrypted_state) if not self.__verify_enclave_signature(request.enclave_keys) : raise Exception('failed to verify enclave signature') # Retrieve the encrypted state from the enclave's block store # Note that this channel is untrusted - must verify the retrieved data has the correct hash! # This is intentionally done after the signature verification encrypted_state_u_b64 = self.enclave_service.block_store_get(state_hash_b64) encrypted_state_u_hash_b64 = ContractState.compute_hash(encrypted_state_u_b64, encoding='b64') if (state_hash_b64 != encrypted_state_u_hash_b64): raise Exception('Encrypted state from block store has incorrect hash!') self.encrypted_state = encrypted_state_u_b64;
def __init__(self, request, response) : """ Initialize a contract response object :param request: the ContractRequest object corresponding to the response :param response: diction containing the response from the enclave """ self.status = response['Status'] self.result = response['Result'] self.state_changed = response['StateChanged'] self.new_state_object = request.contract_state if self.status and self.state_changed : self.signature = response['Signature'] state_hash_b64 = response['StateHash'] # we have another mismatch between the field names in the enclave # and the field names expected in the transaction; this needs to # be fixed at some point self.dependencies = [] for dependency in response['Dependencies'] : contract_id = dependency['ContractID'] state_hash = dependency['StateHash'] self.dependencies.append({'contract_id' : contract_id, 'state_hash' : state_hash}) # save the information we will need for the transaction self.channel_keys = request.channel_keys self.contract_id = request.contract_id self.creator_id = request.creator_id self.code_hash = request.contract_code.compute_hash() self.message_hash = request.message.compute_hash() self.new_state_hash = crypto.base64_to_byte_array(state_hash_b64) self.originator_keys = request.originator_keys self.enclave_service = request.enclave_service self.old_state_hash = () if request.operation != 'initialize' : self.old_state_hash = ContractState.compute_hash(request.contract_state.encrypted_state) if not self.__verify_enclave_signature(request.enclave_keys) : raise Exception('failed to verify enclave signature') self.encrypted_state = self.enclave_service.block_store_get(state_hash_b64) self.new_state_object = ContractState(self.contract_id, self.encrypted_state) self.new_state_object.pull_state_from_eservice(self.enclave_service)
def serialize_for_signing(encrypted_state_key, secret_list, contract_id, creator_id): """Create a buffer with the canonical serialization of secret list for verifying the signature from the enclave :param string encrypted_state_key: base64 encoded string :param array of dictionaries secret_list: dictionary defines values for pspk and encrypted_secret :param string contract_id: 16 character, hex encoded, sha256 hashed, registration transaction signature :param string creator_id: PEM encoded ECDSA verifying key """ message = crypto.string_to_byte_array(contract_id) message += crypto.string_to_byte_array(creator_id) for secret in secret_list: message += crypto.string_to_byte_array(secret['pspk']) message += crypto.string_to_byte_array(secret['encrypted_secret']) message += crypto.base64_to_byte_array(encrypted_state_key) return message
def get_state_details(self, contract_id, state_hash): tx_method = "get_details_about_state" tx_params = PayloadBuilder.build_get_details_about_state_from_data(contract_id, \ crypto.base64_to_byte_array(state_hash)) state_details = self.submit_read_request_to_ccf(tx_method, tx_params) # verify ccf signature message = state_details["previous_state_hash"] message+= state_details["message_hash"] message+= state_details["transaction_id"] message+= state_details["dependency_list"] if not CCFSubmitter.verify_ledger_signature(message, state_details["signature"]): raise Exception("Invalid signature on Get State Details from CCF Ledger") return state_details
def __init__(self, request, response, **kwargs): super().__init__(request, response, **kwargs) self.state_changed = True self.request_number = request.request_number self.operation = 'update' self.signature = response['Signature'] # we have another mismatch between the field names in the enclave # and the field names expected in the transaction; this needs to # be fixed at some point for dependency in response['Dependencies']: contract_id = dependency['ContractID'] state_hash = dependency['StateHash'] self.dependencies.append({ 'contract_id': contract_id, 'state_hash': state_hash }) # save the information we will need for the transaction state_hash_b64 = response['StateHash'] self.new_state_hash = crypto.base64_to_byte_array(state_hash_b64) self.old_state_hash = ContractState.compute_hash( request.contract_state.raw_state) message = self.serialize_for_signing() if not self.verify_enclave_signature(message, request.enclave_keys): raise Exception('failed to verify enclave signature') self.raw_state = self.enclave_service.get_block(state_hash_b64) self.new_state_object = ContractState(self.contract_id, self.raw_state) self.new_state_object.pull_state_from_eservice(self.enclave_service) # compute ids of blocks in the change set (used for replication) self.new_state_object.compute_ids_of_newblocks( request.contract_state.component_block_ids) self.replication_params = request.replication_params
def ccl_initialize(self, channel_keys, contract_enclave_id, enclave_signature, contract_id, message_hash, current_state_hash, contract_code_hash, **extra_params): tx_method = "ccl_update" verb = "init" previous_state_hash = []; dependency_list = []; tx_params = PayloadBuilder.build_initialize_contract_state_transaction_from_data( verb, contract_enclave_id, crypto.base64_to_byte_array(enclave_signature), contract_id, current_state_hash, previous_state_hash, dependency_list, message_hash, contract_code_hash, self.pdo_signer.signing_key, self.pdo_signer.verifying_key, nonce = channel_keys ) try: response = self.submit_rpc_to_ccf(tx_method, tx_params) if response.result: # result will be True for successful init transaction return tx_params['nonce'] # this will represent the transaction id else: raise Exception(response.error['message']) except Exception as e: raise
def raw_encryption_key(self) : return pcrypto.base64_to_byte_array(self.encryption_key)
def __decrypt_response(self, response): decoded_response = crypto.base64_to_byte_array(response) return crypto.SKENC_DecryptMessage(self.session_key, decoded_response)
def KeyValueGetBlock(hash_identity) : raw_hash_identity = pcrypto.base64_to_byte_array(hash_identity) return kvs.block_store_get(raw_hash_identity)
"Symmetric decryption (random IV) invalid key detection test successful!" ) else: logger.error( "ERROR: Symmetric decryption (random IV) invalid key detection test failed: ", exc) sys.exit(-1) try: iv = crypto.SKENC_GenerateIV("A message") except Exception as exc: logger.error( "ERROR: Symmetric encryption deterministic iv generation test failed: ", exc) sys.exit(-1) logger.debug( "Symmetric encryption deterministic iv generation test successful!") try: rand = crypto.random_bit_string(16) except Exception as exc: logger.error("ERROR: Random number generation failed: ", exc) sys.exit(-1) logger.debug("Random number generation successful!") hash = crypto.compute_message_hash(rand) bhash = bytearray(hash) b64hash = crypto.byte_array_to_base64(bhash) logger.debug("Hash computed!") crypto.base64_to_byte_array(b64hash) logger.debug("SWIG CRYPTO_WRAPPER TEST SUCCESSFUL!") sys.exit(0)
def raw_hash_identity(self) : if self.hash_identity is None : return None return pcrypto.base64_to_byte_array(self.hash_identity)