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 __init__(self, code, name, nonce = None) : if nonce is None : nonce = crypto.byte_array_to_hex(crypto.random_bit_string(16)) self.code = code self.name = name self.nonce = nonce
def _GetContractSecret(self, contracttxnid): """ Retrieve or create the secret for a particular contract, returned in raw format """ file_secrets = dict() with open(self.secrets_file_path, "r") as f: for line in f: key, val = line.partition(":")[::2] file_secrets[key.strip()] = val.strip() # If secret already exists, return it, otherwise create, store, and return a new secret if contracttxnid in file_secrets: secret = file_secrets[contracttxnid] logger.debug('Secret for contract %s found', contracttxnid) else: secret = pcrypto.byte_array_to_hex(pcrypto.SKENC_GenerateKey()) file_secrets[contracttxnid] = secret logger.debug('Creating new Secret for contract %s', contracttxnid) with open(self.secrets_file_path, "w") as f: for key in file_secrets: f.write(key + ' : ' + file_secrets[key] + "\n") return secret
def sign(self, message, encoding='hex'): """ sign a message from the agent :param message: the message for verification, no encoding :param encoding: the encoding used for the signature; one of raw, hex, b64 """ 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') signature = self._signing_key.SignMessage(message_byte_array) if encoding == 'raw': encoded_signature = signature elif encoding == 'hex': encoded_signature = crypto.byte_array_to_hex(signature) elif encoding == 'b64': encoded_signature = crypto.byte_array_to_base64(signature) else: raise ValueError('unknown encoding; {0}'.format(encoding)) logger.debug("message: %s", message) logger.debug("signature: %s", encoded_signature) return encoded_signature
def encrypt(self, message, encoding='raw'): """ encrypt a message to send privately to the enclave :param message: text to encrypt :param encoding: encoding for the encrypted cipher text, one of raw, hex, b64 """ 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') encrypted_byte_array = self._encryption_key.EncryptMessage( message_byte_array) if encoding == 'raw': encoded_bytes = encrypted_byte_array elif encoding == 'hex': encoded_bytes = crypto.byte_array_to_hex(encrypted_byte_array) elif encoding == 'b64': encoded_bytes = crypto.byte_array_to_base64(encrypted_byte_array) else: raise ValueError('unknown encoding; {0}'.format(encoding)) logger.debug("message: %s", message) logger.debug("encrypted message: %s", encoded_bytes) return encoded_bytes
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 __init__(self, request_originator_keys, channel_keys, **kwargs): """ :param request_originator_keys: object of type ServiceKeys :param channel_keys: object of type TransactionKeys """ self.__request_originator_keys = request_originator_keys self.__channel_keys = channel_keys self.expression = kwargs.get('expression', '') self.nonce = crypto.byte_array_to_hex(crypto.random_bit_string(16))
def compute_hash(self, encoding = 'raw') : serialized = self.__serialize_for_hashing() code_hash = crypto.compute_message_hash(crypto.string_to_byte_array(serialized)) if encoding == 'raw' : return code_hash elif encoding == 'hex' : return crypto.byte_array_to_hex(code_hash) elif encoding == 'b64' : return crypto.byte_array_to_base64(code_hash) else : raise ValueError('unknown hash encoding; {}'.format(encoding))
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 compute_hash(raw_state, encoding='raw'): """ compute the hash of the contract state :param raw_state string: root block of contract state, json string """ state_hash = crypto.compute_message_hash(raw_state) 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 register_contract(self, contract_code_hash, provisioning_service_ids, **extra_params): tx_method = "register_contract" tx_params = PayloadBuilder.build_contract_registration_from_data( self.pdo_signer, contract_code_hash, provisioning_service_ids) try: response = self.ccf_client.submit_rpc(tx_method, tx_params) if response.result: # result will be "True" for contract registration transaction return crypto.byte_array_to_hex(tx_params['signature']) else: raise Exception(response.error) except Exception as e: raise
def compute_hash(self, encoding = 'raw') : # the code hash is a combination of the hash of the actual code, # and the hash of the nonce. # this makes it possible to use the nonce to verify the identity # of the actual code (think MRENCLAVE). code_hash = crypto.compute_message_hash(crypto.string_to_byte_array(self.code + self.name)) nonce_hash = crypto.compute_message_hash(crypto.string_to_byte_array(self.nonce)) message = code_hash + nonce_hash code_hash = crypto.compute_message_hash(message) if encoding == 'raw' : return code_hash elif encoding == 'hex' : return crypto.byte_array_to_hex(code_hash) elif encoding == 'b64' : return crypto.byte_array_to_base64(code_hash) else : raise ValueError('unknown hash encoding; {}'.format(encoding))
def __init__(self, request_originator_keys, channel_keys, **kwargs): """ :param request_originator_keys: object of type ServiceKeys :param channel_keys: object of type TransactionKeys """ self.__request_originator_keys = request_originator_keys self.__channel_keys = channel_keys # remove this when we are convinced that we've converted # all forms to use InvocationRequest invocation_request = kwargs.get('invocation_request') if invocation_request: if not issubclass(type(invocation_request), InvocationRequest): logger.warn("not an InvocationRequest: %s", str(invocation_request)) self.invocation_request = str(kwargs.get('invocation_request', '')) # remove this when we are convinced that we've removed # all forms expressing the message through 'expression' assert kwargs.get('expression') is None self.nonce = crypto.byte_array_to_hex(crypto.random_bit_string(16))
def verify(self, message, encoded_signature, encoding='b64'): """ verify a signature that was created by the enclave :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)) logger.debug("verifying key: %s", self._verifying_key.Serialize()) logger.debug("signature for verification: %s", crypto.byte_array_to_hex(decoded_signature)) result = self._verifying_key.VerifySignature(message_byte_array, decoded_signature) if result < 0: raise Error('malformed signature') return result
logger.error(str(e)) ErrorShutdown() try : if config.get('StorageService') is None : config['StorageService'] = { 'BlockStore' : os.path.join(config['Contract']['DataDirectory'], 'test-request.mdb'), } except KeyError as ke : logger.error('missing configuration for %s', str(ke)) ErrorShutdown() contract_creator_keys = keys.ServiceKeys.create_service_keys() contract_creator_id = contract_creator_keys.identity contract_id = crypto.byte_array_to_hex(crypto.random_bit_string(256))[:32] try : block_store_file = config['StorageService']['BlockStore'] block_store = BlockStoreManager(block_store_file, create_block_store=True) except Exception as e : logger.error('failed to initialize the block store; %s', str(e)) ErrorShutdown() # ----------------------------------------------------------------- # ----------------------------------------------------------------- plogger.setup_loggers({'LogLevel' : options.loglevel.upper(), 'LogFile' : options.logfile}) # ----------------------------------------------------------------- # ----------------------------------------------------------------- enclave_helper.initialize_enclave(config)
def hashed_identity(self): key_byte_array = crypto.string_to_byte_array(self.txn_public) hashed_txn_key = crypto.compute_message_hash(key_byte_array) encoded_hashed_key = crypto.byte_array_to_hex(hashed_txn_key) encoded_hashed_key = encoded_hashed_key.lower() return encoded_hashed_key
def _secretreq(self, minfo): # unpack the request try: enclave_id = minfo['enclave_id'] contract_id = minfo['contract_id'] opk = minfo['opk'] signature = minfo['signature'] except KeyError as ke: raise Error(http.BAD_REQUEST, 'missing required field {0}'.format(ke)) logger.debug('request for key for contract %s, enclave %s', contract_id, enclave_id) # verify the signature, that is, make sure that the request was really signed by opk try: opkkey = pcrypto.SIG_PublicKey(opk) opkkey.VerifySignature( pcrypto.string_to_byte_array(enclave_id + contract_id), pcrypto.hex_to_byte_array(signature)) except: logger.warn("Signature verification failed") raise Error(http.BAD_REQUEST, 'Signature Mismatch') # Get enclave state try: logger.debug('retrieve information for enclave %s', enclave_id) enclave_info = self.__registry_helper.get_enclave_dict(enclave_id) logger.debug("enclave information retrieved: %s", enclave_info) except BaseException as err: logger.warn( 'exception occurred when getting ledger information for enclave %s; %s', enclave_id, str(err)) raise Error(http.BAD_REQUEST, 'could not retrieve enclave state; {0}'.format(err)) except ClientConnectException as err: logger.warn( 'client exception occurred when getting ledger information for enclave %s; %s', enclave_id, str(err)) raise Error(http.BAD_REQUEST, 'could not retrieve enclave state; {0}'.format(err)) # Get contract state try: logger.debug('retrieve information for contract <%s>', contract_id) contract_info = self.__registry_helper.get_contract_dict( contract_id) logger.debug("contract_info from ledger: %s", contract_info) except BaseException as err: logger.warn( 'exception occurred when getting ledger information for contract %s; %s', contract_id, str(err)) raise Error(http.BAD_REQUEST, 'could not retrieve contract state; {0}'.format(err)) except ClientConnectException as err: logger.warn( 'client exception occurred when getting ledger information for contract %s; %s', contract_id, str(err)) raise Error(http.BAD_REQUEST, 'could not retrieve contract state; {0}'.format(err)) # make sure that the signer of this request is really the owner of the contract try: # make sure that the signer of this request is really the owner of the contract # PdoContractInfo.pdo_contract_creator_pem_key is the VerifyingKey logger.debug("Contract creator's public key: %s", contract_info['pdo_contract_creator_pem_key']) logger.debug("Expected public key: %s", opk) assert contract_info['pdo_contract_creator_pem_key'] == opk except: logger.error( 'request to create secret did not come from the contract owner; %s != %s', contracttxn.OriginatorID, opk) raise Error(http.NOT_ALLOWED, 'operation not allowed for {0}'.format(opk)) # make sure the provisioning service is allowed to access contract by the checking the list of allowed provisioning services try: logger.debug("Contract allowed service ids: %s", contract_info['provisioning_service_ids']) logger.debug("Expected provisioning service id: %s", self.PSPK.Serialize()) assert self.PSPK.Serialize( ) in contract_info['provisioning_service_ids'] except: logger.error( 'This Pservice is not the list of allowed provisioning services, PSerivce ID: %s', self.PSPK.Serialize()) raise Error( http.NOT_ALLOWED, 'operation not allowed for {0}'.format(self.PSPK.Serialize())) # retrieve the secret secret = self._GetContractSecret(contract_id) # create the signature message = secret + enclave_id + contract_id + opk secretsig = pcrypto.byte_array_to_hex( self.SigningKey.SignMessage(pcrypto.string_to_byte_array(message))) # pad secret to required max size # TODO: Eventually this requirement needs to be fixed in the crypto library itself required_padding = 2 * pcrypto.MAX_SIG_SIZE - len(secretsig) secretsig = secretsig + ('0' * required_padding) enclavekey = pcrypto.PKENC_PublicKey(enclave_info['encryption_key']) esecret = pcrypto.byte_array_to_base64( enclavekey.EncryptMessage( pcrypto.string_to_byte_array(secret + secretsig))) logger.debug("Encrypted secret for contract %s: %s", contract_id, esecret) # create the response response = dict() response['pspk'] = self.PSPK.Serialize() response['encrypted_secret'] = esecret logger.info('created secret for contract %s and enclave %s', contract_id, enclave_id) return response