Modifies behaviour towards a failed EncryptedBlob decrpytion

The decryption for the `EncryptedBlob` using AES-GCM-128 (the only cipher available atm) raises an `InvalidTag` exception. This was not properly captured by the watcher making it crash. This behavior was already discovered during the `EncryptedBlob` unit testing and left to be fixed in the `Watcher` unit testing.

However, making the EncryptedBlob raise such an exception may not be a good practice, since other ciphers may run into different exceptions. Therefore, the `EncryptedBlob` has been modified to return None upon facing a decryption issue, the `BlockProcessor` will detect that and return a None justice_txm and justice_txid. Upon receiving a None `justice_txid` the `Watcher` will delete the appointment without notifiying the `Responder`.
This commit is contained in:
Sergi Delgado Segura
2019-10-14 16:34:41 +01:00
parent d43ab76220
commit d7c89ddc91
4 changed files with 26 additions and 18 deletions

View File

@@ -74,15 +74,17 @@ class BlockProcessor:
# ToDo: #20-test-tx-decrypting-edge-cases # ToDo: #20-test-tx-decrypting-edge-cases
justice_rawtx = appointments[uuid].encrypted_blob.decrypt(dispute_txid) justice_rawtx = appointments[uuid].encrypted_blob.decrypt(dispute_txid)
justice_txid = bitcoin_cli.decoderawtransaction(justice_rawtx).get('txid') justice_txid = bitcoin_cli.decoderawtransaction(justice_rawtx).get('txid')
matches.append((locator, uuid, dispute_txid, justice_txid, justice_rawtx))
logger.info("Match found for locator.", locator=locator, uuid=uuid, justice_txid=justice_txid) logger.info("Match found for locator.", locator=locator, uuid=uuid, justice_txid=justice_txid)
except JSONRPCException as e: except JSONRPCException as e:
# Tx decode failed returns error code -22, maybe we should be more strict here. Leaving it simple # Tx decode failed returns error code -22, maybe we should be more strict here. Leaving it simple
# for the POC # for the POC
justice_txid = None
justice_rawtx = None
logger.error("Can't build transaction from decoded data.", error=e.error) logger.error("Can't build transaction from decoded data.", error=e.error)
matches.append((locator, uuid, dispute_txid, justice_txid, justice_rawtx))
return matches return matches
# DISCUSS: This method comes from the Responder and seems like it could go back there. # DISCUSS: This method comes from the Responder and seems like it could go back there.

View File

@@ -1,6 +1,8 @@
from hashlib import sha256 from hashlib import sha256
from binascii import unhexlify, hexlify from binascii import unhexlify, hexlify
from cryptography.exceptions import InvalidTag
from cryptography.hazmat.primitives.ciphers.aead import AESGCM from cryptography.hazmat.primitives.ciphers.aead import AESGCM
from pisa.logger import Logger from pisa.logger import Logger
logger = Logger("Watcher") logger = Logger("Watcher")
@@ -33,7 +35,12 @@ class EncryptedBlob:
# Decrypt # Decrypt
aesgcm = AESGCM(sk) aesgcm = AESGCM(sk)
data = unhexlify(self.data.encode()) data = unhexlify(self.data.encode())
raw_tx = aesgcm.decrypt(nonce=nonce, data=data, associated_data=None)
hex_raw_tx = hexlify(raw_tx).decode('utf8') try:
raw_tx = aesgcm.decrypt(nonce=nonce, data=data, associated_data=None)
hex_raw_tx = hexlify(raw_tx).decode('utf8')
except InvalidTag:
hex_raw_tx = None
return hex_raw_tx return hex_raw_tx

View File

@@ -49,7 +49,7 @@ class Watcher:
if self.asleep: if self.asleep:
self.asleep = False self.asleep = False
self.block_queue = Queue() self.block_queue = Queue()
zmq_thread = Thread(target=self.do_subscribe, args=[self.block_queue]) zmq_thread = Thread(target=self.do_subscribe)
watcher = Thread(target=self.do_watch) watcher = Thread(target=self.do_watch)
zmq_thread.start() zmq_thread.start()
watcher.start() watcher.start()
@@ -67,9 +67,9 @@ class Watcher:
return appointment_added return appointment_added
def do_subscribe(self, block_queue): def do_subscribe(self):
self.zmq_subscriber = ZMQHandler(parent="Watcher") self.zmq_subscriber = ZMQHandler(parent="Watcher")
self.zmq_subscriber.handle(block_queue) self.zmq_subscriber.handle(self.block_queue)
def do_watch(self): def do_watch(self):
while len(self.appointments) > 0: while len(self.appointments) > 0:
@@ -92,11 +92,13 @@ class Watcher:
matches = BlockProcessor.get_matches(potential_matches, self.locator_uuid_map, self.appointments) matches = BlockProcessor.get_matches(potential_matches, self.locator_uuid_map, self.appointments)
for locator, uuid, dispute_txid, justice_txid, justice_rawtx in matches: for locator, uuid, dispute_txid, justice_txid, justice_rawtx in matches:
logger.info("Notifying responder and deleting appointment.", # Errors decrypting the Blob will result in a None justice_txid
justice_txid=justice_txid, locator=locator, uuid=uuid) if justice_txid is not None:
logger.info("Notifying responder and deleting appointment.", justice_txid=justice_txid,
locator=locator, uuid=uuid)
self.responder.add_response(uuid, dispute_txid, justice_txid, justice_rawtx, self.responder.add_response(uuid, dispute_txid, justice_txid, justice_rawtx,
self.appointments[uuid].end_time) self.appointments[uuid].end_time)
# Delete the appointment # Delete the appointment
self.appointments.pop(uuid) self.appointments.pop(uuid)

View File

@@ -19,13 +19,10 @@ def test_decrypt():
encrypted_data = urandom(64).hex() encrypted_data = urandom(64).hex()
encrypted_blob = EncryptedBlob(encrypted_data) encrypted_blob = EncryptedBlob(encrypted_data)
# Trying to decrypt random data (in AES_GCM-128) should result in an InvalidTag exception # Trying to decrypt random data (in AES_GCM-128) should result in an InvalidTag exception. Our decrypt function
try: # returns None
encrypted_blob.decrypt(key) hex_tx = encrypted_blob.decrypt(key)
assert False, "Able to decrypt random data with random key" assert hex_tx is None
except InvalidTag:
assert True
# Valid data should run with no InvalidTag and verify # Valid data should run with no InvalidTag and verify
data = "6097cdf52309b1b2124efeed36bd34f46dc1c25ad23ac86f28380f746254f777" data = "6097cdf52309b1b2124efeed36bd34f46dc1c25ad23ac86f28380f746254f777"