def __encrypt_data(self, data, encrypted_data_encryption_key=None, data_iv=None): """ Encrypt data and encode in base64 format. If key is None or "" or null, use session key. If key is "-" skip encryption and just encode base64. Parameters: data Data to encrypt encrypted_data_encryption_key Encryption private key. Pass "-" for no encryption. Pass "" or None to encrypt with the session key data_iv IV for data Returns: Encrypted (if requested) and base64 encoded data. """ 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 = crypto_utility.encrypt_data( data, self.session_key, self.session_iv ) return crypto_utility.byte_array_to_base64(enc_data) elif encrypted_data_encryption_key == "-": # Skip encryption and just encode workorder data to # base64 format. enc_data = crypto_utility.byte_array_to_base64(data) return enc_data else: enc_data = crypto_utility.encrypt_data( data, encrypted_data_encryption_key, data_iv) return crypto_utility.byte_array_to_base64(enc_data)
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 Trusted Compute EEA 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'] 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 = crypto_utility.encrypt_data(data, session_key, session_iv) input_json_params['inData'][i]['data'] = \ crypto_utility.byte_array_to_base64(enc_data) logger.debug("encrypted indata - %s", crypto_utility.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_utility.byte_array_to_base64(data) else: enc_data = crypto_utility.encrypt_data(data, data_key, data_iv) input_json_params['inData'][i]['data'] = \ crypto_utility.byte_array_to_base64(enc_data) logger.debug("encrypted indata - %s", crypto_utility.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 hash 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 = crypto_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 = crypto_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 = crypto_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 = crypto_utility.encrypt_data( data, encrypted_data_encryption_key, data_iv) return crypto.byte_array_to_base64(enc_data)
def add_encrypted_request_hash(self): """ Calculates request hash based on EEA trusted-computing spec 6.1.8.1 and set encryptedRequestHash parameter in the request. """ try: sig_obj = signature.ClientSignature() self.request_hash = sig_obj.calculate_request_hash(self.params_obj) encrypted_request_hash = crypto_utility.encrypt_data( self.request_hash, self.session_key, self.session_iv) enc_request_hash_hex = crypto_utility.byte_array_to_hex( encrypted_request_hash) self.params_obj["encryptedRequestHash"] = enc_request_hash_hex return None except Exception as err: return util.create_error_response( WorkOrderStatus.INVALID_PARAMETER_FORMAT_OR_VALUE, 0, err)
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 Trusted Compute EEA 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 initialization 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 input_json_str, SignatureStatus.FAILED 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 input_json_str, SignatureStatus.FAILED 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 input_json_str, SignatureStatus.FAILED input_json = json.loads(input_json_str) input_json_params = input_json['params'] input_json_params["sessionKeyIv"] = byte_array_to_hex_str(session_iv) encrypted_session_key_str = byte_array_to_hex_str( encrypted_session_key) self.__encrypt_workorder_indata( input_json_params, session_key, session_iv, worker.encryption_key, data_key, data_iv) if "requesterNonce" in input_json_params: if len(input_json_params["requesterNonce"]) == 0: # [NO_OF_BYTES] 16 BYTES for nonce. # This is the recommendation by NIST to # avoid collisions by the "Birthday Paradox". input_json_params["requesterNonce"] = secrets.token_hex( NO_OF_BYTES) elif not is_valid_hex_str(input_json_params["requesterNonce"]): logger.error("Invalid data format for requesterNonce") return input_json_params, SignatureStatus.FAILED else: logger.error("Missing parameter requesterNonce") return input_json_params, SignatureStatus.FAILED hash_string_1 = self.__calculate_hash_on_concatenated_string( input_json_params, input_json_params["requesterNonce"].encode( 'UTF-8' )) 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'] 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 = crypto_utility.encrypt_data( final_hash, session_key, session_iv) encrypted_request_hash_str = \ byte_array_to_hex_str(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 is False: return input_json_str, 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'] = 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)["result"]["details"]) 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() # Initialization 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)