def _get_work_order_result(response_json, session_key, session_key_iv): encrypt = worker_encryption.WorkerEncrypt() encrypt.decrypt_work_order_data_json(response_json["result"]["outData"], session_key, session_key_iv) decrypted_out_bytes = response_json["result"]["outData"][0]["data"] decrypted_out_msg = decrypted_out_bytes.decode("UTF-8") return decrypted_out_msg
def __init__(self): super().__init__() self._worker_registry_list_instance = None self._worker_instance = None self._work_order_instance = None self._work_order_receipt_instance = None self.encrypt = worker_encryption.WorkerEncrypt() self.signer = worker_signing.WorkerSign()
def register_wo_processor(self, unique_verification_id, encryption_key, proof_data, mr_enclave): """ Request to register this WPE with the KME Parameters : @param unique_verification_id - Unique verifying key received from KME. @param encryption_key - encryption key of WPE @param proof_data - The IAS attestation report/DCAP quote @param mr_enclave - MRENCLAVE for this WPE Returns : @returns status - The status of the registration. True, for success. None, in case of errors. """ workload_id = "kme-reg" registration_params = { "unique_id": unique_verification_id, "proof_data": proof_data, "wpe_encryption_key": encryption_key, "mr_enclave": mr_enclave } in_data = [json.dumps(registration_params)] # Create session key and iv to sign work order request worker_encrypt = worker_encryption.WorkerEncrypt() session_key = worker_encrypt.generate_key() session_iv = worker_encrypt.generate_iv() wo_req = self._construct_wo_req( in_data, workload_id, self._worker.encryption_key, session_key, session_iv) response = self._post_and_get_result(wo_req) if "result" in response: wo_response_json = response["result"] if "error" not in wo_response_json and self._verify_res_signature( wo_response_json, self._worker.verification_key, wo_req["params"]["requesterNonce"]): decrypted_res = worker_encrypt.decrypted_response( wo_response_json, session_key, session_iv) # Response contains an array of results. In this case, the # array has single element and the data field is of interest. # It is integer with status of registration. return decrypted_res[0]['data'] return None else: logger.error("Could not register this WPE with the KME : {}" .format(response)) return None
def _generate_worker_keys(self): """ Generates worker signing and encryption keys. """ # Generate worker signing key logger.info("Generate worker signing and encryption keys") self.sign = worker_signing.WorkerSign() self.sign.generate_signing_key() self.worker_public_sign_key = self.sign.get_public_sign_key() # Generate worker encryption key self.encrypt = worker_encryption.WorkerEncrypt() self.encrypt.generate_rsa_key() self.worker_public_enc_key = self.encrypt.get_rsa_public_key() # Sign worker encryption key hash hash_obj = worker_hash.WorkerHash() hash_val = hash_obj.compute_message_hash(self.worker_public_enc_key) self.worker_public_enc_key_sign = self.sign.sign_message(hash_val)
def _create_work_order_request(workload_id, input_data_str, session_key, session_key_iv, worker_signup_json): worker_enc_key_str = worker_signup_json["encryption_key"] encrypt = worker_encryption.WorkerEncrypt() encrypted_session_key = encrypt.encrypt_session_key( session_key, worker_enc_key_str) msg_bytes = input_data_str.encode('UTF-8') input_json = dict() input_json["jsonrpc"] = "2.0" input_json["method"] = "WorkOrderSubmit" input_json["id"] = "1" input_json["params"] = dict() input_json["params"]["encryptedSessionKey"] = encrypted_session_key.hex() if session_key_iv: input_json["params"]["sessionKeyIv"] = session_key_iv.hex() input_json["params"]["workloadId"] = workload_id.encode("UTF-8").hex() input_json["params"]["workOrderId"] = secrets.token_hex(32) worker_id = hashlib.sha256("graphene-hello".encode("UTF-8")).hexdigest() input_json["params"]["workerId"] = worker_id input_json["params"]["requesterId"] = secrets.token_hex(32) input_json["params"]["requesterNonce"] = secrets.token_hex(32) in_data = dict() in_data["index"] = 0 in_data["dataHash"] = "" in_data["data"] = msg_bytes in_data["encryptedDataEncryptionKey"] = "null" in_data["iv"] = "" input_json["params"]["inData"] = [in_data] # Encrypt inData encrypt.encrypt_work_order_data_json(input_json["params"]["inData"], session_key, session_key_iv) req_hash = worker_hash.WorkerHash().calculate_request_hash( input_json["params"]) encrypted_req_hash = encrypt.encrypt_data(req_hash, session_key, session_key_iv) input_json["params"]["encryptedRequestHash"] = encrypted_req_hash.hex() return json.dumps(input_json)
def get_unique_verification_key(self, verification_key_nonce): """ Request wrapper to get a unique id from the KME Parameters : @param verification_key_nonce - Random nonce generated by this WPE Returns : @returns result - Result received from the KME which includes the public verification key which is supposed to be included in REPORTDATA by the WPE. None, in case of failure. """ workload_id = "kme-uid" in_data = [verification_key_nonce] # Create session key and iv to sign work order request worker_encrypt = worker_encryption.WorkerEncrypt() session_key = worker_encrypt.generate_key() session_iv = worker_encrypt.generate_iv() wo_req = self._construct_wo_req( in_data, workload_id, self._worker.encryption_key, session_key, session_iv) response = self._post_and_get_result(wo_req) if "result" in response: wo_response_json = response["result"] if self._verify_res_signature(wo_response_json, self._worker.verification_key, wo_req["params"]["requesterNonce"]): decrypted_res = worker_encrypt.decrypted_response( wo_response_json, session_key, session_iv) # Response contains an array of results. In this case, the # array has single element and the data field is of interest. # The data contains result,verification_key and # verification_key_signature delimited by ' '. # @TODO : Update to use multiple out_data fields. return decrypted_res[0]['data'] return None else: logger.error("Could not get a unique id from the KME : {}" .format(response)) return None
def get_unique_verification_key(self, verification_key_nonce): """ Request wrapper to get a unique id from the KME Parameters : @param verification_key_nonce - Random nonce generated by this WPE Returns : @returns result - Result received from the KME which includes the public verification key which is supposed to be included in REPORTDATA by the WPE. None, in case of failure. """ workload_id = "kme-uid" in_data = [verification_key_nonce] logger.info("in wpe_requester.py get_unique_verification_key") # Create session key and iv to sign work order request worker_encrypt = worker_encryption.WorkerEncrypt() session_key = worker_encrypt.generate_session_key() session_iv = worker_encrypt.generate_iv() wo_req = self._construct_wo_req(in_data, workload_id, self._worker.encryption_key, session_key, session_iv) response = self._post_and_get_result(wo_req) if "result" in response: wo_response_json = response["result"] if self._verify_res_signature(wo_response_json, self._worker.verification_key, wo_req["params"]["requesterNonce"]): return self.decrypt_wo_response(wo_response_json, session_key, session_iv, worker_encrypt) return None else: logger.error( "Could not get a unique id from the KME : {}".format(response)) return None
def preprocess_work_order(self, wo_request, encryption_key): """ Request to preprocess a work order Parameters : @param wo_request - The original work order request as str @param encryption_key - WPE's public encryption key Returns : @returns result - Result from KME that includes the workorder key info. error response, in case of failure. """ workload_id = "kme-preprocess" in_data = [wo_request, encryption_key] # Create session key and iv to sign work order request worker_encrypt = worker_encryption.WorkerEncrypt() session_key = worker_encrypt.generate_key() session_iv = worker_encrypt.generate_iv() wo_req = self._construct_wo_req( in_data, workload_id, self._worker.encryption_key, session_key, session_iv) response = self._post_and_get_result(wo_req) if "result" in response: wo_response_json = response["result"] if self._verify_res_signature(wo_response_json, self._worker.verification_key, wo_req["params"]["requesterNonce"]): decrypted_res = worker_encrypt.decrypted_response( wo_response_json, session_key, session_iv) # Response contains an array of results. In this case, the # array has single element and the data field is of interest. return decrypted_res[0]['data'] return None else: logger.error("Could not preprocess work order at KME : {}" .format(response)) return response
def preprocess_work_order(self, wo_request, encryption_key): """ Request to preprocess a work order Parameters : @param wo_request - The original work order request as str @param encryption_key - WPE's public encryption key Returns : @returns result - Result from KME that includes the workorder key info. error response, in case of failure. """ workload_id = "kme-preprocess" in_data = [wo_request, encryption_key] # Create session key and iv to sign work order request worker_encrypt = worker_encryption.WorkerEncrypt() session_key = worker_encrypt.generate_session_key() session_iv = worker_encrypt.generate_iv() wo_req = self._construct_wo_req(in_data, workload_id, self._worker.encryption_key, session_key, session_iv) response = self._post_and_get_result(wo_req) if "result" in response: wo_response_json = response["result"] logger.info("verify result signature\n\n") if self._verify_res_signature(wo_response_json, self._worker.verification_key, wo_req["params"]["requesterNonce"]): return self.decrypt_wo_response(wo_response_json, session_key, session_iv, worker_encrypt) return None else: logger.error( "Could not preprocess work order at KME : {}".format(response)) return response
def _generate_session_key_iv(): encrypt = worker_encryption.WorkerEncrypt() session_key = encrypt.generate_session_key() session_key_iv = encrypt.generate_iv() return (session_key, session_key_iv)
def Main(args=None): parser = GenericClient(args) generic_client_obj = None if parser.is_direct_mode(): generic_client_obj = DirectModelGenericClient(parser.get_config()) elif parser.get_blockchain_type() in ["fabric", "ethereum"]: generic_client_obj = ProxyModelGenericClient( parser.get_config(), parser.get_blockchain_type()) else: logging.error("Invalid inputs to generic client") sys.exit(-1) # Retrieve JSON RPC uri from registry list if not parser.uri() and parser.mode() == "listing": self._uri = self.retrieve_uri_from_registry_list(self._config) # Prepare worker worker_id = parser.get_worker_id() if worker_id is None: logging.error("worker id is missing") sys.exit(-1) if worker_id is None: logging.error("\n Unable to get worker {}\n".format(worker_id)) sys.exit(-1) # Retrieve worker details worker_obj = generic_client_obj.get_worker_details(worker_id) if worker_obj is None: logging.error("Unable to retrieve worker details\n") sys.exit(-1) encrypt = worker_encrypt.WorkerEncrypt() # Create session key and iv to sign work order request session_key = encrypt.generate_session_key() session_iv = encrypt.generate_iv() # Do worker verification generic_client_obj.do_worker_verification(worker_obj) logging.info( "**********Worker details Updated with Worker ID" + "*********\n%s\n", worker_id) # Create work order if parser.in_data_plain_text(): # As per TC spec, if encryptedDataEncryptionKey is "-" then # input data is not encrypted encrypted_data_encryption_key = "-" else: # As per TC spec, if encryptedDataEncryptionKey is not # provided then set it to None which means # use default session key to encrypt input data encrypted_data_encryption_key = None code, wo_params = generic_client_obj.create_work_order_params( worker_id, parser.workload_id(), parser.in_data(), worker_obj.encryption_key, session_key, session_iv, encrypted_data_encryption_key) if not code: logging.error("Work order request creation failed \ \n {}".format(wo_params)) sys.exit(-1) signer = worker_signing.WorkerSign() client_private_key = signer.generate_signing_key() if parser.requester_signature(): # Add requester signature and requester verifying_key if wo_params.add_requester_signature(client_private_key) is False: logging.info("Work order request signing failed") sys.exit(-1) submit_status, wo_submit_res = generic_client_obj.submit_work_order( wo_params) if submit_status: # Create receipt if parser.show_receipt(): generic_client_obj.create_work_order_receipt( wo_params, client_private_key) work_order_id = wo_params.get_work_order_id() # Retrieve work order result status, wo_res = generic_client_obj.get_work_order_result( work_order_id) # Check if result field is present in work order response if status: # Verify work order response signature if generic_client_obj.verify_wo_response_signature( wo_res['result'], worker_obj.verification_key, wo_params.get_requester_nonce()) is False: logging.error("Work order response signature" " verification Failed") sys.exit(-1) # Decrypt work order response if parser.show_decrypted_output(): decrypted_res = generic_client_obj.decrypt_wo_response( wo_res['result']) logging.info( "\nDecrypted response:\n {}".format(decrypted_res)) else: logging.error("\n Work order get result failed\n") sys.exit(-1) if parser.show_receipt(): # Retrieve receipt retrieve_wo_receipt = \ generic_client_obj.retrieve_work_order_receipt( work_order_id) # Verify receipt signature if retrieve_wo_receipt: if "result" in retrieve_wo_receipt: if generic_client_obj.verify_receipt_signature( retrieve_wo_receipt) is False: logging.error("Receipt signature verification Failed") sys.exit(-1) else: logging.info("Work Order receipt retrieve failed") sys.exit(-1) else: logging.error("Work order submit failed {}".format(wo_submit_res)) sys.exit(-1)
def main(argv): encrypt = worker_encryption.WorkerEncrypt() # Test session key Encryption and Decryption encrypt.generate_rsa_key() worker_rsa_public_key = encrypt.get_rsa_public_key() logger.info("worker_rsa_public_key = {}".format(worker_rsa_public_key)) session_key = encrypt.generate_session_key() encrypted_session_key = encrypt.encrypt_session_key(session_key) decrypted_session_key = encrypt.decrypt_session_key(encrypted_session_key) if session_key == decrypted_session_key: logger.info("Session key Encryption and Decryption Success") else: logger.error("Session key Encryption and Decryption Success") # Test Encryption and Decryption message = "Hello world" session_key = encrypt.generate_session_key() session_key_iv = encrypt.generate_iv() encrypt_msg_bytes = encrypt.encrypt_data(message.encode("utf-8"), session_key, session_key_iv) decrypt_message = encrypt.decrypt_data(encrypt_msg_bytes, session_key, session_key_iv) decrypt_message = decrypt_message.decode("utf-8") if message == decrypt_message: logger.info("Message Encryption and Decryption Success") else: logger.error("Message Encryption and Decryption Success") # Test inData Encryption and Decryption input_json = dict() input_json["jsonrpc"] = "2.0" input_json["method"] = "WorkOrderSubmit" input_json["id"] = "1" input_json["params"] = dict() inData = dict() inData["index"] = 0 inData["dataHash"] = "" inData["data"] = message.encode("utf-8") inData["encryptedDataEncryptionKey"] = "null" inData["iv"] = "" input_json["params"]["inData"] = [inData] # Encrypt inData (will be done at client end) encrypt.encrypt_work_order_data_json(input_json["params"]["inData"], session_key, session_key_iv) # Decrypt inData encrypt.decrypt_work_order_data_json(input_json["params"]["inData"], session_key, session_key_iv) for item in input_json["params"]["inData"]: decrypted_data_bytes = item["data"] decrypted_data_str = decrypted_data_bytes.decode("UTF-8") logger.info("Decrypted data :{}".format(decrypted_data_str)) if message == input_json["params"]["inData"][0]["data"].decode("UTF-8"): logger.info("inData Decryption Success") else: logger.error("inData Decryption Success") # Encrypt outData outData = inData out_message = "Received Hello world" outData["data"] = out_message.encode("UTF-8") input_json["params"]["outData"] = [outData] encrypt.encrypt_work_order_data_json(input_json["params"]["outData"], session_key, session_key_iv) # Decrypt outData (will be done at client end) encrypt.decrypt_work_order_data_json(input_json["params"]["outData"], session_key, session_key_iv) decrypted_out_bytes = input_json["params"]["outData"][0]["data"] decrypted_out_message = decrypted_out_bytes.decode("UTF-8") if out_message == decrypted_out_message: logger.info("outData Decryption Success") else: logger.error("outData Decryption Success")
def local_main(config): global input_json_str if not input_json_str and not input_json_dir: LOGGER.error("JSON input file is not provided") exit(1) if not output_json_file_name: LOGGER.error("JSON output file is not provided") exit(1) if not server_uri: LOGGER.error("Server URI is not provided") exit(1) LOGGER.info("Execute work order") uri_client = HttpJrpcClient(server_uri) response = None wo_id = None if input_json_dir: directory = os.fsencode(input_json_dir) files = os.listdir(directory) for file in sorted(files): LOGGER.info("---------------- Input file name: %s -------------\n", file.decode("utf-8")) input_json_str = futils.read_json_file( (directory.decode("utf-8") + file.decode("utf-8"))) # ----------------------------------------------------------------- # If Client request is WorkOrderSubmit, a requester payload's # signature with the requester private signing key is generated. if "WorkOrderSubmit" in input_json_str: # Update workOrderId , workerId and workloadId input_json_obj = json.loads(input_json_str) wo_id = hex(random.randint(1, 2**64 - 1)) input_json_obj["params"]["workOrderId"] = wo_id input_json_obj["params"]["workerId"] = worker_id # Convert workloadId to a hex string and update the request workload_id = input_json_obj["params"]["workloadId"] workload_id_hex = workload_id.encode("UTF-8").hex() input_json_obj["params"]["workloadId"] = workload_id_hex encrypt = worker_encryption.WorkerEncrypt() # Generate session key, session iv and encrypted session key session_key = encrypt.generate_session_key() session_iv = encrypt.generate_iv() encrypted_session_key = encrypt.encrypt_session_key( session_key, worker_obj.encryption_key) input_json_obj["params"]["encryptedSessionKey"] = \ crypto_utility.byte_array_to_hex(encrypted_session_key) input_json_obj["params"]["sessionKeyIv"] = \ crypto_utility.byte_array_to_hex(session_iv) if "requesterNonce" in input_json_obj["params"]: if len(input_json_obj["params"]["requesterNonce"]) == 0: # [NO_OF_BYTES] 16 BYTES for nonce. # This is the recommendation by NIST to # avoid collisions by the "Birthday Paradox". requester_nonce = secrets.token_hex(NO_OF_BYTES) input_json_obj["params"]["requesterNonce"] = \ requester_nonce requester_nonce = input_json_obj["params"]["requesterNonce"] # Encode data in inData for data_obj in input_json_obj["params"]["inData"]: encoded_data = data_obj["data"].encode('UTF-8') data_obj["data"] = encoded_data # Encrypt inData encrypt.encrypt_work_order_data_json( input_json_obj["params"]["inData"], session_key, session_iv) req_hash = worker_hash.WorkerHash().calculate_request_hash( input_json_obj["params"]) encrypted_req_hash = encrypt.encrypt_data( req_hash, session_key, session_iv) input_json_obj["params"]["encryptedRequestHash"] = \ encrypted_req_hash.hex() signer = worker_signing.WorkerSign() signer.generate_signing_key() wo_req_sig = signer.sign_message(req_hash) input_json_obj["params"]["requesterSignature"] = \ crypto_utility.byte_array_to_base64(wo_req_sig) input_json_obj["params"]["verifyingKey"] = \ signer.get_public_sign_key().decode('utf-8') input_json_str = json.dumps(input_json_obj) if input_json_str is None: continue # ----------------------------------------------------------------- # Update the worker ID if response: if "workerId" in input_json_str: # Retrieve the worker id from the "WorkerRetrieve" # response and update the worker id information for # further json requests. if "result" in response and \ "ids" in response["result"].keys() and \ len(response["result"]["ids"]) > 0: input_json_final = json.loads(input_json_str) worker_id = response["result"]["ids"][0] input_json_final["params"]["workerId"] = worker_id input_json_str = json.dumps(input_json_final) LOGGER.info( "********** Worker details Updated with " "Worker ID*********\n%s\n", input_json_str) # ----------------------------------------------------------------- if "WorkOrderGetResult" in input_json_str or \ "WorkOrderReceiptRetrieve" in input_json_str: input_json_obj = json.loads(input_json_str) input_json_obj["params"]["workOrderId"] = wo_id input_json_str = json.dumps(input_json_obj) LOGGER.info("*********Request Json********* \n%s\n", input_json_str) response = uri_client._postmsg(input_json_str) LOGGER.info("**********Received Response*********\n%s\n", response) # ----------------------------------------------------------------- # Worker details are loaded into Worker_Obj if "WorkerRetrieve" in input_json_str and "result" in response: worker_obj.load_worker(response["result"]["details"]) # ----------------------------------------------------------------- # Poll for "WorkOrderGetResult" and break when you get the result while ("WorkOrderGetResult" in input_json_str and "result" not in response): if response["error"]["code"] != WorkOrderStatus.PENDING: break response = uri_client._postmsg(input_json_str) LOGGER.info("Received Response: %s, \n \n ", response) time.sleep(3) # ----------------------------------------------------------------- # Verify the signature if "WorkOrderGetResult" in input_json_str: if "error" in response: # Response has error, hence skip Signature verification LOGGER.info("Work order response has error; " "skipping signature verification") continue sig_bool = signer.verify_signature(response['result'], worker_obj.verification_key, requester_nonce) try: if sig_bool > 0: LOGGER.info("Signature Verified") encrypt.decrypt_work_order_data_json( response['result']['outData'], session_key, session_iv) else: LOGGER.info("Signature verification Failed") exit(1) except Exception as e: LOGGER.error("ERROR: Failed to verify signature of " + "work order response") exit(1) # ----------------------------------------------------------------- else: LOGGER.info("Input Request %s", input_json_str) response = uri_client._postmsg(input_json_str) LOGGER.info("Received Response: %s , \n \n ", response) exit(0)
def __init__(self): self.params_obj = {} self.signer = worker_signing.WorkerSign() self.encrypt = worker_encryption.WorkerEncrypt() self.hasher = worker_hash.WorkerHash()