mirror of
https://github.com/markqvist/Reticulum.git
synced 2024-11-22 21:50:18 +00:00
Compare commits
29 Commits
01a91ccd6c
...
9b7a9ad0cd
Author | SHA1 | Date | |
---|---|---|---|
|
9b7a9ad0cd | ||
|
c119ef4273 | ||
|
b506ca94d0 | ||
|
a072a5b074 | ||
|
3a580e74de | ||
|
fe054fd03c | ||
|
4524a17e67 | ||
|
8a82d6bfeb | ||
|
971f5ffadd | ||
|
6a392fdb0f | ||
|
b42e075be0 | ||
|
4bc8a0b69b | ||
|
9ef10a7b3e | ||
|
320704f812 | ||
|
c5e5986b89 | ||
|
d21dda2830 | ||
|
6ac393bbcd | ||
|
0c04663942 | ||
|
bfa216de54 | ||
|
a4b1606921 | ||
|
ad0db9c95c | ||
|
2fdcbec860 | ||
|
dd889d16d4 | ||
|
a11f14e75f | ||
|
c32086c6f1 | ||
|
54eaff203f | ||
|
2bf75f60bc | ||
|
3f64141455 | ||
|
063ea2bb7a |
@ -5,7 +5,6 @@
|
|||||||
# of the packet. #
|
# of the packet. #
|
||||||
##########################################################
|
##########################################################
|
||||||
|
|
||||||
import os
|
|
||||||
import argparse
|
import argparse
|
||||||
import RNS
|
import RNS
|
||||||
|
|
||||||
@ -28,19 +27,8 @@ def server(configpath):
|
|||||||
# We must first initialise Reticulum
|
# We must first initialise Reticulum
|
||||||
reticulum = RNS.Reticulum(configpath)
|
reticulum = RNS.Reticulum(configpath)
|
||||||
|
|
||||||
# Load identity from file if it exist or randomley create
|
# Randomly create a new identity for our echo server
|
||||||
if configpath:
|
|
||||||
ifilepath = "%s/storage/identitiesy/%s" % (configpath,APP_NAME)
|
|
||||||
else:
|
|
||||||
ifilepath = "%s/storage/identities/%s" % (RNS.Reticulum.configdir,APP_NAME)
|
|
||||||
if os.path.exists(ifilepath):
|
|
||||||
# Load identity from file
|
|
||||||
server_identity = RNS.Identity.from_file(ifilepath)
|
|
||||||
RNS.log("loaded identity from file: "+ifilepath, RNS.LOG_VERBOSE)
|
|
||||||
else:
|
|
||||||
# Randomly create a new identity for our echo example
|
|
||||||
server_identity = RNS.Identity()
|
server_identity = RNS.Identity()
|
||||||
RNS.log("created new identity", RNS.LOG_VERBOSE)
|
|
||||||
|
|
||||||
# We create a destination that clients can query. We want
|
# We create a destination that clients can query. We want
|
||||||
# to be able to verify echo replies to our clients, so we
|
# to be able to verify echo replies to our clients, so we
|
||||||
|
@ -28,8 +28,8 @@ def server(configpath):
|
|||||||
# We must first initialise Reticulum
|
# We must first initialise Reticulum
|
||||||
reticulum = RNS.Reticulum(configpath)
|
reticulum = RNS.Reticulum(configpath)
|
||||||
|
|
||||||
|
# Randomly create a new identity for our link example
|
||||||
server_identity = RNS.Identity()
|
server_identity = RNS.Identity()
|
||||||
RNS.log("created new identity", RNS.LOG_VERBOSE)
|
|
||||||
|
|
||||||
# We create a destination that clients can connect to. We
|
# We create a destination that clients can connect to. We
|
||||||
# want clients to create links to this destination, so we
|
# want clients to create links to this destination, so we
|
||||||
@ -58,7 +58,7 @@ def server_loop(destination):
|
|||||||
" running, waiting for a connection."
|
" running, waiting for a connection."
|
||||||
)
|
)
|
||||||
|
|
||||||
RNS.log("Hit enter to manually send an announce (Ctrl-C or \"quit\" to quit)")
|
RNS.log("Hit enter to manually send an announce (Ctrl-C to quit)")
|
||||||
|
|
||||||
# We enter a loop that runs until the users exits.
|
# We enter a loop that runs until the users exits.
|
||||||
# If the user hits enter, we will announce our server
|
# If the user hits enter, we will announce our server
|
||||||
@ -68,12 +68,6 @@ def server_loop(destination):
|
|||||||
entered = input()
|
entered = input()
|
||||||
destination.announce()
|
destination.announce()
|
||||||
RNS.log("Sent announce from "+RNS.prettyhexrep(destination.hash))
|
RNS.log("Sent announce from "+RNS.prettyhexrep(destination.hash))
|
||||||
if entered == "quit":
|
|
||||||
if latest_client_link:
|
|
||||||
latest_client_link.teardown()
|
|
||||||
break
|
|
||||||
print("")
|
|
||||||
exit()
|
|
||||||
|
|
||||||
# When a client establishes a link to our server
|
# When a client establishes a link to our server
|
||||||
# destination, this function will be called with
|
# destination, this function will be called with
|
||||||
|
343
Examples/Ratchets.py
Normal file
343
Examples/Ratchets.py
Normal file
@ -0,0 +1,343 @@
|
|||||||
|
##########################################################
|
||||||
|
# This RNS example demonstrates a simple client/server #
|
||||||
|
# echo utility that uses ratchets to rotate encryption #
|
||||||
|
# keys everytime an announce is sent. #
|
||||||
|
##########################################################
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import RNS
|
||||||
|
|
||||||
|
# Let's define an app name. We'll use this for all
|
||||||
|
# destinations we create. Since this echo example
|
||||||
|
# is part of a range of example utilities, we'll put
|
||||||
|
# them all within the app namespace "example_utilities"
|
||||||
|
APP_NAME = "example_utilities"
|
||||||
|
|
||||||
|
|
||||||
|
##########################################################
|
||||||
|
#### Server Part #########################################
|
||||||
|
##########################################################
|
||||||
|
|
||||||
|
# This initialisation is executed when the users chooses
|
||||||
|
# to run as a server
|
||||||
|
def server(configpath):
|
||||||
|
global reticulum
|
||||||
|
|
||||||
|
# We must first initialise Reticulum
|
||||||
|
reticulum = RNS.Reticulum(configpath)
|
||||||
|
|
||||||
|
# TODO: Remove
|
||||||
|
RNS.loglevel = RNS.LOG_DEBUG
|
||||||
|
|
||||||
|
# Randomly create a new identity for our echo server
|
||||||
|
server_identity = RNS.Identity()
|
||||||
|
|
||||||
|
# We create a destination that clients can query. We want
|
||||||
|
# to be able to verify echo replies to our clients, so we
|
||||||
|
# create a "single" destination that can receive encrypted
|
||||||
|
# messages. This way the client can send a request and be
|
||||||
|
# certain that no-one else than this destination was able
|
||||||
|
# to read it.
|
||||||
|
echo_destination = RNS.Destination(
|
||||||
|
server_identity,
|
||||||
|
RNS.Destination.IN,
|
||||||
|
RNS.Destination.SINGLE,
|
||||||
|
APP_NAME,
|
||||||
|
"ratchet",
|
||||||
|
"echo",
|
||||||
|
"request"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Enable ratchets on the destination by providing a file
|
||||||
|
# path to store ratchets. In this example, we will just
|
||||||
|
# use a temporary file, but in real-world applications,
|
||||||
|
# it's extremely important to keep this file secure, since
|
||||||
|
# it contains encryption keys for the destination.
|
||||||
|
destination_hexhash = RNS.hexrep(echo_destination.hash, delimit=False)
|
||||||
|
echo_destination.enable_ratchets(f"/tmp/{destination_hexhash}.ratchets")
|
||||||
|
|
||||||
|
# We configure the destination to automatically prove all
|
||||||
|
# packets addressed to it. By doing this, RNS will automatically
|
||||||
|
# generate a proof for each incoming packet and transmit it
|
||||||
|
# back to the sender of that packet.
|
||||||
|
echo_destination.set_proof_strategy(RNS.Destination.PROVE_ALL)
|
||||||
|
|
||||||
|
# Tell the destination which function in our program to
|
||||||
|
# run when a packet is received. We do this so we can
|
||||||
|
# print a log message when the server receives a request
|
||||||
|
echo_destination.set_packet_callback(server_callback)
|
||||||
|
|
||||||
|
# Everything's ready!
|
||||||
|
# Let's Wait for client requests or user input
|
||||||
|
announceLoop(echo_destination)
|
||||||
|
|
||||||
|
|
||||||
|
def announceLoop(destination):
|
||||||
|
# Let the user know that everything is ready
|
||||||
|
RNS.log(
|
||||||
|
"Ratcheted echo server "+
|
||||||
|
RNS.prettyhexrep(destination.hash)+
|
||||||
|
" running, hit enter to manually send an announce (Ctrl-C to quit)"
|
||||||
|
)
|
||||||
|
|
||||||
|
# We enter a loop that runs until the users exits.
|
||||||
|
# If the user hits enter, we will announce our server
|
||||||
|
# destination on the network, which will let clients
|
||||||
|
# know how to create messages directed towards it.
|
||||||
|
while True:
|
||||||
|
entered = input()
|
||||||
|
destination.announce()
|
||||||
|
RNS.log("Sent announce from "+RNS.prettyhexrep(destination.hash))
|
||||||
|
|
||||||
|
|
||||||
|
def server_callback(message, packet):
|
||||||
|
global reticulum
|
||||||
|
|
||||||
|
# Tell the user that we received an echo request, and
|
||||||
|
# that we are going to send a reply to the requester.
|
||||||
|
# Sending the proof is handled automatically, since we
|
||||||
|
# set up the destination to prove all incoming packets.
|
||||||
|
|
||||||
|
reception_stats = ""
|
||||||
|
if reticulum.is_connected_to_shared_instance:
|
||||||
|
reception_rssi = reticulum.get_packet_rssi(packet.packet_hash)
|
||||||
|
reception_snr = reticulum.get_packet_snr(packet.packet_hash)
|
||||||
|
|
||||||
|
if reception_rssi != None:
|
||||||
|
reception_stats += " [RSSI "+str(reception_rssi)+" dBm]"
|
||||||
|
|
||||||
|
if reception_snr != None:
|
||||||
|
reception_stats += " [SNR "+str(reception_snr)+" dBm]"
|
||||||
|
|
||||||
|
else:
|
||||||
|
if packet.rssi != None:
|
||||||
|
reception_stats += " [RSSI "+str(packet.rssi)+" dBm]"
|
||||||
|
|
||||||
|
if packet.snr != None:
|
||||||
|
reception_stats += " [SNR "+str(packet.snr)+" dB]"
|
||||||
|
|
||||||
|
RNS.log("Received packet from echo client, proof sent"+reception_stats)
|
||||||
|
|
||||||
|
|
||||||
|
##########################################################
|
||||||
|
#### Client Part #########################################
|
||||||
|
##########################################################
|
||||||
|
|
||||||
|
# This initialisation is executed when the users chooses
|
||||||
|
# to run as a client
|
||||||
|
def client(destination_hexhash, configpath, timeout=None):
|
||||||
|
global reticulum
|
||||||
|
|
||||||
|
# We need a binary representation of the destination
|
||||||
|
# hash that was entered on the command line
|
||||||
|
try:
|
||||||
|
dest_len = (RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2
|
||||||
|
if len(destination_hexhash) != dest_len:
|
||||||
|
raise ValueError(
|
||||||
|
"Destination length is invalid, must be {hex} hexadecimal characters ({byte} bytes).".format(hex=dest_len, byte=dest_len//2)
|
||||||
|
)
|
||||||
|
|
||||||
|
destination_hash = bytes.fromhex(destination_hexhash)
|
||||||
|
except Exception as e:
|
||||||
|
RNS.log("Invalid destination entered. Check your input!")
|
||||||
|
RNS.log(str(e)+"\n")
|
||||||
|
exit()
|
||||||
|
|
||||||
|
# We must first initialise Reticulum
|
||||||
|
reticulum = RNS.Reticulum(configpath)
|
||||||
|
|
||||||
|
# We override the loglevel to provide feedback when
|
||||||
|
# an announce is received
|
||||||
|
if RNS.loglevel < RNS.LOG_INFO:
|
||||||
|
RNS.loglevel = RNS.LOG_INFO
|
||||||
|
|
||||||
|
# Tell the user that the client is ready!
|
||||||
|
RNS.log(
|
||||||
|
"Echo client ready, hit enter to send echo request to "+
|
||||||
|
destination_hexhash+
|
||||||
|
" (Ctrl-C to quit)"
|
||||||
|
)
|
||||||
|
|
||||||
|
# We enter a loop that runs until the user exits.
|
||||||
|
# If the user hits enter, we will try to send an
|
||||||
|
# echo request to the destination specified on the
|
||||||
|
# command line.
|
||||||
|
while True:
|
||||||
|
input()
|
||||||
|
|
||||||
|
# Let's first check if RNS knows a path to the destination.
|
||||||
|
# If it does, we'll load the server identity and create a packet
|
||||||
|
if RNS.Transport.has_path(destination_hash):
|
||||||
|
|
||||||
|
# To address the server, we need to know it's public
|
||||||
|
# key, so we check if Reticulum knows this destination.
|
||||||
|
# This is done by calling the "recall" method of the
|
||||||
|
# Identity module. If the destination is known, it will
|
||||||
|
# return an Identity instance that can be used in
|
||||||
|
# outgoing destinations.
|
||||||
|
server_identity = RNS.Identity.recall(destination_hash)
|
||||||
|
|
||||||
|
# We got the correct identity instance from the
|
||||||
|
# recall method, so let's create an outgoing
|
||||||
|
# destination. We use the naming convention:
|
||||||
|
# example_utilities.ratchet.echo.request
|
||||||
|
# This matches the naming we specified in the
|
||||||
|
# server part of the code.
|
||||||
|
request_destination = RNS.Destination(
|
||||||
|
server_identity,
|
||||||
|
RNS.Destination.OUT,
|
||||||
|
RNS.Destination.SINGLE,
|
||||||
|
APP_NAME,
|
||||||
|
"ratchet",
|
||||||
|
"echo",
|
||||||
|
"request"
|
||||||
|
)
|
||||||
|
|
||||||
|
# The destination is ready, so let's create a packet.
|
||||||
|
# We set the destination to the request_destination
|
||||||
|
# that was just created, and the only data we add
|
||||||
|
# is a random hash.
|
||||||
|
echo_request = RNS.Packet(request_destination, RNS.Identity.get_random_hash())
|
||||||
|
|
||||||
|
# Send the packet! If the packet is successfully
|
||||||
|
# sent, it will return a PacketReceipt instance.
|
||||||
|
packet_receipt = echo_request.send()
|
||||||
|
|
||||||
|
# If the user specified a timeout, we set this
|
||||||
|
# timeout on the packet receipt, and configure
|
||||||
|
# a callback function, that will get called if
|
||||||
|
# the packet times out.
|
||||||
|
if timeout != None:
|
||||||
|
packet_receipt.set_timeout(timeout)
|
||||||
|
packet_receipt.set_timeout_callback(packet_timed_out)
|
||||||
|
|
||||||
|
# We can then set a delivery callback on the receipt.
|
||||||
|
# This will get automatically called when a proof for
|
||||||
|
# this specific packet is received from the destination.
|
||||||
|
packet_receipt.set_delivery_callback(packet_delivered)
|
||||||
|
|
||||||
|
# Tell the user that the echo request was sent
|
||||||
|
RNS.log("Sent echo request to "+RNS.prettyhexrep(request_destination.hash))
|
||||||
|
else:
|
||||||
|
# If we do not know this destination, tell the
|
||||||
|
# user to wait for an announce to arrive.
|
||||||
|
RNS.log("Destination is not yet known. Requesting path...")
|
||||||
|
RNS.log("Hit enter to manually retry once an announce is received.")
|
||||||
|
RNS.Transport.request_path(destination_hash)
|
||||||
|
|
||||||
|
# This function is called when our reply destination
|
||||||
|
# receives a proof packet.
|
||||||
|
def packet_delivered(receipt):
|
||||||
|
global reticulum
|
||||||
|
|
||||||
|
if receipt.status == RNS.PacketReceipt.DELIVERED:
|
||||||
|
rtt = receipt.get_rtt()
|
||||||
|
if (rtt >= 1):
|
||||||
|
rtt = round(rtt, 3)
|
||||||
|
rttstring = str(rtt)+" seconds"
|
||||||
|
else:
|
||||||
|
rtt = round(rtt*1000, 3)
|
||||||
|
rttstring = str(rtt)+" milliseconds"
|
||||||
|
|
||||||
|
reception_stats = ""
|
||||||
|
if reticulum.is_connected_to_shared_instance:
|
||||||
|
reception_rssi = reticulum.get_packet_rssi(receipt.proof_packet.packet_hash)
|
||||||
|
reception_snr = reticulum.get_packet_snr(receipt.proof_packet.packet_hash)
|
||||||
|
|
||||||
|
if reception_rssi != None:
|
||||||
|
reception_stats += " [RSSI "+str(reception_rssi)+" dBm]"
|
||||||
|
|
||||||
|
if reception_snr != None:
|
||||||
|
reception_stats += " [SNR "+str(reception_snr)+" dB]"
|
||||||
|
|
||||||
|
else:
|
||||||
|
if receipt.proof_packet != None:
|
||||||
|
if receipt.proof_packet.rssi != None:
|
||||||
|
reception_stats += " [RSSI "+str(receipt.proof_packet.rssi)+" dBm]"
|
||||||
|
|
||||||
|
if receipt.proof_packet.snr != None:
|
||||||
|
reception_stats += " [SNR "+str(receipt.proof_packet.snr)+" dB]"
|
||||||
|
|
||||||
|
RNS.log(
|
||||||
|
"Valid reply received from "+
|
||||||
|
RNS.prettyhexrep(receipt.destination.hash)+
|
||||||
|
", round-trip time is "+rttstring+
|
||||||
|
reception_stats
|
||||||
|
)
|
||||||
|
|
||||||
|
# This function is called if a packet times out.
|
||||||
|
def packet_timed_out(receipt):
|
||||||
|
if receipt.status == RNS.PacketReceipt.FAILED:
|
||||||
|
RNS.log("Packet "+RNS.prettyhexrep(receipt.hash)+" timed out")
|
||||||
|
|
||||||
|
|
||||||
|
##########################################################
|
||||||
|
#### Program Startup #####################################
|
||||||
|
##########################################################
|
||||||
|
|
||||||
|
# This part of the program gets run at startup,
|
||||||
|
# and parses input from the user, and then starts
|
||||||
|
# the desired program mode.
|
||||||
|
if __name__ == "__main__":
|
||||||
|
try:
|
||||||
|
parser = argparse.ArgumentParser(description="Simple ratcheted echo server and client utility")
|
||||||
|
|
||||||
|
parser.add_argument(
|
||||||
|
"-s",
|
||||||
|
"--server",
|
||||||
|
action="store_true",
|
||||||
|
help="wait for incoming packets from clients"
|
||||||
|
)
|
||||||
|
|
||||||
|
parser.add_argument(
|
||||||
|
"-t",
|
||||||
|
"--timeout",
|
||||||
|
action="store",
|
||||||
|
metavar="s",
|
||||||
|
default=None,
|
||||||
|
help="set a reply timeout in seconds",
|
||||||
|
type=float
|
||||||
|
)
|
||||||
|
|
||||||
|
parser.add_argument("--config",
|
||||||
|
action="store",
|
||||||
|
default=None,
|
||||||
|
help="path to alternative Reticulum config directory",
|
||||||
|
type=str
|
||||||
|
)
|
||||||
|
|
||||||
|
parser.add_argument(
|
||||||
|
"destination",
|
||||||
|
nargs="?",
|
||||||
|
default=None,
|
||||||
|
help="hexadecimal hash of the server destination",
|
||||||
|
type=str
|
||||||
|
)
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
if args.server:
|
||||||
|
configarg=None
|
||||||
|
if args.config:
|
||||||
|
configarg = args.config
|
||||||
|
server(configarg)
|
||||||
|
else:
|
||||||
|
if args.config:
|
||||||
|
configarg = args.config
|
||||||
|
else:
|
||||||
|
configarg = None
|
||||||
|
|
||||||
|
if args.timeout:
|
||||||
|
timeoutarg = float(args.timeout)
|
||||||
|
else:
|
||||||
|
timeoutarg = None
|
||||||
|
|
||||||
|
if (args.destination == None):
|
||||||
|
print("")
|
||||||
|
parser.print_help()
|
||||||
|
print("")
|
||||||
|
else:
|
||||||
|
client(args.destination, configarg, timeout=timeoutarg)
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
print("")
|
||||||
|
exit()
|
@ -306,9 +306,11 @@ general-purpose CPUs and on microcontrollers. The necessary primitives are:
|
|||||||
- X22519 for ECDH key exchanges
|
- X22519 for ECDH key exchanges
|
||||||
- HKDF for key derivation
|
- HKDF for key derivation
|
||||||
- Modified Fernet for encrypted tokens
|
- Modified Fernet for encrypted tokens
|
||||||
- AES-128 in CBC mode
|
- Ephemeral keys derived from an ECDH key exchange on Curve25519
|
||||||
- HMAC for message authentication
|
- AES-128 in CBC mode with PKCS7 padding
|
||||||
- No Fernet version and timestamp fields
|
- HMAC using SHA256 for message authentication
|
||||||
|
- IVs are generated through os.urandom()
|
||||||
|
- No Fernet version and timestamp metadata fields
|
||||||
- SHA-256
|
- SHA-256
|
||||||
- SHA-512
|
- SHA-512
|
||||||
|
|
||||||
|
@ -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
|
||||||
@ -20,11 +20,14 @@
|
|||||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
# SOFTWARE.
|
# SOFTWARE.
|
||||||
|
|
||||||
|
import os
|
||||||
import math
|
import math
|
||||||
import time
|
import time
|
||||||
|
import threading
|
||||||
import RNS
|
import RNS
|
||||||
|
|
||||||
from RNS.Cryptography import Fernet
|
from RNS.Cryptography import Fernet
|
||||||
|
from .vendor import umsgpack as umsgpack
|
||||||
|
|
||||||
class Callbacks:
|
class Callbacks:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
@ -38,14 +41,14 @@ class Destination:
|
|||||||
instances are used both to create outgoing and incoming endpoints. The
|
instances are used both to create outgoing and incoming endpoints. The
|
||||||
destination type will decide if encryption, and what type, is used in
|
destination type will decide if encryption, and what type, is used in
|
||||||
communication with the endpoint. A destination can also announce its
|
communication with the endpoint. A destination can also announce its
|
||||||
presence on the network, which will also distribute necessary keys for
|
presence on the network, which will distribute necessary keys for
|
||||||
encrypted communication with it.
|
encrypted communication with it.
|
||||||
|
|
||||||
:param identity: An instance of :ref:`RNS.Identity<api-identity>`. Can hold only public keys for an outgoing destination, or holding private keys for an ingoing.
|
:param identity: An instance of :ref:`RNS.Identity<api-identity>`. Can hold only public keys for an outgoing destination, or holding private keys for an ingoing.
|
||||||
:param direction: ``RNS.Destination.IN`` or ``RNS.Destination.OUT``.
|
:param direction: ``RNS.Destination.IN`` or ``RNS.Destination.OUT``.
|
||||||
:param type: ``RNS.Destination.SINGLE``, ``RNS.Destination.GROUP`` or ``RNS.Destination.PLAIN``.
|
:param type: ``RNS.Destination.SINGLE``, ``RNS.Destination.GROUP`` or ``RNS.Destination.PLAIN``.
|
||||||
:param app_name: A string specifying the app name.
|
:param app_name: A string specifying the app name.
|
||||||
:param \*aspects: Any non-zero number of string arguments.
|
:param \\*aspects: Any non-zero number of string arguments.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Constants
|
# Constants
|
||||||
@ -71,6 +74,16 @@ class Destination:
|
|||||||
|
|
||||||
PR_TAG_WINDOW = 30
|
PR_TAG_WINDOW = 30
|
||||||
|
|
||||||
|
RATCHET_COUNT = 512
|
||||||
|
"""
|
||||||
|
The default number of generated ratchet keys a destination will retain, if it has ratchets enabled.
|
||||||
|
"""
|
||||||
|
|
||||||
|
RATCHET_INTERVAL = 30*60
|
||||||
|
"""
|
||||||
|
The minimum interval between rotating ratchet keys, in seconds.
|
||||||
|
"""
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def expand_name(identity, app_name, *aspects):
|
def expand_name(identity, app_name, *aspects):
|
||||||
"""
|
"""
|
||||||
@ -137,6 +150,14 @@ class Destination:
|
|||||||
self.type = type
|
self.type = type
|
||||||
self.direction = direction
|
self.direction = direction
|
||||||
self.proof_strategy = Destination.PROVE_NONE
|
self.proof_strategy = Destination.PROVE_NONE
|
||||||
|
self.ratchets = None
|
||||||
|
self.ratchets_path = None
|
||||||
|
self.ratchet_interval = Destination.RATCHET_INTERVAL
|
||||||
|
self.ratchet_file_lock = threading.Lock()
|
||||||
|
self.retained_ratchets = Destination.RATCHET_COUNT
|
||||||
|
self.latest_ratchet_time = None
|
||||||
|
self.latest_ratchet_id = None
|
||||||
|
self.__enforce_ratchets = False
|
||||||
self.mtu = 0
|
self.mtu = 0
|
||||||
|
|
||||||
self.path_responses = {}
|
self.path_responses = {}
|
||||||
@ -170,6 +191,39 @@ class Destination:
|
|||||||
"""
|
"""
|
||||||
return "<"+self.name+"/"+self.hexhash+">"
|
return "<"+self.name+"/"+self.hexhash+">"
|
||||||
|
|
||||||
|
def _clean_ratchets(self):
|
||||||
|
if self.ratchets != None:
|
||||||
|
if len (self.ratchets) > self.retained_ratchets:
|
||||||
|
self.ratchets = self.ratchets[:Destination.RATCHET_COUNT]
|
||||||
|
|
||||||
|
def _persist_ratchets(self):
|
||||||
|
try:
|
||||||
|
with self.ratchet_file_lock:
|
||||||
|
packed_ratchets = umsgpack.packb(self.ratchets)
|
||||||
|
persisted_data = {"signature": self.sign(packed_ratchets), "ratchets": packed_ratchets}
|
||||||
|
ratchets_file = open(self.ratchets_path, "wb")
|
||||||
|
ratchets_file.write(umsgpack.packb(persisted_data))
|
||||||
|
ratchets_file.close()
|
||||||
|
except Exception as e:
|
||||||
|
self.ratchets = None
|
||||||
|
self.ratchets_path = None
|
||||||
|
raise OSError("Could not write ratchet file contents for "+str(self)+". The contained exception was: "+str(e), RNS.LOG_ERROR)
|
||||||
|
|
||||||
|
def rotate_ratchets(self):
|
||||||
|
if self.ratchets != None:
|
||||||
|
now = time.time()
|
||||||
|
if now > self.latest_ratchet_time+self.ratchet_interval:
|
||||||
|
RNS.log("Rotating ratchets for "+str(self), RNS.LOG_DEBUG)
|
||||||
|
new_ratchet = RNS.Identity._generate_ratchet()
|
||||||
|
self.ratchets.insert(0, new_ratchet)
|
||||||
|
self.latest_ratchet_time = now
|
||||||
|
self._clean_ratchets()
|
||||||
|
self._persist_ratchets()
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
raise SystemError("Cannot rotate ratchet on "+str(self)+", ratchets are not enabled")
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
def announce(self, app_data=None, path_response=False, attached_interface=None, tag=None, send=True):
|
def announce(self, app_data=None, path_response=False, attached_interface=None, tag=None, send=True):
|
||||||
"""
|
"""
|
||||||
@ -185,6 +239,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:
|
||||||
@ -211,6 +266,11 @@ class Destination:
|
|||||||
destination_hash = self.hash
|
destination_hash = self.hash
|
||||||
random_hash = RNS.Identity.get_random_hash()[0:5]+int(time.time()).to_bytes(5, "big")
|
random_hash = RNS.Identity.get_random_hash()[0:5]+int(time.time()).to_bytes(5, "big")
|
||||||
|
|
||||||
|
if self.ratchets != None:
|
||||||
|
self.rotate_ratchets()
|
||||||
|
ratchet = RNS.Identity._ratchet_public_bytes(self.ratchets[0])
|
||||||
|
RNS.Identity._remember_ratchet(self.hash, ratchet)
|
||||||
|
|
||||||
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):
|
||||||
app_data = self.default_app_data
|
app_data = self.default_app_data
|
||||||
@ -219,13 +279,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
|
||||||
@ -237,8 +296,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:
|
||||||
@ -298,7 +362,6 @@ class Destination:
|
|||||||
else:
|
else:
|
||||||
self.proof_strategy = proof_strategy
|
self.proof_strategy = proof_strategy
|
||||||
|
|
||||||
|
|
||||||
def register_request_handler(self, path, response_generator = None, allow = ALLOW_NONE, allowed_list = None):
|
def register_request_handler(self, path, response_generator = None, allow = ALLOW_NONE, allowed_list = None):
|
||||||
"""
|
"""
|
||||||
Registers a request handler.
|
Registers a request handler.
|
||||||
@ -320,7 +383,6 @@ class Destination:
|
|||||||
request_handler = [path, response_generator, allow, allowed_list]
|
request_handler = [path, response_generator, allow, allowed_list]
|
||||||
self.request_handlers[path_hash] = request_handler
|
self.request_handlers[path_hash] = request_handler
|
||||||
|
|
||||||
|
|
||||||
def deregister_request_handler(self, path):
|
def deregister_request_handler(self, path):
|
||||||
"""
|
"""
|
||||||
Deregisters a request handler.
|
Deregisters a request handler.
|
||||||
@ -335,14 +397,13 @@ class Destination:
|
|||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def receive(self, packet):
|
def receive(self, packet):
|
||||||
if packet.packet_type == RNS.Packet.LINKREQUEST:
|
if packet.packet_type == RNS.Packet.LINKREQUEST:
|
||||||
plaintext = packet.data
|
plaintext = packet.data
|
||||||
self.incoming_link_request(plaintext, packet)
|
self.incoming_link_request(plaintext, packet)
|
||||||
else:
|
else:
|
||||||
plaintext = self.decrypt(packet.data)
|
plaintext = self.decrypt(packet.data)
|
||||||
|
packet.ratchet_id = self.latest_ratchet_id
|
||||||
if plaintext != None:
|
if plaintext != None:
|
||||||
if packet.packet_type == RNS.Packet.DATA:
|
if packet.packet_type == RNS.Packet.DATA:
|
||||||
if self.callbacks.packet != None:
|
if self.callbacks.packet != None:
|
||||||
@ -351,13 +412,103 @@ class Destination:
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
RNS.log("Error while executing receive callback from "+str(self)+". The contained exception was: "+str(e), RNS.LOG_ERROR)
|
RNS.log("Error while executing receive callback from "+str(self)+". The contained exception was: "+str(e), RNS.LOG_ERROR)
|
||||||
|
|
||||||
|
|
||||||
def incoming_link_request(self, data, packet):
|
def incoming_link_request(self, data, packet):
|
||||||
if self.accept_link_requests:
|
if self.accept_link_requests:
|
||||||
link = RNS.Link.validate_request(self, data, packet)
|
link = RNS.Link.validate_request(self, data, packet)
|
||||||
if link != None:
|
if link != None:
|
||||||
self.links.append(link)
|
self.links.append(link)
|
||||||
|
|
||||||
|
def _reload_ratchets(self, ratchets_path):
|
||||||
|
if os.path.isfile(ratchets_path):
|
||||||
|
with self.ratchet_file_lock:
|
||||||
|
try:
|
||||||
|
ratchets_file = open(ratchets_path, "rb")
|
||||||
|
persisted_data = umsgpack.unpackb(ratchets_file.read())
|
||||||
|
if "signature" in persisted_data and "ratchets" in persisted_data:
|
||||||
|
if self.identity.validate(persisted_data["signature"], persisted_data["ratchets"]):
|
||||||
|
self.ratchets = umsgpack.unpackb(persisted_data["ratchets"])
|
||||||
|
self.ratchets_path = ratchets_path
|
||||||
|
else:
|
||||||
|
raise KeyError("Invalid ratchet file signature")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
self.ratchets = None
|
||||||
|
self.ratchets_path = None
|
||||||
|
raise OSError("Could not read ratchet file contents for "+str(self)+". The contained exception was: "+str(e), RNS.LOG_ERROR)
|
||||||
|
else:
|
||||||
|
RNS.log("No existing ratchet data found, initialising new ratchet file for "+str(self), RNS.LOG_DEBUG)
|
||||||
|
self.ratchets = []
|
||||||
|
self.ratchets_path = ratchets_path
|
||||||
|
self._persist_ratchets()
|
||||||
|
|
||||||
|
def enable_ratchets(self, ratchets_path):
|
||||||
|
"""
|
||||||
|
Enables ratchets on the destination. When ratchets are enabled, Reticulum will automatically rotate
|
||||||
|
the keys used to encrypt packets to this destination, and include the latest ratchet key in announces.
|
||||||
|
|
||||||
|
Enabling ratchets on a destination will provide forward secrecy for packets sent to that destination,
|
||||||
|
even when sent outside a ``Link``. The normal Reticulum ``Link`` establishment procedure already performs
|
||||||
|
its own ephemeral key exchange for each link establishment, which means that ratchets are not necessary
|
||||||
|
to provide forward secrecy for links.
|
||||||
|
|
||||||
|
Enabling ratchets will have a small impact on announce size, adding 32 bytes to every sent announce.
|
||||||
|
|
||||||
|
:param ratchets_path: The path to a file to store ratchet data in.
|
||||||
|
:returns: True if the operation succeeded, otherwise False.
|
||||||
|
"""
|
||||||
|
if ratchets_path != None:
|
||||||
|
self.latest_ratchet_time = 0
|
||||||
|
self._reload_ratchets(ratchets_path)
|
||||||
|
|
||||||
|
# TODO: Remove at some point
|
||||||
|
RNS.log("Ratchets enabled on "+str(self), RNS.LOG_DEBUG)
|
||||||
|
return True
|
||||||
|
|
||||||
|
else:
|
||||||
|
raise ValueError("No ratchet file path specified for "+str(self))
|
||||||
|
|
||||||
|
def enforce_ratchets(self):
|
||||||
|
"""
|
||||||
|
When ratchet enforcement is enabled, this destination will never accept packets that use its
|
||||||
|
base Identity key for encryption, but only accept packets encrypted with one of the retained
|
||||||
|
ratchet keys.
|
||||||
|
"""
|
||||||
|
if self.ratchets != None:
|
||||||
|
self.__enforce_ratchets = True
|
||||||
|
RNS.log("Ratchets enforced on "+str(self), RNS.LOG_DEBUG)
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def set_retained_ratchets(self, retained_ratchets):
|
||||||
|
"""
|
||||||
|
Sets the number of previously generated ratchet keys this destination will retain,
|
||||||
|
and try to use when decrypting incoming packets. Defaults to ``Destination.RATCHET_COUNT``.
|
||||||
|
|
||||||
|
:param retained_ratchets: The number of generated ratchets to retain.
|
||||||
|
:returns: True if the operation succeeded, False if not.
|
||||||
|
"""
|
||||||
|
if isinstance(retained_ratchets, int) and retained_ratchets > 0:
|
||||||
|
self.retained_ratchets = retained_ratchets
|
||||||
|
self._clean_ratchets()
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def set_ratchet_interval(self, interval):
|
||||||
|
"""
|
||||||
|
Sets the minimum interval in seconds between ratchet key rotation.
|
||||||
|
Defaults to ``Destination.RATCHET_INTERVAL``.
|
||||||
|
|
||||||
|
:param interval: The minimum interval in seconds.
|
||||||
|
:returns: True if the operation succeeded, False if not.
|
||||||
|
"""
|
||||||
|
if isinstance(interval, int) and interval > 0:
|
||||||
|
self.ratchet_interval = interval
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
def create_keys(self):
|
def create_keys(self):
|
||||||
"""
|
"""
|
||||||
For a ``RNS.Destination.GROUP`` type destination, creates a new symmetric key.
|
For a ``RNS.Destination.GROUP`` type destination, creates a new symmetric key.
|
||||||
@ -374,7 +525,6 @@ class Destination:
|
|||||||
self.prv_bytes = Fernet.generate_key()
|
self.prv_bytes = Fernet.generate_key()
|
||||||
self.prv = Fernet(self.prv_bytes)
|
self.prv = Fernet(self.prv_bytes)
|
||||||
|
|
||||||
|
|
||||||
def get_private_key(self):
|
def get_private_key(self):
|
||||||
"""
|
"""
|
||||||
For a ``RNS.Destination.GROUP`` type destination, returns the symmetric private key.
|
For a ``RNS.Destination.GROUP`` type destination, returns the symmetric private key.
|
||||||
@ -388,7 +538,6 @@ class Destination:
|
|||||||
else:
|
else:
|
||||||
return self.prv_bytes
|
return self.prv_bytes
|
||||||
|
|
||||||
|
|
||||||
def load_private_key(self, key):
|
def load_private_key(self, key):
|
||||||
"""
|
"""
|
||||||
For a ``RNS.Destination.GROUP`` type destination, loads a symmetric private key.
|
For a ``RNS.Destination.GROUP`` type destination, loads a symmetric private key.
|
||||||
@ -412,7 +561,6 @@ class Destination:
|
|||||||
else:
|
else:
|
||||||
raise TypeError("A single destination holds keys through an Identity instance")
|
raise TypeError("A single destination holds keys through an Identity instance")
|
||||||
|
|
||||||
|
|
||||||
def encrypt(self, plaintext):
|
def encrypt(self, plaintext):
|
||||||
"""
|
"""
|
||||||
Encrypts information for ``RNS.Destination.SINGLE`` or ``RNS.Destination.GROUP`` type destination.
|
Encrypts information for ``RNS.Destination.SINGLE`` or ``RNS.Destination.GROUP`` type destination.
|
||||||
@ -424,7 +572,10 @@ 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)
|
selected_ratchet = RNS.Identity.get_ratchet(self.hash)
|
||||||
|
if selected_ratchet:
|
||||||
|
self.latest_ratchet_id = RNS.Identity._get_ratchet_id(selected_ratchet)
|
||||||
|
return self.identity.encrypt(plaintext, ratchet=selected_ratchet)
|
||||||
|
|
||||||
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:
|
||||||
@ -436,8 +587,6 @@ class Destination:
|
|||||||
else:
|
else:
|
||||||
raise ValueError("No private key held by GROUP destination. Did you create or load one?")
|
raise ValueError("No private key held by GROUP destination. Did you create or load one?")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def decrypt(self, ciphertext):
|
def decrypt(self, ciphertext):
|
||||||
"""
|
"""
|
||||||
Decrypts information for ``RNS.Destination.SINGLE`` or ``RNS.Destination.GROUP`` type destination.
|
Decrypts information for ``RNS.Destination.SINGLE`` or ``RNS.Destination.GROUP`` type destination.
|
||||||
@ -449,7 +598,28 @@ 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)
|
if self.ratchets:
|
||||||
|
decrypted = None
|
||||||
|
try:
|
||||||
|
decrypted = self.identity.decrypt(ciphertext, ratchets=self.ratchets, enforce_ratchets=self.__enforce_ratchets, ratchet_id_receiver=self)
|
||||||
|
except:
|
||||||
|
decrypted = None
|
||||||
|
|
||||||
|
if not decrypted:
|
||||||
|
try:
|
||||||
|
RNS.log(f"Decryption with ratchets failed on {self}, reloading ratchets from storage and retrying", RNS.LOG_ERROR)
|
||||||
|
self._reload_ratchets(self.ratchets_path)
|
||||||
|
decrypted = self.identity.decrypt(ciphertext, ratchets=self.ratchets, enforce_ratchets=self.__enforce_ratchets, ratchet_id_receiver=self)
|
||||||
|
except Exception as e:
|
||||||
|
RNS.log(f"Decryption still failing after ratchet reload. The contained exception was: {e}", RNS.LOG_ERROR)
|
||||||
|
raise e
|
||||||
|
|
||||||
|
RNS.log("Decryption succeeded after ratchet reload", RNS.LOG_NOTICE)
|
||||||
|
|
||||||
|
return decrypted
|
||||||
|
|
||||||
|
else:
|
||||||
|
return self.identity.decrypt(ciphertext, ratchets=None, enforce_ratchets=self.__enforce_ratchets, ratchet_id_receiver=self)
|
||||||
|
|
||||||
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:
|
||||||
@ -461,7 +631,6 @@ class Destination:
|
|||||||
else:
|
else:
|
||||||
raise ValueError("No private key held by GROUP destination. Did you create or load one?")
|
raise ValueError("No private key held by GROUP destination. Did you create or load one?")
|
||||||
|
|
||||||
|
|
||||||
def sign(self, message):
|
def sign(self, message):
|
||||||
"""
|
"""
|
||||||
Signs information for ``RNS.Destination.SINGLE`` type destination.
|
Signs information for ``RNS.Destination.SINGLE`` type destination.
|
||||||
|
229
RNS/Identity.py
229
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
|
||||||
@ -26,6 +26,7 @@ import RNS
|
|||||||
import time
|
import time
|
||||||
import atexit
|
import atexit
|
||||||
import hashlib
|
import hashlib
|
||||||
|
import threading
|
||||||
|
|
||||||
from .vendor import umsgpack as umsgpack
|
from .vendor import umsgpack as umsgpack
|
||||||
|
|
||||||
@ -49,7 +50,19 @@ class Identity:
|
|||||||
|
|
||||||
KEYSIZE = 256*2
|
KEYSIZE = 256*2
|
||||||
"""
|
"""
|
||||||
X25519 key size in bits. A complete key is the concatenation of a 256 bit encryption key, and a 256 bit signing key.
|
X.25519 key size in bits. A complete key is the concatenation of a 256 bit encryption key, and a 256 bit signing key.
|
||||||
|
"""
|
||||||
|
|
||||||
|
RATCHETSIZE = 256
|
||||||
|
"""
|
||||||
|
X.25519 ratchet key size in bits.
|
||||||
|
"""
|
||||||
|
|
||||||
|
RATCHET_EXPIRY = 60*60*24*30
|
||||||
|
"""
|
||||||
|
The expiry time for received ratchets in seconds, defaults to 30 days. Reticulum will always use the most recently
|
||||||
|
announced ratchet, and remember it for up to ``RATCHET_EXPIRY`` since receiving it, after which it will be discarded.
|
||||||
|
If a newer ratchet is announced in the meantime, it will be replace the already known ratchet.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Non-configurable constants
|
# Non-configurable constants
|
||||||
@ -67,6 +80,9 @@ class Identity:
|
|||||||
|
|
||||||
# Storage
|
# Storage
|
||||||
known_destinations = {}
|
known_destinations = {}
|
||||||
|
known_ratchets = {}
|
||||||
|
|
||||||
|
ratchet_persist_lock = threading.Lock()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def remember(packet_hash, destination_hash, public_key, app_data = None):
|
def remember(packet_hash, destination_hash, public_key, app_data = None):
|
||||||
@ -197,7 +213,7 @@ class Identity:
|
|||||||
Get a SHA-256 hash of passed data.
|
Get a SHA-256 hash of passed data.
|
||||||
|
|
||||||
:param data: Data to be hashed as *bytes*.
|
:param data: Data to be hashed as *bytes*.
|
||||||
:returns: SHA-256 hash as *bytes*
|
:returns: SHA-256 hash as *bytes*.
|
||||||
"""
|
"""
|
||||||
return RNS.Cryptography.sha256(data)
|
return RNS.Cryptography.sha256(data)
|
||||||
|
|
||||||
@ -207,7 +223,7 @@ class Identity:
|
|||||||
Get a truncated SHA-256 hash of passed data.
|
Get a truncated SHA-256 hash of passed data.
|
||||||
|
|
||||||
:param data: Data to be hashed as *bytes*.
|
:param data: Data to be hashed as *bytes*.
|
||||||
:returns: Truncated SHA-256 hash as *bytes*
|
:returns: Truncated SHA-256 hash as *bytes*.
|
||||||
"""
|
"""
|
||||||
return Identity.full_hash(data)[:(Identity.TRUNCATED_HASHLENGTH//8)]
|
return Identity.full_hash(data)[:(Identity.TRUNCATED_HASHLENGTH//8)]
|
||||||
|
|
||||||
@ -217,24 +233,158 @@ class Identity:
|
|||||||
Get a random SHA-256 hash.
|
Get a random SHA-256 hash.
|
||||||
|
|
||||||
:param data: Data to be hashed as *bytes*.
|
:param data: Data to be hashed as *bytes*.
|
||||||
:returns: Truncated SHA-256 hash of random data as *bytes*
|
:returns: Truncated SHA-256 hash of random data as *bytes*.
|
||||||
"""
|
"""
|
||||||
return Identity.truncated_hash(os.urandom(Identity.TRUNCATED_HASHLENGTH//8))
|
return Identity.truncated_hash(os.urandom(Identity.TRUNCATED_HASHLENGTH//8))
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def current_ratchet_id(destination_hash):
|
||||||
|
"""
|
||||||
|
Get the ID of the currently used ratchet key for a given destination hash
|
||||||
|
|
||||||
|
:param destination_hash: A destination hash as *bytes*.
|
||||||
|
:returns: A ratchet ID as *bytes* or *None*.
|
||||||
|
"""
|
||||||
|
ratchet = Identity.get_ratchet(destination_hash)
|
||||||
|
if ratchet == None:
|
||||||
|
return None
|
||||||
|
else:
|
||||||
|
return Identity._get_ratchet_id(ratchet)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _get_ratchet_id(ratchet_pub_bytes):
|
||||||
|
return Identity.full_hash(ratchet_pub_bytes)[:Identity.NAME_HASH_LENGTH//8]
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _ratchet_public_bytes(ratchet):
|
||||||
|
return X25519PrivateKey.from_private_bytes(ratchet).public_key().public_bytes()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _generate_ratchet():
|
||||||
|
ratchet_prv = X25519PrivateKey.generate()
|
||||||
|
ratchet_pub = ratchet_prv.public_key()
|
||||||
|
return ratchet_prv.private_bytes()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _remember_ratchet(destination_hash, ratchet):
|
||||||
|
# TODO: Remove at some point, and only log new ratchets
|
||||||
|
RNS.log(f"Remembering ratchet {RNS.prettyhexrep(Identity._get_ratchet_id(ratchet))} for {RNS.prettyhexrep(destination_hash)}", RNS.LOG_EXTREME)
|
||||||
|
try:
|
||||||
|
Identity.known_ratchets[destination_hash] = ratchet
|
||||||
|
|
||||||
|
if not RNS.Transport.owner.is_connected_to_shared_instance:
|
||||||
|
def persist_job():
|
||||||
|
with Identity.ratchet_persist_lock:
|
||||||
|
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)
|
||||||
|
|
||||||
|
|
||||||
|
threading.Thread(target=persist_job, daemon=True).start()
|
||||||
|
|
||||||
|
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 _clean_ratchets():
|
||||||
|
RNS.log("Cleaning ratchets...", RNS.LOG_DEBUG)
|
||||||
|
try:
|
||||||
|
now = time.time()
|
||||||
|
ratchetdir = RNS.Reticulum.storagepath+"/ratchets"
|
||||||
|
if os.path.isdir(ratchetdir):
|
||||||
|
for filename in os.listdir(ratchetdir):
|
||||||
|
try:
|
||||||
|
expired = False
|
||||||
|
with open(f"{ratchetdir}/{filename}", "rb") as rf:
|
||||||
|
ratchet_data = umsgpack.unpackb(rf.read())
|
||||||
|
if now > ratchet_data["received"]+Identity.RATCHET_EXPIRY:
|
||||||
|
expired = True
|
||||||
|
|
||||||
|
if expired:
|
||||||
|
os.unlink(f"{ratchetdir}/{filename}")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
RNS.log(f"An error occurred while cleaning ratchets, in the processing of {ratchetdir}/{filename}.", RNS.LOG_ERROR)
|
||||||
|
RNS.log(f"The contained exception was: {e}", RNS.LOG_ERROR)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
RNS.log(f"An error occurred while cleaning ratchets. The contained exception was: {e}", RNS.LOG_ERROR)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_ratchet(destination_hash):
|
||||||
|
if not destination_hash in Identity.known_ratchets:
|
||||||
|
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(ratchet_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:
|
||||||
|
RNS.log(f"Could not load ratchet for {RNS.prettyhexrep(destination_hash)}", RNS.LOG_DEBUG)
|
||||||
|
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
|
||||||
@ -281,6 +431,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:
|
||||||
@ -469,7 +622,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.
|
||||||
|
|
||||||
@ -481,7 +634,12 @@ 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:
|
||||||
|
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,
|
||||||
@ -499,7 +657,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, enforce_ratchets=False, ratchet_id_receiver=None):
|
||||||
"""
|
"""
|
||||||
Decrypts information for the identity.
|
Decrypts information for the identity.
|
||||||
|
|
||||||
@ -513,9 +671,14 @@ 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)
|
||||||
|
ciphertext = ciphertext_token[Identity.KEYSIZE//8//2:]
|
||||||
|
|
||||||
shared_key = self.prv.exchange(peer_pub)
|
if ratchets:
|
||||||
|
for ratchet in ratchets:
|
||||||
|
try:
|
||||||
|
ratchet_prv = X25519PrivateKey.from_private_bytes(ratchet)
|
||||||
|
ratchet_id = Identity._get_ratchet_id(ratchet_prv.public_key().public_bytes())
|
||||||
|
shared_key = ratchet_prv.exchange(peer_pub)
|
||||||
derived_key = RNS.Cryptography.hkdf(
|
derived_key = RNS.Cryptography.hkdf(
|
||||||
length=32,
|
length=32,
|
||||||
derive_from=shared_key,
|
derive_from=shared_key,
|
||||||
@ -524,11 +687,39 @@ class Identity:
|
|||||||
)
|
)
|
||||||
|
|
||||||
fernet = Fernet(derived_key)
|
fernet = Fernet(derived_key)
|
||||||
ciphertext = ciphertext_token[Identity.KEYSIZE//8//2:]
|
|
||||||
plaintext = fernet.decrypt(ciphertext)
|
plaintext = fernet.decrypt(ciphertext)
|
||||||
|
if ratchet_id_receiver:
|
||||||
|
ratchet_id_receiver.latest_ratchet_id = ratchet_id
|
||||||
|
|
||||||
|
break
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
pass
|
||||||
|
|
||||||
|
if enforce_ratchets and plaintext == None:
|
||||||
|
RNS.log("Decryption with ratchet enforcement by "+RNS.prettyhexrep(self.hash)+" failed. Dropping packet.", RNS.LOG_DEBUG)
|
||||||
|
if ratchet_id_receiver:
|
||||||
|
ratchet_id_receiver.latest_ratchet_id = None
|
||||||
|
return None
|
||||||
|
|
||||||
|
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)
|
||||||
|
if ratchet_id_receiver:
|
||||||
|
ratchet_id_receiver.latest_ratchet_id = None
|
||||||
|
|
||||||
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)
|
||||||
|
if ratchet_id_receiver:
|
||||||
|
ratchet_id_receiver.latest_ratchet_id = None
|
||||||
|
|
||||||
return plaintext;
|
return plaintext;
|
||||||
else:
|
else:
|
||||||
|
@ -116,40 +116,42 @@ class KISS():
|
|||||||
SX1280 = 0x21
|
SX1280 = 0x21
|
||||||
|
|
||||||
def int_data_cmd_to_index(int_data_cmd):
|
def int_data_cmd_to_index(int_data_cmd):
|
||||||
match int_data_cmd:
|
if int_data_cmd == KISS.CMD_INT0_DATA:
|
||||||
case KISS.CMD_INT0_DATA:
|
|
||||||
return 0
|
return 0
|
||||||
case KISS.CMD_INT1_DATA:
|
elif int_data_cmd == KISS.CMD_INT1_DATA:
|
||||||
return 1
|
return 1
|
||||||
case KISS.CMD_INT2_DATA:
|
elif int_data_cmd == KISS.CMD_INT2_DATA:
|
||||||
return 2
|
return 2
|
||||||
case KISS.CMD_INT3_DATA:
|
elif int_data_cmd == KISS.CMD_INT3_DATA:
|
||||||
return 3
|
return 3
|
||||||
case KISS.CMD_INT4_DATA:
|
elif int_data_cmd == KISS.CMD_INT4_DATA:
|
||||||
return 4
|
return 4
|
||||||
case KISS.CMD_INT5_DATA:
|
elif int_data_cmd == KISS.CMD_INT5_DATA:
|
||||||
return 5
|
return 5
|
||||||
case KISS.CMD_INT6_DATA:
|
elif int_data_cmd == KISS.CMD_INT6_DATA:
|
||||||
return 6
|
return 6
|
||||||
case KISS.CMD_INT7_DATA:
|
elif int_data_cmd == KISS.CMD_INT7_DATA:
|
||||||
return 7
|
return 7
|
||||||
case KISS.CMD_INT8_DATA:
|
elif int_data_cmd == KISS.CMD_INT8_DATA:
|
||||||
return 8
|
return 8
|
||||||
case KISS.CMD_INT9_DATA:
|
elif int_data_cmd == KISS.CMD_INT9_DATA:
|
||||||
return 9
|
return 9
|
||||||
case KISS.CMD_INT10_DATA:
|
elif int_data_cmd == KISS.CMD_INT10_DATA:
|
||||||
return 10
|
return 10
|
||||||
case KISS.CMD_INT11_DATA:
|
elif int_data_cmd == KISS.CMD_INT11_DATA:
|
||||||
return 11
|
return 11
|
||||||
|
else:
|
||||||
|
return 0
|
||||||
|
|
||||||
def interface_type_to_str(interface_type):
|
def interface_type_to_str(interface_type):
|
||||||
match interface_type:
|
if interface_type == KISS.SX126X or interface_type == KISS.SX1262:
|
||||||
case KISS.SX126X | KISS.SX1262:
|
|
||||||
return "SX126X"
|
return "SX126X"
|
||||||
case KISS.SX127X | KISS.SX1276 | KISS.SX1278:
|
elif interface_type == KISS.SX127X or interface_type == KISS.SX1276 or interface_type == KISS.SX1278:
|
||||||
return "SX127X"
|
return "SX127X"
|
||||||
case KISS.SX128X | KISS.SX1280:
|
elif interface_type == KISS.SX128X or interface_type == KISS.SX1280:
|
||||||
return "SX128X"
|
return "SX128X"
|
||||||
|
else:
|
||||||
|
return "SX127X"
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def escape(data):
|
def escape(data):
|
||||||
@ -915,44 +917,43 @@ class RNodeSubInterface(Interface):
|
|||||||
|
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
match index:
|
if index == 0:
|
||||||
case 0:
|
|
||||||
sel_cmd = KISS.CMD_SEL_INT0
|
sel_cmd = KISS.CMD_SEL_INT0
|
||||||
data_cmd= KISS.CMD_INT0_DATA
|
data_cmd= KISS.CMD_INT0_DATA
|
||||||
case 1:
|
elif index == 1:
|
||||||
sel_cmd = KISS.CMD_SEL_INT1
|
sel_cmd = KISS.CMD_SEL_INT1
|
||||||
data_cmd= KISS.CMD_INT1_DATA
|
data_cmd= KISS.CMD_INT1_DATA
|
||||||
case 2:
|
elif index == 2:
|
||||||
sel_cmd = KISS.CMD_SEL_INT2
|
sel_cmd = KISS.CMD_SEL_INT2
|
||||||
data_cmd= KISS.CMD_INT2_DATA
|
data_cmd= KISS.CMD_INT2_DATA
|
||||||
case 3:
|
elif index == 3:
|
||||||
sel_cmd = KISS.CMD_SEL_INT3
|
sel_cmd = KISS.CMD_SEL_INT3
|
||||||
data_cmd= KISS.CMD_INT3_DATA
|
data_cmd= KISS.CMD_INT3_DATA
|
||||||
case 4:
|
elif index == 4:
|
||||||
sel_cmd = KISS.CMD_SEL_INT4
|
sel_cmd = KISS.CMD_SEL_INT4
|
||||||
data_cmd= KISS.CMD_INT4_DATA
|
data_cmd= KISS.CMD_INT4_DATA
|
||||||
case 5:
|
elif index == 5:
|
||||||
sel_cmd = KISS.CMD_SEL_INT5
|
sel_cmd = KISS.CMD_SEL_INT5
|
||||||
data_cmd= KISS.CMD_INT5_DATA
|
data_cmd= KISS.CMD_INT5_DATA
|
||||||
case 6:
|
elif index == 6:
|
||||||
sel_cmd = KISS.CMD_SEL_INT6
|
sel_cmd = KISS.CMD_SEL_INT6
|
||||||
data_cmd= KISS.CMD_INT6_DATA
|
data_cmd= KISS.CMD_INT6_DATA
|
||||||
case 7:
|
elif index == 7:
|
||||||
sel_cmd = KISS.CMD_SEL_INT7
|
sel_cmd = KISS.CMD_SEL_INT7
|
||||||
data_cmd= KISS.CMD_INT7_DATA
|
data_cmd= KISS.CMD_INT7_DATA
|
||||||
case 8:
|
elif index == 8:
|
||||||
sel_cmd = KISS.CMD_SEL_INT8
|
sel_cmd = KISS.CMD_SEL_INT8
|
||||||
data_cmd= KISS.CMD_INT8_DATA
|
data_cmd= KISS.CMD_INT8_DATA
|
||||||
case 9:
|
elif index == 9:
|
||||||
sel_cmd = KISS.CMD_SEL_INT9
|
sel_cmd = KISS.CMD_SEL_INT9
|
||||||
data_cmd= KISS.CMD_INT9_DATA
|
data_cmd= KISS.CMD_INT9_DATA
|
||||||
case 10:
|
elif index == 10:
|
||||||
sel_cmd = KISS.CMD_SEL_INT10
|
sel_cmd = KISS.CMD_SEL_INT10
|
||||||
data_cmd= KISS.CMD_INT10_DATA
|
data_cmd= KISS.CMD_INT10_DATA
|
||||||
case 11:
|
elif index == 11:
|
||||||
sel_cmd = KISS.CMD_SEL_INT11
|
sel_cmd = KISS.CMD_SEL_INT11
|
||||||
data_cmd= KISS.CMD_INT11_DATA
|
data_cmd= KISS.CMD_INT11_DATA
|
||||||
case _:
|
else:
|
||||||
sel_cmd = KISS.CMD_SEL_INT0
|
sel_cmd = KISS.CMD_SEL_INT0
|
||||||
data_cmd= KISS.CMD_INT0_DATA
|
data_cmd= KISS.CMD_INT0_DATA
|
||||||
|
|
||||||
|
@ -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
|
||||||
@ -142,6 +142,7 @@ class Link:
|
|||||||
raise TypeError("Links can only be established to the \"single\" destination type")
|
raise TypeError("Links can only be established to the \"single\" destination type")
|
||||||
self.rtt = None
|
self.rtt = None
|
||||||
self.establishment_cost = 0
|
self.establishment_cost = 0
|
||||||
|
self.establishment_rate = None
|
||||||
self.callbacks = LinkCallbacks()
|
self.callbacks = LinkCallbacks()
|
||||||
self.resource_strategy = Link.ACCEPT_NONE
|
self.resource_strategy = Link.ACCEPT_NONE
|
||||||
self.outgoing_resources = []
|
self.outgoing_resources = []
|
||||||
@ -774,6 +775,7 @@ class Link:
|
|||||||
should_query = False
|
should_query = False
|
||||||
if packet.context == RNS.Packet.NONE:
|
if packet.context == RNS.Packet.NONE:
|
||||||
plaintext = self.decrypt(packet.data)
|
plaintext = self.decrypt(packet.data)
|
||||||
|
packet.ratchet_id = self.link_id
|
||||||
if plaintext != None:
|
if plaintext != None:
|
||||||
if self.callbacks.packet != None:
|
if self.callbacks.packet != None:
|
||||||
thread = threading.Thread(target=self.callbacks.packet, args=(plaintext, packet))
|
thread = threading.Thread(target=self.callbacks.packet, args=(plaintext, packet))
|
||||||
|
@ -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
|
||||||
@ -133,6 +140,7 @@ class Packet:
|
|||||||
self.MTU = RNS.Reticulum.MTU
|
self.MTU = RNS.Reticulum.MTU
|
||||||
self.sent_at = None
|
self.sent_at = None
|
||||||
self.packet_hash = None
|
self.packet_hash = None
|
||||||
|
self.ratchet_id = None
|
||||||
|
|
||||||
self.attached_interface = attached_interface
|
self.attached_interface = attached_interface
|
||||||
self.receiving_interface = None
|
self.receiving_interface = None
|
||||||
@ -142,9 +150,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):
|
||||||
@ -187,6 +196,8 @@ class Packet:
|
|||||||
# In all other cases, we encrypt the packet
|
# In all other cases, we encrypt the packet
|
||||||
# with the destination's encryption method
|
# with the destination's encryption method
|
||||||
self.ciphertext = self.destination.encrypt(self.data)
|
self.ciphertext = self.destination.encrypt(self.data)
|
||||||
|
if hasattr(self.destination, "latest_ratchet_id"):
|
||||||
|
self.ratchet_id = self.destination.latest_ratchet_id
|
||||||
|
|
||||||
if self.header_type == Packet.HEADER_2:
|
if self.header_type == Packet.HEADER_2:
|
||||||
if self.transport_id != None:
|
if self.transport_id != None:
|
||||||
@ -216,7 +227,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)
|
||||||
|
|
||||||
@ -409,6 +421,7 @@ class PacketReceipt:
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
RNS.log("An error occurred while evaluating external delivery callback for "+str(link), RNS.LOG_ERROR)
|
RNS.log("An error occurred while evaluating external delivery callback for "+str(link), RNS.LOG_ERROR)
|
||||||
RNS.log("The contained exception was: "+str(e), RNS.LOG_ERROR)
|
RNS.log("The contained exception was: "+str(e), RNS.LOG_ERROR)
|
||||||
|
RNS.trace_exception(e)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
|
@ -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
|
||||||
@ -295,6 +295,7 @@ class Reticulum:
|
|||||||
|
|
||||||
def __start_jobs(self):
|
def __start_jobs(self):
|
||||||
if self.jobs_thread == None:
|
if self.jobs_thread == None:
|
||||||
|
RNS.Identity._clean_ratchets()
|
||||||
self.jobs_thread = threading.Thread(target=self.__jobs)
|
self.jobs_thread = threading.Thread(target=self.__jobs)
|
||||||
self.jobs_thread.daemon = True
|
self.jobs_thread.daemon = True
|
||||||
self.jobs_thread.start()
|
self.jobs_thread.start()
|
||||||
|
@ -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]
|
||||||
@ -1603,7 +1604,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 = local_interface
|
attached_interface = local_interface,
|
||||||
|
context_flag = packet.context_flag,
|
||||||
)
|
)
|
||||||
|
|
||||||
new_announce.hops = packet.hops
|
new_announce.hops = packet.hops
|
||||||
@ -1620,7 +1622,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 = local_interface
|
attached_interface = local_interface,
|
||||||
|
context_flag = packet.context_flag,
|
||||||
)
|
)
|
||||||
|
|
||||||
new_announce.hops = packet.hops
|
new_announce.hops = packet.hops
|
||||||
@ -1651,7 +1654,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_announce.hops = packet.hops
|
new_announce.hops = packet.hops
|
||||||
@ -1673,7 +1677,6 @@ class Transport:
|
|||||||
|
|
||||||
# Call externally registered callbacks from apps
|
# Call externally registered callbacks from apps
|
||||||
# wanting to know when an announce arrives
|
# wanting to know when an announce arrives
|
||||||
if packet.context != RNS.Packet.PATH_RESPONSE:
|
|
||||||
for handler in Transport.announce_handlers:
|
for handler in Transport.announce_handlers:
|
||||||
try:
|
try:
|
||||||
# Check that the announced destination matches
|
# Check that the announced destination matches
|
||||||
@ -1688,6 +1691,15 @@ class Transport:
|
|||||||
handler_expected_hash = RNS.Destination.hash_from_name_and_identity(handler.aspect_filter, announce_identity)
|
handler_expected_hash = RNS.Destination.hash_from_name_and_identity(handler.aspect_filter, announce_identity)
|
||||||
if packet.destination_hash == handler_expected_hash:
|
if packet.destination_hash == handler_expected_hash:
|
||||||
execute_callback = True
|
execute_callback = True
|
||||||
|
|
||||||
|
# If this is a path response, check whether the
|
||||||
|
# handler wants to receive it.
|
||||||
|
if packet.context == RNS.Packet.PATH_RESPONSE:
|
||||||
|
if hasattr(handler, "receive_path_responses") and handler.receive_path_responses == True:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
execute_callback = False
|
||||||
|
|
||||||
if execute_callback:
|
if execute_callback:
|
||||||
handler.received_announce(
|
handler.received_announce(
|
||||||
destination_hash=packet.destination_hash,
|
destination_hash=packet.destination_hash,
|
||||||
@ -1697,6 +1709,7 @@ class Transport:
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
RNS.log("Error while processing external announce callback.", RNS.LOG_ERROR)
|
RNS.log("Error while processing external announce callback.", RNS.LOG_ERROR)
|
||||||
RNS.log("The contained exception was: "+str(e), RNS.LOG_ERROR)
|
RNS.log("The contained exception was: "+str(e), RNS.LOG_ERROR)
|
||||||
|
RNS.trace_exception(e)
|
||||||
|
|
||||||
# Handling for link requests to local destinations
|
# Handling for link requests to local destinations
|
||||||
elif packet.packet_type == RNS.Packet.LINKREQUEST:
|
elif packet.packet_type == RNS.Packet.LINKREQUEST:
|
||||||
@ -1975,7 +1988,9 @@ class Transport:
|
|||||||
"""
|
"""
|
||||||
Registers an announce handler.
|
Registers an announce handler.
|
||||||
|
|
||||||
:param handler: Must be an object with an *aspect_filter* attribute and a *received_announce(destination_hash, announced_identity, app_data)* callable. See the :ref:`Announce Example<example-announce>` for more info.
|
:param handler: Must be an object with an *aspect_filter* attribute and a *received_announce(destination_hash, announced_identity, app_data)*
|
||||||
|
callable. Can optionally have a *receive_path_responses* attribute set to ``True``, to also receive all path responses, in addition to live
|
||||||
|
announces. See the :ref:`Announce Example<example-announce>` for more info.
|
||||||
"""
|
"""
|
||||||
if hasattr(handler, "received_announce") and callable(handler.received_announce):
|
if hasattr(handler, "received_announce") and callable(handler.received_announce):
|
||||||
if hasattr(handler, "aspect_filter"):
|
if hasattr(handler, "aspect_filter"):
|
||||||
|
@ -1 +1 @@
|
|||||||
__version__ = "0.7.6"
|
__version__ = "0.7.7"
|
||||||
|
Binary file not shown.
Binary file not shown.
@ -1,4 +1,4 @@
|
|||||||
# Sphinx build info version 1
|
# Sphinx build info version 1
|
||||||
# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done.
|
# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done.
|
||||||
config: 4a5b669a6756de77e9b7c6b7dc5d5702
|
config: 895ecce87b0f2ca7fbb104a33248dc3e
|
||||||
tags: 645f666f9bcd5a90fca523b33c5a78b7
|
tags: 645f666f9bcd5a90fca523b33c5a78b7
|
||||||
|
@ -134,10 +134,11 @@ be sufficient, even far into the future.
|
|||||||
By default Reticulum encrypts all data using elliptic curve cryptography and AES. Any packet sent to a
|
By default Reticulum encrypts all data using elliptic curve cryptography and AES. Any packet sent to a
|
||||||
destination is encrypted with a per-packet derived key. Reticulum can also set up an encrypted
|
destination is encrypted with a per-packet derived key. Reticulum can also set up an encrypted
|
||||||
channel to a destination, called a *Link*. Both data sent over Links and single packets offer
|
channel to a destination, called a *Link*. Both data sent over Links and single packets offer
|
||||||
*Initiator Anonymity*, and links additionally offer *Forward Secrecy* by using an Elliptic Curve
|
*Initiator Anonymity*. Links additionally offer *Forward Secrecy* by default, employing an Elliptic Curve
|
||||||
Diffie Hellman key exchange on Curve25519 to derive per-link ephemeral keys. The multi-hop transport,
|
Diffie Hellman key exchange on Curve25519 to derive per-link ephemeral keys. Asymmetric, link-less
|
||||||
coordination, verification and reliability layers are fully autonomous and also based on elliptic
|
packet communication can also provide forward secrecy, with automatic key ratcheting, by enabling
|
||||||
curve cryptography.
|
ratchets on a per-destination basis. The multi-hop transport, coordination, verification and reliability
|
||||||
|
layers are fully autonomous and also based on elliptic curve cryptography.
|
||||||
|
|
||||||
Reticulum also offers symmetric key encryption for group-oriented communications, as well as
|
Reticulum also offers symmetric key encryption for group-oriented communications, as well as
|
||||||
unencrypted packets for local broadcast purposes.
|
unencrypted packets for local broadcast purposes.
|
||||||
@ -431,7 +432,7 @@ For exchanges of small amounts of information, Reticulum offers the *Packet* API
|
|||||||
|
|
||||||
* | A packet is always created with an associated destination and some payload data. When the packet is sent
|
* | A packet is always created with an associated destination and some payload data. When the packet is sent
|
||||||
to a *single* destination type, Reticulum will automatically create an ephemeral encryption key, perform
|
to a *single* destination type, Reticulum will automatically create an ephemeral encryption key, perform
|
||||||
an ECDH key exchange with the destination's public key, and encrypt the information.
|
an ECDH key exchange with the destination's public key (or ratchet key, if available), and encrypt the information.
|
||||||
|
|
||||||
* | It is important to note that this key exchange does not require any network traffic. The sender already
|
* | It is important to note that this key exchange does not require any network traffic. The sender already
|
||||||
knows the public key of the destination from an earlier received *announce*, and can thus perform the ECDH
|
knows the public key of the destination from an earlier received *announce*, and can thus perform the ECDH
|
||||||
@ -693,7 +694,8 @@ Wire Format
|
|||||||
[HEADER 2 bytes] [ADDRESSES 16/32 bytes] [CONTEXT 1 byte] [DATA 0-465 bytes]
|
[HEADER 2 bytes] [ADDRESSES 16/32 bytes] [CONTEXT 1 byte] [DATA 0-465 bytes]
|
||||||
|
|
||||||
* The HEADER field is 2 bytes long.
|
* The HEADER field is 2 bytes long.
|
||||||
* Byte 1: [IFAC Flag], [Header Type], [Propagation Type], [Destination Type] and [Packet Type]
|
* Byte 1: [IFAC Flag], [Header Type], [Context Flag], [Propagation Type],
|
||||||
|
[Destination Type] and [Packet Type]
|
||||||
* Byte 2: Number of hops
|
* Byte 2: Number of hops
|
||||||
|
|
||||||
* Interface Access Code field if the IFAC flag was set.
|
* Interface Access Code field if the IFAC flag was set.
|
||||||
@ -725,12 +727,16 @@ Wire Format
|
|||||||
type 2 1 Two byte header, two 16 byte address fields
|
type 2 1 Two byte header, two 16 byte address fields
|
||||||
|
|
||||||
|
|
||||||
|
Context Flag
|
||||||
|
-----------------
|
||||||
|
unset 0 The context flag is used for various types
|
||||||
|
set 1 of signalling, depending on packet context
|
||||||
|
|
||||||
|
|
||||||
Propagation Types
|
Propagation Types
|
||||||
-----------------
|
-----------------
|
||||||
broadcast 00
|
broadcast 0
|
||||||
transport 01
|
transport 1
|
||||||
reserved 10
|
|
||||||
reserved 11
|
|
||||||
|
|
||||||
|
|
||||||
Destination Types
|
Destination Types
|
||||||
@ -862,12 +868,14 @@ both on general-purpose CPUs and on microcontrollers. The necessary primitives a
|
|||||||
|
|
||||||
* HKDF for key derivation
|
* HKDF for key derivation
|
||||||
|
|
||||||
* Fernet for encrypted tokens
|
* Modified Fernet for encrypted tokens
|
||||||
|
|
||||||
* AES-128 in CBC mode
|
* AES-128 in CBC mode
|
||||||
|
|
||||||
* HMAC for message authentication
|
* HMAC for message authentication
|
||||||
|
|
||||||
|
* No Version and Timestamp metadata included
|
||||||
|
|
||||||
* SHA-256
|
* SHA-256
|
||||||
|
|
||||||
* SHA-512
|
* SHA-512
|
||||||
|
@ -53,9 +53,9 @@ What does Reticulum Offer?
|
|||||||
|
|
||||||
* Forward Secrecy by using ephemeral Elliptic Curve Diffie-Hellman keys on Curve25519
|
* Forward Secrecy by using ephemeral Elliptic Curve Diffie-Hellman keys on Curve25519
|
||||||
|
|
||||||
* Reticulum uses the `Fernet <https://github.com/fernet/spec/blob/master/Spec.md>`_ specification for on-the-wire / over-the-air encryption
|
* Reticulum uses a modified version of the `Fernet <https://github.com/fernet/spec/blob/master/Spec.md>`_ specification for on-the-wire / over-the-air encryption
|
||||||
|
|
||||||
* All keys are ephemeral and derived from an ECDH key exchange on Curve25519
|
* Keys are ephemeral and derived from an ECDH key exchange on Curve25519
|
||||||
|
|
||||||
* AES-128 in CBC mode with PKCS7 padding
|
* AES-128 in CBC mode with PKCS7 padding
|
||||||
|
|
||||||
@ -63,6 +63,8 @@ What does Reticulum Offer?
|
|||||||
|
|
||||||
* IVs are generated through os.urandom()
|
* IVs are generated through os.urandom()
|
||||||
|
|
||||||
|
* No Version and Timestamp metadata included
|
||||||
|
|
||||||
* Unforgeable packet delivery confirmations
|
* Unforgeable packet delivery confirmations
|
||||||
|
|
||||||
* A variety of supported interface types
|
* A variety of supported interface types
|
||||||
@ -99,7 +101,8 @@ of the types of interfaces Reticulum was designed for.
|
|||||||
An open-source LoRa-based interface called `RNode <https://unsigned.io/rnode>`_
|
An open-source LoRa-based interface called `RNode <https://unsigned.io/rnode>`_
|
||||||
has been designed as an example transceiver that is very suitable for
|
has been designed as an example transceiver that is very suitable for
|
||||||
Reticulum. It is possible to build it yourself, to transform a common LoRa
|
Reticulum. It is possible to build it yourself, to transform a common LoRa
|
||||||
development board into one, or it can be purchased as a complete transceiver.
|
development board into one, or it can be purchased as a complete transceiver
|
||||||
|
from various vendors.
|
||||||
|
|
||||||
Reticulum can also be encapsulated over existing IP networks, so there's
|
Reticulum can also be encapsulated over existing IP networks, so there's
|
||||||
nothing stopping you from using it over wired Ethernet or your local WiFi
|
nothing stopping you from using it over wired Ethernet or your local WiFi
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
var DOCUMENTATION_OPTIONS = {
|
var DOCUMENTATION_OPTIONS = {
|
||||||
URL_ROOT: document.getElementById("documentation_options").getAttribute('data-url_root'),
|
URL_ROOT: document.getElementById("documentation_options").getAttribute('data-url_root'),
|
||||||
VERSION: '0.7.6 beta',
|
VERSION: '0.7.7 beta',
|
||||||
LANGUAGE: 'en',
|
LANGUAGE: 'en',
|
||||||
COLLAPSE_INDEX: false,
|
COLLAPSE_INDEX: false,
|
||||||
BUILDER: 'html',
|
BUILDER: 'html',
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
<link rel="index" title="Index" href="genindex.html" /><link rel="search" title="Search" href="search.html" /><link rel="next" title="Support Reticulum" href="support.html" /><link rel="prev" title="Building Networks" href="networks.html" />
|
<link rel="index" title="Index" href="genindex.html" /><link rel="search" title="Search" href="search.html" /><link rel="next" title="Support Reticulum" href="support.html" /><link rel="prev" title="Building Networks" href="networks.html" />
|
||||||
|
|
||||||
<meta name="generator" content="sphinx-5.3.0, furo 2022.09.29.dev1"/>
|
<meta name="generator" content="sphinx-5.3.0, furo 2022.09.29.dev1"/>
|
||||||
<title>Code Examples - Reticulum Network Stack 0.7.6 beta documentation</title>
|
<title>Code Examples - Reticulum Network Stack 0.7.7 beta documentation</title>
|
||||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
|
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
|
||||||
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=189ec851f9bb375a2509b67be1f64f0cf212b702" />
|
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=189ec851f9bb375a2509b67be1f64f0cf212b702" />
|
||||||
<link rel="stylesheet" type="text/css" href="_static/copybutton.css" />
|
<link rel="stylesheet" type="text/css" href="_static/copybutton.css" />
|
||||||
@ -141,7 +141,7 @@
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="header-center">
|
<div class="header-center">
|
||||||
<a href="index.html"><div class="brand">Reticulum Network Stack 0.7.6 beta documentation</div></a>
|
<a href="index.html"><div class="brand">Reticulum Network Stack 0.7.7 beta documentation</div></a>
|
||||||
</div>
|
</div>
|
||||||
<div class="header-right">
|
<div class="header-right">
|
||||||
<div class="theme-toggle-container theme-toggle-header">
|
<div class="theme-toggle-container theme-toggle-header">
|
||||||
@ -167,7 +167,7 @@
|
|||||||
<img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/>
|
<img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<span class="sidebar-brand-text">Reticulum Network Stack 0.7.6 beta documentation</span>
|
<span class="sidebar-brand-text">Reticulum Network Stack 0.7.7 beta documentation</span>
|
||||||
|
|
||||||
</a><form class="sidebar-search-container" method="get" action="search.html" role="search">
|
</a><form class="sidebar-search-container" method="get" action="search.html" role="search">
|
||||||
<input class="sidebar-search" placeholder="Search" name="q" aria-label="Search">
|
<input class="sidebar-search" placeholder="Search" name="q" aria-label="Search">
|
||||||
@ -656,7 +656,6 @@ the Packet interface.</p>
|
|||||||
<span class="c1"># of the packet. #</span>
|
<span class="c1"># of the packet. #</span>
|
||||||
<span class="c1">##########################################################</span>
|
<span class="c1">##########################################################</span>
|
||||||
|
|
||||||
<span class="kn">import</span> <span class="nn">os</span>
|
|
||||||
<span class="kn">import</span> <span class="nn">argparse</span>
|
<span class="kn">import</span> <span class="nn">argparse</span>
|
||||||
<span class="kn">import</span> <span class="nn">RNS</span>
|
<span class="kn">import</span> <span class="nn">RNS</span>
|
||||||
|
|
||||||
@ -679,19 +678,8 @@ the Packet interface.</p>
|
|||||||
<span class="c1"># We must first initialise Reticulum</span>
|
<span class="c1"># We must first initialise Reticulum</span>
|
||||||
<span class="n">reticulum</span> <span class="o">=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Reticulum</span><span class="p">(</span><span class="n">configpath</span><span class="p">)</span>
|
<span class="n">reticulum</span> <span class="o">=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Reticulum</span><span class="p">(</span><span class="n">configpath</span><span class="p">)</span>
|
||||||
|
|
||||||
<span class="c1"># Load identity from file if it exist or randomley create</span>
|
<span class="c1"># Randomly create a new identity for our echo server</span>
|
||||||
<span class="k">if</span> <span class="n">configpath</span><span class="p">:</span>
|
|
||||||
<span class="n">ifilepath</span> <span class="o">=</span> <span class="s2">"</span><span class="si">%s</span><span class="s2">/storage/identitiesy/</span><span class="si">%s</span><span class="s2">"</span> <span class="o">%</span> <span class="p">(</span><span class="n">configpath</span><span class="p">,</span><span class="n">APP_NAME</span><span class="p">)</span>
|
|
||||||
<span class="k">else</span><span class="p">:</span>
|
|
||||||
<span class="n">ifilepath</span> <span class="o">=</span> <span class="s2">"</span><span class="si">%s</span><span class="s2">/storage/identities/</span><span class="si">%s</span><span class="s2">"</span> <span class="o">%</span> <span class="p">(</span><span class="n">RNS</span><span class="o">.</span><span class="n">Reticulum</span><span class="o">.</span><span class="n">configdir</span><span class="p">,</span><span class="n">APP_NAME</span><span class="p">)</span>
|
|
||||||
<span class="k">if</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">exists</span><span class="p">(</span><span class="n">ifilepath</span><span class="p">):</span>
|
|
||||||
<span class="c1"># Load identity from file</span>
|
|
||||||
<span class="n">server_identity</span> <span class="o">=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Identity</span><span class="o">.</span><span class="n">from_file</span><span class="p">(</span><span class="n">ifilepath</span><span class="p">)</span>
|
|
||||||
<span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"loaded identity from file: "</span><span class="o">+</span><span class="n">ifilepath</span><span class="p">,</span> <span class="n">RNS</span><span class="o">.</span><span class="n">LOG_VERBOSE</span><span class="p">)</span>
|
|
||||||
<span class="k">else</span><span class="p">:</span>
|
|
||||||
<span class="c1"># Randomly create a new identity for our echo example</span>
|
|
||||||
<span class="n">server_identity</span> <span class="o">=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Identity</span><span class="p">()</span>
|
<span class="n">server_identity</span> <span class="o">=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Identity</span><span class="p">()</span>
|
||||||
<span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"created new identity"</span><span class="p">,</span> <span class="n">RNS</span><span class="o">.</span><span class="n">LOG_VERBOSE</span><span class="p">)</span>
|
|
||||||
|
|
||||||
<span class="c1"># We create a destination that clients can query. We want</span>
|
<span class="c1"># We create a destination that clients can query. We want</span>
|
||||||
<span class="c1"># to be able to verify echo replies to our clients, so we</span>
|
<span class="c1"># to be able to verify echo replies to our clients, so we</span>
|
||||||
@ -1030,8 +1018,8 @@ destination, and passing traffic back and forth over the link.</p>
|
|||||||
<span class="c1"># We must first initialise Reticulum</span>
|
<span class="c1"># We must first initialise Reticulum</span>
|
||||||
<span class="n">reticulum</span> <span class="o">=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Reticulum</span><span class="p">(</span><span class="n">configpath</span><span class="p">)</span>
|
<span class="n">reticulum</span> <span class="o">=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Reticulum</span><span class="p">(</span><span class="n">configpath</span><span class="p">)</span>
|
||||||
|
|
||||||
|
<span class="c1"># Randomly create a new identity for our link example</span>
|
||||||
<span class="n">server_identity</span> <span class="o">=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Identity</span><span class="p">()</span>
|
<span class="n">server_identity</span> <span class="o">=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Identity</span><span class="p">()</span>
|
||||||
<span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"created new identity"</span><span class="p">,</span> <span class="n">RNS</span><span class="o">.</span><span class="n">LOG_VERBOSE</span><span class="p">)</span>
|
|
||||||
|
|
||||||
<span class="c1"># We create a destination that clients can connect to. We</span>
|
<span class="c1"># We create a destination that clients can connect to. We</span>
|
||||||
<span class="c1"># want clients to create links to this destination, so we</span>
|
<span class="c1"># want clients to create links to this destination, so we</span>
|
||||||
@ -1060,7 +1048,7 @@ destination, and passing traffic back and forth over the link.</p>
|
|||||||
<span class="s2">" running, waiting for a connection."</span>
|
<span class="s2">" running, waiting for a connection."</span>
|
||||||
<span class="p">)</span>
|
<span class="p">)</span>
|
||||||
|
|
||||||
<span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Hit enter to manually send an announce (Ctrl-C or </span><span class="se">\"</span><span class="s2">quit</span><span class="se">\"</span><span class="s2"> to quit)"</span><span class="p">)</span>
|
<span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Hit enter to manually send an announce (Ctrl-C to quit)"</span><span class="p">)</span>
|
||||||
|
|
||||||
<span class="c1"># We enter a loop that runs until the users exits.</span>
|
<span class="c1"># We enter a loop that runs until the users exits.</span>
|
||||||
<span class="c1"># If the user hits enter, we will announce our server</span>
|
<span class="c1"># If the user hits enter, we will announce our server</span>
|
||||||
@ -1070,12 +1058,6 @@ destination, and passing traffic back and forth over the link.</p>
|
|||||||
<span class="n">entered</span> <span class="o">=</span> <span class="nb">input</span><span class="p">()</span>
|
<span class="n">entered</span> <span class="o">=</span> <span class="nb">input</span><span class="p">()</span>
|
||||||
<span class="n">destination</span><span class="o">.</span><span class="n">announce</span><span class="p">()</span>
|
<span class="n">destination</span><span class="o">.</span><span class="n">announce</span><span class="p">()</span>
|
||||||
<span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Sent announce from "</span><span class="o">+</span><span class="n">RNS</span><span class="o">.</span><span class="n">prettyhexrep</span><span class="p">(</span><span class="n">destination</span><span class="o">.</span><span class="n">hash</span><span class="p">))</span>
|
<span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Sent announce from "</span><span class="o">+</span><span class="n">RNS</span><span class="o">.</span><span class="n">prettyhexrep</span><span class="p">(</span><span class="n">destination</span><span class="o">.</span><span class="n">hash</span><span class="p">))</span>
|
||||||
<span class="k">if</span> <span class="n">entered</span> <span class="o">==</span> <span class="s2">"quit"</span><span class="p">:</span>
|
|
||||||
<span class="k">if</span> <span class="n">latest_client_link</span><span class="p">:</span>
|
|
||||||
<span class="n">latest_client_link</span><span class="o">.</span><span class="n">teardown</span><span class="p">()</span>
|
|
||||||
<span class="k">break</span>
|
|
||||||
<span class="nb">print</span><span class="p">(</span><span class="s2">""</span><span class="p">)</span>
|
|
||||||
<span class="n">exit</span><span class="p">()</span>
|
|
||||||
|
|
||||||
<span class="c1"># When a client establishes a link to our server</span>
|
<span class="c1"># When a client establishes a link to our server</span>
|
||||||
<span class="c1"># destination, this function will be called with</span>
|
<span class="c1"># destination, this function will be called with</span>
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
<link rel="index" title="Index" href="genindex.html" /><link rel="search" title="Search" href="search.html" />
|
<link rel="index" title="Index" href="genindex.html" /><link rel="search" title="Search" href="search.html" />
|
||||||
|
|
||||||
<meta name="generator" content="sphinx-5.3.0, furo 2022.09.29.dev1"/>
|
<meta name="generator" content="sphinx-5.3.0, furo 2022.09.29.dev1"/>
|
||||||
<title>An Explanation of Reticulum for Human Beings - Reticulum Network Stack 0.7.6 beta documentation</title>
|
<title>An Explanation of Reticulum for Human Beings - Reticulum Network Stack 0.7.7 beta documentation</title>
|
||||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
|
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
|
||||||
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=189ec851f9bb375a2509b67be1f64f0cf212b702" />
|
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=189ec851f9bb375a2509b67be1f64f0cf212b702" />
|
||||||
<link rel="stylesheet" type="text/css" href="_static/copybutton.css" />
|
<link rel="stylesheet" type="text/css" href="_static/copybutton.css" />
|
||||||
@ -141,7 +141,7 @@
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="header-center">
|
<div class="header-center">
|
||||||
<a href="index.html"><div class="brand">Reticulum Network Stack 0.7.6 beta documentation</div></a>
|
<a href="index.html"><div class="brand">Reticulum Network Stack 0.7.7 beta documentation</div></a>
|
||||||
</div>
|
</div>
|
||||||
<div class="header-right">
|
<div class="header-right">
|
||||||
<div class="theme-toggle-container theme-toggle-header">
|
<div class="theme-toggle-container theme-toggle-header">
|
||||||
@ -167,7 +167,7 @@
|
|||||||
<img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/>
|
<img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<span class="sidebar-brand-text">Reticulum Network Stack 0.7.6 beta documentation</span>
|
<span class="sidebar-brand-text">Reticulum Network Stack 0.7.7 beta documentation</span>
|
||||||
|
|
||||||
</a><form class="sidebar-search-container" method="get" action="search.html" role="search">
|
</a><form class="sidebar-search-container" method="get" action="search.html" role="search">
|
||||||
<input class="sidebar-search" placeholder="Search" name="q" aria-label="Search">
|
<input class="sidebar-search" placeholder="Search" name="q" aria-label="Search">
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
<meta name="viewport" content="width=device-width,initial-scale=1"/>
|
<meta name="viewport" content="width=device-width,initial-scale=1"/>
|
||||||
<meta name="color-scheme" content="light dark"><link rel="index" title="Index" href="#" /><link rel="search" title="Search" href="search.html" />
|
<meta name="color-scheme" content="light dark"><link rel="index" title="Index" href="#" /><link rel="search" title="Search" href="search.html" />
|
||||||
|
|
||||||
<meta name="generator" content="sphinx-5.3.0, furo 2022.09.29.dev1"/><title>Index - Reticulum Network Stack 0.7.6 beta documentation</title>
|
<meta name="generator" content="sphinx-5.3.0, furo 2022.09.29.dev1"/><title>Index - Reticulum Network Stack 0.7.7 beta documentation</title>
|
||||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
|
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
|
||||||
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=189ec851f9bb375a2509b67be1f64f0cf212b702" />
|
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=189ec851f9bb375a2509b67be1f64f0cf212b702" />
|
||||||
<link rel="stylesheet" type="text/css" href="_static/copybutton.css" />
|
<link rel="stylesheet" type="text/css" href="_static/copybutton.css" />
|
||||||
@ -139,7 +139,7 @@
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="header-center">
|
<div class="header-center">
|
||||||
<a href="index.html"><div class="brand">Reticulum Network Stack 0.7.6 beta documentation</div></a>
|
<a href="index.html"><div class="brand">Reticulum Network Stack 0.7.7 beta documentation</div></a>
|
||||||
</div>
|
</div>
|
||||||
<div class="header-right">
|
<div class="header-right">
|
||||||
<div class="theme-toggle-container theme-toggle-header">
|
<div class="theme-toggle-container theme-toggle-header">
|
||||||
@ -165,7 +165,7 @@
|
|||||||
<img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/>
|
<img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<span class="sidebar-brand-text">Reticulum Network Stack 0.7.6 beta documentation</span>
|
<span class="sidebar-brand-text">Reticulum Network Stack 0.7.7 beta documentation</span>
|
||||||
|
|
||||||
</a><form class="sidebar-search-container" method="get" action="search.html" role="search">
|
</a><form class="sidebar-search-container" method="get" action="search.html" role="search">
|
||||||
<input class="sidebar-search" placeholder="Search" name="q" aria-label="Search">
|
<input class="sidebar-search" placeholder="Search" name="q" aria-label="Search">
|
||||||
@ -293,6 +293,8 @@
|
|||||||
<li><a href="reference.html#RNS.Buffer.create_reader">create_reader() (RNS.Buffer static method)</a>
|
<li><a href="reference.html#RNS.Buffer.create_reader">create_reader() (RNS.Buffer static method)</a>
|
||||||
</li>
|
</li>
|
||||||
<li><a href="reference.html#RNS.Buffer.create_writer">create_writer() (RNS.Buffer static method)</a>
|
<li><a href="reference.html#RNS.Buffer.create_writer">create_writer() (RNS.Buffer static method)</a>
|
||||||
|
</li>
|
||||||
|
<li><a href="reference.html#RNS.Identity.current_ratchet_id">current_ratchet_id() (RNS.Identity static method)</a>
|
||||||
</li>
|
</li>
|
||||||
<li><a href="reference.html#RNS.Identity.CURVE">CURVE (RNS.Identity attribute)</a>
|
<li><a href="reference.html#RNS.Identity.CURVE">CURVE (RNS.Identity attribute)</a>
|
||||||
|
|
||||||
@ -330,6 +332,8 @@
|
|||||||
<h2>E</h2>
|
<h2>E</h2>
|
||||||
<table style="width: 100%" class="indextable genindextable"><tr>
|
<table style="width: 100%" class="indextable genindextable"><tr>
|
||||||
<td style="width: 33%; vertical-align: top;"><ul>
|
<td style="width: 33%; vertical-align: top;"><ul>
|
||||||
|
<li><a href="reference.html#RNS.Destination.enable_ratchets">enable_ratchets() (RNS.Destination method)</a>
|
||||||
|
</li>
|
||||||
<li><a href="reference.html#RNS.Destination.encrypt">encrypt() (RNS.Destination method)</a>
|
<li><a href="reference.html#RNS.Destination.encrypt">encrypt() (RNS.Destination method)</a>
|
||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
@ -339,6 +343,8 @@
|
|||||||
</ul></td>
|
</ul></td>
|
||||||
<td style="width: 33%; vertical-align: top;"><ul>
|
<td style="width: 33%; vertical-align: top;"><ul>
|
||||||
<li><a href="reference.html#RNS.Packet.ENCRYPTED_MDU">ENCRYPTED_MDU (RNS.Packet attribute)</a>
|
<li><a href="reference.html#RNS.Packet.ENCRYPTED_MDU">ENCRYPTED_MDU (RNS.Packet attribute)</a>
|
||||||
|
</li>
|
||||||
|
<li><a href="reference.html#RNS.Destination.enforce_ratchets">enforce_ratchets() (RNS.Destination method)</a>
|
||||||
</li>
|
</li>
|
||||||
<li><a href="reference.html#RNS.Link.ESTABLISHMENT_TIMEOUT_PER_HOP">ESTABLISHMENT_TIMEOUT_PER_HOP (RNS.Link attribute)</a>
|
<li><a href="reference.html#RNS.Link.ESTABLISHMENT_TIMEOUT_PER_HOP">ESTABLISHMENT_TIMEOUT_PER_HOP (RNS.Link attribute)</a>
|
||||||
</li>
|
</li>
|
||||||
@ -568,6 +574,14 @@
|
|||||||
<h2>R</h2>
|
<h2>R</h2>
|
||||||
<table style="width: 100%" class="indextable genindextable"><tr>
|
<table style="width: 100%" class="indextable genindextable"><tr>
|
||||||
<td style="width: 33%; vertical-align: top;"><ul>
|
<td style="width: 33%; vertical-align: top;"><ul>
|
||||||
|
<li><a href="reference.html#RNS.Destination.RATCHET_COUNT">RATCHET_COUNT (RNS.Destination attribute)</a>
|
||||||
|
</li>
|
||||||
|
<li><a href="reference.html#RNS.Identity.RATCHET_EXPIRY">RATCHET_EXPIRY (RNS.Identity attribute)</a>
|
||||||
|
</li>
|
||||||
|
<li><a href="reference.html#RNS.Destination.RATCHET_INTERVAL">RATCHET_INTERVAL (RNS.Destination attribute)</a>
|
||||||
|
</li>
|
||||||
|
<li><a href="reference.html#RNS.Identity.RATCHETSIZE">RATCHETSIZE (RNS.Identity attribute)</a>
|
||||||
|
</li>
|
||||||
<li><a href="reference.html#RNS.RawChannelReader">RawChannelReader (class in RNS)</a>
|
<li><a href="reference.html#RNS.RawChannelReader">RawChannelReader (class in RNS)</a>
|
||||||
</li>
|
</li>
|
||||||
<li><a href="reference.html#RNS.RawChannelWriter">RawChannelWriter (class in RNS)</a>
|
<li><a href="reference.html#RNS.RawChannelWriter">RawChannelWriter (class in RNS)</a>
|
||||||
@ -580,12 +594,12 @@
|
|||||||
</li>
|
</li>
|
||||||
<li><a href="reference.html#RNS.Channel.Channel.register_message_type">register_message_type() (RNS.Channel.Channel method)</a>
|
<li><a href="reference.html#RNS.Channel.Channel.register_message_type">register_message_type() (RNS.Channel.Channel method)</a>
|
||||||
</li>
|
</li>
|
||||||
|
</ul></td>
|
||||||
|
<td style="width: 33%; vertical-align: top;"><ul>
|
||||||
<li><a href="reference.html#RNS.Destination.register_request_handler">register_request_handler() (RNS.Destination method)</a>
|
<li><a href="reference.html#RNS.Destination.register_request_handler">register_request_handler() (RNS.Destination method)</a>
|
||||||
</li>
|
</li>
|
||||||
<li><a href="reference.html#RNS.Reticulum.remote_management_enabled">remote_management_enabled() (RNS.Reticulum static method)</a>
|
<li><a href="reference.html#RNS.Reticulum.remote_management_enabled">remote_management_enabled() (RNS.Reticulum static method)</a>
|
||||||
</li>
|
</li>
|
||||||
</ul></td>
|
|
||||||
<td style="width: 33%; vertical-align: top;"><ul>
|
|
||||||
<li><a href="reference.html#RNS.Channel.Channel.remove_message_handler">remove_message_handler() (RNS.Channel.Channel method)</a>
|
<li><a href="reference.html#RNS.Channel.Channel.remove_message_handler">remove_message_handler() (RNS.Channel.Channel method)</a>
|
||||||
</li>
|
</li>
|
||||||
<li><a href="reference.html#RNS.RawChannelReader.remove_ready_callback">remove_ready_callback() (RNS.RawChannelReader method)</a>
|
<li><a href="reference.html#RNS.RawChannelReader.remove_ready_callback">remove_ready_callback() (RNS.RawChannelReader method)</a>
|
||||||
@ -633,6 +647,8 @@
|
|||||||
<li><a href="reference.html#RNS.Destination.set_proof_requested_callback">set_proof_requested_callback() (RNS.Destination method)</a>
|
<li><a href="reference.html#RNS.Destination.set_proof_requested_callback">set_proof_requested_callback() (RNS.Destination method)</a>
|
||||||
</li>
|
</li>
|
||||||
<li><a href="reference.html#RNS.Destination.set_proof_strategy">set_proof_strategy() (RNS.Destination method)</a>
|
<li><a href="reference.html#RNS.Destination.set_proof_strategy">set_proof_strategy() (RNS.Destination method)</a>
|
||||||
|
</li>
|
||||||
|
<li><a href="reference.html#RNS.Destination.set_ratchet_interval">set_ratchet_interval() (RNS.Destination method)</a>
|
||||||
</li>
|
</li>
|
||||||
<li><a href="reference.html#RNS.Link.set_remote_identified_callback">set_remote_identified_callback() (RNS.Link method)</a>
|
<li><a href="reference.html#RNS.Link.set_remote_identified_callback">set_remote_identified_callback() (RNS.Link method)</a>
|
||||||
</li>
|
</li>
|
||||||
@ -645,6 +661,8 @@
|
|||||||
<li><a href="reference.html#RNS.Link.set_resource_started_callback">set_resource_started_callback() (RNS.Link method)</a>
|
<li><a href="reference.html#RNS.Link.set_resource_started_callback">set_resource_started_callback() (RNS.Link method)</a>
|
||||||
</li>
|
</li>
|
||||||
<li><a href="reference.html#RNS.Link.set_resource_strategy">set_resource_strategy() (RNS.Link method)</a>
|
<li><a href="reference.html#RNS.Link.set_resource_strategy">set_resource_strategy() (RNS.Link method)</a>
|
||||||
|
</li>
|
||||||
|
<li><a href="reference.html#RNS.Destination.set_retained_ratchets">set_retained_ratchets() (RNS.Destination method)</a>
|
||||||
</li>
|
</li>
|
||||||
<li><a href="reference.html#RNS.PacketReceipt.set_timeout">set_timeout() (RNS.PacketReceipt method)</a>
|
<li><a href="reference.html#RNS.PacketReceipt.set_timeout">set_timeout() (RNS.PacketReceipt method)</a>
|
||||||
</li>
|
</li>
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
<link rel="index" title="Index" href="genindex.html" /><link rel="search" title="Search" href="search.html" /><link rel="next" title="Using Reticulum on Your System" href="using.html" /><link rel="prev" title="What is Reticulum?" href="whatis.html" />
|
<link rel="index" title="Index" href="genindex.html" /><link rel="search" title="Search" href="search.html" /><link rel="next" title="Using Reticulum on Your System" href="using.html" /><link rel="prev" title="What is Reticulum?" href="whatis.html" />
|
||||||
|
|
||||||
<meta name="generator" content="sphinx-5.3.0, furo 2022.09.29.dev1"/>
|
<meta name="generator" content="sphinx-5.3.0, furo 2022.09.29.dev1"/>
|
||||||
<title>Getting Started Fast - Reticulum Network Stack 0.7.6 beta documentation</title>
|
<title>Getting Started Fast - Reticulum Network Stack 0.7.7 beta documentation</title>
|
||||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
|
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
|
||||||
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=189ec851f9bb375a2509b67be1f64f0cf212b702" />
|
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=189ec851f9bb375a2509b67be1f64f0cf212b702" />
|
||||||
<link rel="stylesheet" type="text/css" href="_static/copybutton.css" />
|
<link rel="stylesheet" type="text/css" href="_static/copybutton.css" />
|
||||||
@ -141,7 +141,7 @@
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="header-center">
|
<div class="header-center">
|
||||||
<a href="index.html"><div class="brand">Reticulum Network Stack 0.7.6 beta documentation</div></a>
|
<a href="index.html"><div class="brand">Reticulum Network Stack 0.7.7 beta documentation</div></a>
|
||||||
</div>
|
</div>
|
||||||
<div class="header-right">
|
<div class="header-right">
|
||||||
<div class="theme-toggle-container theme-toggle-header">
|
<div class="theme-toggle-container theme-toggle-header">
|
||||||
@ -167,7 +167,7 @@
|
|||||||
<img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/>
|
<img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<span class="sidebar-brand-text">Reticulum Network Stack 0.7.6 beta documentation</span>
|
<span class="sidebar-brand-text">Reticulum Network Stack 0.7.7 beta documentation</span>
|
||||||
|
|
||||||
</a><form class="sidebar-search-container" method="get" action="search.html" role="search">
|
</a><form class="sidebar-search-container" method="get" action="search.html" role="search">
|
||||||
<input class="sidebar-search" placeholder="Search" name="q" aria-label="Search">
|
<input class="sidebar-search" placeholder="Search" name="q" aria-label="Search">
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
<link rel="index" title="Index" href="genindex.html" /><link rel="search" title="Search" href="search.html" /><link rel="next" title="Configuring Interfaces" href="interfaces.html" /><link rel="prev" title="Understanding Reticulum" href="understanding.html" />
|
<link rel="index" title="Index" href="genindex.html" /><link rel="search" title="Search" href="search.html" /><link rel="next" title="Configuring Interfaces" href="interfaces.html" /><link rel="prev" title="Understanding Reticulum" href="understanding.html" />
|
||||||
|
|
||||||
<meta name="generator" content="sphinx-5.3.0, furo 2022.09.29.dev1"/>
|
<meta name="generator" content="sphinx-5.3.0, furo 2022.09.29.dev1"/>
|
||||||
<title>Communications Hardware - Reticulum Network Stack 0.7.6 beta documentation</title>
|
<title>Communications Hardware - Reticulum Network Stack 0.7.7 beta documentation</title>
|
||||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
|
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
|
||||||
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=189ec851f9bb375a2509b67be1f64f0cf212b702" />
|
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=189ec851f9bb375a2509b67be1f64f0cf212b702" />
|
||||||
<link rel="stylesheet" type="text/css" href="_static/copybutton.css" />
|
<link rel="stylesheet" type="text/css" href="_static/copybutton.css" />
|
||||||
@ -141,7 +141,7 @@
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="header-center">
|
<div class="header-center">
|
||||||
<a href="index.html"><div class="brand">Reticulum Network Stack 0.7.6 beta documentation</div></a>
|
<a href="index.html"><div class="brand">Reticulum Network Stack 0.7.7 beta documentation</div></a>
|
||||||
</div>
|
</div>
|
||||||
<div class="header-right">
|
<div class="header-right">
|
||||||
<div class="theme-toggle-container theme-toggle-header">
|
<div class="theme-toggle-container theme-toggle-header">
|
||||||
@ -167,7 +167,7 @@
|
|||||||
<img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/>
|
<img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<span class="sidebar-brand-text">Reticulum Network Stack 0.7.6 beta documentation</span>
|
<span class="sidebar-brand-text">Reticulum Network Stack 0.7.7 beta documentation</span>
|
||||||
|
|
||||||
</a><form class="sidebar-search-container" method="get" action="search.html" role="search">
|
</a><form class="sidebar-search-container" method="get" action="search.html" role="search">
|
||||||
<input class="sidebar-search" placeholder="Search" name="q" aria-label="Search">
|
<input class="sidebar-search" placeholder="Search" name="q" aria-label="Search">
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
<link rel="index" title="Index" href="genindex.html" /><link rel="search" title="Search" href="search.html" /><link rel="next" title="What is Reticulum?" href="whatis.html" />
|
<link rel="index" title="Index" href="genindex.html" /><link rel="search" title="Search" href="search.html" /><link rel="next" title="What is Reticulum?" href="whatis.html" />
|
||||||
|
|
||||||
<meta name="generator" content="sphinx-5.3.0, furo 2022.09.29.dev1"/>
|
<meta name="generator" content="sphinx-5.3.0, furo 2022.09.29.dev1"/>
|
||||||
<title>Reticulum Network Stack 0.7.6 beta documentation</title>
|
<title>Reticulum Network Stack 0.7.7 beta documentation</title>
|
||||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
|
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
|
||||||
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=189ec851f9bb375a2509b67be1f64f0cf212b702" />
|
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=189ec851f9bb375a2509b67be1f64f0cf212b702" />
|
||||||
<link rel="stylesheet" type="text/css" href="_static/copybutton.css" />
|
<link rel="stylesheet" type="text/css" href="_static/copybutton.css" />
|
||||||
@ -141,7 +141,7 @@
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="header-center">
|
<div class="header-center">
|
||||||
<a href="#"><div class="brand">Reticulum Network Stack 0.7.6 beta documentation</div></a>
|
<a href="#"><div class="brand">Reticulum Network Stack 0.7.7 beta documentation</div></a>
|
||||||
</div>
|
</div>
|
||||||
<div class="header-right">
|
<div class="header-right">
|
||||||
<div class="theme-toggle-container theme-toggle-header">
|
<div class="theme-toggle-container theme-toggle-header">
|
||||||
@ -167,7 +167,7 @@
|
|||||||
<img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/>
|
<img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<span class="sidebar-brand-text">Reticulum Network Stack 0.7.6 beta documentation</span>
|
<span class="sidebar-brand-text">Reticulum Network Stack 0.7.7 beta documentation</span>
|
||||||
|
|
||||||
</a><form class="sidebar-search-container" method="get" action="search.html" role="search">
|
</a><form class="sidebar-search-container" method="get" action="search.html" role="search">
|
||||||
<input class="sidebar-search" placeholder="Search" name="q" aria-label="Search">
|
<input class="sidebar-search" placeholder="Search" name="q" aria-label="Search">
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
<link rel="index" title="Index" href="genindex.html" /><link rel="search" title="Search" href="search.html" /><link rel="next" title="Building Networks" href="networks.html" /><link rel="prev" title="Communications Hardware" href="hardware.html" />
|
<link rel="index" title="Index" href="genindex.html" /><link rel="search" title="Search" href="search.html" /><link rel="next" title="Building Networks" href="networks.html" /><link rel="prev" title="Communications Hardware" href="hardware.html" />
|
||||||
|
|
||||||
<meta name="generator" content="sphinx-5.3.0, furo 2022.09.29.dev1"/>
|
<meta name="generator" content="sphinx-5.3.0, furo 2022.09.29.dev1"/>
|
||||||
<title>Configuring Interfaces - Reticulum Network Stack 0.7.6 beta documentation</title>
|
<title>Configuring Interfaces - Reticulum Network Stack 0.7.7 beta documentation</title>
|
||||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
|
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
|
||||||
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=189ec851f9bb375a2509b67be1f64f0cf212b702" />
|
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=189ec851f9bb375a2509b67be1f64f0cf212b702" />
|
||||||
<link rel="stylesheet" type="text/css" href="_static/copybutton.css" />
|
<link rel="stylesheet" type="text/css" href="_static/copybutton.css" />
|
||||||
@ -141,7 +141,7 @@
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="header-center">
|
<div class="header-center">
|
||||||
<a href="index.html"><div class="brand">Reticulum Network Stack 0.7.6 beta documentation</div></a>
|
<a href="index.html"><div class="brand">Reticulum Network Stack 0.7.7 beta documentation</div></a>
|
||||||
</div>
|
</div>
|
||||||
<div class="header-right">
|
<div class="header-right">
|
||||||
<div class="theme-toggle-container theme-toggle-header">
|
<div class="theme-toggle-container theme-toggle-header">
|
||||||
@ -167,7 +167,7 @@
|
|||||||
<img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/>
|
<img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<span class="sidebar-brand-text">Reticulum Network Stack 0.7.6 beta documentation</span>
|
<span class="sidebar-brand-text">Reticulum Network Stack 0.7.7 beta documentation</span>
|
||||||
|
|
||||||
</a><form class="sidebar-search-container" method="get" action="search.html" role="search">
|
</a><form class="sidebar-search-container" method="get" action="search.html" role="search">
|
||||||
<input class="sidebar-search" placeholder="Search" name="q" aria-label="Search">
|
<input class="sidebar-search" placeholder="Search" name="q" aria-label="Search">
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
<link rel="index" title="Index" href="genindex.html" /><link rel="search" title="Search" href="search.html" /><link rel="next" title="Code Examples" href="examples.html" /><link rel="prev" title="Configuring Interfaces" href="interfaces.html" />
|
<link rel="index" title="Index" href="genindex.html" /><link rel="search" title="Search" href="search.html" /><link rel="next" title="Code Examples" href="examples.html" /><link rel="prev" title="Configuring Interfaces" href="interfaces.html" />
|
||||||
|
|
||||||
<meta name="generator" content="sphinx-5.3.0, furo 2022.09.29.dev1"/>
|
<meta name="generator" content="sphinx-5.3.0, furo 2022.09.29.dev1"/>
|
||||||
<title>Building Networks - Reticulum Network Stack 0.7.6 beta documentation</title>
|
<title>Building Networks - Reticulum Network Stack 0.7.7 beta documentation</title>
|
||||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
|
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
|
||||||
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=189ec851f9bb375a2509b67be1f64f0cf212b702" />
|
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=189ec851f9bb375a2509b67be1f64f0cf212b702" />
|
||||||
<link rel="stylesheet" type="text/css" href="_static/copybutton.css" />
|
<link rel="stylesheet" type="text/css" href="_static/copybutton.css" />
|
||||||
@ -141,7 +141,7 @@
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="header-center">
|
<div class="header-center">
|
||||||
<a href="index.html"><div class="brand">Reticulum Network Stack 0.7.6 beta documentation</div></a>
|
<a href="index.html"><div class="brand">Reticulum Network Stack 0.7.7 beta documentation</div></a>
|
||||||
</div>
|
</div>
|
||||||
<div class="header-right">
|
<div class="header-right">
|
||||||
<div class="theme-toggle-container theme-toggle-header">
|
<div class="theme-toggle-container theme-toggle-header">
|
||||||
@ -167,7 +167,7 @@
|
|||||||
<img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/>
|
<img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<span class="sidebar-brand-text">Reticulum Network Stack 0.7.6 beta documentation</span>
|
<span class="sidebar-brand-text">Reticulum Network Stack 0.7.7 beta documentation</span>
|
||||||
|
|
||||||
</a><form class="sidebar-search-container" method="get" action="search.html" role="search">
|
</a><form class="sidebar-search-container" method="get" action="search.html" role="search">
|
||||||
<input class="sidebar-search" placeholder="Search" name="q" aria-label="Search">
|
<input class="sidebar-search" placeholder="Search" name="q" aria-label="Search">
|
||||||
|
Binary file not shown.
@ -6,7 +6,7 @@
|
|||||||
<link rel="index" title="Index" href="genindex.html" /><link rel="search" title="Search" href="search.html" /><link rel="prev" title="Support Reticulum" href="support.html" />
|
<link rel="index" title="Index" href="genindex.html" /><link rel="search" title="Search" href="search.html" /><link rel="prev" title="Support Reticulum" href="support.html" />
|
||||||
|
|
||||||
<meta name="generator" content="sphinx-5.3.0, furo 2022.09.29.dev1"/>
|
<meta name="generator" content="sphinx-5.3.0, furo 2022.09.29.dev1"/>
|
||||||
<title>API Reference - Reticulum Network Stack 0.7.6 beta documentation</title>
|
<title>API Reference - Reticulum Network Stack 0.7.7 beta documentation</title>
|
||||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
|
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
|
||||||
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=189ec851f9bb375a2509b67be1f64f0cf212b702" />
|
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=189ec851f9bb375a2509b67be1f64f0cf212b702" />
|
||||||
<link rel="stylesheet" type="text/css" href="_static/copybutton.css" />
|
<link rel="stylesheet" type="text/css" href="_static/copybutton.css" />
|
||||||
@ -141,7 +141,7 @@
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="header-center">
|
<div class="header-center">
|
||||||
<a href="index.html"><div class="brand">Reticulum Network Stack 0.7.6 beta documentation</div></a>
|
<a href="index.html"><div class="brand">Reticulum Network Stack 0.7.7 beta documentation</div></a>
|
||||||
</div>
|
</div>
|
||||||
<div class="header-right">
|
<div class="header-right">
|
||||||
<div class="theme-toggle-container theme-toggle-header">
|
<div class="theme-toggle-container theme-toggle-header">
|
||||||
@ -167,7 +167,7 @@
|
|||||||
<img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/>
|
<img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<span class="sidebar-brand-text">Reticulum Network Stack 0.7.6 beta documentation</span>
|
<span class="sidebar-brand-text">Reticulum Network Stack 0.7.7 beta documentation</span>
|
||||||
|
|
||||||
</a><form class="sidebar-search-container" method="get" action="search.html" role="search">
|
</a><form class="sidebar-search-container" method="get" action="search.html" role="search">
|
||||||
<input class="sidebar-search" placeholder="Search" name="q" aria-label="Search">
|
<input class="sidebar-search" placeholder="Search" name="q" aria-label="Search">
|
||||||
@ -356,7 +356,21 @@ for all encrypted communication over Reticulum networks.</p>
|
|||||||
<dl class="py attribute">
|
<dl class="py attribute">
|
||||||
<dt class="sig sig-object py" id="RNS.Identity.KEYSIZE">
|
<dt class="sig sig-object py" id="RNS.Identity.KEYSIZE">
|
||||||
<span class="sig-name descname"><span class="pre">KEYSIZE</span></span><em class="property"><span class="w"> </span><span class="p"><span class="pre">=</span></span><span class="w"> </span><span class="pre">512</span></em><a class="headerlink" href="#RNS.Identity.KEYSIZE" title="Permalink to this definition">#</a></dt>
|
<span class="sig-name descname"><span class="pre">KEYSIZE</span></span><em class="property"><span class="w"> </span><span class="p"><span class="pre">=</span></span><span class="w"> </span><span class="pre">512</span></em><a class="headerlink" href="#RNS.Identity.KEYSIZE" title="Permalink to this definition">#</a></dt>
|
||||||
<dd><p>X25519 key size in bits. A complete key is the concatenation of a 256 bit encryption key, and a 256 bit signing key.</p>
|
<dd><p>X.25519 key size in bits. A complete key is the concatenation of a 256 bit encryption key, and a 256 bit signing key.</p>
|
||||||
|
</dd></dl>
|
||||||
|
|
||||||
|
<dl class="py attribute">
|
||||||
|
<dt class="sig sig-object py" id="RNS.Identity.RATCHETSIZE">
|
||||||
|
<span class="sig-name descname"><span class="pre">RATCHETSIZE</span></span><em class="property"><span class="w"> </span><span class="p"><span class="pre">=</span></span><span class="w"> </span><span class="pre">256</span></em><a class="headerlink" href="#RNS.Identity.RATCHETSIZE" title="Permalink to this definition">#</a></dt>
|
||||||
|
<dd><p>X.25519 ratchet key size in bits.</p>
|
||||||
|
</dd></dl>
|
||||||
|
|
||||||
|
<dl class="py attribute">
|
||||||
|
<dt class="sig sig-object py" id="RNS.Identity.RATCHET_EXPIRY">
|
||||||
|
<span class="sig-name descname"><span class="pre">RATCHET_EXPIRY</span></span><em class="property"><span class="w"> </span><span class="p"><span class="pre">=</span></span><span class="w"> </span><span class="pre">2592000</span></em><a class="headerlink" href="#RNS.Identity.RATCHET_EXPIRY" title="Permalink to this definition">#</a></dt>
|
||||||
|
<dd><p>The expiry time for received ratchets in seconds, defaults to 30 days. Reticulum will always use the most recently
|
||||||
|
announced ratchet, and remember it for up to <code class="docutils literal notranslate"><span class="pre">RATCHET_EXPIRY</span></code> since receiving it, after which it will be discarded.
|
||||||
|
If a newer ratchet is announced in the meantime, it will be replace the already known ratchet.</p>
|
||||||
</dd></dl>
|
</dd></dl>
|
||||||
|
|
||||||
<dl class="py attribute">
|
<dl class="py attribute">
|
||||||
@ -403,7 +417,7 @@ for addressable hashes and other purposes. Non-configurable.</p>
|
|||||||
<dd class="field-odd"><p><strong>data</strong> – Data to be hashed as <em>bytes</em>.</p>
|
<dd class="field-odd"><p><strong>data</strong> – Data to be hashed as <em>bytes</em>.</p>
|
||||||
</dd>
|
</dd>
|
||||||
<dt class="field-even">Returns<span class="colon">:</span></dt>
|
<dt class="field-even">Returns<span class="colon">:</span></dt>
|
||||||
<dd class="field-even"><p>SHA-256 hash as <em>bytes</em></p>
|
<dd class="field-even"><p>SHA-256 hash as <em>bytes</em>.</p>
|
||||||
</dd>
|
</dd>
|
||||||
</dl>
|
</dl>
|
||||||
</dd></dl>
|
</dd></dl>
|
||||||
@ -417,7 +431,7 @@ for addressable hashes and other purposes. Non-configurable.</p>
|
|||||||
<dd class="field-odd"><p><strong>data</strong> – Data to be hashed as <em>bytes</em>.</p>
|
<dd class="field-odd"><p><strong>data</strong> – Data to be hashed as <em>bytes</em>.</p>
|
||||||
</dd>
|
</dd>
|
||||||
<dt class="field-even">Returns<span class="colon">:</span></dt>
|
<dt class="field-even">Returns<span class="colon">:</span></dt>
|
||||||
<dd class="field-even"><p>Truncated SHA-256 hash as <em>bytes</em></p>
|
<dd class="field-even"><p>Truncated SHA-256 hash as <em>bytes</em>.</p>
|
||||||
</dd>
|
</dd>
|
||||||
</dl>
|
</dl>
|
||||||
</dd></dl>
|
</dd></dl>
|
||||||
@ -431,7 +445,21 @@ for addressable hashes and other purposes. Non-configurable.</p>
|
|||||||
<dd class="field-odd"><p><strong>data</strong> – Data to be hashed as <em>bytes</em>.</p>
|
<dd class="field-odd"><p><strong>data</strong> – Data to be hashed as <em>bytes</em>.</p>
|
||||||
</dd>
|
</dd>
|
||||||
<dt class="field-even">Returns<span class="colon">:</span></dt>
|
<dt class="field-even">Returns<span class="colon">:</span></dt>
|
||||||
<dd class="field-even"><p>Truncated SHA-256 hash of random data as <em>bytes</em></p>
|
<dd class="field-even"><p>Truncated SHA-256 hash of random data as <em>bytes</em>.</p>
|
||||||
|
</dd>
|
||||||
|
</dl>
|
||||||
|
</dd></dl>
|
||||||
|
|
||||||
|
<dl class="py method">
|
||||||
|
<dt class="sig sig-object py" id="RNS.Identity.current_ratchet_id">
|
||||||
|
<em class="property"><span class="pre">static</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">current_ratchet_id</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">destination_hash</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#RNS.Identity.current_ratchet_id" title="Permalink to this definition">#</a></dt>
|
||||||
|
<dd><p>Get the ID of the currently used ratchet key for a given destination hash</p>
|
||||||
|
<dl class="field-list simple">
|
||||||
|
<dt class="field-odd">Parameters<span class="colon">:</span></dt>
|
||||||
|
<dd class="field-odd"><p><strong>destination_hash</strong> – A destination hash as <em>bytes</em>.</p>
|
||||||
|
</dd>
|
||||||
|
<dt class="field-even">Returns<span class="colon">:</span></dt>
|
||||||
|
<dd class="field-even"><p>A ratchet ID as <em>bytes</em> or <em>None</em>.</p>
|
||||||
</dd>
|
</dd>
|
||||||
</dl>
|
</dl>
|
||||||
</dd></dl>
|
</dd></dl>
|
||||||
@ -532,7 +560,7 @@ communication for the identity. Be very careful with this method.</p>
|
|||||||
|
|
||||||
<dl class="py method">
|
<dl class="py method">
|
||||||
<dt class="sig sig-object py" id="RNS.Identity.encrypt">
|
<dt class="sig sig-object py" id="RNS.Identity.encrypt">
|
||||||
<span class="sig-name descname"><span class="pre">encrypt</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">plaintext</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#RNS.Identity.encrypt" title="Permalink to this definition">#</a></dt>
|
<span class="sig-name descname"><span class="pre">encrypt</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">plaintext</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">ratchet</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#RNS.Identity.encrypt" title="Permalink to this definition">#</a></dt>
|
||||||
<dd><p>Encrypts information for the identity.</p>
|
<dd><p>Encrypts information for the identity.</p>
|
||||||
<dl class="field-list simple">
|
<dl class="field-list simple">
|
||||||
<dt class="field-odd">Parameters<span class="colon">:</span></dt>
|
<dt class="field-odd">Parameters<span class="colon">:</span></dt>
|
||||||
@ -549,7 +577,7 @@ communication for the identity. Be very careful with this method.</p>
|
|||||||
|
|
||||||
<dl class="py method">
|
<dl class="py method">
|
||||||
<dt class="sig sig-object py" id="RNS.Identity.decrypt">
|
<dt class="sig sig-object py" id="RNS.Identity.decrypt">
|
||||||
<span class="sig-name descname"><span class="pre">decrypt</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">ciphertext_token</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#RNS.Identity.decrypt" title="Permalink to this definition">#</a></dt>
|
<span class="sig-name descname"><span class="pre">decrypt</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">ciphertext_token</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">ratchets</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">enforce_ratchets</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">False</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">ratchet_id_receiver</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#RNS.Identity.decrypt" title="Permalink to this definition">#</a></dt>
|
||||||
<dd><p>Decrypts information for the identity.</p>
|
<dd><p>Decrypts information for the identity.</p>
|
||||||
<dl class="field-list simple">
|
<dl class="field-list simple">
|
||||||
<dt class="field-odd">Parameters<span class="colon">:</span></dt>
|
<dt class="field-odd">Parameters<span class="colon">:</span></dt>
|
||||||
@ -611,7 +639,7 @@ communication for the identity. Be very careful with this method.</p>
|
|||||||
instances are used both to create outgoing and incoming endpoints. The
|
instances are used both to create outgoing and incoming endpoints. The
|
||||||
destination type will decide if encryption, and what type, is used in
|
destination type will decide if encryption, and what type, is used in
|
||||||
communication with the endpoint. A destination can also announce its
|
communication with the endpoint. A destination can also announce its
|
||||||
presence on the network, which will also distribute necessary keys for
|
presence on the network, which will distribute necessary keys for
|
||||||
encrypted communication with it.</p>
|
encrypted communication with it.</p>
|
||||||
<dl class="field-list simple">
|
<dl class="field-list simple">
|
||||||
<dt class="field-odd">Parameters<span class="colon">:</span></dt>
|
<dt class="field-odd">Parameters<span class="colon">:</span></dt>
|
||||||
@ -624,6 +652,18 @@ encrypted communication with it.</p>
|
|||||||
</ul>
|
</ul>
|
||||||
</dd>
|
</dd>
|
||||||
</dl>
|
</dl>
|
||||||
|
<dl class="py attribute">
|
||||||
|
<dt class="sig sig-object py" id="RNS.Destination.RATCHET_COUNT">
|
||||||
|
<span class="sig-name descname"><span class="pre">RATCHET_COUNT</span></span><em class="property"><span class="w"> </span><span class="p"><span class="pre">=</span></span><span class="w"> </span><span class="pre">512</span></em><a class="headerlink" href="#RNS.Destination.RATCHET_COUNT" title="Permalink to this definition">#</a></dt>
|
||||||
|
<dd><p>The default number of generated ratchet keys a destination will retain, if it has ratchets enabled.</p>
|
||||||
|
</dd></dl>
|
||||||
|
|
||||||
|
<dl class="py attribute">
|
||||||
|
<dt class="sig sig-object py" id="RNS.Destination.RATCHET_INTERVAL">
|
||||||
|
<span class="sig-name descname"><span class="pre">RATCHET_INTERVAL</span></span><em class="property"><span class="w"> </span><span class="p"><span class="pre">=</span></span><span class="w"> </span><span class="pre">1800</span></em><a class="headerlink" href="#RNS.Destination.RATCHET_INTERVAL" title="Permalink to this definition">#</a></dt>
|
||||||
|
<dd><p>The minimum interval between rotating ratchet keys, in seconds.</p>
|
||||||
|
</dd></dl>
|
||||||
|
|
||||||
<dl class="py method">
|
<dl class="py method">
|
||||||
<dt class="sig sig-object py" id="RNS.Destination.expand_name">
|
<dt class="sig sig-object py" id="RNS.Destination.expand_name">
|
||||||
<em class="property"><span class="pre">static</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">expand_name</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">identity</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">app_name</span></span></em>, <em class="sig-param"><span class="o"><span class="pre">*</span></span><span class="n"><span class="pre">aspects</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#RNS.Destination.expand_name" title="Permalink to this definition">#</a></dt>
|
<em class="property"><span class="pre">static</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">expand_name</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">identity</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">app_name</span></span></em>, <em class="sig-param"><span class="o"><span class="pre">*</span></span><span class="n"><span class="pre">aspects</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#RNS.Destination.expand_name" title="Permalink to this definition">#</a></dt>
|
||||||
@ -774,6 +814,64 @@ proofs should be returned for received packets.</p>
|
|||||||
</dl>
|
</dl>
|
||||||
</dd></dl>
|
</dd></dl>
|
||||||
|
|
||||||
|
<dl class="py method">
|
||||||
|
<dt class="sig sig-object py" id="RNS.Destination.enable_ratchets">
|
||||||
|
<span class="sig-name descname"><span class="pre">enable_ratchets</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">ratchets_path</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#RNS.Destination.enable_ratchets" title="Permalink to this definition">#</a></dt>
|
||||||
|
<dd><p>Enables ratchets on the destination. When ratchets are enabled, Reticulum will automatically rotate
|
||||||
|
the keys used to encrypt packets to this destination, and include the latest ratchet key in announces.</p>
|
||||||
|
<p>Enabling ratchets on a destination will provide forward secrecy for packets sent to that destination,
|
||||||
|
even when sent outside a <code class="docutils literal notranslate"><span class="pre">Link</span></code>. The normal Reticulum <code class="docutils literal notranslate"><span class="pre">Link</span></code> establishment procedure already performs
|
||||||
|
its own ephemeral key exchange for each link establishment, which means that ratchets are not necessary
|
||||||
|
to provide forward secrecy for links.</p>
|
||||||
|
<p>Enabling ratchets will have a small impact on announce size, adding 32 bytes to every sent announce.</p>
|
||||||
|
<dl class="field-list simple">
|
||||||
|
<dt class="field-odd">Parameters<span class="colon">:</span></dt>
|
||||||
|
<dd class="field-odd"><p><strong>ratchets_path</strong> – The path to a file to store ratchet data in.</p>
|
||||||
|
</dd>
|
||||||
|
<dt class="field-even">Returns<span class="colon">:</span></dt>
|
||||||
|
<dd class="field-even"><p>True if the operation succeeded, otherwise False.</p>
|
||||||
|
</dd>
|
||||||
|
</dl>
|
||||||
|
</dd></dl>
|
||||||
|
|
||||||
|
<dl class="py method">
|
||||||
|
<dt class="sig sig-object py" id="RNS.Destination.enforce_ratchets">
|
||||||
|
<span class="sig-name descname"><span class="pre">enforce_ratchets</span></span><span class="sig-paren">(</span><span class="sig-paren">)</span><a class="headerlink" href="#RNS.Destination.enforce_ratchets" title="Permalink to this definition">#</a></dt>
|
||||||
|
<dd><p>When ratchet enforcement is enabled, this destination will never accept packets that use its
|
||||||
|
base Identity key for encryption, but only accept packets encrypted with one of the retained
|
||||||
|
ratchet keys.</p>
|
||||||
|
</dd></dl>
|
||||||
|
|
||||||
|
<dl class="py method">
|
||||||
|
<dt class="sig sig-object py" id="RNS.Destination.set_retained_ratchets">
|
||||||
|
<span class="sig-name descname"><span class="pre">set_retained_ratchets</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">retained_ratchets</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#RNS.Destination.set_retained_ratchets" title="Permalink to this definition">#</a></dt>
|
||||||
|
<dd><p>Sets the number of previously generated ratchet keys this destination will retain,
|
||||||
|
and try to use when decrypting incoming packets. Defaults to <code class="docutils literal notranslate"><span class="pre">Destination.RATCHET_COUNT</span></code>.</p>
|
||||||
|
<dl class="field-list simple">
|
||||||
|
<dt class="field-odd">Parameters<span class="colon">:</span></dt>
|
||||||
|
<dd class="field-odd"><p><strong>retained_ratchets</strong> – The number of generated ratchets to retain.</p>
|
||||||
|
</dd>
|
||||||
|
<dt class="field-even">Returns<span class="colon">:</span></dt>
|
||||||
|
<dd class="field-even"><p>True if the operation succeeded, False if not.</p>
|
||||||
|
</dd>
|
||||||
|
</dl>
|
||||||
|
</dd></dl>
|
||||||
|
|
||||||
|
<dl class="py method">
|
||||||
|
<dt class="sig sig-object py" id="RNS.Destination.set_ratchet_interval">
|
||||||
|
<span class="sig-name descname"><span class="pre">set_ratchet_interval</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">interval</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#RNS.Destination.set_ratchet_interval" title="Permalink to this definition">#</a></dt>
|
||||||
|
<dd><p>Sets the minimum interval in seconds between ratchet key rotation.
|
||||||
|
Defaults to <code class="docutils literal notranslate"><span class="pre">Destination.RATCHET_INTERVAL</span></code>.</p>
|
||||||
|
<dl class="field-list simple">
|
||||||
|
<dt class="field-odd">Parameters<span class="colon">:</span></dt>
|
||||||
|
<dd class="field-odd"><p><strong>interval</strong> – The minimum interval in seconds.</p>
|
||||||
|
</dd>
|
||||||
|
<dt class="field-even">Returns<span class="colon">:</span></dt>
|
||||||
|
<dd class="field-even"><p>True if the operation succeeded, False if not.</p>
|
||||||
|
</dd>
|
||||||
|
</dl>
|
||||||
|
</dd></dl>
|
||||||
|
|
||||||
<dl class="py method">
|
<dl class="py method">
|
||||||
<dt class="sig sig-object py" id="RNS.Destination.create_keys">
|
<dt class="sig sig-object py" id="RNS.Destination.create_keys">
|
||||||
<span class="sig-name descname"><span class="pre">create_keys</span></span><span class="sig-paren">(</span><span class="sig-paren">)</span><a class="headerlink" href="#RNS.Destination.create_keys" title="Permalink to this definition">#</a></dt>
|
<span class="sig-name descname"><span class="pre">create_keys</span></span><span class="sig-paren">(</span><span class="sig-paren">)</span><a class="headerlink" href="#RNS.Destination.create_keys" title="Permalink to this definition">#</a></dt>
|
||||||
@ -1814,7 +1912,9 @@ Transport system of Reticulum.</p>
|
|||||||
<dd><p>Registers an announce handler.</p>
|
<dd><p>Registers an announce handler.</p>
|
||||||
<dl class="field-list simple">
|
<dl class="field-list simple">
|
||||||
<dt class="field-odd">Parameters<span class="colon">:</span></dt>
|
<dt class="field-odd">Parameters<span class="colon">:</span></dt>
|
||||||
<dd class="field-odd"><p><strong>handler</strong> – Must be an object with an <em>aspect_filter</em> attribute and a <em>received_announce(destination_hash, announced_identity, app_data)</em> callable. See the <a class="reference internal" href="examples.html#example-announce"><span class="std std-ref">Announce Example</span></a> for more info.</p>
|
<dd class="field-odd"><p><strong>handler</strong> – Must be an object with an <em>aspect_filter</em> attribute and a <em>received_announce(destination_hash, announced_identity, app_data)</em>
|
||||||
|
callable. Can optionally have a <em>receive_path_responses</em> attribute set to <code class="docutils literal notranslate"><span class="pre">True</span></code>, to also receive all path responses, in addition to live
|
||||||
|
announces. See the <a class="reference internal" href="examples.html#example-announce"><span class="std std-ref">Announce Example</span></a> for more info.</p>
|
||||||
</dd>
|
</dd>
|
||||||
</dl>
|
</dl>
|
||||||
</dd></dl>
|
</dd></dl>
|
||||||
@ -1964,12 +2064,15 @@ will announce it.</p>
|
|||||||
<li><a class="reference internal" href="#RNS.Identity"><code class="docutils literal notranslate"><span class="pre">Identity</span></code></a><ul>
|
<li><a class="reference internal" href="#RNS.Identity"><code class="docutils literal notranslate"><span class="pre">Identity</span></code></a><ul>
|
||||||
<li><a class="reference internal" href="#RNS.Identity.CURVE"><code class="docutils literal notranslate"><span class="pre">CURVE</span></code></a></li>
|
<li><a class="reference internal" href="#RNS.Identity.CURVE"><code class="docutils literal notranslate"><span class="pre">CURVE</span></code></a></li>
|
||||||
<li><a class="reference internal" href="#RNS.Identity.KEYSIZE"><code class="docutils literal notranslate"><span class="pre">KEYSIZE</span></code></a></li>
|
<li><a class="reference internal" href="#RNS.Identity.KEYSIZE"><code class="docutils literal notranslate"><span class="pre">KEYSIZE</span></code></a></li>
|
||||||
|
<li><a class="reference internal" href="#RNS.Identity.RATCHETSIZE"><code class="docutils literal notranslate"><span class="pre">RATCHETSIZE</span></code></a></li>
|
||||||
|
<li><a class="reference internal" href="#RNS.Identity.RATCHET_EXPIRY"><code class="docutils literal notranslate"><span class="pre">RATCHET_EXPIRY</span></code></a></li>
|
||||||
<li><a class="reference internal" href="#RNS.Identity.TRUNCATED_HASHLENGTH"><code class="docutils literal notranslate"><span class="pre">TRUNCATED_HASHLENGTH</span></code></a></li>
|
<li><a class="reference internal" href="#RNS.Identity.TRUNCATED_HASHLENGTH"><code class="docutils literal notranslate"><span class="pre">TRUNCATED_HASHLENGTH</span></code></a></li>
|
||||||
<li><a class="reference internal" href="#RNS.Identity.recall"><code class="docutils literal notranslate"><span class="pre">recall()</span></code></a></li>
|
<li><a class="reference internal" href="#RNS.Identity.recall"><code class="docutils literal notranslate"><span class="pre">recall()</span></code></a></li>
|
||||||
<li><a class="reference internal" href="#RNS.Identity.recall_app_data"><code class="docutils literal notranslate"><span class="pre">recall_app_data()</span></code></a></li>
|
<li><a class="reference internal" href="#RNS.Identity.recall_app_data"><code class="docutils literal notranslate"><span class="pre">recall_app_data()</span></code></a></li>
|
||||||
<li><a class="reference internal" href="#RNS.Identity.full_hash"><code class="docutils literal notranslate"><span class="pre">full_hash()</span></code></a></li>
|
<li><a class="reference internal" href="#RNS.Identity.full_hash"><code class="docutils literal notranslate"><span class="pre">full_hash()</span></code></a></li>
|
||||||
<li><a class="reference internal" href="#RNS.Identity.truncated_hash"><code class="docutils literal notranslate"><span class="pre">truncated_hash()</span></code></a></li>
|
<li><a class="reference internal" href="#RNS.Identity.truncated_hash"><code class="docutils literal notranslate"><span class="pre">truncated_hash()</span></code></a></li>
|
||||||
<li><a class="reference internal" href="#RNS.Identity.get_random_hash"><code class="docutils literal notranslate"><span class="pre">get_random_hash()</span></code></a></li>
|
<li><a class="reference internal" href="#RNS.Identity.get_random_hash"><code class="docutils literal notranslate"><span class="pre">get_random_hash()</span></code></a></li>
|
||||||
|
<li><a class="reference internal" href="#RNS.Identity.current_ratchet_id"><code class="docutils literal notranslate"><span class="pre">current_ratchet_id()</span></code></a></li>
|
||||||
<li><a class="reference internal" href="#RNS.Identity.from_bytes"><code class="docutils literal notranslate"><span class="pre">from_bytes()</span></code></a></li>
|
<li><a class="reference internal" href="#RNS.Identity.from_bytes"><code class="docutils literal notranslate"><span class="pre">from_bytes()</span></code></a></li>
|
||||||
<li><a class="reference internal" href="#RNS.Identity.from_file"><code class="docutils literal notranslate"><span class="pre">from_file()</span></code></a></li>
|
<li><a class="reference internal" href="#RNS.Identity.from_file"><code class="docutils literal notranslate"><span class="pre">from_file()</span></code></a></li>
|
||||||
<li><a class="reference internal" href="#RNS.Identity.to_file"><code class="docutils literal notranslate"><span class="pre">to_file()</span></code></a></li>
|
<li><a class="reference internal" href="#RNS.Identity.to_file"><code class="docutils literal notranslate"><span class="pre">to_file()</span></code></a></li>
|
||||||
@ -1984,6 +2087,8 @@ will announce it.</p>
|
|||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
<li><a class="reference internal" href="#RNS.Destination"><code class="docutils literal notranslate"><span class="pre">Destination</span></code></a><ul>
|
<li><a class="reference internal" href="#RNS.Destination"><code class="docutils literal notranslate"><span class="pre">Destination</span></code></a><ul>
|
||||||
|
<li><a class="reference internal" href="#RNS.Destination.RATCHET_COUNT"><code class="docutils literal notranslate"><span class="pre">RATCHET_COUNT</span></code></a></li>
|
||||||
|
<li><a class="reference internal" href="#RNS.Destination.RATCHET_INTERVAL"><code class="docutils literal notranslate"><span class="pre">RATCHET_INTERVAL</span></code></a></li>
|
||||||
<li><a class="reference internal" href="#RNS.Destination.expand_name"><code class="docutils literal notranslate"><span class="pre">expand_name()</span></code></a></li>
|
<li><a class="reference internal" href="#RNS.Destination.expand_name"><code class="docutils literal notranslate"><span class="pre">expand_name()</span></code></a></li>
|
||||||
<li><a class="reference internal" href="#RNS.Destination.app_and_aspects_from_name"><code class="docutils literal notranslate"><span class="pre">app_and_aspects_from_name()</span></code></a></li>
|
<li><a class="reference internal" href="#RNS.Destination.app_and_aspects_from_name"><code class="docutils literal notranslate"><span class="pre">app_and_aspects_from_name()</span></code></a></li>
|
||||||
<li><a class="reference internal" href="#RNS.Destination.hash_from_name_and_identity"><code class="docutils literal notranslate"><span class="pre">hash_from_name_and_identity()</span></code></a></li>
|
<li><a class="reference internal" href="#RNS.Destination.hash_from_name_and_identity"><code class="docutils literal notranslate"><span class="pre">hash_from_name_and_identity()</span></code></a></li>
|
||||||
@ -1996,6 +2101,10 @@ will announce it.</p>
|
|||||||
<li><a class="reference internal" href="#RNS.Destination.set_proof_strategy"><code class="docutils literal notranslate"><span class="pre">set_proof_strategy()</span></code></a></li>
|
<li><a class="reference internal" href="#RNS.Destination.set_proof_strategy"><code class="docutils literal notranslate"><span class="pre">set_proof_strategy()</span></code></a></li>
|
||||||
<li><a class="reference internal" href="#RNS.Destination.register_request_handler"><code class="docutils literal notranslate"><span class="pre">register_request_handler()</span></code></a></li>
|
<li><a class="reference internal" href="#RNS.Destination.register_request_handler"><code class="docutils literal notranslate"><span class="pre">register_request_handler()</span></code></a></li>
|
||||||
<li><a class="reference internal" href="#RNS.Destination.deregister_request_handler"><code class="docutils literal notranslate"><span class="pre">deregister_request_handler()</span></code></a></li>
|
<li><a class="reference internal" href="#RNS.Destination.deregister_request_handler"><code class="docutils literal notranslate"><span class="pre">deregister_request_handler()</span></code></a></li>
|
||||||
|
<li><a class="reference internal" href="#RNS.Destination.enable_ratchets"><code class="docutils literal notranslate"><span class="pre">enable_ratchets()</span></code></a></li>
|
||||||
|
<li><a class="reference internal" href="#RNS.Destination.enforce_ratchets"><code class="docutils literal notranslate"><span class="pre">enforce_ratchets()</span></code></a></li>
|
||||||
|
<li><a class="reference internal" href="#RNS.Destination.set_retained_ratchets"><code class="docutils literal notranslate"><span class="pre">set_retained_ratchets()</span></code></a></li>
|
||||||
|
<li><a class="reference internal" href="#RNS.Destination.set_ratchet_interval"><code class="docutils literal notranslate"><span class="pre">set_ratchet_interval()</span></code></a></li>
|
||||||
<li><a class="reference internal" href="#RNS.Destination.create_keys"><code class="docutils literal notranslate"><span class="pre">create_keys()</span></code></a></li>
|
<li><a class="reference internal" href="#RNS.Destination.create_keys"><code class="docutils literal notranslate"><span class="pre">create_keys()</span></code></a></li>
|
||||||
<li><a class="reference internal" href="#RNS.Destination.get_private_key"><code class="docutils literal notranslate"><span class="pre">get_private_key()</span></code></a></li>
|
<li><a class="reference internal" href="#RNS.Destination.get_private_key"><code class="docutils literal notranslate"><span class="pre">get_private_key()</span></code></a></li>
|
||||||
<li><a class="reference internal" href="#RNS.Destination.load_private_key"><code class="docutils literal notranslate"><span class="pre">load_private_key()</span></code></a></li>
|
<li><a class="reference internal" href="#RNS.Destination.load_private_key"><code class="docutils literal notranslate"><span class="pre">load_private_key()</span></code></a></li>
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
<meta name="viewport" content="width=device-width,initial-scale=1"/>
|
<meta name="viewport" content="width=device-width,initial-scale=1"/>
|
||||||
<meta name="color-scheme" content="light dark"><link rel="index" title="Index" href="genindex.html" /><link rel="search" title="Search" href="#" />
|
<meta name="color-scheme" content="light dark"><link rel="index" title="Index" href="genindex.html" /><link rel="search" title="Search" href="#" />
|
||||||
|
|
||||||
<meta name="generator" content="sphinx-5.3.0, furo 2022.09.29.dev1"/><title>Search - Reticulum Network Stack 0.7.6 beta documentation</title><link rel="stylesheet" type="text/css" href="_static/pygments.css" />
|
<meta name="generator" content="sphinx-5.3.0, furo 2022.09.29.dev1"/><title>Search - Reticulum Network Stack 0.7.7 beta documentation</title><link rel="stylesheet" type="text/css" href="_static/pygments.css" />
|
||||||
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=189ec851f9bb375a2509b67be1f64f0cf212b702" />
|
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=189ec851f9bb375a2509b67be1f64f0cf212b702" />
|
||||||
<link rel="stylesheet" type="text/css" href="_static/copybutton.css" />
|
<link rel="stylesheet" type="text/css" href="_static/copybutton.css" />
|
||||||
<link rel="stylesheet" type="text/css" href="_static/styles/furo-extensions.css?digest=30d1aed668e5c3a91c3e3bf6a60b675221979f0e" />
|
<link rel="stylesheet" type="text/css" href="_static/styles/furo-extensions.css?digest=30d1aed668e5c3a91c3e3bf6a60b675221979f0e" />
|
||||||
@ -138,7 +138,7 @@
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="header-center">
|
<div class="header-center">
|
||||||
<a href="index.html"><div class="brand">Reticulum Network Stack 0.7.6 beta documentation</div></a>
|
<a href="index.html"><div class="brand">Reticulum Network Stack 0.7.7 beta documentation</div></a>
|
||||||
</div>
|
</div>
|
||||||
<div class="header-right">
|
<div class="header-right">
|
||||||
<div class="theme-toggle-container theme-toggle-header">
|
<div class="theme-toggle-container theme-toggle-header">
|
||||||
@ -164,7 +164,7 @@
|
|||||||
<img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/>
|
<img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<span class="sidebar-brand-text">Reticulum Network Stack 0.7.6 beta documentation</span>
|
<span class="sidebar-brand-text">Reticulum Network Stack 0.7.7 beta documentation</span>
|
||||||
|
|
||||||
</a><form class="sidebar-search-container" method="get" action="#" role="search">
|
</a><form class="sidebar-search-container" method="get" action="#" role="search">
|
||||||
<input class="sidebar-search" placeholder="Search" name="q" aria-label="Search">
|
<input class="sidebar-search" placeholder="Search" name="q" aria-label="Search">
|
||||||
|
File diff suppressed because one or more lines are too long
@ -6,7 +6,7 @@
|
|||||||
<link rel="index" title="Index" href="genindex.html" /><link rel="search" title="Search" href="search.html" /><link rel="next" title="API Reference" href="reference.html" /><link rel="prev" title="Code Examples" href="examples.html" />
|
<link rel="index" title="Index" href="genindex.html" /><link rel="search" title="Search" href="search.html" /><link rel="next" title="API Reference" href="reference.html" /><link rel="prev" title="Code Examples" href="examples.html" />
|
||||||
|
|
||||||
<meta name="generator" content="sphinx-5.3.0, furo 2022.09.29.dev1"/>
|
<meta name="generator" content="sphinx-5.3.0, furo 2022.09.29.dev1"/>
|
||||||
<title>Support Reticulum - Reticulum Network Stack 0.7.6 beta documentation</title>
|
<title>Support Reticulum - Reticulum Network Stack 0.7.7 beta documentation</title>
|
||||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
|
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
|
||||||
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=189ec851f9bb375a2509b67be1f64f0cf212b702" />
|
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=189ec851f9bb375a2509b67be1f64f0cf212b702" />
|
||||||
<link rel="stylesheet" type="text/css" href="_static/copybutton.css" />
|
<link rel="stylesheet" type="text/css" href="_static/copybutton.css" />
|
||||||
@ -141,7 +141,7 @@
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="header-center">
|
<div class="header-center">
|
||||||
<a href="index.html"><div class="brand">Reticulum Network Stack 0.7.6 beta documentation</div></a>
|
<a href="index.html"><div class="brand">Reticulum Network Stack 0.7.7 beta documentation</div></a>
|
||||||
</div>
|
</div>
|
||||||
<div class="header-right">
|
<div class="header-right">
|
||||||
<div class="theme-toggle-container theme-toggle-header">
|
<div class="theme-toggle-container theme-toggle-header">
|
||||||
@ -167,7 +167,7 @@
|
|||||||
<img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/>
|
<img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<span class="sidebar-brand-text">Reticulum Network Stack 0.7.6 beta documentation</span>
|
<span class="sidebar-brand-text">Reticulum Network Stack 0.7.7 beta documentation</span>
|
||||||
|
|
||||||
</a><form class="sidebar-search-container" method="get" action="search.html" role="search">
|
</a><form class="sidebar-search-container" method="get" action="search.html" role="search">
|
||||||
<input class="sidebar-search" placeholder="Search" name="q" aria-label="Search">
|
<input class="sidebar-search" placeholder="Search" name="q" aria-label="Search">
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
<link rel="index" title="Index" href="genindex.html" /><link rel="search" title="Search" href="search.html" /><link rel="next" title="Communications Hardware" href="hardware.html" /><link rel="prev" title="Using Reticulum on Your System" href="using.html" />
|
<link rel="index" title="Index" href="genindex.html" /><link rel="search" title="Search" href="search.html" /><link rel="next" title="Communications Hardware" href="hardware.html" /><link rel="prev" title="Using Reticulum on Your System" href="using.html" />
|
||||||
|
|
||||||
<meta name="generator" content="sphinx-5.3.0, furo 2022.09.29.dev1"/>
|
<meta name="generator" content="sphinx-5.3.0, furo 2022.09.29.dev1"/>
|
||||||
<title>Understanding Reticulum - Reticulum Network Stack 0.7.6 beta documentation</title>
|
<title>Understanding Reticulum - Reticulum Network Stack 0.7.7 beta documentation</title>
|
||||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
|
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
|
||||||
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=189ec851f9bb375a2509b67be1f64f0cf212b702" />
|
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=189ec851f9bb375a2509b67be1f64f0cf212b702" />
|
||||||
<link rel="stylesheet" type="text/css" href="_static/copybutton.css" />
|
<link rel="stylesheet" type="text/css" href="_static/copybutton.css" />
|
||||||
@ -141,7 +141,7 @@
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="header-center">
|
<div class="header-center">
|
||||||
<a href="index.html"><div class="brand">Reticulum Network Stack 0.7.6 beta documentation</div></a>
|
<a href="index.html"><div class="brand">Reticulum Network Stack 0.7.7 beta documentation</div></a>
|
||||||
</div>
|
</div>
|
||||||
<div class="header-right">
|
<div class="header-right">
|
||||||
<div class="theme-toggle-container theme-toggle-header">
|
<div class="theme-toggle-container theme-toggle-header">
|
||||||
@ -167,7 +167,7 @@
|
|||||||
<img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/>
|
<img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<span class="sidebar-brand-text">Reticulum Network Stack 0.7.6 beta documentation</span>
|
<span class="sidebar-brand-text">Reticulum Network Stack 0.7.7 beta documentation</span>
|
||||||
|
|
||||||
</a><form class="sidebar-search-container" method="get" action="search.html" role="search">
|
</a><form class="sidebar-search-container" method="get" action="search.html" role="search">
|
||||||
<input class="sidebar-search" placeholder="Search" name="q" aria-label="Search">
|
<input class="sidebar-search" placeholder="Search" name="q" aria-label="Search">
|
||||||
@ -360,10 +360,11 @@ be sufficient, even far into the future.</p>
|
|||||||
<p>By default Reticulum encrypts all data using elliptic curve cryptography and AES. Any packet sent to a
|
<p>By default Reticulum encrypts all data using elliptic curve cryptography and AES. Any packet sent to a
|
||||||
destination is encrypted with a per-packet derived key. Reticulum can also set up an encrypted
|
destination is encrypted with a per-packet derived key. Reticulum can also set up an encrypted
|
||||||
channel to a destination, called a <em>Link</em>. Both data sent over Links and single packets offer
|
channel to a destination, called a <em>Link</em>. Both data sent over Links and single packets offer
|
||||||
<em>Initiator Anonymity</em>, and links additionally offer <em>Forward Secrecy</em> by using an Elliptic Curve
|
<em>Initiator Anonymity</em>. Links additionally offer <em>Forward Secrecy</em> by default, employing an Elliptic Curve
|
||||||
Diffie Hellman key exchange on Curve25519 to derive per-link ephemeral keys. The multi-hop transport,
|
Diffie Hellman key exchange on Curve25519 to derive per-link ephemeral keys. Asymmetric, link-less
|
||||||
coordination, verification and reliability layers are fully autonomous and also based on elliptic
|
packet communication can also provide forward secrecy, with automatic key ratcheting, by enabling
|
||||||
curve cryptography.</p>
|
ratchets on a per-destination basis. The multi-hop transport, coordination, verification and reliability
|
||||||
|
layers are fully autonomous and also based on elliptic curve cryptography.</p>
|
||||||
<p>Reticulum also offers symmetric key encryption for group-oriented communications, as well as
|
<p>Reticulum also offers symmetric key encryption for group-oriented communications, as well as
|
||||||
unencrypted packets for local broadcast purposes.</p>
|
unencrypted packets for local broadcast purposes.</p>
|
||||||
<p>Reticulum can connect to a variety of interfaces such as radio modems, data radios and serial ports,
|
<p>Reticulum can connect to a variety of interfaces such as radio modems, data radios and serial ports,
|
||||||
@ -639,7 +640,7 @@ expect. Reticulum offers two ways to do this.</p>
|
|||||||
<li><div class="line-block">
|
<li><div class="line-block">
|
||||||
<div class="line">A packet is always created with an associated destination and some payload data. When the packet is sent
|
<div class="line">A packet is always created with an associated destination and some payload data. When the packet is sent
|
||||||
to a <em>single</em> destination type, Reticulum will automatically create an ephemeral encryption key, perform
|
to a <em>single</em> destination type, Reticulum will automatically create an ephemeral encryption key, perform
|
||||||
an ECDH key exchange with the destination’s public key, and encrypt the information.</div>
|
an ECDH key exchange with the destination’s public key (or ratchet key, if available), and encrypt the information.</div>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
<li><div class="line-block">
|
<li><div class="line-block">
|
||||||
@ -927,7 +928,8 @@ A Reticulum packet is composed of the following fields:
|
|||||||
[HEADER 2 bytes] [ADDRESSES 16/32 bytes] [CONTEXT 1 byte] [DATA 0-465 bytes]
|
[HEADER 2 bytes] [ADDRESSES 16/32 bytes] [CONTEXT 1 byte] [DATA 0-465 bytes]
|
||||||
|
|
||||||
* The HEADER field is 2 bytes long.
|
* The HEADER field is 2 bytes long.
|
||||||
* Byte 1: [IFAC Flag], [Header Type], [Propagation Type], [Destination Type] and [Packet Type]
|
* Byte 1: [IFAC Flag], [Header Type], [Context Flag], [Propagation Type],
|
||||||
|
[Destination Type] and [Packet Type]
|
||||||
* Byte 2: Number of hops
|
* Byte 2: Number of hops
|
||||||
|
|
||||||
* Interface Access Code field if the IFAC flag was set.
|
* Interface Access Code field if the IFAC flag was set.
|
||||||
@ -959,12 +961,16 @@ type 1 0 Two byte header, one 16 byte address field
|
|||||||
type 2 1 Two byte header, two 16 byte address fields
|
type 2 1 Two byte header, two 16 byte address fields
|
||||||
|
|
||||||
|
|
||||||
|
Context Flag
|
||||||
|
-----------------
|
||||||
|
unset 0 The context flag is used for various types
|
||||||
|
set 1 of signalling, depending on packet context
|
||||||
|
|
||||||
|
|
||||||
Propagation Types
|
Propagation Types
|
||||||
-----------------
|
-----------------
|
||||||
broadcast 00
|
broadcast 0
|
||||||
transport 01
|
transport 1
|
||||||
reserved 10
|
|
||||||
reserved 11
|
|
||||||
|
|
||||||
|
|
||||||
Destination Types
|
Destination Types
|
||||||
@ -1063,10 +1069,11 @@ both on general-purpose CPUs and on microcontrollers. The necessary primitives a
|
|||||||
<li><p>Ed25519 for signatures</p></li>
|
<li><p>Ed25519 for signatures</p></li>
|
||||||
<li><p>X25519 for ECDH key exchanges</p></li>
|
<li><p>X25519 for ECDH key exchanges</p></li>
|
||||||
<li><p>HKDF for key derivation</p></li>
|
<li><p>HKDF for key derivation</p></li>
|
||||||
<li><p>Fernet for encrypted tokens</p>
|
<li><p>Modified Fernet for encrypted tokens</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li><p>AES-128 in CBC mode</p></li>
|
<li><p>AES-128 in CBC mode</p></li>
|
||||||
<li><p>HMAC for message authentication</p></li>
|
<li><p>HMAC for message authentication</p></li>
|
||||||
|
<li><p>No Version and Timestamp metadata included</p></li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
<li><p>SHA-256</p></li>
|
<li><p>SHA-256</p></li>
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
<link rel="index" title="Index" href="genindex.html" /><link rel="search" title="Search" href="search.html" /><link rel="next" title="Understanding Reticulum" href="understanding.html" /><link rel="prev" title="Getting Started Fast" href="gettingstartedfast.html" />
|
<link rel="index" title="Index" href="genindex.html" /><link rel="search" title="Search" href="search.html" /><link rel="next" title="Understanding Reticulum" href="understanding.html" /><link rel="prev" title="Getting Started Fast" href="gettingstartedfast.html" />
|
||||||
|
|
||||||
<meta name="generator" content="sphinx-5.3.0, furo 2022.09.29.dev1"/>
|
<meta name="generator" content="sphinx-5.3.0, furo 2022.09.29.dev1"/>
|
||||||
<title>Using Reticulum on Your System - Reticulum Network Stack 0.7.6 beta documentation</title>
|
<title>Using Reticulum on Your System - Reticulum Network Stack 0.7.7 beta documentation</title>
|
||||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
|
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
|
||||||
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=189ec851f9bb375a2509b67be1f64f0cf212b702" />
|
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=189ec851f9bb375a2509b67be1f64f0cf212b702" />
|
||||||
<link rel="stylesheet" type="text/css" href="_static/copybutton.css" />
|
<link rel="stylesheet" type="text/css" href="_static/copybutton.css" />
|
||||||
@ -141,7 +141,7 @@
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="header-center">
|
<div class="header-center">
|
||||||
<a href="index.html"><div class="brand">Reticulum Network Stack 0.7.6 beta documentation</div></a>
|
<a href="index.html"><div class="brand">Reticulum Network Stack 0.7.7 beta documentation</div></a>
|
||||||
</div>
|
</div>
|
||||||
<div class="header-right">
|
<div class="header-right">
|
||||||
<div class="theme-toggle-container theme-toggle-header">
|
<div class="theme-toggle-container theme-toggle-header">
|
||||||
@ -167,7 +167,7 @@
|
|||||||
<img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/>
|
<img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<span class="sidebar-brand-text">Reticulum Network Stack 0.7.6 beta documentation</span>
|
<span class="sidebar-brand-text">Reticulum Network Stack 0.7.7 beta documentation</span>
|
||||||
|
|
||||||
</a><form class="sidebar-search-container" method="get" action="search.html" role="search">
|
</a><form class="sidebar-search-container" method="get" action="search.html" role="search">
|
||||||
<input class="sidebar-search" placeholder="Search" name="q" aria-label="Search">
|
<input class="sidebar-search" placeholder="Search" name="q" aria-label="Search">
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
<link rel="index" title="Index" href="genindex.html" /><link rel="search" title="Search" href="search.html" /><link rel="next" title="Getting Started Fast" href="gettingstartedfast.html" /><link rel="prev" title="Reticulum Network Stack Manual" href="index.html" />
|
<link rel="index" title="Index" href="genindex.html" /><link rel="search" title="Search" href="search.html" /><link rel="next" title="Getting Started Fast" href="gettingstartedfast.html" /><link rel="prev" title="Reticulum Network Stack Manual" href="index.html" />
|
||||||
|
|
||||||
<meta name="generator" content="sphinx-5.3.0, furo 2022.09.29.dev1"/>
|
<meta name="generator" content="sphinx-5.3.0, furo 2022.09.29.dev1"/>
|
||||||
<title>What is Reticulum? - Reticulum Network Stack 0.7.6 beta documentation</title>
|
<title>What is Reticulum? - Reticulum Network Stack 0.7.7 beta documentation</title>
|
||||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
|
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
|
||||||
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=189ec851f9bb375a2509b67be1f64f0cf212b702" />
|
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=189ec851f9bb375a2509b67be1f64f0cf212b702" />
|
||||||
<link rel="stylesheet" type="text/css" href="_static/copybutton.css" />
|
<link rel="stylesheet" type="text/css" href="_static/copybutton.css" />
|
||||||
@ -141,7 +141,7 @@
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="header-center">
|
<div class="header-center">
|
||||||
<a href="index.html"><div class="brand">Reticulum Network Stack 0.7.6 beta documentation</div></a>
|
<a href="index.html"><div class="brand">Reticulum Network Stack 0.7.7 beta documentation</div></a>
|
||||||
</div>
|
</div>
|
||||||
<div class="header-right">
|
<div class="header-right">
|
||||||
<div class="theme-toggle-container theme-toggle-header">
|
<div class="theme-toggle-container theme-toggle-header">
|
||||||
@ -167,7 +167,7 @@
|
|||||||
<img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/>
|
<img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<span class="sidebar-brand-text">Reticulum Network Stack 0.7.6 beta documentation</span>
|
<span class="sidebar-brand-text">Reticulum Network Stack 0.7.7 beta documentation</span>
|
||||||
|
|
||||||
</a><form class="sidebar-search-container" method="get" action="search.html" role="search">
|
</a><form class="sidebar-search-container" method="get" action="search.html" role="search">
|
||||||
<input class="sidebar-search" placeholder="Search" name="q" aria-label="Search">
|
<input class="sidebar-search" placeholder="Search" name="q" aria-label="Search">
|
||||||
@ -262,12 +262,13 @@ considered complete and stable at the moment, but could change if absolutely war
|
|||||||
<li><p>Complete initiator anonymity, communicate without revealing your identity</p></li>
|
<li><p>Complete initiator anonymity, communicate without revealing your identity</p></li>
|
||||||
<li><p>Asymmetric encryption based on X25519, and Ed25519 signatures as a basis for all communication</p></li>
|
<li><p>Asymmetric encryption based on X25519, and Ed25519 signatures as a basis for all communication</p></li>
|
||||||
<li><p>Forward Secrecy by using ephemeral Elliptic Curve Diffie-Hellman keys on Curve25519</p></li>
|
<li><p>Forward Secrecy by using ephemeral Elliptic Curve Diffie-Hellman keys on Curve25519</p></li>
|
||||||
<li><p>Reticulum uses the <a class="reference external" href="https://github.com/fernet/spec/blob/master/Spec.md">Fernet</a> specification for on-the-wire / over-the-air encryption</p>
|
<li><p>Reticulum uses a modified version of the <a class="reference external" href="https://github.com/fernet/spec/blob/master/Spec.md">Fernet</a> specification for on-the-wire / over-the-air encryption</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li><p>All keys are ephemeral and derived from an ECDH key exchange on Curve25519</p></li>
|
<li><p>Keys are ephemeral and derived from an ECDH key exchange on Curve25519</p></li>
|
||||||
<li><p>AES-128 in CBC mode with PKCS7 padding</p></li>
|
<li><p>AES-128 in CBC mode with PKCS7 padding</p></li>
|
||||||
<li><p>HMAC using SHA256 for authentication</p></li>
|
<li><p>HMAC using SHA256 for authentication</p></li>
|
||||||
<li><p>IVs are generated through os.urandom()</p></li>
|
<li><p>IVs are generated through os.urandom()</p></li>
|
||||||
|
<li><p>No Version and Timestamp metadata included</p></li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
<li><p>Unforgeable packet delivery confirmations</p></li>
|
<li><p>Unforgeable packet delivery confirmations</p></li>
|
||||||
@ -300,7 +301,8 @@ of the types of interfaces Reticulum was designed for.</p>
|
|||||||
<p>An open-source LoRa-based interface called <a class="reference external" href="https://unsigned.io/rnode">RNode</a>
|
<p>An open-source LoRa-based interface called <a class="reference external" href="https://unsigned.io/rnode">RNode</a>
|
||||||
has been designed as an example transceiver that is very suitable for
|
has been designed as an example transceiver that is very suitable for
|
||||||
Reticulum. It is possible to build it yourself, to transform a common LoRa
|
Reticulum. It is possible to build it yourself, to transform a common LoRa
|
||||||
development board into one, or it can be purchased as a complete transceiver.</p>
|
development board into one, or it can be purchased as a complete transceiver
|
||||||
|
from various vendors.</p>
|
||||||
<p>Reticulum can also be encapsulated over existing IP networks, so there’s
|
<p>Reticulum can also be encapsulated over existing IP networks, so there’s
|
||||||
nothing stopping you from using it over wired Ethernet or your local WiFi
|
nothing stopping you from using it over wired Ethernet or your local WiFi
|
||||||
network, where it’ll work just as well. In fact, one of the strengths of
|
network, where it’ll work just as well. In fact, one of the strengths of
|
||||||
|
@ -134,10 +134,11 @@ be sufficient, even far into the future.
|
|||||||
By default Reticulum encrypts all data using elliptic curve cryptography and AES. Any packet sent to a
|
By default Reticulum encrypts all data using elliptic curve cryptography and AES. Any packet sent to a
|
||||||
destination is encrypted with a per-packet derived key. Reticulum can also set up an encrypted
|
destination is encrypted with a per-packet derived key. Reticulum can also set up an encrypted
|
||||||
channel to a destination, called a *Link*. Both data sent over Links and single packets offer
|
channel to a destination, called a *Link*. Both data sent over Links and single packets offer
|
||||||
*Initiator Anonymity*, and links additionally offer *Forward Secrecy* by using an Elliptic Curve
|
*Initiator Anonymity*. Links additionally offer *Forward Secrecy* by default, employing an Elliptic Curve
|
||||||
Diffie Hellman key exchange on Curve25519 to derive per-link ephemeral keys. The multi-hop transport,
|
Diffie Hellman key exchange on Curve25519 to derive per-link ephemeral keys. Asymmetric, link-less
|
||||||
coordination, verification and reliability layers are fully autonomous and also based on elliptic
|
packet communication can also provide forward secrecy, with automatic key ratcheting, by enabling
|
||||||
curve cryptography.
|
ratchets on a per-destination basis. The multi-hop transport, coordination, verification and reliability
|
||||||
|
layers are fully autonomous and also based on elliptic curve cryptography.
|
||||||
|
|
||||||
Reticulum also offers symmetric key encryption for group-oriented communications, as well as
|
Reticulum also offers symmetric key encryption for group-oriented communications, as well as
|
||||||
unencrypted packets for local broadcast purposes.
|
unencrypted packets for local broadcast purposes.
|
||||||
@ -431,7 +432,7 @@ For exchanges of small amounts of information, Reticulum offers the *Packet* API
|
|||||||
|
|
||||||
* | A packet is always created with an associated destination and some payload data. When the packet is sent
|
* | A packet is always created with an associated destination and some payload data. When the packet is sent
|
||||||
to a *single* destination type, Reticulum will automatically create an ephemeral encryption key, perform
|
to a *single* destination type, Reticulum will automatically create an ephemeral encryption key, perform
|
||||||
an ECDH key exchange with the destination's public key, and encrypt the information.
|
an ECDH key exchange with the destination's public key (or ratchet key, if available), and encrypt the information.
|
||||||
|
|
||||||
* | It is important to note that this key exchange does not require any network traffic. The sender already
|
* | It is important to note that this key exchange does not require any network traffic. The sender already
|
||||||
knows the public key of the destination from an earlier received *announce*, and can thus perform the ECDH
|
knows the public key of the destination from an earlier received *announce*, and can thus perform the ECDH
|
||||||
@ -693,7 +694,8 @@ Wire Format
|
|||||||
[HEADER 2 bytes] [ADDRESSES 16/32 bytes] [CONTEXT 1 byte] [DATA 0-465 bytes]
|
[HEADER 2 bytes] [ADDRESSES 16/32 bytes] [CONTEXT 1 byte] [DATA 0-465 bytes]
|
||||||
|
|
||||||
* The HEADER field is 2 bytes long.
|
* The HEADER field is 2 bytes long.
|
||||||
* Byte 1: [IFAC Flag], [Header Type], [Propagation Type], [Destination Type] and [Packet Type]
|
* Byte 1: [IFAC Flag], [Header Type], [Context Flag], [Propagation Type],
|
||||||
|
[Destination Type] and [Packet Type]
|
||||||
* Byte 2: Number of hops
|
* Byte 2: Number of hops
|
||||||
|
|
||||||
* Interface Access Code field if the IFAC flag was set.
|
* Interface Access Code field if the IFAC flag was set.
|
||||||
@ -725,12 +727,16 @@ Wire Format
|
|||||||
type 2 1 Two byte header, two 16 byte address fields
|
type 2 1 Two byte header, two 16 byte address fields
|
||||||
|
|
||||||
|
|
||||||
|
Context Flag
|
||||||
|
-----------------
|
||||||
|
unset 0 The context flag is used for various types
|
||||||
|
set 1 of signalling, depending on packet context
|
||||||
|
|
||||||
|
|
||||||
Propagation Types
|
Propagation Types
|
||||||
-----------------
|
-----------------
|
||||||
broadcast 00
|
broadcast 0
|
||||||
transport 01
|
transport 1
|
||||||
reserved 10
|
|
||||||
reserved 11
|
|
||||||
|
|
||||||
|
|
||||||
Destination Types
|
Destination Types
|
||||||
@ -862,12 +868,14 @@ both on general-purpose CPUs and on microcontrollers. The necessary primitives a
|
|||||||
|
|
||||||
* HKDF for key derivation
|
* HKDF for key derivation
|
||||||
|
|
||||||
* Fernet for encrypted tokens
|
* Modified Fernet for encrypted tokens
|
||||||
|
|
||||||
* AES-128 in CBC mode
|
* AES-128 in CBC mode
|
||||||
|
|
||||||
* HMAC for message authentication
|
* HMAC for message authentication
|
||||||
|
|
||||||
|
* No Version and Timestamp metadata included
|
||||||
|
|
||||||
* SHA-256
|
* SHA-256
|
||||||
|
|
||||||
* SHA-512
|
* SHA-512
|
||||||
|
@ -53,9 +53,9 @@ What does Reticulum Offer?
|
|||||||
|
|
||||||
* Forward Secrecy by using ephemeral Elliptic Curve Diffie-Hellman keys on Curve25519
|
* Forward Secrecy by using ephemeral Elliptic Curve Diffie-Hellman keys on Curve25519
|
||||||
|
|
||||||
* Reticulum uses the `Fernet <https://github.com/fernet/spec/blob/master/Spec.md>`_ specification for on-the-wire / over-the-air encryption
|
* Reticulum uses a modified version of the `Fernet <https://github.com/fernet/spec/blob/master/Spec.md>`_ specification for on-the-wire / over-the-air encryption
|
||||||
|
|
||||||
* All keys are ephemeral and derived from an ECDH key exchange on Curve25519
|
* Keys are ephemeral and derived from an ECDH key exchange on Curve25519
|
||||||
|
|
||||||
* AES-128 in CBC mode with PKCS7 padding
|
* AES-128 in CBC mode with PKCS7 padding
|
||||||
|
|
||||||
@ -63,6 +63,8 @@ What does Reticulum Offer?
|
|||||||
|
|
||||||
* IVs are generated through os.urandom()
|
* IVs are generated through os.urandom()
|
||||||
|
|
||||||
|
* No Version and Timestamp metadata included
|
||||||
|
|
||||||
* Unforgeable packet delivery confirmations
|
* Unforgeable packet delivery confirmations
|
||||||
|
|
||||||
* A variety of supported interface types
|
* A variety of supported interface types
|
||||||
@ -99,7 +101,8 @@ of the types of interfaces Reticulum was designed for.
|
|||||||
An open-source LoRa-based interface called `RNode <https://unsigned.io/rnode>`_
|
An open-source LoRa-based interface called `RNode <https://unsigned.io/rnode>`_
|
||||||
has been designed as an example transceiver that is very suitable for
|
has been designed as an example transceiver that is very suitable for
|
||||||
Reticulum. It is possible to build it yourself, to transform a common LoRa
|
Reticulum. It is possible to build it yourself, to transform a common LoRa
|
||||||
development board into one, or it can be purchased as a complete transceiver.
|
development board into one, or it can be purchased as a complete transceiver
|
||||||
|
from various vendors.
|
||||||
|
|
||||||
Reticulum can also be encapsulated over existing IP networks, so there's
|
Reticulum can also be encapsulated over existing IP networks, so there's
|
||||||
nothing stopping you from using it over wired Ethernet or your local WiFi
|
nothing stopping you from using it over wired Ethernet or your local WiFi
|
||||||
|
Loading…
Reference in New Issue
Block a user