mirror of
https://github.com/markqvist/Reticulum.git
synced 2024-11-22 21:50:18 +00:00
Compare commits
34 Commits
283cff258f
...
f4b882a042
Author | SHA1 | Date | |
---|---|---|---|
|
f4b882a042 | ||
|
7b7ebbec90 | ||
|
8b3523dee0 | ||
|
2901ed2bae | ||
|
34010c94d1 | ||
|
a4b5248a4c | ||
|
75272d77a5 | ||
|
d4ad4589dd | ||
|
8d45ad36eb | ||
|
2a0d411869 | ||
|
b9421347ef | ||
|
ffec78d49a | ||
|
356ae378f9 | ||
|
28e3919dbd | ||
|
58a19610c4 | ||
|
50b1eae380 | ||
|
c119ef4273 | ||
|
b506ca94d0 | ||
|
a072a5b074 | ||
|
3a580e74de | ||
|
9a20a3929a | ||
|
fe054fd03c | ||
|
3eb8d92028 | ||
|
ef3baf2cd9 | ||
|
f2f936d846 | ||
|
6599e210de | ||
|
b4ac3df2d0 | ||
|
8193f3621c | ||
|
5166596375 | ||
|
625db2622d | ||
|
a8bc468e21 | ||
|
95c4269869 | ||
|
65a40aefb6 | ||
|
a840bd4aaf |
28
.github/workflows/python-app.yml
vendored
Normal file
28
.github/workflows/python-app.yml
vendored
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
# This workflow will install Python dependencies, run tests and lint with a single version of Python
|
||||||
|
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python
|
||||||
|
|
||||||
|
name: Test suite
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ "master" ]
|
||||||
|
pull_request:
|
||||||
|
branches: [ "master" ]
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Set up Python 3.10
|
||||||
|
uses: actions/setup-python@v3
|
||||||
|
with:
|
||||||
|
python-version: "3.10"
|
||||||
|
- name: Test
|
||||||
|
run: |
|
||||||
|
make test
|
27
Changelog.md
27
Changelog.md
@ -1,6 +1,31 @@
|
|||||||
|
### 2024-09-09: RNS β 0.7.7
|
||||||
|
|
||||||
|
This release adds support for automatic encryption key ratcheting for all packets, not just those sent over Reticulum links. In practical terms, this adds forward secrecy to packets sent with the raw `Packet` API.
|
||||||
|
|
||||||
|
In this release, the ratchets feature must be enabled on a per-destination basis by calling the `enable_ratchets` method on the relevant destination. In a future release, ratchets may become the default option, but for backwards-compatibility, it is currently optional. For more information, read the API documentation.
|
||||||
|
|
||||||
|
**Please note!** Versions of RNS prior to `0.7.7` will not be able to pass announces for destinations with ratchets enabled! If you use applications that can use ratchets (for example, LXMF version `0.5.0` and up), it is important that you update all transport instances on your network to `0.7.7`.
|
||||||
|
|
||||||
|
Thanks to @deavmi, @faragher, @jacobeva, @jeremy and @jeremybox for contributing to this release!
|
||||||
|
|
||||||
|
**Changes**
|
||||||
|
- Added key ratchet rotation and signalling
|
||||||
|
- Added ratchet API to documentation
|
||||||
|
- Added initial support for flashing T-Echo devices to `rnodeconf`
|
||||||
|
- Added remote management config options to example config
|
||||||
|
- Added automtic integration tests to source repository
|
||||||
|
- Fixed a regression that caused RNS not to work on Python versions lower than 3.10
|
||||||
|
- Fixed missing `establishment_rate` property init on Link objects
|
||||||
|
|
||||||
|
**Release Hashes**
|
||||||
|
```
|
||||||
|
0a3ab6dc82567a19adabe737358daee3002b60beda8ac0bf228f2a0c134ff6d8 rns-0.7.7-py3-none-any.whl
|
||||||
|
89b33fe9ab923139d3f5d43726d92817642be05a8c9d328c3becfc3c409e4b4b rnspure-0.7.7-py3-none-any.whl
|
||||||
|
```
|
||||||
|
|
||||||
### 2024-05-18: RNS β 0.7.6
|
### 2024-05-18: RNS β 0.7.6
|
||||||
|
|
||||||
This release add support for RNodes with multiple radio transceivers, courtesy of @jacobeva. It also brings a number of functionality and performance improvements, and fixes several bugs.
|
This release adds support for RNodes with multiple radio transceivers, courtesy of @jacobeva. It also brings a number of functionality and performance improvements, and fixes several bugs.
|
||||||
|
|
||||||
Thanks to @jacobeva, @faragher, @nathmo, @jschulthess and @liamcottle for contributing to this release!
|
Thanks to @jacobeva, @faragher, @nathmo, @jschulthess and @liamcottle for contributing to this release!
|
||||||
|
|
||||||
|
2
Makefile
2
Makefile
@ -2,7 +2,7 @@ all: release
|
|||||||
|
|
||||||
test:
|
test:
|
||||||
@echo Running tests...
|
@echo Running tests...
|
||||||
python -m tests.all
|
python3 -m tests.all
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
@echo Cleaning...
|
@echo Cleaning...
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
Reticulum Network Stack β <img align="right" src="https://static.pepy.tech/personalized-badge/rns?period=total&units=international_system&left_color=grey&right_color=blue&left_text=Installs"/>
|
Reticulum Network Stack β <img align="right" src="https://static.pepy.tech/personalized-badge/rns?period=total&units=international_system&left_color=grey&right_color=blue&left_text=Installs" style="padding-left:10px"/><a href="https://github.com/markqvist/reticulum/actions/workflows/python-app.yml"><img align="right" src="https://github.com/markqvist/reticulum/actions/workflows/python-app.yml/badge.svg"/></a>
|
||||||
==========
|
==========
|
||||||
|
|
||||||
<p align="center"><img width="200" src="https://raw.githubusercontent.com/markqvist/Reticulum/master/docs/source/graphics/rns_logo_512.png"></p>
|
<p align="center"><img width="200" src="https://raw.githubusercontent.com/markqvist/Reticulum/master/docs/source/graphics/rns_logo_512.png"></p>
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
import os
|
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
|
||||||
@ -152,8 +153,10 @@ class Destination:
|
|||||||
self.ratchets = None
|
self.ratchets = None
|
||||||
self.ratchets_path = None
|
self.ratchets_path = None
|
||||||
self.ratchet_interval = Destination.RATCHET_INTERVAL
|
self.ratchet_interval = Destination.RATCHET_INTERVAL
|
||||||
|
self.ratchet_file_lock = threading.Lock()
|
||||||
self.retained_ratchets = Destination.RATCHET_COUNT
|
self.retained_ratchets = Destination.RATCHET_COUNT
|
||||||
self.latest_ratchet_time = None
|
self.latest_ratchet_time = None
|
||||||
|
self.latest_ratchet_id = None
|
||||||
self.__enforce_ratchets = False
|
self.__enforce_ratchets = False
|
||||||
self.mtu = 0
|
self.mtu = 0
|
||||||
|
|
||||||
@ -195,11 +198,12 @@ class Destination:
|
|||||||
|
|
||||||
def _persist_ratchets(self):
|
def _persist_ratchets(self):
|
||||||
try:
|
try:
|
||||||
packed_ratchets = umsgpack.packb(self.ratchets)
|
with self.ratchet_file_lock:
|
||||||
persisted_data = {"signature": self.sign(packed_ratchets), "ratchets": packed_ratchets}
|
packed_ratchets = umsgpack.packb(self.ratchets)
|
||||||
ratchets_file = open(self.ratchets_path, "wb")
|
persisted_data = {"signature": self.sign(packed_ratchets), "ratchets": packed_ratchets}
|
||||||
ratchets_file.write(umsgpack.packb(persisted_data))
|
ratchets_file = open(self.ratchets_path, "wb")
|
||||||
ratchets_file.close()
|
ratchets_file.write(umsgpack.packb(persisted_data))
|
||||||
|
ratchets_file.close()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.ratchets = None
|
self.ratchets = None
|
||||||
self.ratchets_path = None
|
self.ratchets_path = None
|
||||||
@ -265,9 +269,7 @@ class Destination:
|
|||||||
if self.ratchets != None:
|
if self.ratchets != None:
|
||||||
self.rotate_ratchets()
|
self.rotate_ratchets()
|
||||||
ratchet = RNS.Identity._ratchet_public_bytes(self.ratchets[0])
|
ratchet = RNS.Identity._ratchet_public_bytes(self.ratchets[0])
|
||||||
|
RNS.Identity._remember_ratchet(self.hash, ratchet)
|
||||||
# TODO: Remove at some point
|
|
||||||
RNS.log(f"Including ratchet {RNS.prettyhexrep(RNS.Identity.truncated_hash(ratchet))} in announce", RNS.LOG_EXTREME)
|
|
||||||
|
|
||||||
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):
|
||||||
@ -401,6 +403,7 @@ class Destination:
|
|||||||
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:
|
||||||
@ -415,6 +418,29 @@ class Destination:
|
|||||||
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):
|
def enable_ratchets(self, ratchets_path):
|
||||||
"""
|
"""
|
||||||
Enables ratchets on the destination. When ratchets are enabled, Reticulum will automatically rotate
|
Enables ratchets on the destination. When ratchets are enabled, Reticulum will automatically rotate
|
||||||
@ -432,26 +458,7 @@ class Destination:
|
|||||||
"""
|
"""
|
||||||
if ratchets_path != None:
|
if ratchets_path != None:
|
||||||
self.latest_ratchet_time = 0
|
self.latest_ratchet_time = 0
|
||||||
if os.path.isfile(ratchets_path):
|
self._reload_ratchets(ratchets_path)
|
||||||
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()
|
|
||||||
|
|
||||||
# TODO: Remove at some point
|
# TODO: Remove at some point
|
||||||
RNS.log("Ratchets enabled on "+str(self), RNS.LOG_DEBUG)
|
RNS.log("Ratchets enabled on "+str(self), RNS.LOG_DEBUG)
|
||||||
@ -565,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, ratchet=RNS.Identity.get_ratchet(self.hash))
|
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:
|
||||||
@ -588,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, ratchets=self.ratchets, enforce_ratchets=self.__enforce_ratchets)
|
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:
|
||||||
|
@ -213,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)
|
||||||
|
|
||||||
@ -223,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)]
|
||||||
|
|
||||||
@ -233,10 +233,28 @@ 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
|
@staticmethod
|
||||||
def _ratchet_public_bytes(ratchet):
|
def _ratchet_public_bytes(ratchet):
|
||||||
return X25519PrivateKey.from_private_bytes(ratchet).public_key().public_bytes()
|
return X25519PrivateKey.from_private_bytes(ratchet).public_key().public_bytes()
|
||||||
@ -250,7 +268,7 @@ class Identity:
|
|||||||
@staticmethod
|
@staticmethod
|
||||||
def _remember_ratchet(destination_hash, ratchet):
|
def _remember_ratchet(destination_hash, ratchet):
|
||||||
# TODO: Remove at some point, and only log new ratchets
|
# TODO: Remove at some point, and only log new ratchets
|
||||||
RNS.log(f"Remembering ratchet {RNS.prettyhexrep(Identity.truncated_hash(ratchet))} for {RNS.prettyhexrep(destination_hash)}", RNS.LOG_EXTREME)
|
RNS.log(f"Remembering ratchet {RNS.prettyhexrep(Identity._get_ratchet_id(ratchet))} for {RNS.prettyhexrep(destination_hash)}", RNS.LOG_EXTREME)
|
||||||
try:
|
try:
|
||||||
Identity.known_ratchets[destination_hash] = ratchet
|
Identity.known_ratchets[destination_hash] = ratchet
|
||||||
|
|
||||||
@ -270,7 +288,7 @@ class Identity:
|
|||||||
ratchet_file = open(outpath, "wb")
|
ratchet_file = open(outpath, "wb")
|
||||||
ratchet_file.write(umsgpack.packb(ratchet_data))
|
ratchet_file.write(umsgpack.packb(ratchet_data))
|
||||||
ratchet_file.close()
|
ratchet_file.close()
|
||||||
os.rename(outpath, finalpath)
|
os.replace(outpath, finalpath)
|
||||||
|
|
||||||
|
|
||||||
threading.Thread(target=persist_job, daemon=True).start()
|
threading.Thread(target=persist_job, daemon=True).start()
|
||||||
@ -310,11 +328,11 @@ class Identity:
|
|||||||
if not destination_hash in Identity.known_ratchets:
|
if not destination_hash in Identity.known_ratchets:
|
||||||
ratchetdir = RNS.Reticulum.storagepath+"/ratchets"
|
ratchetdir = RNS.Reticulum.storagepath+"/ratchets"
|
||||||
hexhash = RNS.hexrep(destination_hash, delimit=False)
|
hexhash = RNS.hexrep(destination_hash, delimit=False)
|
||||||
ratchet_path = f"{ratchetdir}/hexhash"
|
ratchet_path = f"{ratchetdir}/{hexhash}"
|
||||||
if os.path.isfile(ratchet_path):
|
if os.path.isfile(ratchet_path):
|
||||||
try:
|
try:
|
||||||
ratchet_file = open(ratchet_path, "rb")
|
ratchet_file = open(ratchet_path, "rb")
|
||||||
ratchet_data = umsgpack.unpackb(ratchets_file.read())
|
ratchet_data = umsgpack.unpackb(ratchet_file.read())
|
||||||
if time.time() < ratchet_data["received"]+Identity.RATCHET_EXPIRY and len(ratchet_data["ratchet"]) == Identity.RATCHETSIZE//8:
|
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"]
|
Identity.known_ratchets[destination_hash] = ratchet_data["ratchet"]
|
||||||
else:
|
else:
|
||||||
@ -617,8 +635,6 @@ class Identity:
|
|||||||
ephemeral_pub_bytes = ephemeral_key.public_key().public_bytes()
|
ephemeral_pub_bytes = ephemeral_key.public_key().public_bytes()
|
||||||
|
|
||||||
if ratchet != None:
|
if ratchet != None:
|
||||||
# TODO: Remove at some point
|
|
||||||
RNS.log(f"Encrypting with ratchet {RNS.prettyhexrep(RNS.Identity.truncated_hash(ratchet))}", RNS.LOG_EXTREME)
|
|
||||||
target_public_key = X25519PublicKey.from_public_bytes(ratchet)
|
target_public_key = X25519PublicKey.from_public_bytes(ratchet)
|
||||||
else:
|
else:
|
||||||
target_public_key = self.pub
|
target_public_key = self.pub
|
||||||
@ -641,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, ratchets=None, enforce_ratchets=False):
|
def decrypt(self, ciphertext_token, ratchets=None, enforce_ratchets=False, ratchet_id_receiver=None):
|
||||||
"""
|
"""
|
||||||
Decrypts information for the identity.
|
Decrypts information for the identity.
|
||||||
|
|
||||||
@ -661,6 +677,7 @@ class Identity:
|
|||||||
for ratchet in ratchets:
|
for ratchet in ratchets:
|
||||||
try:
|
try:
|
||||||
ratchet_prv = X25519PrivateKey.from_private_bytes(ratchet)
|
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)
|
shared_key = ratchet_prv.exchange(peer_pub)
|
||||||
derived_key = RNS.Cryptography.hkdf(
|
derived_key = RNS.Cryptography.hkdf(
|
||||||
length=32,
|
length=32,
|
||||||
@ -671,9 +688,8 @@ class Identity:
|
|||||||
|
|
||||||
fernet = Fernet(derived_key)
|
fernet = Fernet(derived_key)
|
||||||
plaintext = fernet.decrypt(ciphertext)
|
plaintext = fernet.decrypt(ciphertext)
|
||||||
|
if ratchet_id_receiver:
|
||||||
# TODO: Remove at some point
|
ratchet_id_receiver.latest_ratchet_id = ratchet_id
|
||||||
RNS.log(f"Decrypted with ratchet {RNS.prettyhexrep(RNS.Identity.truncated_hash(ratchet_prv.public_key().public_bytes()))}", RNS.LOG_EXTREME)
|
|
||||||
|
|
||||||
break
|
break
|
||||||
|
|
||||||
@ -682,6 +698,8 @@ class Identity:
|
|||||||
|
|
||||||
if enforce_ratchets and plaintext == None:
|
if enforce_ratchets and plaintext == None:
|
||||||
RNS.log("Decryption with ratchet enforcement by "+RNS.prettyhexrep(self.hash)+" failed. Dropping packet.", RNS.LOG_DEBUG)
|
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
|
return None
|
||||||
|
|
||||||
if plaintext == None:
|
if plaintext == None:
|
||||||
@ -695,9 +713,13 @@ class Identity:
|
|||||||
|
|
||||||
fernet = Fernet(derived_key)
|
fernet = Fernet(derived_key)
|
||||||
plaintext = fernet.decrypt(ciphertext)
|
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:
|
||||||
|
@ -623,7 +623,6 @@ class RNodeInterface(Interface):
|
|||||||
self.r_state = byte
|
self.r_state = byte
|
||||||
if self.r_state:
|
if self.r_state:
|
||||||
pass
|
pass
|
||||||
#RNS.log(str(self)+" Radio reporting state is online", RNS.LOG_DEBUG)
|
|
||||||
else:
|
else:
|
||||||
RNS.log(str(self)+" Radio reporting state is offline", RNS.LOG_DEBUG)
|
RNS.log(str(self)+" Radio reporting state is offline", RNS.LOG_DEBUG)
|
||||||
|
|
||||||
|
@ -775,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))
|
||||||
|
@ -140,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
|
||||||
@ -195,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:
|
||||||
@ -418,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:
|
||||||
|
@ -52,16 +52,16 @@ class Transport:
|
|||||||
Maximum amount of hops that Reticulum will transport a packet.
|
Maximum amount of hops that Reticulum will transport a packet.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
PATHFINDER_R = 1 # Retransmit retries
|
PATHFINDER_R = 1 # Retransmit retries
|
||||||
PATHFINDER_G = 5 # Retry grace period
|
PATHFINDER_G = 5 # Retry grace period
|
||||||
PATHFINDER_RW = 0.5 # Random window for announce rebroadcast
|
PATHFINDER_RW = 0.5 # Random window for announce rebroadcast
|
||||||
PATHFINDER_E = 60*60*24*7 # Path expiration of one week
|
PATHFINDER_E = 60*60*24*7 # Path expiration of one week
|
||||||
AP_PATH_TIME = 60*60*24 # Path expiration of one day for Access Point paths
|
AP_PATH_TIME = 60*60*24 # Path expiration of one day for Access Point paths
|
||||||
ROAMING_PATH_TIME = 60*60*6 # Path expiration of 6 hours for Roaming paths
|
ROAMING_PATH_TIME = 60*60*6 # Path expiration of 6 hours for Roaming paths
|
||||||
|
|
||||||
# TODO: Calculate an optimal number for this in
|
# TODO: Calculate an optimal number for this in
|
||||||
# various situations
|
# various situations
|
||||||
LOCAL_REBROADCASTS_MAX = 2 # How many local rebroadcasts of an announce is allowed
|
LOCAL_REBROADCASTS_MAX = 2 # How many local rebroadcasts of an announce is allowed
|
||||||
|
|
||||||
PATH_REQUEST_TIMEOUT = 15 # Default timuout for client path requests in seconds
|
PATH_REQUEST_TIMEOUT = 15 # Default timuout for client path requests in seconds
|
||||||
PATH_REQUEST_GRACE = 0.4 # Grace time before a path announcement is made, allows directly reachable peers to respond first
|
PATH_REQUEST_GRACE = 0.4 # Grace time before a path announcement is made, allows directly reachable peers to respond first
|
||||||
@ -1709,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:
|
||||||
|
@ -128,10 +128,6 @@ class ROM():
|
|||||||
MCU_ESP32 = 0x81
|
MCU_ESP32 = 0x81
|
||||||
MCU_NRF52 = 0x71
|
MCU_NRF52 = 0x71
|
||||||
|
|
||||||
PRODUCT_RAK4631 = 0x10
|
|
||||||
MODEL_11 = 0x11
|
|
||||||
MODEL_12 = 0x12
|
|
||||||
|
|
||||||
PRODUCT_RNODE = 0x03
|
PRODUCT_RNODE = 0x03
|
||||||
MODEL_A1 = 0xA1
|
MODEL_A1 = 0xA1
|
||||||
MODEL_A6 = 0xA6
|
MODEL_A6 = 0xA6
|
||||||
@ -171,6 +167,14 @@ class ROM():
|
|||||||
MODEL_E3 = 0xE3
|
MODEL_E3 = 0xE3
|
||||||
MODEL_E8 = 0xE8
|
MODEL_E8 = 0xE8
|
||||||
|
|
||||||
|
PRODUCT_RAK4631 = 0x10
|
||||||
|
MODEL_11 = 0x11
|
||||||
|
MODEL_12 = 0x12
|
||||||
|
|
||||||
|
PRODUCT_TECHO = 0x15
|
||||||
|
MODEL_T4 = 0x16
|
||||||
|
MODEL_T9 = 0x17
|
||||||
|
|
||||||
PRODUCT_HMBRW = 0xF0
|
PRODUCT_HMBRW = 0xF0
|
||||||
MODEL_FF = 0xFF
|
MODEL_FF = 0xFF
|
||||||
MODEL_FE = 0xFE
|
MODEL_FE = 0xFE
|
||||||
@ -200,6 +204,7 @@ class ROM():
|
|||||||
BOARD_GENERIC_ESP32 = 0x35
|
BOARD_GENERIC_ESP32 = 0x35
|
||||||
BOARD_LORA32_V2_0 = 0x36
|
BOARD_LORA32_V2_0 = 0x36
|
||||||
BOARD_LORA32_V2_1 = 0x37
|
BOARD_LORA32_V2_1 = 0x37
|
||||||
|
BOARD_TECHO = 0x43
|
||||||
BOARD_RAK4631 = 0x51
|
BOARD_RAK4631 = 0x51
|
||||||
|
|
||||||
MANUAL_FLASH_MODELS = [MODEL_A1, MODEL_A6]
|
MANUAL_FLASH_MODELS = [MODEL_A1, MODEL_A6]
|
||||||
@ -214,6 +219,7 @@ products = {
|
|||||||
ROM.PRODUCT_T32_21: "LilyGO LoRa32 v2.1",
|
ROM.PRODUCT_T32_21: "LilyGO LoRa32 v2.1",
|
||||||
ROM.PRODUCT_H32_V2: "Heltec LoRa32 v2",
|
ROM.PRODUCT_H32_V2: "Heltec LoRa32 v2",
|
||||||
ROM.PRODUCT_H32_V3: "Heltec LoRa32 v3",
|
ROM.PRODUCT_H32_V3: "Heltec LoRa32 v3",
|
||||||
|
ROM.PRODUCT_TECHO: "LilyGO T-Echo",
|
||||||
ROM.PRODUCT_RAK4631: "RAK4631",
|
ROM.PRODUCT_RAK4631: "RAK4631",
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -231,8 +237,6 @@ mcus = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
models = {
|
models = {
|
||||||
0x11: [430000000, 510000000, 22, "430 - 510 MHz", "rnode_firmware_rak4631.zip", "SX1262"],
|
|
||||||
0x12: [779000000, 928000000, 22, "779 - 928 MHz", "rnode_firmware_rak4631.zip", "SX1262"],
|
|
||||||
0xA4: [410000000, 525000000, 14, "410 - 525 MHz", "rnode_firmware.hex", "SX1278"],
|
0xA4: [410000000, 525000000, 14, "410 - 525 MHz", "rnode_firmware.hex", "SX1278"],
|
||||||
0xA9: [820000000, 1020000000, 17, "820 - 1020 MHz", "rnode_firmware.hex", "SX1276"],
|
0xA9: [820000000, 1020000000, 17, "820 - 1020 MHz", "rnode_firmware.hex", "SX1276"],
|
||||||
0xA1: [410000000, 525000000, 22, "410 - 525 MHz", "rnode_firmware_t3s3.zip", "SX1268"],
|
0xA1: [410000000, 525000000, 22, "410 - 525 MHz", "rnode_firmware_t3s3.zip", "SX1268"],
|
||||||
@ -257,6 +261,10 @@ models = {
|
|||||||
0xE9: [850000000, 950000000, 17, "850 - 950 MHz", "rnode_firmware_tbeam.zip", "SX1276"],
|
0xE9: [850000000, 950000000, 17, "850 - 950 MHz", "rnode_firmware_tbeam.zip", "SX1276"],
|
||||||
0xE3: [420000000, 520000000, 22, "420 - 520 MHz", "rnode_firmware_tbeam_sx1262.zip", "SX1268"],
|
0xE3: [420000000, 520000000, 22, "420 - 520 MHz", "rnode_firmware_tbeam_sx1262.zip", "SX1268"],
|
||||||
0xE8: [850000000, 950000000, 22, "850 - 950 MHz", "rnode_firmware_tbeam_sx1262.zip", "SX1262"],
|
0xE8: [850000000, 950000000, 22, "850 - 950 MHz", "rnode_firmware_tbeam_sx1262.zip", "SX1262"],
|
||||||
|
0x11: [430000000, 510000000, 22, "430 - 510 MHz", "rnode_firmware_rak4631.zip", "SX1262"],
|
||||||
|
0x12: [779000000, 928000000, 22, "779 - 928 MHz", "rnode_firmware_rak4631.zip", "SX1262"],
|
||||||
|
0x16: [779000000, 928000000, 22, "430 - 510 Mhz", "rnode_firmware_techo.zip", "SX1262"],
|
||||||
|
0x17: [779000000, 928000000, 22, "779 - 928 Mhz", "rnode_firmware_techo.zip", "SX1262"],
|
||||||
0xFE: [100000000, 1100000000, 17, "(Band capabilities unknown)", None, "Unknown"],
|
0xFE: [100000000, 1100000000, 17, "(Band capabilities unknown)", None, "Unknown"],
|
||||||
0xFF: [100000000, 1100000000, 14, "(Band capabilities unknown)", None, "Unknown"],
|
0xFF: [100000000, 1100000000, 14, "(Band capabilities unknown)", None, "Unknown"],
|
||||||
}
|
}
|
||||||
@ -1603,6 +1611,7 @@ def main():
|
|||||||
print("[8] Heltec LoRa32 v3")
|
print("[8] Heltec LoRa32 v3")
|
||||||
print("[9] LilyGO LoRa T3S3")
|
print("[9] LilyGO LoRa T3S3")
|
||||||
print("[10] RAK4631")
|
print("[10] RAK4631")
|
||||||
|
print("[11] LilyGo T-Echo")
|
||||||
print(" .")
|
print(" .")
|
||||||
print(" / \\ Select one of these options if you want to easily turn")
|
print(" / \\ Select one of these options if you want to easily turn")
|
||||||
print(" | a supported development board into an RNode.")
|
print(" | a supported development board into an RNode.")
|
||||||
@ -1614,7 +1623,7 @@ def main():
|
|||||||
try:
|
try:
|
||||||
c_dev = int(input())
|
c_dev = int(input())
|
||||||
c_mod = False
|
c_mod = False
|
||||||
if c_dev < 1 or c_dev > 10:
|
if c_dev < 1 or c_dev > 11:
|
||||||
raise ValueError()
|
raise ValueError()
|
||||||
elif c_dev == 1:
|
elif c_dev == 1:
|
||||||
selected_product = ROM.PRODUCT_RNODE
|
selected_product = ROM.PRODUCT_RNODE
|
||||||
@ -1756,6 +1765,19 @@ def main():
|
|||||||
print("who would like to experiment with it. Hit enter to continue.")
|
print("who would like to experiment with it. Hit enter to continue.")
|
||||||
print("---------------------------------------------------------------------------")
|
print("---------------------------------------------------------------------------")
|
||||||
input()
|
input()
|
||||||
|
elif c_dev == 11:
|
||||||
|
selected_product = ROM.PRODUCT_TECHO
|
||||||
|
clear()
|
||||||
|
print("")
|
||||||
|
print("---------------------------------------------------------------------------")
|
||||||
|
print(" LilyGo T-Echo RNode Installer")
|
||||||
|
print("")
|
||||||
|
print("Important! Using RNode firmware on LilyGo T-Echo devices should currently be")
|
||||||
|
print("considered experimental. It is not intended for production or critical use.")
|
||||||
|
print("The currently supplied firmware is provided AS-IS as a courtesey to those")
|
||||||
|
print("who would like to experiment with it. Hit enter to continue.")
|
||||||
|
print("---------------------------------------------------------------------------")
|
||||||
|
input()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print("That device type does not exist, exiting now.")
|
print("That device type does not exist, exiting now.")
|
||||||
graceful_exit()
|
graceful_exit()
|
||||||
@ -2042,6 +2064,27 @@ def main():
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
print("That band does not exist, exiting now.")
|
print("That band does not exist, exiting now.")
|
||||||
graceful_exit()
|
graceful_exit()
|
||||||
|
elif selected_product == ROM.PRODUCT_TECHO:
|
||||||
|
selected_mcu = ROM.MCU_NRF52
|
||||||
|
print("\nWhat band is this T-Echo for?\n")
|
||||||
|
print("[1] 433 MHz")
|
||||||
|
print("[2] 868 MHz")
|
||||||
|
print("[3] 915 MHz")
|
||||||
|
print("[4] 923 MHz")
|
||||||
|
print("\n? ", end="")
|
||||||
|
try:
|
||||||
|
c_model = int(input())
|
||||||
|
if c_model < 1 or c_model > 1:
|
||||||
|
raise ValueError()
|
||||||
|
elif c_model == 1:
|
||||||
|
selected_model = ROM.MODEL_T4
|
||||||
|
selected_platform = ROM.PLATFORM_NRF52
|
||||||
|
elif c_model > 1:
|
||||||
|
selected_model = ROM.MODEL_T9
|
||||||
|
selected_platform = ROM.PLATFORM_NRF52
|
||||||
|
except Exception as e:
|
||||||
|
print("That band does not exist, exiting now.")
|
||||||
|
graceful_exit()
|
||||||
|
|
||||||
if selected_model != ROM.MODEL_FF and selected_model != ROM.MODEL_FE:
|
if selected_model != ROM.MODEL_FF and selected_model != ROM.MODEL_FE:
|
||||||
fw_filename = models[selected_model][4]
|
fw_filename = models[selected_model][4]
|
||||||
|
@ -15,6 +15,9 @@ This document outlines the currently established development roadmap for Reticul
|
|||||||
For each release cycle of Reticulum, improvements and additions from the five [Primary Efforts](#primary-efforts) are selected as active work areas, and can be expected to be included in the upcoming releases within that cycle. While not entirely set in stone for each release cycle, they serve as a pointer of what to expect in the near future.
|
For each release cycle of Reticulum, improvements and additions from the five [Primary Efforts](#primary-efforts) are selected as active work areas, and can be expected to be included in the upcoming releases within that cycle. While not entirely set in stone for each release cycle, they serve as a pointer of what to expect in the near future.
|
||||||
|
|
||||||
- The current `0.7.x` release cycle aims at completing
|
- The current `0.7.x` release cycle aims at completing
|
||||||
|
- [x] Automatic asynchronous key ratcheting for non-link traffic
|
||||||
|
- [ ] API improvements based on real-world usage and feedback
|
||||||
|
- [ ] Expanded hardware support
|
||||||
- [ ] Overhauling and updating the documentation
|
- [ ] Overhauling and updating the documentation
|
||||||
- [ ] Distributed Destination Naming System
|
- [ ] Distributed Destination Naming System
|
||||||
- [ ] Create a standalone RNS Daemon app for Android
|
- [ ] Create a standalone RNS Daemon app for Android
|
||||||
|
Binary file not shown.
Binary file not shown.
@ -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>
|
||||||
|
|
||||||
|
Binary file not shown.
@ -417,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>
|
||||||
@ -431,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>
|
||||||
@ -445,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>
|
||||||
@ -563,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>, <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><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>
|
||||||
@ -2058,6 +2072,7 @@ will announce it.</p>
|
|||||||
<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>
|
||||||
|
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user