mirror of
https://github.com/markqvist/Reticulum.git
synced 2024-11-22 13:40:19 +00:00
Restructuring and packet format
This commit is contained in:
parent
4c92493bc2
commit
3ea36ff9b3
@ -1,8 +1,7 @@
|
||||
import base64
|
||||
import math
|
||||
from Identity import Identity
|
||||
from Transport import Transport
|
||||
from Packet import Packet
|
||||
import FPE
|
||||
|
||||
from cryptography.fernet import Fernet
|
||||
from cryptography.hazmat.primitives import hashes
|
||||
from cryptography.hazmat.backends import default_backend
|
||||
@ -10,15 +9,17 @@ from cryptography.hazmat.primitives import serialization
|
||||
from cryptography.hazmat.primitives.asymmetric import rsa
|
||||
from cryptography.hazmat.primitives.asymmetric import padding
|
||||
|
||||
|
||||
class Destination:
|
||||
KEYSIZE = Identity.KEYSIZE;
|
||||
PADDINGSIZE= Identity.PADDINGSIZE;
|
||||
KEYSIZE = FPE.Identity.KEYSIZE;
|
||||
PADDINGSIZE= FPE.Identity.PADDINGSIZE;
|
||||
|
||||
# Constants
|
||||
SINGLE = 0x01;
|
||||
GROUP = 0x02;
|
||||
PLAIN = 0x03;
|
||||
types = [SINGLE, GROUP, PLAIN]
|
||||
SINGLE = 0x00;
|
||||
GROUP = 0x01;
|
||||
PLAIN = 0x02;
|
||||
LINK = 0x03;
|
||||
types = [SINGLE, GROUP, PLAIN, LINK]
|
||||
|
||||
IN = 0x11;
|
||||
OUT = 0x12;
|
||||
@ -70,7 +71,7 @@ class Destination:
|
||||
|
||||
self.callback = None
|
||||
|
||||
Transport.registerDestination(self)
|
||||
FPE.Transport.registerDestination(self)
|
||||
|
||||
|
||||
def __str__(self):
|
||||
|
@ -1,4 +1,6 @@
|
||||
from Interfaces import *
|
||||
import FPE
|
||||
|
||||
import ConfigParser
|
||||
import jsonpickle
|
||||
from vendor.configobj import ConfigObj
|
||||
@ -25,8 +27,9 @@ class FlexPE:
|
||||
|
||||
if os.path.isfile(self.configpath):
|
||||
self.config = ConfigObj(self.configpath)
|
||||
FPE.log("Configuration loaded from "+self.configpath)
|
||||
else:
|
||||
print("Could not load config file, creating default configuration...")
|
||||
FPE.log("Could not load config file, creating default configuration...")
|
||||
self.createDefaultConfig()
|
||||
|
||||
self.applyConfig()
|
||||
@ -39,23 +42,26 @@ class FlexPE:
|
||||
|
||||
@staticmethod
|
||||
def incoming(data):
|
||||
|
||||
header = struct.unpack("B", data[0])
|
||||
|
||||
hash = data[1:11]
|
||||
type = header[0] & 0x03
|
||||
packet = FPE.Packet(None, data)
|
||||
packet.unpack()
|
||||
|
||||
for destination in FlexPE.destinations:
|
||||
if destination.hash == hash and destination.type == type:
|
||||
destination.receive(data[11:])
|
||||
if destination.hash == packet.destination_hash and destination.type == packet.destination_type:
|
||||
destination.receive(packet.data)
|
||||
|
||||
@staticmethod
|
||||
def outbound(raw):
|
||||
for interface in FlexPE.interfaces:
|
||||
if interface.OUT:
|
||||
FPE.log("Transmitting via: "+str(interface), FPE.LOG_DEBUG)
|
||||
interface.processOutgoing(raw)
|
||||
|
||||
def applyConfig(self):
|
||||
for option in self.config["logging"]:
|
||||
value = self.config["logging"][option]
|
||||
if option == "loglevel":
|
||||
FPE.loglevel = int(value)
|
||||
|
||||
for name in self.config["interfaces"]:
|
||||
c = self.config["interfaces"][name]
|
||||
try:
|
||||
@ -91,8 +97,8 @@ class FlexPE:
|
||||
FlexPE.interfaces.append(interface)
|
||||
|
||||
except Exception as e:
|
||||
print("The interface \""+name+"\" could not be created. Check your configuration file for errors!")
|
||||
print("The contained error was: "+str(e))
|
||||
FPE.log("The interface \""+name+"\" could not be created. Check your configuration file for errors!", FPE.LOG_ERROR)
|
||||
FPE.log("The contained exception was: "+str(e), FPE.LOG_ERROR)
|
||||
|
||||
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
import base64
|
||||
import math
|
||||
import FPE
|
||||
from cryptography.hazmat.primitives import hashes
|
||||
from cryptography.hazmat.backends import default_backend
|
||||
from cryptography.hazmat.primitives import serialization
|
||||
@ -51,8 +52,7 @@ class Identity:
|
||||
self.hash = Identity.getHash(self.pub_bytes)
|
||||
self.hexhash = self.hash.encode("hex_codec")
|
||||
|
||||
print("Identity keys created, private length is "+str(len(self.prv_bytes)))
|
||||
print("Identity keys created, public length is "+str(len(self.pub_bytes)))
|
||||
FPE.log("Identity keys created, private length is "+str(len(self.prv_bytes))+" public length is "+str(len(self.pub_bytes)), FPE.LOG_INFO)
|
||||
|
||||
def getPrivateKey(self):
|
||||
return self.prv_bytes
|
||||
@ -83,7 +83,7 @@ class Identity:
|
||||
if self.prv != None:
|
||||
chunksize = (Identity.KEYSIZE-Identity.PADDINGSIZE)/8
|
||||
chunks = int(math.ceil(len(plaintext)/(float(chunksize))))
|
||||
print("Plaintext size is "+str(len(plaintext))+", with "+str(chunks)+" chunks")
|
||||
# TODO: Remove debug output print("Plaintext size is "+str(len(plaintext))+", with "+str(chunks)+" chunks")
|
||||
|
||||
ciphertext = "";
|
||||
for chunk in range(chunks):
|
||||
@ -92,7 +92,7 @@ class Identity:
|
||||
if (chunk+1)*chunksize > len(plaintext):
|
||||
end = len(plaintext)
|
||||
|
||||
print("Processing chunk "+str(chunk+1)+" of "+str(chunks)+". Starting at "+str(start)+" and stopping at "+str(end)+". The length is "+str(len(plaintext[start:end])))
|
||||
# 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(plaintext[start:end])))
|
||||
|
||||
ciphertext += self.pub.encrypt(
|
||||
plaintext[start:end],
|
||||
@ -102,7 +102,7 @@ class Identity:
|
||||
label=None
|
||||
)
|
||||
)
|
||||
print("Plaintext encrypted, ciphertext length is "+str(len(ciphertext))+" bytes.")
|
||||
# TODO: Remove debug output print("Plaintext encrypted, ciphertext length is "+str(len(ciphertext))+" bytes.")
|
||||
return ciphertext
|
||||
else:
|
||||
raise KeyError("Encryption failed because identity does not hold a private key")
|
||||
@ -110,7 +110,7 @@ class Identity:
|
||||
|
||||
def decrypt(self, ciphertext):
|
||||
if self.prv != None:
|
||||
print("Ciphertext length is "+str(len(ciphertext))+". ")
|
||||
# TODO: Remove debug output print("Ciphertext length is "+str(len(ciphertext))+". ")
|
||||
chunksize = (Identity.KEYSIZE)/8
|
||||
chunks = int(math.ceil(len(ciphertext)/(float(chunksize))))
|
||||
|
||||
@ -121,7 +121,7 @@ class Identity:
|
||||
if (chunk+1)*chunksize > len(ciphertext):
|
||||
end = len(ciphertext)
|
||||
|
||||
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])))
|
||||
# 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],
|
||||
@ -150,3 +150,5 @@ class Identity:
|
||||
else:
|
||||
raise KeyError("Signing failed because identity does not hold a private key")
|
||||
|
||||
def announce(self):
|
||||
pass
|
@ -1,8 +1,10 @@
|
||||
from __future__ import print_function
|
||||
from Interface import Interface
|
||||
from time import sleep
|
||||
import sys
|
||||
import serial
|
||||
import threading
|
||||
import FPE
|
||||
|
||||
class SerialInterface(Interface):
|
||||
MAX_CHUNK = 32768
|
||||
@ -17,6 +19,7 @@ class SerialInterface(Interface):
|
||||
serial = None
|
||||
|
||||
def __init__(self, owner, port, speed, databits, parity, stopbits):
|
||||
self.serial = None
|
||||
self.owner = owner
|
||||
self.port = port
|
||||
self.speed = speed
|
||||
@ -31,6 +34,7 @@ class SerialInterface(Interface):
|
||||
self.parity = serial.PARITY_ODD
|
||||
|
||||
try:
|
||||
FPE.log("Opening serial port "+self.port+"...")
|
||||
self.serial = serial.Serial(
|
||||
port = self.port,
|
||||
baudrate = self.speed,
|
||||
@ -43,16 +47,16 @@ class SerialInterface(Interface):
|
||||
write_timeout = None,
|
||||
dsrdtr = False,
|
||||
)
|
||||
print(self.serial.inter_byte_timeout)
|
||||
except Exception as e:
|
||||
print("Could not create serial port", file=sys.stderr)
|
||||
FPE.log("Could not create serial port", FPE.LOG_ERROR)
|
||||
raise e
|
||||
|
||||
#self.serial.open()
|
||||
if self.serial.is_open:
|
||||
thread = threading.Thread(target=self.readLoop)
|
||||
thread.setDaemon(True)
|
||||
thread.start()
|
||||
sleep(0.5)
|
||||
FPE.log("Serial port "+self.port+" is now open")
|
||||
else:
|
||||
raise IOError("Could not open serial port")
|
||||
|
||||
@ -62,10 +66,13 @@ class SerialInterface(Interface):
|
||||
|
||||
|
||||
def processOutgoing(self,data):
|
||||
self.serial.write(data)
|
||||
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 == "":
|
||||
|
@ -2,4 +2,4 @@ import os
|
||||
import glob
|
||||
|
||||
modules = glob.glob(os.path.dirname(__file__)+"/*.py")
|
||||
__all__ = [ os.path.basename(f)[:-3] for f in modules if not f.endswith('__init__.py')]
|
||||
__all__ = [ os.path.basename(f)[:-3] for f in modules if not f.endswith('__init__.py')]
|
101
FPE/Packet.py
101
FPE/Packet.py
@ -1,30 +1,91 @@
|
||||
import struct
|
||||
from Transport import *
|
||||
import FPE
|
||||
|
||||
class Packet:
|
||||
# Constants
|
||||
MESSAGE = 0x00;
|
||||
RESOURCE = 0x01;
|
||||
LINKREQUEST = 0x02;
|
||||
PROOF = 0x03;
|
||||
types = [MESSAGE, RESOURCE, LINKREQUEST, PROOF]
|
||||
|
||||
def __init__(self, destination, data):
|
||||
self.destination = destination
|
||||
self.data = data
|
||||
self.flags = 0x00
|
||||
self.header = 0x00
|
||||
self.raw = None
|
||||
self.sent = False
|
||||
self.mtu = 0
|
||||
HEADER_1 = 0x00; # Normal header format
|
||||
HEADER_2 = 0x01; # Header format used for link packets in transport
|
||||
HEADER_3 = 0x02; # Reserved
|
||||
HEADER_4 = 0x03; # Reserved
|
||||
header_types = [HEADER_1, HEADER_2, HEADER_3, HEADER_4]
|
||||
|
||||
def __init__(self, destination, data, packet_type = MESSAGE, transport_type = None, header_type = HEADER_1, transport_id = None):
|
||||
if destination != None:
|
||||
if transport_type == None:
|
||||
transport_type = FPE.Transport.BROADCAST
|
||||
|
||||
self.header_type = header_type
|
||||
self.packet_type = packet_type
|
||||
self.transport_type = transport_type
|
||||
|
||||
self.hops = 0;
|
||||
self.destination = destination
|
||||
self.transport_id = transport_id
|
||||
self.data = data
|
||||
self.flags = self.getPackedFlags()
|
||||
|
||||
self.raw = None
|
||||
self.packed = False
|
||||
self.sent = False
|
||||
self.MTU = self.destination.MTU
|
||||
else:
|
||||
self.raw = data
|
||||
self.packed = True
|
||||
|
||||
def getPackedFlags(self):
|
||||
packed_flags = (self.header_type << 6) | (self.transport_type << 4) | (self.destination.type << 2) | self.packet_type
|
||||
return packed_flags
|
||||
|
||||
def pack(self):
|
||||
self.header = ""
|
||||
self.header += struct.pack("!B", self.flags)
|
||||
self.header += struct.pack("!B", self.hops)
|
||||
if self.header_type == Packet.HEADER_2:
|
||||
if t_destination != None:
|
||||
self.header += self.t_destination
|
||||
else:
|
||||
raise IOError("Packet with header type 2 must have a transport ID")
|
||||
|
||||
self.header += self.destination.hash
|
||||
self.ciphertext = self.destination.encrypt(self.data)
|
||||
self.raw = self.header + self.ciphertext
|
||||
|
||||
if len(self.raw) > self.MTU:
|
||||
raise IOError("Packet size of "+str(len(self.raw))+" exceeds MTU of "+str(self.MTU)+" bytes")
|
||||
|
||||
self.packed = True
|
||||
|
||||
def unpack(self):
|
||||
self.flags = ord(self.raw[0])
|
||||
self.hops = ord(self.raw[1])
|
||||
|
||||
self.header_type = (self.flags & 0b11000000) >> 6
|
||||
self.transport_type = (self.flags & 0b00110000) >> 4
|
||||
self.destination_type = (self.flags & 0b00001100) >> 2
|
||||
self.packet_type = (self.flags & 0b00000011)
|
||||
|
||||
if self.header_type == Packet.HEADER_2:
|
||||
self.transport_id = self.raw[2:12]
|
||||
self.destination_hash = self.raw[12:22]
|
||||
self.data = self.raw[22:]
|
||||
else:
|
||||
self.transport_id = None
|
||||
self.destination_hash = self.raw[2:12]
|
||||
self.data = self.raw[12:]
|
||||
|
||||
self.packed = False
|
||||
|
||||
def send(self):
|
||||
if not self.sent:
|
||||
self.MTU = self.destination.MTU
|
||||
self.header = struct.pack("!B", self.header ^ self.destination.type ^ self.flags)
|
||||
self.header += self.destination.hash
|
||||
self.ciphertext = self.destination.encrypt(self.data)
|
||||
self.raw = self.header + self.ciphertext
|
||||
|
||||
if len(self.raw) > self.MTU:
|
||||
raise IOError("Packet size of "+str(len(self.raw))+" exceeds MTU of "+str(self.MTU)+" bytes")
|
||||
|
||||
print("Size: "+str(len(self.raw)))
|
||||
Transport.outbound(self.raw)
|
||||
self.pack()
|
||||
FPE.log("Size: "+str(len(self.raw))+" header is "+str(len(self.header))+" payload is "+str(len(self.ciphertext)), FPE.LOG_DEBUG)
|
||||
FPE.Transport.outbound(self.raw)
|
||||
self.sent = True
|
||||
else:
|
||||
raise IOError("Packet was already sent")
|
||||
|
@ -1,10 +1,17 @@
|
||||
from FlexPE import FlexPE
|
||||
import FPE
|
||||
|
||||
class Transport:
|
||||
# Constants
|
||||
BROADCAST = 0x00;
|
||||
TRANSPORT = 0x01;
|
||||
RELAY = 0x02;
|
||||
TUNNEL = 0x03;
|
||||
types = [BROADCAST, TRANSPORT, RELAY, TUNNEL]
|
||||
|
||||
@staticmethod
|
||||
def outbound(raw):
|
||||
FlexPE.outbound(raw)
|
||||
FPE.FlexPE.outbound(raw)
|
||||
|
||||
@staticmethod
|
||||
def registerDestination(destination):
|
||||
FlexPE.addDestination(destination)
|
||||
FPE.FlexPE.addDestination(destination)
|
@ -1,11 +1,60 @@
|
||||
import os
|
||||
import glob
|
||||
import time
|
||||
|
||||
from .Destination import Destination
|
||||
from .FlexPE import FlexPE
|
||||
from .Identity import Identity
|
||||
from .Packet import Packet
|
||||
from .Transport import Transport
|
||||
from .Destination import Destination
|
||||
from .Packet import Packet
|
||||
|
||||
modules = glob.glob(os.path.dirname(__file__)+"/*.py")
|
||||
__all__ = [ os.path.basename(f)[:-3] for f in modules if not f.endswith('__init__.py')]
|
||||
__all__ = [ os.path.basename(f)[:-3] for f in modules if not f.endswith('__init__.py')]
|
||||
|
||||
LOG_CRITICAL = 0
|
||||
LOG_ERROR = 1
|
||||
LOG_WARNING = 2
|
||||
LOG_NOTICE = 3
|
||||
LOG_INFO = 4
|
||||
LOG_VERBOSE = 5
|
||||
LOG_DEBUG = 6
|
||||
|
||||
LOG_STDOUT = 0x91
|
||||
LOG_FILE = 0x92
|
||||
|
||||
loglevel = LOG_NOTICE
|
||||
logfile = None
|
||||
logdest = LOG_STDOUT
|
||||
logtimefmt = "%Y-%m-%d %H:%M:%S"
|
||||
|
||||
def loglevelname(level):
|
||||
if (level == LOG_CRITICAL):
|
||||
return "Critical"
|
||||
if (level == LOG_ERROR):
|
||||
return "Error"
|
||||
if (level == LOG_WARNING):
|
||||
return "Warning"
|
||||
if (level == LOG_NOTICE):
|
||||
return "Notice"
|
||||
if (level == LOG_INFO):
|
||||
return "Info"
|
||||
if (level == LOG_VERBOSE):
|
||||
return "Verbose"
|
||||
if (level == LOG_DEBUG):
|
||||
return "Debug"
|
||||
|
||||
return "Unknown"
|
||||
|
||||
def log(msg, level=3):
|
||||
# TODO: not thread safe
|
||||
if loglevel >= level:
|
||||
timestamp = time.time()
|
||||
logstring = "["+time.strftime(logtimefmt)+"] ["+loglevelname(level)+"] "+msg
|
||||
|
||||
if (logdest == LOG_STDOUT):
|
||||
print(logstring)
|
||||
|
||||
if (logdest == LOG_FILE and logfile != None):
|
||||
file = open(logfile, "a")
|
||||
file.write(logstring+"\n")
|
||||
file.close()
|
||||
|
30
Notes/Header format
Normal file
30
Notes/Header format
Normal file
@ -0,0 +1,30 @@
|
||||
header types
|
||||
-----------------
|
||||
type 1 00 One byte header, one 10 byte address field
|
||||
type 2 01 One byte header, two 10 byte address fields
|
||||
type 3 10 Reserved
|
||||
type 4 11 Reserved
|
||||
|
||||
|
||||
propagation types
|
||||
-----------------
|
||||
broadcast 00
|
||||
transport 01
|
||||
relay 10
|
||||
tunnel 11
|
||||
|
||||
|
||||
destination types
|
||||
-----------------
|
||||
single 00
|
||||
group 01
|
||||
plain 10
|
||||
link 11
|
||||
|
||||
|
||||
packet types
|
||||
-----------------
|
||||
message 00
|
||||
resource 01
|
||||
link request 10
|
||||
proof 11
|
31
t.py
31
t.py
@ -19,33 +19,32 @@ identity = Identity()
|
||||
d1=Destination(identity, Destination.IN, Destination.SINGLE, "messenger", "user")
|
||||
d1.setCallback(testCallback)
|
||||
|
||||
d2=Destination(identity, Destination.IN, Destination.PLAIN, "messenger", "user")
|
||||
d2.setCallback(testCallback)
|
||||
|
||||
# d2=Destination(identity, Destination.IN, Destination.PLAIN, "plainchat", "markqvist")
|
||||
# d2.setCallback(testCallback)
|
||||
|
||||
print identity.hexhash
|
||||
print d1.name
|
||||
print d1.hexhash
|
||||
print d1.identity.pub
|
||||
print "---"
|
||||
print
|
||||
#print identity.hexhash
|
||||
#print d1.name
|
||||
#print d1.hexhash
|
||||
#print d1.identity.pub
|
||||
#print "---"
|
||||
#print
|
||||
|
||||
# p1=Packet(d1, "testmessage")
|
||||
# p1.send()
|
||||
msg=""
|
||||
for x in range(300):
|
||||
msg += "a"
|
||||
signed = d1.sign(msg)
|
||||
sl = len(signed)
|
||||
pl = len(d1.identity.pub_bytes)
|
||||
print("Signature length is "+str(sl))
|
||||
print("Minimum announce is "+str(pl+sl+8))
|
||||
#print("Signature length is "+str(sl))
|
||||
#print("Minimum announce is "+str(pl+sl+8))
|
||||
|
||||
p1=Packet(d1, msg)
|
||||
p1.send()
|
||||
|
||||
p2=Packet(d1, msg)
|
||||
p2.send()
|
||||
|
||||
# p2=Packet(d2, "something else")
|
||||
# p2=Packet(d2,"Test af msg")
|
||||
# p2.send()
|
||||
|
||||
raw_input()
|
||||
|
||||
raw_input()
|
Loading…
Reference in New Issue
Block a user