mirror of
https://github.com/markqvist/Reticulum.git
synced 2024-11-11 00:30:14 +00:00
Implemented ratchets
This commit is contained in:
parent
c32086c6f1
commit
a11f14e75f
@ -1,6 +1,6 @@
|
|||||||
# MIT License
|
# MIT License
|
||||||
#
|
#
|
||||||
# Copyright (c) 2016-2023 Mark Qvist / unsigned.io and contributors
|
# Copyright (c) 2016-2024 Mark Qvist / unsigned.io and contributors
|
||||||
#
|
#
|
||||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
# of this software and associated documentation files (the "Software"), to deal
|
# of this software and associated documentation files (the "Software"), to deal
|
||||||
@ -72,7 +72,7 @@ class Destination:
|
|||||||
directions = [IN, OUT]
|
directions = [IN, OUT]
|
||||||
|
|
||||||
PR_TAG_WINDOW = 30
|
PR_TAG_WINDOW = 30
|
||||||
RATCHET_COUNT = 128
|
RATCHET_COUNT = 256
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def expand_name(identity, app_name, *aspects):
|
def expand_name(identity, app_name, *aspects):
|
||||||
@ -219,7 +219,7 @@ class Destination:
|
|||||||
def rotate_ratchets(self):
|
def rotate_ratchets(self):
|
||||||
if self.ratchets != None:
|
if self.ratchets != None:
|
||||||
RNS.log("Rotating ratchets for "+str(self), RNS.LOG_DEBUG) # TODO: Remove
|
RNS.log("Rotating ratchets for "+str(self), RNS.LOG_DEBUG) # TODO: Remove
|
||||||
new_ratchet = RNS.Identity.generate_ratchet()
|
new_ratchet = RNS.Identity._generate_ratchet()
|
||||||
self.ratchets.insert(0, new_ratchet)
|
self.ratchets.insert(0, new_ratchet)
|
||||||
if len (self.ratchets) > Destination.RATCHET_COUNT:
|
if len (self.ratchets) > Destination.RATCHET_COUNT:
|
||||||
self.ratchets = self.ratchets[:Destination.RATCHET_COUNT]
|
self.ratchets = self.ratchets[:Destination.RATCHET_COUNT]
|
||||||
@ -241,6 +241,7 @@ class Destination:
|
|||||||
if self.direction != Destination.IN:
|
if self.direction != Destination.IN:
|
||||||
raise TypeError("Only IN destination types can be announced")
|
raise TypeError("Only IN destination types can be announced")
|
||||||
|
|
||||||
|
ratchet = b""
|
||||||
now = time.time()
|
now = time.time()
|
||||||
stale_responses = []
|
stale_responses = []
|
||||||
for entry_tag in self.path_responses:
|
for entry_tag in self.path_responses:
|
||||||
@ -269,8 +270,8 @@ class Destination:
|
|||||||
|
|
||||||
if self.ratchets != None:
|
if self.ratchets != None:
|
||||||
self.rotate_ratchets()
|
self.rotate_ratchets()
|
||||||
ratchet_pub = RNS.Identity.ratchet_public_bytes(self.ratchets[0])
|
ratchet = RNS.Identity._ratchet_public_bytes(self.ratchets[0])
|
||||||
RNS.log(f"Including {len(ratchet_pub)*8}-bit ratchet {RNS.hexrep(ratchet_pub)} in announce", RNS.LOG_DEBUG) # TODO: Remove
|
RNS.log(f"Including {len(ratchet)*8}-bit ratchet {RNS.hexrep(ratchet)} in announce", RNS.LOG_DEBUG) # TODO: Remove
|
||||||
|
|
||||||
if app_data == None and self.default_app_data != None:
|
if app_data == None and self.default_app_data != None:
|
||||||
if isinstance(self.default_app_data, bytes):
|
if isinstance(self.default_app_data, bytes):
|
||||||
@ -280,13 +281,12 @@ class Destination:
|
|||||||
if isinstance(returned_app_data, bytes):
|
if isinstance(returned_app_data, bytes):
|
||||||
app_data = returned_app_data
|
app_data = returned_app_data
|
||||||
|
|
||||||
signed_data = self.hash+self.identity.get_public_key()+self.name_hash+random_hash
|
signed_data = self.hash+self.identity.get_public_key()+self.name_hash+random_hash+ratchet
|
||||||
if app_data != None:
|
if app_data != None:
|
||||||
signed_data += app_data
|
signed_data += app_data
|
||||||
|
|
||||||
signature = self.identity.sign(signed_data)
|
signature = self.identity.sign(signed_data)
|
||||||
|
announce_data = self.identity.get_public_key()+self.name_hash+random_hash+ratchet+signature
|
||||||
announce_data = self.identity.get_public_key()+self.name_hash+random_hash+signature
|
|
||||||
|
|
||||||
if app_data != None:
|
if app_data != None:
|
||||||
announce_data += app_data
|
announce_data += app_data
|
||||||
@ -298,8 +298,13 @@ class Destination:
|
|||||||
else:
|
else:
|
||||||
announce_context = RNS.Packet.NONE
|
announce_context = RNS.Packet.NONE
|
||||||
|
|
||||||
announce_packet = RNS.Packet(self, announce_data, RNS.Packet.ANNOUNCE, context = announce_context, attached_interface = attached_interface)
|
if ratchet:
|
||||||
|
context_flag = RNS.Packet.FLAG_SET
|
||||||
|
else:
|
||||||
|
context_flag = RNS.Packet.FLAG_UNSET
|
||||||
|
|
||||||
|
announce_packet = RNS.Packet(self, announce_data, RNS.Packet.ANNOUNCE, context = announce_context,
|
||||||
|
attached_interface = attached_interface, context_flag=context_flag)
|
||||||
if send:
|
if send:
|
||||||
announce_packet.send()
|
announce_packet.send()
|
||||||
else:
|
else:
|
||||||
@ -485,7 +490,7 @@ class Destination:
|
|||||||
return plaintext
|
return plaintext
|
||||||
|
|
||||||
if self.type == Destination.SINGLE and self.identity != None:
|
if self.type == Destination.SINGLE and self.identity != None:
|
||||||
return self.identity.encrypt(plaintext)
|
return self.identity.encrypt(plaintext, ratchet=RNS.Identity.get_ratchet(self.hash))
|
||||||
|
|
||||||
if self.type == Destination.GROUP:
|
if self.type == Destination.GROUP:
|
||||||
if hasattr(self, "prv") and self.prv != None:
|
if hasattr(self, "prv") and self.prv != None:
|
||||||
@ -510,7 +515,7 @@ class Destination:
|
|||||||
return ciphertext
|
return ciphertext
|
||||||
|
|
||||||
if self.type == Destination.SINGLE and self.identity != None:
|
if self.type == Destination.SINGLE and self.identity != None:
|
||||||
return self.identity.decrypt(ciphertext)
|
return self.identity.decrypt(ciphertext, ratchets=self.ratchets)
|
||||||
|
|
||||||
if self.type == Destination.GROUP:
|
if self.type == Destination.GROUP:
|
||||||
if hasattr(self, "prv") and self.prv != None:
|
if hasattr(self, "prv") and self.prv != None:
|
||||||
|
161
RNS/Identity.py
161
RNS/Identity.py
@ -1,6 +1,6 @@
|
|||||||
# MIT License
|
# MIT License
|
||||||
#
|
#
|
||||||
# Copyright (c) 2016-2023 Mark Qvist / unsigned.io and contributors.
|
# Copyright (c) 2016-2024 Mark Qvist / unsigned.io and contributors.
|
||||||
#
|
#
|
||||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
# of this software and associated documentation files (the "Software"), to deal
|
# of this software and associated documentation files (the "Software"), to deal
|
||||||
@ -52,6 +52,9 @@ class Identity:
|
|||||||
X25519 key size in bits. A complete key is the concatenation of a 256 bit encryption key, and a 256 bit signing key.
|
X25519 key size in bits. A complete key is the concatenation of a 256 bit encryption key, and a 256 bit signing key.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
RATCHETSIZE = 256
|
||||||
|
RATCHET_EXPIRY = 60*60*24*30
|
||||||
|
|
||||||
# Non-configurable constants
|
# Non-configurable constants
|
||||||
FERNET_OVERHEAD = RNS.Cryptography.Fernet.FERNET_OVERHEAD
|
FERNET_OVERHEAD = RNS.Cryptography.Fernet.FERNET_OVERHEAD
|
||||||
AES128_BLOCKSIZE = 16 # In bytes
|
AES128_BLOCKSIZE = 16 # In bytes
|
||||||
@ -67,6 +70,7 @@ class Identity:
|
|||||||
|
|
||||||
# Storage
|
# Storage
|
||||||
known_destinations = {}
|
known_destinations = {}
|
||||||
|
known_ratchets = {}
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def remember(packet_hash, destination_hash, public_key, app_data = None):
|
def remember(packet_hash, destination_hash, public_key, app_data = None):
|
||||||
@ -222,29 +226,102 @@ class Identity:
|
|||||||
return Identity.truncated_hash(os.urandom(Identity.TRUNCATED_HASHLENGTH//8))
|
return Identity.truncated_hash(os.urandom(Identity.TRUNCATED_HASHLENGTH//8))
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def generate_ratchet():
|
def _ratchet_public_bytes(ratchet):
|
||||||
|
return X25519PrivateKey.from_private_bytes(ratchet).public_key().public_bytes()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _generate_ratchet():
|
||||||
ratchet_prv = X25519PrivateKey.generate()
|
ratchet_prv = X25519PrivateKey.generate()
|
||||||
ratchet_pub = ratchet_prv.public_key()
|
ratchet_pub = ratchet_prv.public_key()
|
||||||
return ratchet_prv.private_bytes()
|
return ratchet_prv.private_bytes()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def ratchet_public_bytes(ratchet):
|
def _remember_ratchet(destination_hash, ratchet):
|
||||||
return X25519PrivateKey.from_private_bytes(ratchet).public_key().public_bytes()
|
RNS.log(f"Remembering ratchet {RNS.hexrep(ratchet)} for {RNS.prettyhexrep(destination_hash)}", RNS.LOG_DEBUG) # TODO: Remove
|
||||||
|
try:
|
||||||
|
Identity.known_ratchets[destination_hash] = ratchet
|
||||||
|
hexhash = RNS.hexrep(destination_hash, delimit=False)
|
||||||
|
ratchet_data = {"ratchet": ratchet, "received": time.time()}
|
||||||
|
|
||||||
|
ratchetdir = RNS.Reticulum.storagepath+"/ratchets"
|
||||||
|
|
||||||
|
if not os.path.isdir(ratchetdir):
|
||||||
|
os.makedirs(ratchetdir)
|
||||||
|
|
||||||
|
outpath = f"{ratchetdir}/{hexhash}.out"
|
||||||
|
finalpath = f"{ratchetdir}/{hexhash}"
|
||||||
|
ratchet_file = open(outpath, "wb")
|
||||||
|
ratchet_file.write(umsgpack.packb(ratchet_data))
|
||||||
|
ratchet_file.close()
|
||||||
|
os.rename(outpath, finalpath)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
RNS.log(f"Could not persist ratchet for {RNS.prettyhexrep(destination_hash)} to storage.", RNS.LOG_ERROR)
|
||||||
|
RNS.log(f"The contained exception was: {e}")
|
||||||
|
RNS.trace_exception(e)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_ratchet(destination_hash):
|
||||||
|
if not destination_hash in Identity.known_ratchets:
|
||||||
|
RNS.log(f"Trying to load ratchet for {RNS.prettyhexrep(destination_hash)} from storage") # TODO: Remove
|
||||||
|
ratchetdir = RNS.Reticulum.storagepath+"/ratchets"
|
||||||
|
hexhash = RNS.hexrep(destination_hash, delimit=False)
|
||||||
|
ratchet_path = f"{ratchetdir}/hexhash"
|
||||||
|
if os.path.isfile(ratchet_path):
|
||||||
|
try:
|
||||||
|
ratchet_file = open(ratchet_path, "rb")
|
||||||
|
ratchet_data = umsgpack.unpackb(ratchets_file.read())
|
||||||
|
if time.time() < ratchet_data["received"]+Identity.RATCHET_EXPIRY and len(ratchet_data["ratchet"]) == Identity.RATCHETSIZE//8:
|
||||||
|
Identity.known_ratchets[destination_hash] = ratchet_data["ratchet"]
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
RNS.log(f"An error occurred while loading ratchet data for {RNS.prettyhexrep(destination_hash)} from storage.", RNS.LOG_ERROR)
|
||||||
|
RNS.log(f"The contained exception was: {e}", RNS.LOG_ERROR)
|
||||||
|
return None
|
||||||
|
|
||||||
|
if destination_hash in Identity.known_ratchets:
|
||||||
|
return Identity.known_ratchets[destination_hash]
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def validate_announce(packet, only_validate_signature=False):
|
def validate_announce(packet, only_validate_signature=False):
|
||||||
try:
|
try:
|
||||||
if packet.packet_type == RNS.Packet.ANNOUNCE:
|
if packet.packet_type == RNS.Packet.ANNOUNCE:
|
||||||
|
keysize = Identity.KEYSIZE//8
|
||||||
|
ratchetsize = Identity.RATCHETSIZE//8
|
||||||
|
name_hash_len = Identity.NAME_HASH_LENGTH//8
|
||||||
|
sig_len = Identity.SIGLENGTH//8
|
||||||
destination_hash = packet.destination_hash
|
destination_hash = packet.destination_hash
|
||||||
public_key = packet.data[:Identity.KEYSIZE//8]
|
|
||||||
name_hash = packet.data[Identity.KEYSIZE//8:Identity.KEYSIZE//8+Identity.NAME_HASH_LENGTH//8]
|
|
||||||
random_hash = packet.data[Identity.KEYSIZE//8+Identity.NAME_HASH_LENGTH//8:Identity.KEYSIZE//8+Identity.NAME_HASH_LENGTH//8+10]
|
|
||||||
signature = packet.data[Identity.KEYSIZE//8+Identity.NAME_HASH_LENGTH//8+10:Identity.KEYSIZE//8+Identity.NAME_HASH_LENGTH//8+10+Identity.SIGLENGTH//8]
|
|
||||||
app_data = b""
|
|
||||||
if len(packet.data) > Identity.KEYSIZE//8+Identity.NAME_HASH_LENGTH//8+10+Identity.SIGLENGTH//8:
|
|
||||||
app_data = packet.data[Identity.KEYSIZE//8+Identity.NAME_HASH_LENGTH//8+10+Identity.SIGLENGTH//8:]
|
|
||||||
|
|
||||||
signed_data = destination_hash+public_key+name_hash+random_hash+app_data
|
# Get public key bytes from announce
|
||||||
|
public_key = packet.data[:keysize]
|
||||||
|
|
||||||
|
# If the packet context flag is set,
|
||||||
|
# this announce contains a new ratchet
|
||||||
|
if packet.context_flag == RNS.Packet.FLAG_SET:
|
||||||
|
name_hash = packet.data[keysize:keysize+name_hash_len ]
|
||||||
|
random_hash = packet.data[keysize+name_hash_len:keysize+name_hash_len+10]
|
||||||
|
ratchet = packet.data[keysize+name_hash_len+10:keysize+name_hash_len+10+ratchetsize]
|
||||||
|
signature = packet.data[keysize+name_hash_len+10+ratchetsize:keysize+name_hash_len+10+ratchetsize+sig_len]
|
||||||
|
app_data = b""
|
||||||
|
if len(packet.data) > keysize+name_hash_len+10+sig_len+ratchetsize:
|
||||||
|
app_data = packet.data[keysize+name_hash_len+10+sig_len+ratchetsize:]
|
||||||
|
|
||||||
|
# If the packet context flag is not set,
|
||||||
|
# this announce does not contain a ratchet
|
||||||
|
else:
|
||||||
|
ratchet = b""
|
||||||
|
name_hash = packet.data[keysize:keysize+name_hash_len]
|
||||||
|
random_hash = packet.data[keysize+name_hash_len:keysize+name_hash_len+10]
|
||||||
|
signature = packet.data[keysize+name_hash_len+10:keysize+name_hash_len+10+sig_len]
|
||||||
|
app_data = b""
|
||||||
|
if len(packet.data) > keysize+name_hash_len+10+sig_len:
|
||||||
|
app_data = packet.data[keysize+name_hash_len+10+sig_len:]
|
||||||
|
|
||||||
|
signed_data = destination_hash+public_key+name_hash+random_hash+ratchet+app_data
|
||||||
|
|
||||||
if not len(packet.data) > Identity.KEYSIZE//8+Identity.NAME_HASH_LENGTH//8+10+Identity.SIGLENGTH//8:
|
if not len(packet.data) > Identity.KEYSIZE//8+Identity.NAME_HASH_LENGTH//8+10+Identity.SIGLENGTH//8:
|
||||||
app_data = None
|
app_data = None
|
||||||
@ -291,6 +368,9 @@ class Identity:
|
|||||||
else:
|
else:
|
||||||
RNS.log("Valid announce for "+RNS.prettyhexrep(destination_hash)+" "+str(packet.hops)+" hops away, received on "+str(packet.receiving_interface)+signal_str, RNS.LOG_EXTREME)
|
RNS.log("Valid announce for "+RNS.prettyhexrep(destination_hash)+" "+str(packet.hops)+" hops away, received on "+str(packet.receiving_interface)+signal_str, RNS.LOG_EXTREME)
|
||||||
|
|
||||||
|
if ratchet:
|
||||||
|
Identity._remember_ratchet(destination_hash, ratchet)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
else:
|
else:
|
||||||
@ -479,7 +559,7 @@ class Identity:
|
|||||||
def get_context(self):
|
def get_context(self):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def encrypt(self, plaintext):
|
def encrypt(self, plaintext, ratchet=None):
|
||||||
"""
|
"""
|
||||||
Encrypts information for the identity.
|
Encrypts information for the identity.
|
||||||
|
|
||||||
@ -491,7 +571,13 @@ class Identity:
|
|||||||
ephemeral_key = X25519PrivateKey.generate()
|
ephemeral_key = X25519PrivateKey.generate()
|
||||||
ephemeral_pub_bytes = ephemeral_key.public_key().public_bytes()
|
ephemeral_pub_bytes = ephemeral_key.public_key().public_bytes()
|
||||||
|
|
||||||
shared_key = ephemeral_key.exchange(self.pub)
|
if ratchet != None:
|
||||||
|
RNS.log(f"Encrypting with ratchet {RNS.hexrep(ratchet)}", RNS.LOG_DEBUG) # TODO: Remove
|
||||||
|
target_public_key = X25519PublicKey.from_public_bytes(ratchet)
|
||||||
|
else:
|
||||||
|
target_public_key = self.pub
|
||||||
|
|
||||||
|
shared_key = ephemeral_key.exchange(target_public_key)
|
||||||
|
|
||||||
derived_key = RNS.Cryptography.hkdf(
|
derived_key = RNS.Cryptography.hkdf(
|
||||||
length=32,
|
length=32,
|
||||||
@ -509,7 +595,7 @@ class Identity:
|
|||||||
raise KeyError("Encryption failed because identity does not hold a public key")
|
raise KeyError("Encryption failed because identity does not hold a public key")
|
||||||
|
|
||||||
|
|
||||||
def decrypt(self, ciphertext_token):
|
def decrypt(self, ciphertext_token, ratchets=None):
|
||||||
"""
|
"""
|
||||||
Decrypts information for the identity.
|
Decrypts information for the identity.
|
||||||
|
|
||||||
@ -523,19 +609,40 @@ class Identity:
|
|||||||
try:
|
try:
|
||||||
peer_pub_bytes = ciphertext_token[:Identity.KEYSIZE//8//2]
|
peer_pub_bytes = ciphertext_token[:Identity.KEYSIZE//8//2]
|
||||||
peer_pub = X25519PublicKey.from_public_bytes(peer_pub_bytes)
|
peer_pub = X25519PublicKey.from_public_bytes(peer_pub_bytes)
|
||||||
|
|
||||||
shared_key = self.prv.exchange(peer_pub)
|
|
||||||
|
|
||||||
derived_key = RNS.Cryptography.hkdf(
|
|
||||||
length=32,
|
|
||||||
derive_from=shared_key,
|
|
||||||
salt=self.get_salt(),
|
|
||||||
context=self.get_context(),
|
|
||||||
)
|
|
||||||
|
|
||||||
fernet = Fernet(derived_key)
|
|
||||||
ciphertext = ciphertext_token[Identity.KEYSIZE//8//2:]
|
ciphertext = ciphertext_token[Identity.KEYSIZE//8//2:]
|
||||||
plaintext = fernet.decrypt(ciphertext)
|
|
||||||
|
if ratchets:
|
||||||
|
for ratchet in ratchets:
|
||||||
|
try:
|
||||||
|
ratchet_prv = X25519PrivateKey.from_private_bytes(ratchet)
|
||||||
|
shared_key = ratchet_prv.exchange(peer_pub)
|
||||||
|
derived_key = RNS.Cryptography.hkdf(
|
||||||
|
length=32,
|
||||||
|
derive_from=shared_key,
|
||||||
|
salt=self.get_salt(),
|
||||||
|
context=self.get_context(),
|
||||||
|
)
|
||||||
|
|
||||||
|
fernet = Fernet(derived_key)
|
||||||
|
plaintext = fernet.decrypt(ciphertext)
|
||||||
|
RNS.log(f"Decrypted with ratchet {RNS.hexrep(ratchet_prv.public_key().public_bytes())}", RNS.LOG_DEBUG) # TODO: Remove
|
||||||
|
break
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
pass
|
||||||
|
# RNS.log("Decryption using this ratchet failed", RNS.LOG_DEBUG) # TODO: Remove
|
||||||
|
|
||||||
|
if plaintext == None:
|
||||||
|
shared_key = self.prv.exchange(peer_pub)
|
||||||
|
derived_key = RNS.Cryptography.hkdf(
|
||||||
|
length=32,
|
||||||
|
derive_from=shared_key,
|
||||||
|
salt=self.get_salt(),
|
||||||
|
context=self.get_context(),
|
||||||
|
)
|
||||||
|
|
||||||
|
fernet = Fernet(derived_key)
|
||||||
|
plaintext = fernet.decrypt(ciphertext)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
RNS.log("Decryption by "+RNS.prettyhexrep(self.hash)+" failed: "+str(e), RNS.LOG_DEBUG)
|
RNS.log("Decryption by "+RNS.prettyhexrep(self.hash)+" failed: "+str(e), RNS.LOG_DEBUG)
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# MIT License
|
# MIT License
|
||||||
#
|
#
|
||||||
# Copyright (c) 2016-2023 Mark Qvist / unsigned.io and contributors.
|
# Copyright (c) 2016-2024 Mark Qvist / unsigned.io and contributors.
|
||||||
#
|
#
|
||||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
# of this software and associated documentation files (the "Software"), to deal
|
# of this software and associated documentation files (the "Software"), to deal
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# MIT License
|
# MIT License
|
||||||
#
|
#
|
||||||
# Copyright (c) 2016-2023 Mark Qvist / unsigned.io and contributors.
|
# Copyright (c) 2016-2024 Mark Qvist / unsigned.io and contributors.
|
||||||
#
|
#
|
||||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
# of this software and associated documentation files (the "Software"), to deal
|
# of this software and associated documentation files (the "Software"), to deal
|
||||||
@ -83,6 +83,10 @@ class Packet:
|
|||||||
LRRTT = 0xFE # Packet is a link request round-trip time measurement
|
LRRTT = 0xFE # Packet is a link request round-trip time measurement
|
||||||
LRPROOF = 0xFF # Packet is a link request proof
|
LRPROOF = 0xFF # Packet is a link request proof
|
||||||
|
|
||||||
|
# Context flag values
|
||||||
|
FLAG_SET = 0x01
|
||||||
|
FLAG_UNSET = 0x00
|
||||||
|
|
||||||
# This is used to calculate allowable
|
# This is used to calculate allowable
|
||||||
# payload sizes
|
# payload sizes
|
||||||
HEADER_MAXSIZE = RNS.Reticulum.HEADER_MAXSIZE
|
HEADER_MAXSIZE = RNS.Reticulum.HEADER_MAXSIZE
|
||||||
@ -102,7 +106,9 @@ class Packet:
|
|||||||
|
|
||||||
TIMEOUT_PER_HOP = RNS.Reticulum.DEFAULT_PER_HOP_TIMEOUT
|
TIMEOUT_PER_HOP = RNS.Reticulum.DEFAULT_PER_HOP_TIMEOUT
|
||||||
|
|
||||||
def __init__(self, destination, data, packet_type = DATA, context = NONE, transport_type = RNS.Transport.BROADCAST, header_type = HEADER_1, transport_id = None, attached_interface = None, create_receipt = True):
|
def __init__(self, destination, data, packet_type = DATA, context = NONE, transport_type = RNS.Transport.BROADCAST,
|
||||||
|
header_type = HEADER_1, transport_id = None, attached_interface = None, create_receipt = True, context_flag=FLAG_UNSET):
|
||||||
|
|
||||||
if destination != None:
|
if destination != None:
|
||||||
if transport_type == None:
|
if transport_type == None:
|
||||||
transport_type = RNS.Transport.BROADCAST
|
transport_type = RNS.Transport.BROADCAST
|
||||||
@ -111,6 +117,7 @@ class Packet:
|
|||||||
self.packet_type = packet_type
|
self.packet_type = packet_type
|
||||||
self.transport_type = transport_type
|
self.transport_type = transport_type
|
||||||
self.context = context
|
self.context = context
|
||||||
|
self.context_flag = context_flag
|
||||||
|
|
||||||
self.hops = 0;
|
self.hops = 0;
|
||||||
self.destination = destination
|
self.destination = destination
|
||||||
@ -142,9 +149,10 @@ class Packet:
|
|||||||
|
|
||||||
def get_packed_flags(self):
|
def get_packed_flags(self):
|
||||||
if self.context == Packet.LRPROOF:
|
if self.context == Packet.LRPROOF:
|
||||||
packed_flags = (self.header_type << 6) | (self.transport_type << 4) | (RNS.Destination.LINK << 2) | self.packet_type
|
packed_flags = (self.header_type << 6) | (self.context_flag << 5) | (self.transport_type << 4) | (RNS.Destination.LINK << 2) | self.packet_type
|
||||||
else:
|
else:
|
||||||
packed_flags = (self.header_type << 6) | (self.transport_type << 4) | (self.destination.type << 2) | self.packet_type
|
packed_flags = (self.header_type << 6) | (self.context_flag << 5) | (self.transport_type << 4) | (self.destination.type << 2) | self.packet_type
|
||||||
|
|
||||||
return packed_flags
|
return packed_flags
|
||||||
|
|
||||||
def pack(self):
|
def pack(self):
|
||||||
@ -216,7 +224,8 @@ class Packet:
|
|||||||
self.hops = self.raw[1]
|
self.hops = self.raw[1]
|
||||||
|
|
||||||
self.header_type = (self.flags & 0b01000000) >> 6
|
self.header_type = (self.flags & 0b01000000) >> 6
|
||||||
self.transport_type = (self.flags & 0b00110000) >> 4
|
self.context_flag = (self.flags & 0b00100000) >> 5
|
||||||
|
self.transport_type = (self.flags & 0b00010000) >> 4
|
||||||
self.destination_type = (self.flags & 0b00001100) >> 2
|
self.destination_type = (self.flags & 0b00001100) >> 2
|
||||||
self.packet_type = (self.flags & 0b00000011)
|
self.packet_type = (self.flags & 0b00000011)
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# MIT License
|
# MIT License
|
||||||
#
|
#
|
||||||
# Copyright (c) 2016-2023 Mark Qvist / unsigned.io and contributors.
|
# Copyright (c) 2016-2024 Mark Qvist / unsigned.io and contributors.
|
||||||
#
|
#
|
||||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
# of this software and associated documentation files (the "Software"), to deal
|
# of this software and associated documentation files (the "Software"), to deal
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# MIT License
|
# MIT License
|
||||||
#
|
#
|
||||||
# Copyright (c) 2016-2023 Mark Qvist / unsigned.io and contributors.
|
# Copyright (c) 2016-2024 Mark Qvist / unsigned.io and contributors.
|
||||||
#
|
#
|
||||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
# of this software and associated documentation files (the "Software"), to deal
|
# of this software and associated documentation files (the "Software"), to deal
|
||||||
@ -403,7 +403,8 @@ class Transport:
|
|||||||
header_type = RNS.Packet.HEADER_2,
|
header_type = RNS.Packet.HEADER_2,
|
||||||
transport_type = Transport.TRANSPORT,
|
transport_type = Transport.TRANSPORT,
|
||||||
transport_id = Transport.identity.hash,
|
transport_id = Transport.identity.hash,
|
||||||
attached_interface = attached_interface
|
attached_interface = attached_interface,
|
||||||
|
context_flag = packet.context_flag,
|
||||||
)
|
)
|
||||||
|
|
||||||
new_packet.hops = announce_entry[4]
|
new_packet.hops = announce_entry[4]
|
||||||
|
Loading…
Reference in New Issue
Block a user