Ejemplo n.º 1
0
    def test_byte_array_to_hex_str(self):
        """Tests to verify byte_array_to_hex_str(in_byte_array) function
        """
        bytearr = b'teststring'  # positive case
        hexstr = byte_array_to_hex_str(bytearr)
        self.assertEqual(hexstr, "74657374737472696e67")

        bytearr = b''  # empty array case
        hexstr = byte_array_to_hex_str(bytearr)
        self.assertEqual(hexstr, "")
Ejemplo n.º 2
0
    def registry_update(self, org_id, uri, sc_addr, app_type_ids):
        """
        Update a registry.

        Parameters:
        org_id       bytes[] identifies organization that hosts the
                     registry, e.g. a bank in the consortium or an
                     anonymous entity
        uri          string that defines a URI for this registry that
                     supports the Off-Chain Worker Registry
                     JSON RPC API
        sc_addr      bytes[] defines a Fabric chain code name that
                     runs the Worker Registry Smart Contract API
                     smart contract for this registry
        app_type_ids []bytes[] is an optional parameter that defines
                     application types supported by the worker
                     managed by the registry

        Returns:
        Transaction receipt on success or None on error.
        """
        if (self.__fabric_wrapper is not None):
            if (is_valid_hex_str(binascii.hexlify(org_id).decode("utf8")) is
                    False):
                logging.error("Invalid Org id {}".format(org_id))
                return None
            if (sc_addr is not None and is_valid_hex_str(
                    binascii.hexlify(sc_addr).decode("utf8")) is False):
                logging.error(
                    "Invalid smart contract address {}".format(sc_addr))
                return None
            if (not uri):
                logging.error("Empty uri {}".format(uri))
                return None
            app_ids = []
            for aid in app_type_ids:
                if (is_valid_hex_str(binascii.hexlify(aid).decode("utf8")) is
                        False):
                    logging.error("Invalid application id {}".format(aid))
                    return None
                else:
                    app_ids.append(byte_array_to_hex_str(aid))

            params = []
            params.append(byte_array_to_hex_str(org_id))
            params.append(uri)
            params.append(byte_array_to_hex_str(sc_addr))
            params.append(','.join(app_ids))
            txn_status = self.__fabric_wrapper.invoke_chaincode(
                self.CHAIN_CODE, 'registryUpdate', params)
            return txn_status
        else:
            logging.error("Fabric wrapper instance is not initialized")
            return None
Ejemplo n.º 3
0
    def registry_set_status(self, org_id, status):
        """
        Set registry status.

        Parameters:
        org_id  bytes[] identifies organization that hosts the
                registry, e.g. a bank in the consortium or an
                anonymous entity
        status  Defines the registry status to set.
                The currently defined values are:
                1 - the registry is active
                2 - the registry is temporarily "off-line"
                3 - the registry is decommissioned

        Returns:
        Transaction receipt on success or None on error.
        """
        if (self.__fabric_wrapper is not None):
            if (is_valid_hex_str(binascii.hexlify(org_id).decode("utf8")) is
                    False):
                logging.info("Invalid Org id {}".format(org_id))
                return None
            if not isinstance(status, RegistryStatus):
                logging.info("Invalid registry status {}".format(status))
                return None
            params = []
            params.append(byte_array_to_hex_str(org_id))
            params.append(str(status))
            txn_status = self.__fabric_wrapper.invoke_chaincode(
                self.CHAIN_CODE, 'registrySetStatus', params)
            return txn_status
        else:
            logging.error("Fabric wrapper instance is not initialized")
            return None
 def registry_retrieve(self, org_id):
     """
     Retrieving Registry Information identified by organization id
     It returns tuple containing following on success.
     1. uri is string defines a URI for this registry that supports the
     Off-Chain Worker Registry JSON RPC API. It is going to be None
     for proxy model.
     2. sc_addr Fabric address for worker registry smart contract
     address.
     3. application_type_ids list of application ids(array of byte[])
     4. status of the registry
     Returns None on error.
     """
     if (self.__fabric_wrapper is not None):
         if (is_valid_hex_str(binascii.hexlify(org_id).decode("utf8")) is
                 False):
             logging.info("Invalid Org id {}".format(org_id))
             return None
         else:
             params = []
             params.append(byte_array_to_hex_str(org_id))
             registryDetails = \
                 self.__fabric_wrapper.invoke_chaincode(
                     self.CHAIN_CODE,
                     'registryRetrieve',
                     params
                 )
             return registryDetails
     else:
         logging.error("Fabric wrapper instance is not initialized")
         return None
 def registry_lookup(self, app_type_id=None):
     """
     Registry Lookup identified by application type id
     It returns following
     1. totalCount is the total number of entries matching a specified
     lookup criteria.  If this number is larger than the size of the ids
     array, the caller should use the lookupTag to call workerLookUpNext
     to retrieve the rest of the ids.
     2. lookupTag is an optional parameter. If it is returned, it means that
     there are more matching registry ids that can be retrieved by calling
     the function registry_lookup_next with this tag as an input parameter.
     3. ids is an array of the registry organization ids that match the
     input parameters
     Returns tuple containing count, lookup tag and list of organization
     ids on success and returns None on error.
     """
     if (self.__fabric_wrapper is not None):
         if app_type_id is not None:
             if is_valid_hex_str(
                     binascii.hexlify(app_type_id).decode("utf8")):
                 params = []
                 params.append(byte_array_to_hex_str(app_type_id))
                 lookupResult = \
                     self.__fabric_wrapper.invoke_chaincode(
                         self.CHAIN_CODE,
                         'registryLookUp',
                         params)
             else:
                 logging.info(
                     "Invalid application type id {}".format(app_type_id))
                 return None
     else:
         logging.error("Fabric wrapper instance is not initialized")
         return None
Ejemplo n.º 6
0
def verify_data_hash(msg, data_hash):
    '''
    Function to verify data hash
    msg - Input text
    data_hash - hash of the data in hex format
    '''
    verify_success = True
    msg_hash = compute_data_hash(msg)
    # Convert both hash hex string values to upper case
    msg_hash_hex = hex_utils.byte_array_to_hex_str(msg_hash).upper()
    data_hash = data_hash.upper()
    if msg_hash_hex == data_hash:
        logger.info("Computed hash of message matched with data hash")
    else:
        logger.error("Computed hash of message does not match with data hash")
        verify_success = False
    return verify_success
 def test_worker_lookup(self):
     logging.info(
         "Calling worker_lookup..\n worker_type: %d\n orgId: %s\n " +
         "applicationId: %s", self.__worker_type.value,
         hex_to_utf8(self.__org_id), hex_to_utf8(self.__application_ids[0]))
     result = self.__eth_conn.worker_lookup(
         self.__worker_type,
         '419c007ce1f6ecb2e52a830b03a0c8be36438b94c950d9cf2aeb48b0f99a8276',
         '7b1d714fc499ddc59dde26683a0bf928848801087dc5f0372c340c120848ed7b')
     logging.info("worker_lookup result {} {}".format(result, type(result)))
     logging.info("worker_lookup status {} {} {}".format(
         result[0], result[1], result[2]))
     match = byte_array_to_hex_str(self.__worker_id) in result[2]
     self.assertEqual(result[0], 1,
                      "Worker lookup response count doesn't match")
     self.assertTrue(match,
                     "Worker lookup response worker id doesn't match")
Ejemplo n.º 8
0
    def _generate_nonce(self, params):
        """
        Generate nonce of length specified in params.

        Parameters :
            params: Parameters received in request
        Returns :
            JSON RPC response containing requested nonce.
        """
        nonce_size = params["nonce_size"]
        # Generate random bytes of size equivalent to nonce_size/2,
        # so that when encoded to hex string results in string of
        # size equal to nonce_size
        nonce_bytes = crypto_utility.generate_random_bytes(int(nonce_size / 2))
        # Convert nonce to hex string and persist in the EnclaveData
        self._nonce = byte_array_to_hex_str(nonce_bytes)
        return json.dumps({"nonce": self._nonce})
Ejemplo n.º 9
0
    def registry_lookup_next(self, app_type_id, lookup_tag):
        """
        Get additional registry lookup results.
        This function is called to retrieve additional results of the
        Registry lookup initiated by the registry_lookup call.

        Parameters:
        app_type_id    Application type ID that has to be
                       supported by the workers retrieved
        lookup_tag     Returned by a previous call to either this function
                       or to registry_lookup

        Returns:
        Outputs a tuple on success containing the following:
        total_count    Total number of entries matching the lookup
                       criteria. If this number is larger than the number
                       of IDs returned so far, the caller should use
                       lookup_tag to call registry_lookup_next to
                       retrieve the rest of the IDs
        new_lookup_tag is an optional parameter. If it is returned, it means
                       that there are more matching registry IDs that can be
                       retrieved by calling this function again with this tag
                       as an input parameter
        ids            Array of the registry IDs that match the input
                       parameters

        Returns None on error.
        """
        if (self.__fabric_wrapper is not None):
            if is_valid_hex_str(binascii.hexlify(app_type_id).decode("utf8")):
                params = []
                params.append(byte_array_to_hex_str(app_type_id))
                params.append(lookup_tag)
                lookupResult = self.__fabric_wrapper.invoke_chaincode(
                    self.CHAIN_CODE, 'registryLookUpNext', params)
            else:
                logging.info(
                    "Invalid application type id {}".format(app_type_id))
                return None
        else:
            logging.error("Fabric wrapper instance is not initialized")
            return None
Ejemplo n.º 10
0
    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
Ejemplo n.º 11
0
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:
        registry_list_instance = direct_jrpc.get_worker_registry_list_instance(
        )

        # Lookup returns tuple, first element is number of registries and
        # second is element is lookup tag and
        # third is list of organization ids.
        registry_count, lookup_tag, registry_list = \
            registry_list_instance.registry_lookup()
        logger.info("\n Registry lookup response: registry count: {} " +
                    "lookup tag: {} registry list: {}\n".format(
                        registry_count, lookup_tag, registry_list))
        if (registry_count == 0):
            logger.warn("No registries found")
            sys.exit(1)

        # Retrieve the first registry details.
        registry_retrieve_result = registry_list_instance.registry_retrieve(
            registry_list[0])
        logger.info("\n Registry retrieve response: {}\n".format(
            registry_retrieve_result))
        config["tcf"]["json_rpc_uri"] = registry_retrieve_result[0]

    # Prepare worker
    req_id = 31
    global worker_id
    worker_registry_instance = direct_jrpc.get_worker_registry_instance()
    if not worker_id:
        worker_lookup_result = worker_registry_instance.worker_lookup(
            worker_type=WorkerType.TEE_SGX, id=req_id)
        logger.info("\n Worker lookup response: {}\n".format(
            json.dumps(worker_lookup_result, indent=4)))
        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)
    req_id += 1
    worker_retrieve_result = worker_registry_instance.worker_retrieve(
        worker_id, req_id)
    logger.info("\n Worker retrieve response: {}\n".format(
        json.dumps(worker_retrieve_result, indent=4)))
    worker_obj.load_worker(worker_retrieve_result)

    logger.info(
        "**********Worker details Updated with Worker ID" + "*********\n%s\n",
        worker_id)

    # Convert workloadId to hex
    workload_id = "echo-result".encode("UTF-8").hex()
    work_order_id = secrets.token_hex(32)
    requester_id = secrets.token_hex(32)
    session_iv = utility.generate_iv()
    session_key = utility.generate_key()
    requester_nonce = secrets.token_hex(16)

    # Create work order
    wo_params = WorkOrderParams(
        work_order_id,
        worker_id,
        workload_id,
        requester_id,
        session_key,
        session_iv,
        requester_nonce,
        result_uri=" ",
        notify_uri=" ",
        worker_encryption_key=worker_obj.encryption_key,
        data_encryption_algorithm="AES-GCM-256")
    # Add worker input data
    if input_data_hash:
        # Compute data hash for data params inData
        data_hash = utility.compute_data_hash(message)
        # Convert data_hash to hex
        data_hash = hex_utils.byte_array_to_hex_str(data_hash)
        wo_params.add_in_data(message, data_hash)
    else:
        wo_params.add_in_data(message)

    # Encrypt work order request hash
    wo_params.add_encrypted_request_hash()

    private_key = utility.generate_signing_keys()
    if requester_signature:
        # Add requester signature and requester verifying_key
        if wo_params.add_requester_signature(private_key) is False:
            logger.info("Work order request signing failed")
            exit(1)

    # Submit work order
    logger.info("Work order submit request : %s, \n \n ",
                wo_params.to_jrpc_string(req_id))
    work_order_instance = direct_jrpc.get_work_order_instance()
    req_id += 1
    response = work_order_instance.work_order_submit(
        wo_params.get_work_order_id(),
        wo_params.get_worker_id(),
        wo_params.get_requester_id(),
        wo_params.to_string(),
        id=req_id)
    logger.info("Work order submit response : {}\n ".format(
        json.dumps(response, indent=4)))

    if "error" in response and response["error"]["code"] != \
            WorkOrderStatus.PENDING:
        sys.exit(1)

    # Create receipt
    wo_receipt_instance = direct_jrpc.get_work_order_receipt_instance()
    req_id += 1
    # Create work order receipt object using WorkOrderReceiptRequest class
    wo_request = json.loads(wo_params.to_jrpc_string(req_id))
    wo_receipt_obj = WorkOrderReceiptRequest()
    wo_create_receipt = wo_receipt_obj.create_receipt(
        wo_request, ReceiptCreateStatus.PENDING.value, private_key)
    logger.info("Work order create receipt request : {} \n \n ".format(
        json.dumps(wo_create_receipt, indent=4)))
    # Submit work order create receipt jrpc request
    wo_receipt_resp = wo_receipt_instance.work_order_receipt_create(
        wo_create_receipt["workOrderId"], wo_create_receipt["workerServiceId"],
        wo_create_receipt["workerId"], wo_create_receipt["requesterId"],
        wo_create_receipt["receiptCreateStatus"],
        wo_create_receipt["workOrderRequestHash"],
        wo_create_receipt["requesterGeneratedNonce"],
        wo_create_receipt["requesterSignature"],
        wo_create_receipt["signatureRules"],
        wo_create_receipt["receiptVerificationKey"], req_id)
    logger.info("Work order create receipt response : {} \n \n ".format(
        wo_receipt_resp))
    # Retrieve result
    req_id += 1
    res = work_order_instance.work_order_get_result(work_order_id, req_id)

    logger.info("Work order get result : {}\n ".format(
        json.dumps(res, indent=4)))
    sig_obj = signature.ClientSignature()
    if "result" in res:
        status = sig_obj.verify_signature(res, worker_obj.verification_key)
        try:
            if status == SignatureStatus.PASSED:
                logger.info(
                    "Work order response signature verification Successful")
                decrypted_res = utility.decrypted_response(
                    res, session_key, session_iv)
                logger.info("\nDecrypted response:\n {}".format(decrypted_res))
                if input_data_hash:
                    decrypted_data = decrypted_res[0]["data"]
                    data_hash_in_resp = (decrypted_res[0]["dataHash"]).upper()
                    # Verify data hash in response
                    if utility.verify_data_hash(decrypted_data,
                                                data_hash_in_resp) is False:
                        sys.exit(1)
            else:
                logger.info("Signature verification Failed")
                sys.exit(1)
        except Exception as err:
            logger.error("ERROR: Failed to decrypt response: %s", str(err))
            sys.exit(1)
    else:
        logger.info("\n Work order get result failed {}\n".format(res))
        sys.exit(1)

    # Retrieve receipt
    receipt_res = wo_receipt_instance.work_order_receipt_retrieve(
        work_order_id, id=req_id)

    logger.info("\n Retrieve receipt response:\n {}".format(
        json.dumps(receipt_res, indent=4)))

    # Retrieve last update to receipt by passing 0xFFFFFFFF
    req_id += 1
    receipt_update_retrieve = \
        wo_receipt_instance.work_order_receipt_update_retrieve(
            work_order_id,
            None,
            1 << 32,
            id=req_id)
    logger.info("\n Last update to receipt receipt is:\n {}".format(
        json.dumps(receipt_update_retrieve, indent=4)))
    status = sig_obj.verify_update_receipt_signature(receipt_update_retrieve)
    if status == SignatureStatus.PASSED:
        logger.info(
            "Work order receipt retrieve signature verification Successful")
    else:
        logger.info(
            "Work order receipt retrieve signature verification failed!!")
        sys.exit(1)
    # Receipt lookup based on requesterId
    req_id += 1
    receipt_lookup_res = wo_receipt_instance.work_order_receipt_lookup(
        requester_id=requester_id, id=req_id)
    logger.info("\n Work order receipt lookup response :\n {}".format(
        json.dumps(receipt_lookup_res, indent=4)))
Ejemplo n.º 12
0
def byte_array_to_hex(byte_array):
    hex_value = hex_utils.byte_array_to_hex_str(byte_array)
    return hex_value.upper()