From e66622bd69f42c83214e20a25585a79d8deb13a8 Mon Sep 17 00:00:00 2001 From: Mark Qvist Date: Tue, 20 Mar 2018 16:57:26 +0100 Subject: [PATCH] Serial interface and echo example --- FPE/Identity.py | 49 +++++++++++++++++-------------- FPE/Interfaces/SerialInterface.py | 44 ++++++++++++++++++--------- FPE/Utilities/Echo.py | 7 +++-- 3 files changed, 62 insertions(+), 38 deletions(-) diff --git a/FPE/Identity.py b/FPE/Identity.py index 87e0f90..26cc58b 100644 --- a/FPE/Identity.py +++ b/FPE/Identity.py @@ -104,7 +104,7 @@ class Identity: announced_identity = Identity(public_only=True) announced_identity.loadPublicKey(public_key) - if announced_identity.validate(signature, signed_data): + if announced_identity.pub != None and announced_identity.validate(signature, signed_data): FPE.log("Announce is valid", FPE.LOG_VERBOSE) FPE.Identity.remember(FPE.Identity.fullHash(packet.raw), destination_hash, public_key) FPE.log("Stored valid announce from "+FPE.prettyhexrep(destination_hash), FPE.LOG_INFO) @@ -158,9 +158,12 @@ class Identity: self.updateHashes() def loadPublicKey(self, key): - self.pub_bytes = key - self.pub = load_der_public_key(self.pub_bytes, backend=default_backend()) - self.updateHashes() + try: + self.pub_bytes = key + self.pub = load_der_public_key(self.pub_bytes, backend=default_backend()) + self.updateHashes() + except Exception as e: + FPE.log("Error while loading public key, the contained exception was: "+str(e), FPE.LOG_ERROR) def updateHashes(self): self.hash = Identity.truncatedHash(self.pub_bytes) @@ -203,27 +206,29 @@ class Identity: def decrypt(self, ciphertext): if self.prv != None: - # TODO: Remove debug output print("Ciphertext length is "+str(len(ciphertext))+". ") - chunksize = (Identity.KEYSIZE)/8 - chunks = int(math.ceil(len(ciphertext)/(float(chunksize)))) + plaintext = None + try: + chunksize = (Identity.KEYSIZE)/8 + chunks = int(math.ceil(len(ciphertext)/(float(chunksize)))) - plaintext = ""; - for chunk in range(chunks): - start = chunk*chunksize - end = (chunk+1)*chunksize - if (chunk+1)*chunksize > len(ciphertext): - end = len(ciphertext) + plaintext = ""; + for chunk in range(chunks): + start = chunk*chunksize + end = (chunk+1)*chunksize + if (chunk+1)*chunksize > len(ciphertext): + end = len(ciphertext) - # TODO: Remove debug output print("Processing chunk "+str(chunk+1)+" of "+str(chunks)+". Starting at "+str(start)+" and stopping at "+str(end)+". The length is "+str(len(ciphertext[start:end]))) - - plaintext += self.prv.decrypt( - ciphertext[start:end], - padding.OAEP( - mgf=padding.MGF1(algorithm=hashes.SHA1()), - algorithm=hashes.SHA1(), - label=None + plaintext += self.prv.decrypt( + ciphertext[start:end], + padding.OAEP( + mgf=padding.MGF1(algorithm=hashes.SHA1()), + algorithm=hashes.SHA1(), + label=None + ) ) - ) + except: + FPE.log("Decryption by "+FPE.prettyhexrep(self.hash)+" failed") + return plaintext; else: raise KeyError("Decryption failed because identity does not hold a private key") diff --git a/FPE/Interfaces/SerialInterface.py b/FPE/Interfaces/SerialInterface.py index 3c851b3..dfe2699 100755 --- a/FPE/Interfaces/SerialInterface.py +++ b/FPE/Interfaces/SerialInterface.py @@ -4,11 +4,12 @@ from time import sleep import sys import serial import threading +import time import FPE class SerialInterface(Interface): MAX_CHUNK = 32768 - TIMEOUT_SECONDS = 0.15 + TIMEOUT_SECONDS = 1.0 owner = None port = None @@ -26,6 +27,8 @@ class SerialInterface(Interface): self.databits = databits self.parity = serial.PARITY_NONE self.stopbits = stopbits + self.timeout = 100 + self.online = False if parity.lower() == "e" or parity.lower() == "even": self.parity = serial.PARITY_EVEN @@ -41,9 +44,10 @@ class SerialInterface(Interface): bytesize = self.databits, parity = self.parity, stopbits = self.stopbits, - timeout = SerialInterface.TIMEOUT_SECONDS, xonxoff = False, rtscts = False, + timeout = 0, + inter_byte_timeout = None, write_timeout = None, dsrdtr = False, ) @@ -52,10 +56,11 @@ class SerialInterface(Interface): raise e if self.serial.is_open: + sleep(0.5) thread = threading.Thread(target=self.readLoop) thread.setDaemon(True) thread.start() - sleep(0.5) + self.online = True FPE.log("Serial port "+self.port+" is now open") else: raise IOError("Could not open serial port") @@ -66,18 +71,29 @@ class SerialInterface(Interface): def processOutgoing(self,data): - written = self.serial.write(data) - if written != len(data): - raise IOError("Serial interface only wrote "+str(written)+" bytes of "+str(len(data))) + if self.online: + written = self.serial.write(data) + if written != len(data): + raise IOError("Serial interface only wrote "+str(written)+" bytes of "+str(len(data))) def readLoop(self): - #pass - while self.serial.is_open: - data = self.serial.read(size=self.owner.__class__.MTU) - if not data == "": - self.processIncoming(data) - - - + try: + data_buffer = "" + last_read_ms = int(time.time()*1000) + while self.serial.is_open: + if self.serial.in_waiting: + data = self.serial.read(size=self.serial.in_waiting) + data_buffer += data + last_read_ms = int(time.time()*1000) + else: + time_since_last = int(time.time()*1000) - last_read_ms + if len(data_buffer) > 0 and time_since_last > self.timeout: + self.processIncoming(data_buffer) + data_buffer = "" + sleep(0.08) + except Exception as e: + self.online = False + FPE.log("A serial port error occurred, the contained exception was: "+str(e), FPE.LOG_ERROR) + FPE.log("The interface "+str(self.name)+" is now offline. Restart FlexPE to attempt reconnection.", FPE.LOG_ERROR) diff --git a/FPE/Utilities/Echo.py b/FPE/Utilities/Echo.py index ae73112..2d662e8 100644 --- a/FPE/Utilities/Echo.py +++ b/FPE/Utilities/Echo.py @@ -36,7 +36,7 @@ def server(configpath): def announceLoop(destination): # Let the user know that everything is ready - FPE.log("Echo server running, hit enter to send announce (Ctrl-C to quit)") + FPE.log("Echo server "+FPE.prettyhexrep(destination.hash)+" running, hit enter to send announce (Ctrl-C to quit)") # We enter a loop that runs until the users exits. # If the user just hits enter, we will announce our server @@ -102,7 +102,7 @@ def client(destination_hexhash, configpath): exit() # We must first initialise FlexPE - fpe = FPE.FlexPE() + fpe = FPE.FlexPE(configpath) # Randomly create a new identity for our echo server client_identity = FPE.Identity() @@ -191,10 +191,13 @@ def clientProofCallback(proof_packet): else: rtt = round(rtt*1000, 3) rttstring = str(rtt)+" milliseconds" + FPE.log( "Valid echo reply, proved by "+FPE.prettyhexrep(unproven_packet.destination.hash)+ ", round-trip time was "+rttstring ) + sent_requests.remove(unproven_packet) + del unproven_packet else: FPE.log("Proof invalid")