def test_decrypt_odd_length_data(): random_key = get_random_value_hex(32) random_encrypted_data_odd = get_random_value_hex(64)[:-1] random_encrypted_blob_odd = random_encrypted_data_odd with pytest.raises(InvalidParameter, match="Odd-length"): Cryptographer.decrypt(random_encrypted_blob_odd, random_key)
def test_decrypt_wrong_key_size(): random_key = get_random_value_hex(31) random_encrypted_data_odd = get_random_value_hex(64) random_encrypted_blob_odd = random_encrypted_data_odd with pytest.raises(InvalidParameter, match="32-byte hex value"): Cryptographer.decrypt(random_encrypted_blob_odd, random_key)
def test_decrypt_invalid_tag(): random_key = get_random_value_hex(32) random_encrypted_data = get_random_value_hex(64) random_encrypted_blob = random_encrypted_data # Trying to decrypt random data should result in an EncryptionError with pytest.raises(EncryptionError, match="Cannot decrypt blob with the provided key"): Cryptographer.decrypt(random_encrypted_blob, random_key)
def test_decrypt_wrong_key_size(): random_key = get_random_value_hex(31) random_encrypted_data_odd = get_random_value_hex(64) random_encrypted_blob_odd = EncryptedBlob(random_encrypted_data_odd) try: Cryptographer.decrypt(random_encrypted_blob_odd, random_key) assert False except ValueError: assert True
def test_decrypt_odd_length_data(): random_key = get_random_value_hex(32) random_encrypted_data_odd = get_random_value_hex(64)[:-1] random_encrypted_blob_odd = EncryptedBlob(random_encrypted_data_odd) try: Cryptographer.decrypt(random_encrypted_blob_odd, random_key) assert False except ValueError: assert True
def test_decrypt_invalid_tag(): random_key = get_random_value_hex(32) random_encrypted_data = get_random_value_hex(64) random_encrypted_blob = EncryptedBlob(random_encrypted_data) # Trying to decrypt random data should result in an InvalidTag exception. Our decrypt function # returns None hex_tx = Cryptographer.decrypt(random_encrypted_blob, random_key) assert hex_tx is None
def filter_valid_breaches(self, breaches): """ Filters what of the found breaches contain valid transaction data. The :obj:`Watcher` cannot if a given :obj:`EncryptedBlob <common.encrypted_blob.EncryptedBlob>` contains a valid transaction until a breach if seen. Blobs that contain arbitrary data are dropped and not sent to the :obj:`Responder <teos.responder.Responder>`. Args: breaches (:obj:`dict`): a dictionary containing channel breaches (``locator:txid``). Returns: :obj:`dict`: A dictionary containing all the breaches flagged either as valid or invalid. The structure is as follows: ``{locator, dispute_txid, penalty_txid, penalty_rawtx, valid_breach}`` """ valid_breaches = {} invalid_breaches = [] # A cache of the already decrypted blobs so replicate decryption can be avoided decrypted_blobs = {} for locator, dispute_txid in breaches.items(): for uuid in self.locator_uuid_map[locator]: appointment = Appointment.from_dict(self.db_manager.load_watcher_appointment(uuid)) if appointment.encrypted_blob.data in decrypted_blobs: penalty_tx, penalty_rawtx = decrypted_blobs[appointment.encrypted_blob.data] else: try: penalty_rawtx = Cryptographer.decrypt(appointment.encrypted_blob, dispute_txid) except ValueError: penalty_rawtx = None penalty_tx = self.block_processor.decode_raw_transaction(penalty_rawtx) decrypted_blobs[appointment.encrypted_blob.data] = (penalty_tx, penalty_rawtx) if penalty_tx is not None: valid_breaches[uuid] = { "locator": locator, "dispute_txid": dispute_txid, "penalty_txid": penalty_tx.get("txid"), "penalty_rawtx": penalty_rawtx, } logger.info( "Breach found for locator", locator=locator, uuid=uuid, penalty_txid=penalty_tx.get("txid") ) else: invalid_breaches.append(uuid) return valid_breaches, invalid_breaches
def check_breach(self, uuid, appointment, dispute_txid): """ Checks if a breach is valid. Valid breaches should decrypt to a valid transaction. Args: uuid (:obj:`str`): the uuid of the appointment that was triggered by the breach. appointment (:obj:`ExtendedAppointment <teos.extended_appointment.ExtendedAppointment>`): the appointment data. dispute_txid (:obj:`str`): the id of the transaction that triggered the breach. Returns: :obj:`tuple`: A tuple containing the penalty txid and the raw penalty tx. Raises: :obj:`EncryptionError`: if the encrypted blob from the provided appointment cannot be decrypted with the key derived from the breach transaction id. :obj:`InvalidTransactionFormat`: if the decrypted data does not have a valid transaction format. """ try: penalty_rawtx = Cryptographer.decrypt(appointment.encrypted_blob, dispute_txid) penalty_tx = self.block_processor.decode_raw_transaction( penalty_rawtx) except EncryptionError as e: self.logger.info("Transaction cannot be decrypted", uuid=uuid) raise e except InvalidTransactionFormat as e: self.logger.info("The breach contained an invalid transaction", uuid=uuid) raise e self.logger.info("Breach found for locator", locator=appointment.locator, uuid=uuid, penalty_txid=penalty_tx.get("txid")) return penalty_tx.get("txid"), penalty_rawtx
def test_decrypt(): # Valid data should run with no InvalidTag and verify assert Cryptographer.decrypt(encrypted_data, key) == data