mirror of
https://github.com/markqvist/Reticulum.git
synced 2026-06-23 20:34:29 -07:00
Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d17fbf1f34 | |||
| 7398e312fc | |||
| 82fc8720ad | |||
| 4b9686c31a | |||
| 86a5b3302a | |||
| c990aae648 | |||
| 3051b6897d | |||
| 550dfd44cb |
@@ -1,6 +1,6 @@
|
||||
MIT License, unless otherwise noted
|
||||
|
||||
Copyright (c) 2018 Mark Qvist / unsigned.io
|
||||
Copyright (c) 2016-2022 Mark Qvist / unsigned.io
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
Reticulum Network Stack β
|
||||
==========
|
||||
|
||||
Reticulum is a cryptography-based networking stack for wide-area networks built on readily available hardware, and can operate even with very high latency and extremely low bandwidth. Reticulum allows you to build very wide-area networks with off-the-shelf tools, and offers end-to-end encryption, autoconfiguring cryptographically backed multi-hop transport, efficient addressing, unforgeable packet acknowledgements and more.
|
||||
<p align="center"><img width="200" src="https://unsigned.io/wp-content/uploads/2022/03/reticulum_logo_512.png"></p>
|
||||
|
||||
Reticulum is the cryptography-based networking stack for wide-area networks built on readily available hardware. It can operate even with very high latency and extremely low bandwidth. Reticulum allows you to build wide-area networks with off-the-shelf tools, and offers end-to-end encryption, initiator anonymity, autoconfiguring cryptographically backed multi-hop transport, efficient addressing, unforgeable packet acknowledgements and more.
|
||||
|
||||
Reticulum is a complete networking stack, and does not need IP or higher layers, although it is easy to use IP (with TCP or UDP) as the underlying carrier for Reticulum. It is therefore trivial to tunnel Reticulum over the Internet or private IP networks.
|
||||
|
||||
@@ -42,8 +44,9 @@ For more info, see [unsigned.io/projects/reticulum](https://unsigned.io/projects
|
||||
## Examples of Reticulum Applications
|
||||
If you want to quickly get an idea of what Reticulum can do, take a look at the following resources.
|
||||
|
||||
- [LXMF](https://github.com/markqvist/lxmf) is a distributed, delay and disruption tolerant message transfer protocol built on Reticulum
|
||||
- For an off-grid, encrypted and resilient mesh communications platform, see [Nomad Network](https://github.com/markqvist/NomadNet)
|
||||
- For a distributed, delay and disruption tolerant message transfer protocol built on Reticulum, see [LXMF](https://github.com/markqvist/lxmf)
|
||||
- The Android, Linux and macOS app [Sideband](https://unsigned.io/sideband) has a graphical interface and focuses on ease of use.
|
||||
|
||||
## Where can Reticulum be used?
|
||||
Over practically any medium that can support at least a half-duplex channel with 500 bits per second throughput, and an MTU of 500 bytes. Data radios, modems, LoRa radios, serial lines, AX.25 TNCs, amateur radio digital modes, ad-hoc WiFi, free-space optical links and similar systems are all examples of the types of interfaces Reticulum was designed for.
|
||||
@@ -84,8 +87,6 @@ Reticulum implements a range of generalised interface types that covers most of
|
||||
- TCP over IP networks
|
||||
- UDP over IP networks
|
||||
|
||||
|
||||
|
||||
## Planned Features
|
||||
- More interface types for even broader compatibility
|
||||
- ESP32 devices (ESP-Now, Bluetooth, etc.)
|
||||
@@ -113,5 +114,7 @@ You can help support the continued development of open, free and private communi
|
||||
- Bitcoin: 3CPmacGm34qYvR6XWLVEJmi2aNe3PZqUuq
|
||||
- Ko-Fi: https://ko-fi.com/markqvist
|
||||
|
||||
Are certain features in the development roadmap are important to you or your organisation? Make them a reality quickly by sponsoring their implementation.
|
||||
|
||||
## Caveat Emptor
|
||||
Reticulum is experimental software, and should be considered as such. While it has been built with cryptography best-practices very foremost in mind, it _has not_ been externally security audited, and there could very well be privacy-breaking bugs. If you want to help out, or help sponsor an audit, please do get in touch.
|
||||
Reticulum is relatively young software, and should be considered as such. While it has been built with cryptography best-practices very foremost in mind, it _has not_ been externally security audited, and there could very well be privacy-breaking bugs. If you want to help out, or help sponsor an audit, please do get in touch.
|
||||
|
||||
@@ -118,6 +118,9 @@ class Destination:
|
||||
identity = RNS.Identity()
|
||||
aspects = aspects+(identity.hexhash,)
|
||||
|
||||
if identity != None and self.type == Destination.PLAIN:
|
||||
raise TypeError("Selected destination type PLAIN cannot hold an identity")
|
||||
|
||||
self.identity = identity
|
||||
|
||||
self.name = Destination.full_name(app_name, *aspects)
|
||||
@@ -146,6 +149,9 @@ class Destination:
|
||||
:param app_data: *bytes* containing the app_data.
|
||||
:param path_response: Internal flag used by :ref:`RNS.Transport<api-transport>`. Ignore.
|
||||
"""
|
||||
if self.type != Destination.SINGLE:
|
||||
raise TypeError("Only SINGLE destination types can be announced")
|
||||
|
||||
destination_hash = self.hash
|
||||
random_hash = RNS.Identity.get_random_hash()[0:5]+int(time.time()).to_bytes(5, "big")
|
||||
|
||||
|
||||
+10
-2
@@ -14,6 +14,8 @@ from cryptography.hazmat.primitives.asymmetric.x25519 import X25519PrivateKey, X
|
||||
from cryptography.hazmat.primitives.kdf.hkdf import HKDF
|
||||
from cryptography.fernet import Fernet
|
||||
|
||||
cio_default_backend = default_backend()
|
||||
|
||||
class Identity:
|
||||
"""
|
||||
This class is used to manage identities in Reticulum. It provides methods
|
||||
@@ -392,11 +394,14 @@ class Identity:
|
||||
)
|
||||
|
||||
shared_key = ephemeral_key.exchange(self.pub)
|
||||
derived_key = derived_key = HKDF(
|
||||
|
||||
# TODO: Improve this re-allocation of HKDF
|
||||
derived_key = HKDF(
|
||||
algorithm=hashes.SHA256(),
|
||||
length=32,
|
||||
salt=self.get_salt(),
|
||||
info=self.get_context(),
|
||||
backend=cio_default_backend,
|
||||
).derive(shared_key)
|
||||
|
||||
fernet = Fernet(base64.urlsafe_b64encode(derived_key))
|
||||
@@ -424,11 +429,14 @@ class Identity:
|
||||
peer_pub = X25519PublicKey.from_public_bytes(peer_pub_bytes)
|
||||
|
||||
shared_key = self.prv.exchange(peer_pub)
|
||||
derived_key = derived_key = HKDF(
|
||||
|
||||
# TODO: Improve this re-allocation of HKDF
|
||||
derived_key = HKDF(
|
||||
algorithm=hashes.SHA256(),
|
||||
length=32,
|
||||
salt=self.get_salt(),
|
||||
info=self.get_context(),
|
||||
backend=cio_default_backend,
|
||||
).derive(shared_key)
|
||||
|
||||
fernet = Fernet(base64.urlsafe_b64encode(derived_key))
|
||||
|
||||
+6
-1
@@ -15,6 +15,8 @@ import RNS
|
||||
|
||||
import traceback
|
||||
|
||||
cio_default_backend = default_backend()
|
||||
|
||||
class LinkCallbacks:
|
||||
def __init__(self):
|
||||
self.link_established = None
|
||||
@@ -199,11 +201,14 @@ class Link:
|
||||
def handshake(self):
|
||||
self.status = Link.HANDSHAKE
|
||||
self.shared_key = self.prv.exchange(self.peer_pub)
|
||||
|
||||
# TODO: Improve this re-allocation of HKDF
|
||||
self.derived_key = HKDF(
|
||||
algorithm=hashes.SHA256(),
|
||||
length=32,
|
||||
salt=self.get_salt(),
|
||||
info=self.get_context(),
|
||||
backend=cio_default_backend,
|
||||
).derive(self.shared_key)
|
||||
|
||||
def prove(self):
|
||||
@@ -1064,4 +1069,4 @@ class RequestReceiptCallbacks:
|
||||
def __init__(self):
|
||||
self.response = None
|
||||
self.failed = None
|
||||
self.progress = None
|
||||
self.progress = None
|
||||
|
||||
+27
-3
@@ -457,7 +457,7 @@ class Transport:
|
||||
sent = False
|
||||
|
||||
# Check if we have a known path for the destination in the path table
|
||||
if packet.packet_type != RNS.Packet.ANNOUNCE and packet.destination_hash in Transport.destination_table:
|
||||
if packet.packet_type != RNS.Packet.ANNOUNCE and packet.destination.type != RNS.Destination.PLAIN and packet.destination.type != RNS.Destination.GROUP and packet.destination_hash in Transport.destination_table:
|
||||
outbound_interface = Transport.destination_table[packet.destination_hash][5]
|
||||
|
||||
# If there's more than one hop to the destination, and we know
|
||||
@@ -572,14 +572,38 @@ class Transport:
|
||||
return True
|
||||
if packet.context == RNS.Packet.CACHE_REQUEST:
|
||||
return True
|
||||
|
||||
if packet.destination_type == RNS.Destination.PLAIN:
|
||||
return True
|
||||
if packet.packet_type != RNS.Packet.ANNOUNCE:
|
||||
if packet.hops > 1:
|
||||
RNS.log("Dropped PLAIN packet "+RNS.prettyhexrep(packet.hash)+" with "+str(packet.hops)+" hops", RNS.LOG_DEBUG)
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
else:
|
||||
RNS.log("Dropped invalid PLAIN announce packet", RNS.LOG_DEBUG)
|
||||
return False
|
||||
|
||||
if packet.destination_type == RNS.Destination.GROUP:
|
||||
if packet.packet_type != RNS.Packet.ANNOUNCE:
|
||||
if packet.hops > 1:
|
||||
RNS.log("Dropped GROUP packet "+RNS.prettyhexrep(packet.hash)+" with "+str(packet.hops)+" hops", RNS.LOG_DEBUG)
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
else:
|
||||
RNS.log("Dropped invalid GROUP announce packet", RNS.LOG_DEBUG)
|
||||
return False
|
||||
|
||||
if not packet.packet_hash in Transport.packet_hashlist:
|
||||
return True
|
||||
else:
|
||||
if packet.packet_type == RNS.Packet.ANNOUNCE:
|
||||
return True
|
||||
if packet.destination_type == RNS.Destination.SINGLE:
|
||||
return True
|
||||
else:
|
||||
RNS.log("Dropped invalid announce packet", RNS.LOG_DEBUG)
|
||||
return False
|
||||
|
||||
RNS.log("Filtered packet with hash "+RNS.prettyhexrep(packet.packet_hash), RNS.LOG_DEBUG)
|
||||
return False
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
__version__ = "0.3.3"
|
||||
__version__ = "0.3.4"
|
||||
|
||||
Vendored
+7
@@ -36,3 +36,10 @@ def platform_checks():
|
||||
RNS.log("On Windows, Reticulum requires Python 3.8 or higher.", RNS.LOG_ERROR)
|
||||
RNS.log("Please update Python to run Reticulum.", RNS.LOG_ERROR)
|
||||
RNS.panic()
|
||||
|
||||
def cryptography_old_api():
|
||||
import cryptography
|
||||
if cryptography.__version__ == "2.8":
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
Reference in New Issue
Block a user