def __encrypt_workorder_indata(self, input_json_params, encrypted_session_key, session_iv): """ Function to encrypt inData of workorder Parameters: - input_json_params is inData and outData elements within work order request as per TCF API 6.1.7 Work Order Data Formats - encrypted_session_key is a one-time encryption key generated by the participant submitting the work order. - session_iv is an initialization vector if required by the data encryption algorithm (encryptedSessionKey). The default is all zeros. """ indata_objects = input_json_params['inData'] indata_objects.sort(key=lambda x: x['index']) input_json_params['inData'] = indata_objects logger.info("Encrypting Workorder Data"); i = 0 for item in indata_objects: data = item['data'].encode('UTF-8') e_key = item['encryptedDataEncryptionKey'].encode('UTF-8') if (not e_key ) or (e_key == "null".encode('UTF-8')): enc_data = utility.encrypt_data(data, encrypted_session_key, session_iv) input_json_params['inData'][i]['data'] = crypto.byte_array_to_base64(enc_data) input_json_params['inData'][i]['iv'] = input_json_params["sessionKeyIv"] logger.debug("encrypted indata - %s", crypto.byte_array_to_base64(enc_data)) elif e_key == "-".encode('UTF-8'): # Skip encryption and just encode workorder data to base64 format input_json_params['inData'][i]['data'] = crypto.byte_array_to_base64(data) else: #TODO: Explore the necessity of session iv enc_data = utility.encrypt_data(data, e_key, "0") input_json_params['inData'][i]['data'] = crypto.byte_array_to_base64(enc_data) input_json_params['inData'][i]['iv'] = format("0", '02x') logger.debug("encrypted indata - %s", crypto.byte_array_to_base64(enc_data)) i = i + 1 logger.debug("Workorder InData after encryption: %s", indata_objects)
def __encrypt_workorder_indata( self, input_json_params, session_key, session_iv, worker_encryption_key, data_key=None, data_iv=None): """ Function to encrypt inData of workorder Parameters: - input_json_params is inData and outData elements within the work order request as per TCF API 6.1.7 Work Order Data Formats. - session_key is a one-time encryption key generated by the participant submitting the work order. - session_iv is an initialization vector if required by the data encryption algorithm (encryptedSessionKey). The default is all zeros. - data_key is a one time key generated by participant used to encrypt work order indata - data_iv is an initialization vector used along with data_key. Default is all zeros. """ indata_objects = input_json_params['inData'] indata_objects.sort(key=lambda x: x['index']) input_json_params['inData'] = indata_objects logger.info("Encrypting Workorder Data") i = 0 for item in indata_objects: data = item['data'].encode('UTF-8') e_key = item['encryptedDataEncryptionKey'].encode('UTF-8') if (not e_key) or (e_key == "null".encode('UTF-8')): enc_data = utility.encrypt_data(data, session_key, session_iv) input_json_params['inData'][i]['data'] = \ crypto.byte_array_to_base64(enc_data) logger.debug( "encrypted indata - %s", crypto.byte_array_to_base64(enc_data)) elif e_key == "-".encode('UTF-8'): # Skip encryption and just encode workorder data to # base64 format. input_json_params['inData'][i]['data'] = \ crypto.byte_array_to_base64(data) else: enc_data = utility.encrypt_data(data, data_key, data_iv) input_json_params['inData'][i]['data'] = \ crypto.byte_array_to_base64(enc_data) logger.debug("encrypted indata - %s", crypto.byte_array_to_base64(enc_data)) i = i + 1 logger.debug("Workorder InData after encryption: %s", indata_objects)
def add_encrypted_request_hash(self): """ calculates request has based on EEA trusted-computing spec 6.1.8.1 and set encryptedRequestHash parameter in the request. """ sig_obj = signature.ClientSignature() concat_string = self.get_requester_nonce() + \ self.get_work_order_id() + \ self.get_worker_id() + \ self.get_workload_id() + \ self.get_requester_id() concat_bytes = bytes(concat_string, "UTF-8") #SHA-256 hashing is used hash_1 = crypto.byte_array_to_base64( crypto.compute_message_hash(concat_bytes)) hash_2 = sig_obj.calculate_datahash(self.get_in_data()) hash_3 = "" out_data = self.get_out_data() if out_data and len(out_data) > 0: hash_3 = sig_obj.calculate_datahash(out_data) concat_hash = hash_1 + hash_2 + hash_3 concat_hash = bytes(concat_hash, "UTF-8") self.final_hash = crypto.compute_message_hash(concat_hash) encrypted_request_hash = utility.encrypt_data(self.final_hash, self.session_key, self.session_iv) self.params_obj["encryptedRequestHash"] = crypto.byte_array_to_hex( encrypted_request_hash)
def test_encrypt_data(iv, enc_sess_key, data): data_bytes = bytes(data, 'ascii') enc_req_hash = utility.encrypt_data(data_bytes, enc_sess_key, iv) if enc_req_hash: logging.info("Test case: test_encrypt_data PASS...") else: logging.info("Test case: test_encrypt_data FAIL...") return enc_req_hash
def __encrypt_data(self, data, encrypted_data_encryption_key=None, data_iv=None): data = data.encode("UTF-8") if encrypted_data_encryption_key is None or \ encrypted_data_encryption_key == "" or \ encrypted_data_encryption_key == "null": enc_data = utility.encrypt_data(data, self.session_key, self.session_iv) return crypto.byte_array_to_base64(enc_data) elif encrypted_data_encryption_key == "-".encode('UTF-8'): # Skip encryption and just encode workorder data to base64 format enc_data = crypto.byte_array_to_base64(data) return enc_data else: enc_data = utility.encrypt_data(data, encrypted_data_encryption_key, data_iv) return crypto.byte_array_to_base64(enc_data)
def generate_client_signature(self, input_json_str, worker, private_key, session_key, session_iv, encrypted_session_key, data_key=None, data_iv=None): """ Function to generate client signature Parameters: - input_json_str is requester Work Order Request payload in a JSON-RPC based format defined 6.1.1 Work Order Request Payload - worker is a worker object to store all the common details of worker as per TCF API 8.1 Common Data for All Worker Types - private_key is Client private key - session_key is one time session key generated by the participant submitting the work order. - session_iv is an initialization vector if required by the data encryption algorithm (encryptedSessionKey). The default is all zeros. - data_key is a one time key generated by participant used to encrypt work order indata - data_iv is an intialization vector used along with data_key. Default is all zeros. - encrypted_session_key is a encrypted version of session_key. Returns a tuple containing signature and status """ if (self.__payload_json_check(input_json_str) is False): logger.error("ERROR: Signing the request failed") return None if (self.tcs_worker['HashingAlgorithm'] != worker.hashing_algorithm): logger.error( "ERROR: Signing the request failed. Hashing algorithm is not supported for %s", worker.hashing_algorithm) return None if (self.tcs_worker['SigningAlgorithm'] != worker.signing_algorithm): logger.error( "ERROR: Signing the request failed. Signing algorithm is not supported for %s", worker.signing_algorithm) return None input_json = json.loads(input_json_str) input_json_params = input_json['params'] input_json_params["sessionKeyIv"] = ''.join( format(i, '02x') for i in session_iv) encrypted_session_key_str = ''.join( format(i, '02x') for i in encrypted_session_key) self.__encrypt_workorder_indata(input_json_params, session_key, session_iv, worker.encryption_key, data_key, data_iv) if input_json_params["requesterNonce"] and \ is_hex(input_json_params["requesterNonce"]): nonce = crypto.string_to_byte_array( input_json_params["requesterNonce"]) else: # [NO_OF_BYTES] 16 BYTES for nonce, is the recommendation by NIST to # avoid collisions by the "Birthday Paradox". nonce = crypto.random_bit_string(NO_OF_BYTES) request_nonce_hash = crypto.compute_message_hash(nonce) nonce_hash = ( crypto.byte_array_to_base64(request_nonce_hash)).encode('UTF-8') hash_string_1 = self.__calculate_hash_on_concatenated_string( input_json_params, nonce_hash) data_objects = input_json_params['inData'] hash_string_2 = self.calculate_datahash(data_objects) hash_string_3 = "" if 'outData' in input_json_params: data_objects = input_json_params['outData'] data_objects.sort(key=lambda x: x['index']) hash_string_3 = self.calculate_datahash(data_objects) concat_string = hash_string_1 + hash_string_2 + hash_string_3 concat_hash = bytes(concat_string, 'UTF-8') final_hash = crypto.compute_message_hash(concat_hash) encrypted_request_hash = utility.encrypt_data(final_hash, session_key, session_iv) encrypted_request_hash_str = ''.join( format(i, '02x') for i in encrypted_request_hash) logger.debug("encrypted request hash: \n%s", encrypted_request_hash_str) #Update the input json params input_json_params["encryptedRequestHash"] = encrypted_request_hash_str status, signature = self.generate_signature(final_hash, private_key) if status == False: return SignatureStatus.FAILED input_json_params['requesterSignature'] = signature input_json_params["encryptedSessionKey"] = encrypted_session_key_str # Temporary mechanism to share client's public key. Not a part of Spec input_json_params['verifyingKey'] = self.public_key input_json_params['requesterNonce'] = crypto.byte_array_to_base64( request_nonce_hash) input_json['params'] = input_json_params input_json_str = json.dumps(input_json) logger.info("Request Json successfully Signed") return input_json_str, SignatureStatus.PASSED
def Main(args=None): ParseCommandLine(args) config["Logging"] = { "LogFile": "__screen__", "LogLevel": "INFO" } plogger.setup_loggers(config.get("Logging", {})) sys.stdout = plogger.stream_to_logger( logging.getLogger("STDOUT"), logging.DEBUG) sys.stderr = plogger.stream_to_logger( logging.getLogger("STDERR"), logging.WARN) logger.info("***************** AVALON *****************") # Connect to registry list and retrieve registry if not off_chain: direct_wrapper.init_worker_registry_list(config) registry_lookup_result = direct_wrapper.registry_lookup() if (registry_lookup_result[0] == 0): logger.warn("No registries found") sys.exit(1) registry_retrieve_result = direct_wrapper.registry_retrieve( registry_lookup_result[2][0]) config["tcf"]["json_rpc_uri"] = registry_retrieve_result[0] # Prepare worker direct_wrapper.init_worker_registry(config) global worker_id if not worker_id: worker_lookup_json = jrpc_request.WorkerLookupJson( 1, worker_type=1) worker_lookup_result = direct_wrapper.worker_lookup( worker_lookup_json) if "result" in worker_lookup_result and \ "ids" in worker_lookup_result["result"].keys(): if worker_lookup_result["result"]["totalCount"] != 0: worker_id = \ worker_lookup_result["result"]["ids"][0] else: logger.error("ERROR: No workers found") sys.exit(1) else: logger.error("ERROR: Failed to lookup worker") sys.exit(1) worker_retrieve_json = jrpc_request.WorkerRetrieveJson(2, worker_id) worker_obj.load_worker( direct_wrapper.worker_retrieve(worker_retrieve_json)) logger.info("********** Worker details Updated with Worker ID" + "*********\n%s\n", worker_id) # Convert workloadId to hex workload_id = "echo-result" workload_id = workload_id.encode("UTF-8").hex() # Create work order wo_submit_json = jrpc_request.WorkOrderSubmitJson( 3, 6000, "pformat", worker_id, workload_id, "0x2345", worker_encryption_key=base64.b64decode( worker_obj.worker_encryption_key).hex(), data_encryption_algorithm="AES-GCM-256") wo_id = wo_submit_json.get_work_order_id() # Sign work order private_key = utility.generate_signing_keys() session_key = utility.generate_key() session_iv = utility.generate_iv() encrypted_session_key = utility.generate_encrypted_key( session_key, worker_obj.worker_encryption_key) # Generate one time key used for encrypting inData data_key = utility.generate_key() # Initialation vector of size 12 bytes with all zeros. data_iv = bytearray(12) encrypted_key = utility.generate_encrypted_key( data_key, worker_obj.worker_encryption_key) encrypted_data_encryption_key = utility.encrypt_data( encrypted_key, session_key) encrypted_data_encryption_key_str = ''.join( format(i, '02x') for i in encrypted_data_encryption_key) data_iv_str = ''.join(format(i, '02x') for i in data_iv) wo_submit_json.add_in_data( message, None, encrypted_data_encryption_key_str, data_iv_str) # Submit work order direct_wrapper.init_work_order(config) direct_wrapper.work_order_submit( wo_submit_json, encrypted_session_key, worker_obj, private_key, session_key, session_iv, data_key, data_iv) # Retrieve result wo_get_result_json = jrpc_request.WorkOrderGetResultJson(4, wo_id) direct_wrapper.work_order_get_result( wo_get_result_json, session_key, session_iv, data_key, data_iv)