def validate(self, admissions, doctors, vaccines): """Validate the existing signatures. Check if the transaction fulfills the requirements WONTFIX: won't implement checking if patient is registered in presentation demo """ if self.vaccine not in vaccines: logger.debug("vaccine is not registered.") self.validation_text = "vaccine is not registered." return False if self.doctor_pub_key not in doctors: logger.debug("doctor is not registered.") self.validation_text = "doctor is not registered." return False if not self.doctor_signature or not self.patient_signature: return False bin_doctor_key = key_utils.bytes_to_rsa(self.doctor_pub_key) doctor_signature = self._verify_doctor_signature(bin_doctor_key) if not doctor_signature: logger.debug("doctor signature is not valid") self.validation_text = "doctor signature is not valid" return False bin_patient_key = key_utils.bytes_to_rsa(self.patient_pub_key) patient_signature = self._verify_patient_signature(bin_patient_key) if not patient_signature: logger.debug("patient signature is not valid") self.validation_text = "patient signature is not valid" return False self.validation_text = "valid" return True
def _verify_signature(self): """Verify existing signature. Overwrite the method if you need more than one signature. """ if not self.signature: # fail if object has no signature attribute self.validation_text = "No signature found." return False message = crypto.get_bytes(self._get_information_for_hashing()) result = crypto.verify(message, self.signature, key_utils.bytes_to_rsa(self.sender_pubkey)) if not result: self.validation_text = "Signature not valid" return False self.validation_text = "valid" return True
def test_bytes_to_rsa(public_key, private_key): rsa_object = key_utils.bytes_to_rsa(public_key.exportKey("DER")) assert rsa_object == public_key rsa_object = key_utils.bytes_to_rsa(private_key.exportKey("DER")) assert rsa_object == private_key
def validate_block(block, previous_block): """Validate correctness of block by defined rules. This module doesn't check if there are transactions since the demo will generate blocks without transactions. """ if not previous_block: return False # Index is incremented by 1 if block.index != previous_block.index + 1: logger.info( "Wrong index, block index {}, index of last block {}".format( block.index, previous_block.index)) return False # New block references old one if block.previous_block != previous_block.hash: logger.info( ("New block does not reference previous one, block hash" " {}, hash of last block {}").format(block.hash, previous_block.hash)) return False # Matching versions if block.version < CONFIG.version: logger.info("Older version, block version {}, chain version {}".format( block.version, CONFIG.version)) return False # Timestamp not in the future if block.timestamp > int(time()): logger.info("Timestamp of the new block is in the future") return False # Valid signature content_to_sign = str.encode(block._get_content_for_signing()) signature = key_utils.hex_to_bytes(block.signature) public_key = key_utils.bytes_to_rsa(block.public_key) valid = verify(content_to_sign, signature, public_key) if not valid: logger.info("Signature is not valid, block must be altered") return False # Check if all transactions are valid admissions, doctors, vaccines = Chain().\ get_registration_caches_by_blockhash(block.previous_block) for transaction in block.transactions: if not transaction.validate(admissions, doctors, vaccines): logger.info("Block contains invalid transactions") return False # WONTFIX: Actually, a block should never be empty. However, we leave this # check disabled for demo purposes. # Block has no transactions # if len(block.transactions) == 0: # logger.info("Block does not contain any transaction") # return False # Number of transactions exceeds the maximum if len(block.transactions) > CONFIG.block_size: logger.info( "Too many transactions, block has {}, maximum is {}".format( len(block.transactions), CONFIG.block_size)) return False # Duplicate transactions distinct_transactions = len(set([repr(tx) for tx in block.transactions])) if len(block.transactions) > distinct_transactions: logger.info("Block contains duplicate transactions") return False # Block hash valid content_to_hash = block.get_content_for_hashing() sha = sha256() sha.update(content_to_hash.encode("utf-8")) if block.hash != sha.hexdigest(): logger.info("Hash is not valid, block must be altered") return False return True
def _verify_approval_signature(self, approval): # WONTFIX: susceptible to replay attacks because there is no clear indication # which transaction the approval belongs to, approvals could be copy-pasted to confirm malicious actors. approving_pubkey, signature = approval return crypto.verify(approving_pubkey, signature, key_utils.bytes_to_rsa(approving_pubkey))