Migrated all asymmetric crypto operations to ECIES on Curve25519.
This commit is contained in:
		
							parent
							
								
									7f5625a526
								
							
						
					
					
						commit
						ce405b9252
					
				@ -39,7 +39,7 @@ def program_setup(configpath, channel=None):
 | 
			
		||||
 | 
			
		||||
    # We specify a callback that will get called every time
 | 
			
		||||
    # the destination receives data.
 | 
			
		||||
    broadcast_destination.packet_callback(packet_callback)
 | 
			
		||||
    broadcast_destination.set_packet_callback(packet_callback)
 | 
			
		||||
    
 | 
			
		||||
    # Everything's ready!
 | 
			
		||||
    # Let's hand over control to the main loop
 | 
			
		||||
 | 
			
		||||
@ -52,7 +52,7 @@ def server(configpath):
 | 
			
		||||
    # 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.packet_callback(server_callback)
 | 
			
		||||
    echo_destination.set_packet_callback(server_callback)
 | 
			
		||||
 | 
			
		||||
    # Everything's ready!
 | 
			
		||||
    # Let's Wait for client requests or user input
 | 
			
		||||
@ -175,7 +175,7 @@ def client(destination_hexhash, configpath, timeout=None):
 | 
			
		||||
            # 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.delivery_callback(packet_delivered)
 | 
			
		||||
            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))
 | 
			
		||||
@ -189,7 +189,7 @@ def client(destination_hexhash, configpath, timeout=None):
 | 
			
		||||
# receives a proof packet.
 | 
			
		||||
def packet_delivered(receipt):
 | 
			
		||||
    if receipt.status == RNS.PacketReceipt.DELIVERED:
 | 
			
		||||
        rtt = receipt.rtt()
 | 
			
		||||
        rtt = receipt.get_rtt()
 | 
			
		||||
        if (rtt >= 1):
 | 
			
		||||
            rtt = round(rtt, 3)
 | 
			
		||||
            rttstring = str(rtt)+" seconds"
 | 
			
		||||
 | 
			
		||||
@ -65,7 +65,7 @@ def server(configpath, path):
 | 
			
		||||
 | 
			
		||||
    # We configure a function that will get called every time
 | 
			
		||||
    # a new client creates a link to this destination.
 | 
			
		||||
    server_destination.link_established_callback(client_connected)
 | 
			
		||||
    server_destination.set_link_established_callback(client_connected)
 | 
			
		||||
 | 
			
		||||
    # Everything's ready!
 | 
			
		||||
    # Let's Wait for client requests or user input
 | 
			
		||||
@ -102,7 +102,7 @@ def client_connected(link):
 | 
			
		||||
    if os.path.isdir(serve_path):
 | 
			
		||||
        RNS.log("Client connected, sending file list...")
 | 
			
		||||
 | 
			
		||||
        link.link_closed_callback(client_disconnected)
 | 
			
		||||
        link.set_link_closed_callback(client_disconnected)
 | 
			
		||||
 | 
			
		||||
        # We pack a list of files for sending in a packet
 | 
			
		||||
        data = umsgpack.packb(list_files())
 | 
			
		||||
@ -114,7 +114,7 @@ def client_connected(link):
 | 
			
		||||
            list_packet = RNS.Packet(link, data)
 | 
			
		||||
            list_receipt = list_packet.send()
 | 
			
		||||
            list_receipt.set_timeout(APP_TIMEOUT)
 | 
			
		||||
            list_receipt.delivery_callback(list_delivered)
 | 
			
		||||
            list_receipt.set_delivery_callback(list_delivered)
 | 
			
		||||
            list_receipt.timeout_callback(list_timeout)
 | 
			
		||||
        else:
 | 
			
		||||
            RNS.log("Too many files in served directory!", RNS.LOG_ERROR)
 | 
			
		||||
@ -125,7 +125,7 @@ def client_connected(link):
 | 
			
		||||
        # open until the client requests a file. We'll
 | 
			
		||||
        # configure a function that get's called when
 | 
			
		||||
        # the client sends a packet with a file request.
 | 
			
		||||
        link.packet_callback(client_request)
 | 
			
		||||
        link.set_packet_callback(client_request)
 | 
			
		||||
    else:
 | 
			
		||||
        RNS.log("Client connected, but served path no longer exists!", RNS.LOG_ERROR)
 | 
			
		||||
        link.teardown()
 | 
			
		||||
@ -254,18 +254,18 @@ def client(destination_hexhash, configpath):
 | 
			
		||||
    # We expect any normal data packets on the link
 | 
			
		||||
    # to contain a list of served files, so we set
 | 
			
		||||
    # a callback accordingly
 | 
			
		||||
    link.packet_callback(filelist_received)
 | 
			
		||||
    link.set_packet_callback(filelist_received)
 | 
			
		||||
 | 
			
		||||
    # We'll also set up functions to inform the
 | 
			
		||||
    # user when the link is established or closed
 | 
			
		||||
    link.link_established_callback(link_established)
 | 
			
		||||
    link.link_closed_callback(link_closed)
 | 
			
		||||
    link.set_link_established_callback(link_established)
 | 
			
		||||
    link.set_link_closed_callback(link_closed)
 | 
			
		||||
 | 
			
		||||
    # And set the link to automatically begin
 | 
			
		||||
    # downloading advertised resources
 | 
			
		||||
    link.set_resource_strategy(RNS.Link.ACCEPT_ALL)
 | 
			
		||||
    link.resource_started_callback(download_began)
 | 
			
		||||
    link.resource_concluded_callback(download_concluded)
 | 
			
		||||
    link.set_resource_started_callback(download_began)
 | 
			
		||||
    link.set_resource_concluded_callback(download_concluded)
 | 
			
		||||
 | 
			
		||||
    menu()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -44,7 +44,7 @@ def server(configpath):
 | 
			
		||||
 | 
			
		||||
    # We configure a function that will get called every time
 | 
			
		||||
    # a new client creates a link to this destination.
 | 
			
		||||
    server_destination.link_established_callback(client_connected)
 | 
			
		||||
    server_destination.set_link_established_callback(client_connected)
 | 
			
		||||
 | 
			
		||||
    # Everything's ready!
 | 
			
		||||
    # Let's Wait for client requests or user input
 | 
			
		||||
@ -76,8 +76,8 @@ def client_connected(link):
 | 
			
		||||
    global latest_client_link
 | 
			
		||||
 | 
			
		||||
    RNS.log("Client connected")
 | 
			
		||||
    link.link_closed_callback(client_disconnected)
 | 
			
		||||
    link.packet_callback(server_packet_received)
 | 
			
		||||
    link.set_link_closed_callback(client_disconnected)
 | 
			
		||||
    link.set_packet_callback(server_packet_received)
 | 
			
		||||
    latest_client_link = link
 | 
			
		||||
 | 
			
		||||
def client_disconnected(link):
 | 
			
		||||
@ -149,12 +149,12 @@ def client(destination_hexhash, configpath):
 | 
			
		||||
    # We set a callback that will get executed
 | 
			
		||||
    # every time a packet is received over the
 | 
			
		||||
    # link
 | 
			
		||||
    link.packet_callback(client_packet_received)
 | 
			
		||||
    link.set_packet_callback(client_packet_received)
 | 
			
		||||
 | 
			
		||||
    # We'll also set up functions to inform the
 | 
			
		||||
    # user when the link is established or closed
 | 
			
		||||
    link.link_established_callback(link_established)
 | 
			
		||||
    link.link_closed_callback(link_closed)
 | 
			
		||||
    link.set_link_established_callback(link_established)
 | 
			
		||||
    link.set_link_closed_callback(link_closed)
 | 
			
		||||
 | 
			
		||||
    # Everything is set up, so let's enter a loop
 | 
			
		||||
    # for the user to interact with the example
 | 
			
		||||
 | 
			
		||||
@ -133,8 +133,8 @@ class Destination:
 | 
			
		||||
 | 
			
		||||
    def announce(self, app_data=None, path_response=False):
 | 
			
		||||
        """
 | 
			
		||||
        Creates an announce packet for this destination and broadcasts it on
 | 
			
		||||
        all interfaces. Application specific data can be added to the announce.
 | 
			
		||||
        Creates an announce packet for this destination and broadcasts it on all
 | 
			
		||||
        relevant interfaces. Application specific data can be added to the announce.
 | 
			
		||||
 | 
			
		||||
        :param app_data: *bytes* containing the app_data.
 | 
			
		||||
        :param path_response: Internal flag used by :ref:`RNS.Transport<api-transport>`. Ignore.
 | 
			
		||||
@ -172,7 +172,7 @@ class Destination:
 | 
			
		||||
        RNS.Packet(self, announce_data, RNS.Packet.ANNOUNCE, context = announce_context).send()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    def link_established_callback(self, callback):
 | 
			
		||||
    def set_link_established_callback(self, callback):
 | 
			
		||||
        """
 | 
			
		||||
        Registers a function to be called when a link has been established to
 | 
			
		||||
        this destination.
 | 
			
		||||
@ -181,7 +181,7 @@ class Destination:
 | 
			
		||||
        """
 | 
			
		||||
        self.callbacks.link_established = callback
 | 
			
		||||
 | 
			
		||||
    def packet_callback(self, callback):
 | 
			
		||||
    def set_packet_callback(self, callback):
 | 
			
		||||
        """
 | 
			
		||||
        Registers a function to be called when a packet has been received by
 | 
			
		||||
        this destination.
 | 
			
		||||
@ -190,7 +190,7 @@ class Destination:
 | 
			
		||||
        """
 | 
			
		||||
        self.callbacks.packet = callback
 | 
			
		||||
 | 
			
		||||
    def proof_requested_callback(self, callback):
 | 
			
		||||
    def set_proof_requested_callback(self, callback):
 | 
			
		||||
        """
 | 
			
		||||
        Registers a function to be called when a proof has been requested for
 | 
			
		||||
        a packet sent to this destination. Allows control over when and if
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										289
									
								
								RNS/Identity.py
									
									
									
									
									
								
							
							
						
						
									
										289
									
								
								RNS/Identity.py
									
									
									
									
									
								
							@ -4,14 +4,15 @@ import os
 | 
			
		||||
import RNS
 | 
			
		||||
import time
 | 
			
		||||
import atexit
 | 
			
		||||
import base64
 | 
			
		||||
from .vendor import umsgpack as umsgpack
 | 
			
		||||
from cryptography.hazmat.primitives import hashes
 | 
			
		||||
from cryptography.hazmat.backends import default_backend
 | 
			
		||||
from cryptography.hazmat.primitives import hashes
 | 
			
		||||
from cryptography.hazmat.primitives import serialization
 | 
			
		||||
from cryptography.hazmat.primitives.serialization import load_der_public_key
 | 
			
		||||
from cryptography.hazmat.primitives.serialization import load_der_private_key
 | 
			
		||||
from cryptography.hazmat.primitives.asymmetric import rsa
 | 
			
		||||
from cryptography.hazmat.primitives.asymmetric import padding
 | 
			
		||||
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey, Ed25519PublicKey
 | 
			
		||||
from cryptography.hazmat.primitives.asymmetric.x25519 import X25519PrivateKey, X25519PublicKey
 | 
			
		||||
from cryptography.hazmat.primitives.kdf.hkdf import HKDF
 | 
			
		||||
from cryptography.fernet import Fernet
 | 
			
		||||
 | 
			
		||||
class Identity:
 | 
			
		||||
    """
 | 
			
		||||
@ -19,26 +20,29 @@ class Identity:
 | 
			
		||||
    for encryption, decryption, signatures and verification, and is the basis
 | 
			
		||||
    for all encrypted communication over Reticulum networks.
 | 
			
		||||
 | 
			
		||||
    :param public_only: Specifies whether this destination only holds a public key.
 | 
			
		||||
    :param create_keys: Specifies whether new encryption and signing keys should be generated.
 | 
			
		||||
    """
 | 
			
		||||
    KEYSIZE     = 1024
 | 
			
		||||
 | 
			
		||||
    CURVE = "Curve25519"
 | 
			
		||||
    """
 | 
			
		||||
    RSA key size in bits.
 | 
			
		||||
    The curve used for Elliptic Curve DH key exchanges
 | 
			
		||||
    """
 | 
			
		||||
 | 
			
		||||
    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.
 | 
			
		||||
    """   
 | 
			
		||||
    DERKEYSIZE  = KEYSIZE+272
 | 
			
		||||
 | 
			
		||||
    # Non-configurable constants
 | 
			
		||||
    PADDINGSIZE = 336       # In bits
 | 
			
		||||
    HASHLENGTH  = 256       # In bits
 | 
			
		||||
    SIGLENGTH   = KEYSIZE
 | 
			
		||||
 | 
			
		||||
    ENCRYPT_CHUNKSIZE = (KEYSIZE-PADDINGSIZE)//8
 | 
			
		||||
    DECRYPT_CHUNKSIZE = KEYSIZE//8
 | 
			
		||||
    AES_HMAC_OVERHEAD = 58    # In bytes
 | 
			
		||||
    AES128_BLOCKSIZE = 16     # In bytes
 | 
			
		||||
    HASHLENGTH  = 256         # In bits
 | 
			
		||||
    SIGLENGTH   = KEYSIZE     # In bits
 | 
			
		||||
 | 
			
		||||
    TRUNCATED_HASHLENGTH = 80 # In bits
 | 
			
		||||
    """
 | 
			
		||||
    Constant specifying the truncated hash length (in bits) used by Reticulum
 | 
			
		||||
    for addressable hashes. Non-configurable.
 | 
			
		||||
    for addressable hashes and other purposes. Non-configurable.
 | 
			
		||||
    """
 | 
			
		||||
 | 
			
		||||
    # Storage
 | 
			
		||||
@ -60,7 +64,7 @@ class Identity:
 | 
			
		||||
        RNS.log("Searching for "+RNS.prettyhexrep(destination_hash)+"...", RNS.LOG_EXTREME)
 | 
			
		||||
        if destination_hash in Identity.known_destinations:
 | 
			
		||||
            identity_data = Identity.known_destinations[destination_hash]
 | 
			
		||||
            identity = Identity(public_only=True)
 | 
			
		||||
            identity = Identity(create_keys=False)
 | 
			
		||||
            identity.load_public_key(identity_data[2])
 | 
			
		||||
            identity.app_data = identity_data[3]
 | 
			
		||||
            RNS.log("Found "+RNS.prettyhexrep(destination_hash)+" in known destinations", RNS.LOG_EXTREME)
 | 
			
		||||
@ -145,19 +149,19 @@ class Identity:
 | 
			
		||||
        if packet.packet_type == RNS.Packet.ANNOUNCE:
 | 
			
		||||
            RNS.log("Validating announce from "+RNS.prettyhexrep(packet.destination_hash), RNS.LOG_DEBUG)
 | 
			
		||||
            destination_hash = packet.destination_hash
 | 
			
		||||
            public_key = packet.data[10:Identity.DERKEYSIZE//8+10]
 | 
			
		||||
            random_hash = packet.data[Identity.DERKEYSIZE//8+10:Identity.DERKEYSIZE//8+20]
 | 
			
		||||
            signature = packet.data[Identity.DERKEYSIZE//8+20:Identity.DERKEYSIZE//8+20+Identity.KEYSIZE//8]
 | 
			
		||||
            public_key = packet.data[10:Identity.KEYSIZE//8+10]
 | 
			
		||||
            random_hash = packet.data[Identity.KEYSIZE//8+10:Identity.KEYSIZE//8+20]
 | 
			
		||||
            signature = packet.data[Identity.KEYSIZE//8+20:Identity.KEYSIZE//8+20+Identity.KEYSIZE//8]
 | 
			
		||||
            app_data = b""
 | 
			
		||||
            if len(packet.data) > Identity.DERKEYSIZE//8+20+Identity.KEYSIZE//8:
 | 
			
		||||
                app_data = packet.data[Identity.DERKEYSIZE//8+20+Identity.KEYSIZE//8:]
 | 
			
		||||
            if len(packet.data) > Identity.KEYSIZE//8+20+Identity.KEYSIZE//8:
 | 
			
		||||
                app_data = packet.data[Identity.KEYSIZE//8+20+Identity.KEYSIZE//8:]
 | 
			
		||||
 | 
			
		||||
            signed_data = destination_hash+public_key+random_hash+app_data
 | 
			
		||||
 | 
			
		||||
            if not len(packet.data) > Identity.DERKEYSIZE//8+20+Identity.KEYSIZE//8:
 | 
			
		||||
            if not len(packet.data) > Identity.KEYSIZE//8+20+Identity.KEYSIZE//8:
 | 
			
		||||
                app_data = None
 | 
			
		||||
 | 
			
		||||
            announced_identity = Identity(public_only=True)
 | 
			
		||||
            announced_identity = Identity(create_keys=False)
 | 
			
		||||
            announced_identity.load_public_key(public_key)
 | 
			
		||||
 | 
			
		||||
            if announced_identity.pub != None and announced_identity.validate(signature, signed_data):
 | 
			
		||||
@ -184,40 +188,71 @@ class Identity:
 | 
			
		||||
        :param path: The full path to the saved :ref:`RNS.Identity<api-identity>` data
 | 
			
		||||
        :returns: A :ref:`RNS.Identity<api-identity>` instance, or *None* if the loaded data was invalid.
 | 
			
		||||
        """
 | 
			
		||||
        identity = Identity(public_only=True)
 | 
			
		||||
        identity = Identity(create_keys=False)
 | 
			
		||||
        if identity.load(path):
 | 
			
		||||
            return identity
 | 
			
		||||
        else:
 | 
			
		||||
            return None
 | 
			
		||||
 | 
			
		||||
    @staticmethod
 | 
			
		||||
    def from_bytes(prv_bytes):
 | 
			
		||||
        """
 | 
			
		||||
        Create a new :ref:`RNS.Identity<api-identity>` instance from *bytes* of private key.
 | 
			
		||||
        Can be used to load previously created and saved identities into Reticulum.
 | 
			
		||||
 | 
			
		||||
    def __init__(self,public_only=False):
 | 
			
		||||
        :param prv_bytes: The *bytes* of private a saved private key. **HAZARD!** Never not use this to generate a new key by feeding random data in prv_bytes.
 | 
			
		||||
        :returns: A :ref:`RNS.Identity<api-identity>` instance, or *None* if the *bytes* data was invalid.
 | 
			
		||||
        """
 | 
			
		||||
        identity = Identity(create_keys=False)
 | 
			
		||||
        if identity.load_private_key(prv_bytes):
 | 
			
		||||
            return identity
 | 
			
		||||
        else:
 | 
			
		||||
            return None
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    def __init__(self,create_keys=True):
 | 
			
		||||
        # Initialize keys to none
 | 
			
		||||
        self.prv = None
 | 
			
		||||
        self.pub = None
 | 
			
		||||
        self.prv_bytes = None
 | 
			
		||||
        self.pub_bytes = None
 | 
			
		||||
        self.hash = None
 | 
			
		||||
        self.hexhash = None
 | 
			
		||||
        self.prv           = None
 | 
			
		||||
        self.prv_bytes     = None
 | 
			
		||||
        self.sig_prv       = None
 | 
			
		||||
        self.sig_prv_bytes = None
 | 
			
		||||
 | 
			
		||||
        if not public_only:
 | 
			
		||||
        self.pub           = None
 | 
			
		||||
        self.pub_bytes     = None
 | 
			
		||||
        self.sig_pub       = None
 | 
			
		||||
        self.sig_pub_bytes = None
 | 
			
		||||
 | 
			
		||||
        self.hash          = None
 | 
			
		||||
        self.hexhash       = None
 | 
			
		||||
 | 
			
		||||
        if create_keys:
 | 
			
		||||
            self.create_keys()
 | 
			
		||||
 | 
			
		||||
    def create_keys(self):
 | 
			
		||||
        self.prv = rsa.generate_private_key(
 | 
			
		||||
            public_exponent=65537,
 | 
			
		||||
            key_size=Identity.KEYSIZE,
 | 
			
		||||
            backend=default_backend()
 | 
			
		||||
        )
 | 
			
		||||
        self.prv_bytes = self.prv.private_bytes(
 | 
			
		||||
            encoding=serialization.Encoding.DER,
 | 
			
		||||
            format=serialization.PrivateFormat.PKCS8,
 | 
			
		||||
        self.prv           = X25519PrivateKey.generate()
 | 
			
		||||
        self.prv_bytes     = self.prv.private_bytes(
 | 
			
		||||
            encoding=serialization.Encoding.Raw,
 | 
			
		||||
            format=serialization.PrivateFormat.Raw,
 | 
			
		||||
            encryption_algorithm=serialization.NoEncryption()
 | 
			
		||||
        )
 | 
			
		||||
        self.pub = self.prv.public_key()
 | 
			
		||||
        self.pub_bytes = self.pub.public_bytes(
 | 
			
		||||
            encoding=serialization.Encoding.DER,
 | 
			
		||||
            format=serialization.PublicFormat.SubjectPublicKeyInfo
 | 
			
		||||
 | 
			
		||||
        self.sig_prv       = Ed25519PrivateKey.generate()
 | 
			
		||||
        self.sig_prv_bytes = self.sig_prv.private_bytes(
 | 
			
		||||
            encoding=serialization.Encoding.Raw,
 | 
			
		||||
            format=serialization.PrivateFormat.Raw,
 | 
			
		||||
            encryption_algorithm=serialization.NoEncryption()
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        self.pub           = self.prv.public_key()
 | 
			
		||||
        self.pub_bytes     = self.pub.public_bytes(
 | 
			
		||||
            encoding=serialization.Encoding.Raw,
 | 
			
		||||
            format=serialization.PublicFormat.Raw
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        self.sig_pub       = self.sig_prv.public_key()
 | 
			
		||||
        self.sig_pub_bytes = self.sig_pub.public_bytes(
 | 
			
		||||
            encoding=serialization.Encoding.Raw,
 | 
			
		||||
            format=serialization.PublicFormat.Raw
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        self.update_hashes()
 | 
			
		||||
@ -228,13 +263,13 @@ class Identity:
 | 
			
		||||
        """
 | 
			
		||||
        :returns: The private key as *bytes*
 | 
			
		||||
        """
 | 
			
		||||
        return self.prv_bytes
 | 
			
		||||
        return self.prv_bytes+self.sig_prv_bytes
 | 
			
		||||
 | 
			
		||||
    def get_public_key(self):
 | 
			
		||||
        """
 | 
			
		||||
        :returns: The public key as *bytes*
 | 
			
		||||
        """
 | 
			
		||||
        return self.pub_bytes
 | 
			
		||||
        return self.pub_bytes+self.sig_pub_bytes
 | 
			
		||||
 | 
			
		||||
    def load_private_key(self, prv_bytes):
 | 
			
		||||
        """
 | 
			
		||||
@ -244,42 +279,53 @@ class Identity:
 | 
			
		||||
        :returns: True if the key was loaded, otherwise False.
 | 
			
		||||
        """
 | 
			
		||||
        try:
 | 
			
		||||
            self.prv_bytes = prv_bytes
 | 
			
		||||
            self.prv = serialization.load_der_private_key(
 | 
			
		||||
                self.prv_bytes,
 | 
			
		||||
                password=None,
 | 
			
		||||
                backend=default_backend()
 | 
			
		||||
            self.prv_bytes     = prv_bytes[:Identity.KEYSIZE//8//2]
 | 
			
		||||
            self.prv           = X25519PrivateKey.from_private_bytes(self.prv_bytes)
 | 
			
		||||
            self.sig_prv_bytes = prv_bytes[Identity.KEYSIZE//8//2:]
 | 
			
		||||
            self.sig_prv       = Ed25519PrivateKey.from_private_bytes(self.sig_prv_bytes)
 | 
			
		||||
            
 | 
			
		||||
            self.pub           = self.prv.public_key()
 | 
			
		||||
            self.pub_bytes     = self.pub.public_bytes(
 | 
			
		||||
                encoding=serialization.Encoding.Raw,
 | 
			
		||||
                format=serialization.PublicFormat.Raw
 | 
			
		||||
            )
 | 
			
		||||
            self.pub = self.prv.public_key()
 | 
			
		||||
            self.pub_bytes = self.pub.public_bytes(
 | 
			
		||||
                encoding=serialization.Encoding.DER,
 | 
			
		||||
                format=serialization.PublicFormat.SubjectPublicKeyInfo
 | 
			
		||||
 | 
			
		||||
            self.sig_pub       = self.sig_prv.public_key()
 | 
			
		||||
            self.sig_pub_bytes = self.sig_pub.public_bytes(
 | 
			
		||||
                encoding=serialization.Encoding.Raw,
 | 
			
		||||
                format=serialization.PublicFormat.Raw
 | 
			
		||||
            )
 | 
			
		||||
 | 
			
		||||
            self.update_hashes()
 | 
			
		||||
 | 
			
		||||
            return True
 | 
			
		||||
 | 
			
		||||
        except Exception as e:
 | 
			
		||||
            raise e
 | 
			
		||||
            RNS.log("Failed to load identity key", RNS.LOG_ERROR)
 | 
			
		||||
            RNS.log("The contained exception was: "+str(e), RNS.LOG_ERROR)
 | 
			
		||||
            return False
 | 
			
		||||
 | 
			
		||||
    def load_public_key(self, key):
 | 
			
		||||
    def load_public_key(self, pub_bytes):
 | 
			
		||||
        """
 | 
			
		||||
        Load a public key into the instance.
 | 
			
		||||
 | 
			
		||||
        :param prv_bytes: The public key as *bytes*.
 | 
			
		||||
        :param pub_bytes: The public key as *bytes*.
 | 
			
		||||
        :returns: True if the key was loaded, otherwise False.
 | 
			
		||||
        """
 | 
			
		||||
        try:
 | 
			
		||||
            self.pub_bytes = key
 | 
			
		||||
            self.pub = load_der_public_key(self.pub_bytes, backend=default_backend())
 | 
			
		||||
            self.pub_bytes     = pub_bytes[:Identity.KEYSIZE//8//2]
 | 
			
		||||
            self.sig_pub_bytes = pub_bytes[Identity.KEYSIZE//8//2:]
 | 
			
		||||
 | 
			
		||||
            self.pub           = X25519PublicKey.from_public_bytes(self.pub_bytes)
 | 
			
		||||
            self.sig_pub       = Ed25519PublicKey.from_public_bytes(self.sig_pub_bytes)
 | 
			
		||||
 | 
			
		||||
            self.update_hashes()
 | 
			
		||||
        except Exception as e:
 | 
			
		||||
            RNS.log("Error while loading public key, the contained exception was: "+str(e), RNS.LOG_ERROR)
 | 
			
		||||
 | 
			
		||||
    def update_hashes(self):
 | 
			
		||||
        self.hash = Identity.truncated_hash(self.pub_bytes)
 | 
			
		||||
        self.hash = Identity.truncated_hash(self.get_public_key())
 | 
			
		||||
        self.hexhash = self.hash.hex()
 | 
			
		||||
 | 
			
		||||
    def to_file(self, path):
 | 
			
		||||
@ -310,71 +356,78 @@ class Identity:
 | 
			
		||||
            RNS.log("Error while loading identity from "+str(path), RNS.LOG_ERROR)
 | 
			
		||||
            RNS.log("The contained exception was: "+str(e))
 | 
			
		||||
 | 
			
		||||
    def get_salt(self):
 | 
			
		||||
        return self.hash
 | 
			
		||||
 | 
			
		||||
    def get_context(self):
 | 
			
		||||
        return None
 | 
			
		||||
 | 
			
		||||
    def encrypt(self, plaintext):
 | 
			
		||||
        """
 | 
			
		||||
        Encrypts information for the identity.
 | 
			
		||||
 | 
			
		||||
        :param plaintext: The plaintext to be encrypted as *bytes*.
 | 
			
		||||
        :returns: Ciphertext as *bytes*.
 | 
			
		||||
        :raises: *KeyError* if the instance does not hold a public key
 | 
			
		||||
        :returns: Ciphertext token as *bytes*.
 | 
			
		||||
        :raises: *KeyError* if the instance does not hold a public key.
 | 
			
		||||
        """
 | 
			
		||||
        if self.pub != None:
 | 
			
		||||
            chunksize = Identity.ENCRYPT_CHUNKSIZE
 | 
			
		||||
            chunks = int(math.ceil(len(plaintext)/(float(chunksize))))
 | 
			
		||||
            ephemeral_key = X25519PrivateKey.generate()
 | 
			
		||||
            ephemeral_pub_bytes = ephemeral_key.public_key().public_bytes(
 | 
			
		||||
                encoding=serialization.Encoding.Raw,
 | 
			
		||||
                format=serialization.PublicFormat.Raw
 | 
			
		||||
            )
 | 
			
		||||
 | 
			
		||||
            ciphertext = b"";
 | 
			
		||||
            for chunk in range(chunks):
 | 
			
		||||
                start = chunk*chunksize
 | 
			
		||||
                end = (chunk+1)*chunksize
 | 
			
		||||
                if (chunk+1)*chunksize > len(plaintext):
 | 
			
		||||
                    end = len(plaintext)
 | 
			
		||||
            shared_key = ephemeral_key.exchange(self.pub)
 | 
			
		||||
            derived_key = derived_key = HKDF(
 | 
			
		||||
                algorithm=hashes.SHA256(),
 | 
			
		||||
                length=32,
 | 
			
		||||
                salt=self.get_salt(),
 | 
			
		||||
                info=self.get_context(),
 | 
			
		||||
            ).derive(shared_key)
 | 
			
		||||
 | 
			
		||||
                ciphertext += self.pub.encrypt(
 | 
			
		||||
                    plaintext[start:end],
 | 
			
		||||
                    padding.OAEP(
 | 
			
		||||
                        mgf=padding.MGF1(algorithm=hashes.SHA1()),
 | 
			
		||||
                        algorithm=hashes.SHA1(),
 | 
			
		||||
                        label=None
 | 
			
		||||
                    )
 | 
			
		||||
                )
 | 
			
		||||
            return ciphertext
 | 
			
		||||
            fernet = Fernet(base64.urlsafe_b64encode(derived_key))
 | 
			
		||||
            ciphertext = base64.urlsafe_b64decode(fernet.encrypt(plaintext))
 | 
			
		||||
            token = ephemeral_pub_bytes+ciphertext
 | 
			
		||||
 | 
			
		||||
            return token
 | 
			
		||||
        else:
 | 
			
		||||
            raise KeyError("Encryption failed because identity does not hold a public key")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    def decrypt(self, ciphertext):
 | 
			
		||||
    def decrypt(self, ciphertext_token):
 | 
			
		||||
        """
 | 
			
		||||
        Decrypts information for the identity.
 | 
			
		||||
 | 
			
		||||
        :param ciphertext: The ciphertext to be decrypted as *bytes*.
 | 
			
		||||
        :returns: Plaintext as *bytes*, or *None* if decryption fails.
 | 
			
		||||
        :raises: *KeyError* if the instance does not hold a private key
 | 
			
		||||
        :raises: *KeyError* if the instance does not hold a private key.
 | 
			
		||||
        """
 | 
			
		||||
        if self.prv != None:
 | 
			
		||||
            plaintext = None
 | 
			
		||||
            try:
 | 
			
		||||
                chunksize = Identity.DECRYPT_CHUNKSIZE
 | 
			
		||||
                chunks = int(math.ceil(len(ciphertext)/(float(chunksize))))
 | 
			
		||||
            if len(ciphertext_token) > Identity.KEYSIZE//8//2:
 | 
			
		||||
                plaintext = None
 | 
			
		||||
                try:
 | 
			
		||||
                    peer_pub_bytes = ciphertext_token[:Identity.KEYSIZE//8//2]
 | 
			
		||||
                    peer_pub = X25519PublicKey.from_public_bytes(peer_pub_bytes)
 | 
			
		||||
 | 
			
		||||
                plaintext = b"";
 | 
			
		||||
                for chunk in range(chunks):
 | 
			
		||||
                    start = chunk*chunksize
 | 
			
		||||
                    end = (chunk+1)*chunksize
 | 
			
		||||
                    if (chunk+1)*chunksize > len(ciphertext):
 | 
			
		||||
                        end = len(ciphertext)
 | 
			
		||||
                    shared_key = self.prv.exchange(peer_pub)
 | 
			
		||||
                    derived_key = derived_key = HKDF(
 | 
			
		||||
                        algorithm=hashes.SHA256(),
 | 
			
		||||
                        length=32,
 | 
			
		||||
                        salt=self.get_salt(),
 | 
			
		||||
                        info=self.get_context(),
 | 
			
		||||
                    ).derive(shared_key)
 | 
			
		||||
 | 
			
		||||
                    plaintext += self.prv.decrypt(
 | 
			
		||||
                        ciphertext[start:end],
 | 
			
		||||
                        padding.OAEP(
 | 
			
		||||
                            mgf=padding.MGF1(algorithm=hashes.SHA1()),
 | 
			
		||||
                            algorithm=hashes.SHA1(),
 | 
			
		||||
                            label=None
 | 
			
		||||
                        )
 | 
			
		||||
                    )
 | 
			
		||||
            except:
 | 
			
		||||
                RNS.log("Decryption by "+RNS.prettyhexrep(self.hash)+" failed", RNS.LOG_VERBOSE)
 | 
			
		||||
                    fernet = Fernet(base64.urlsafe_b64encode(derived_key))
 | 
			
		||||
                    ciphertext = ciphertext_token[Identity.KEYSIZE//8//2:]
 | 
			
		||||
                    plaintext = fernet.decrypt(base64.urlsafe_b64encode(ciphertext))
 | 
			
		||||
 | 
			
		||||
            return plaintext;
 | 
			
		||||
                except Exception as e:
 | 
			
		||||
                    RNS.log("Decryption by "+RNS.prettyhexrep(self.hash)+" failed: "+str(e), RNS.LOG_DEBUG)
 | 
			
		||||
                    
 | 
			
		||||
                return plaintext;
 | 
			
		||||
            else:
 | 
			
		||||
                RNS.log("Decryption failed because the token size was invalid.", RNS.LOG_DEBUG)
 | 
			
		||||
                return None
 | 
			
		||||
        else:
 | 
			
		||||
            raise KeyError("Decryption failed because identity does not hold a private key")
 | 
			
		||||
 | 
			
		||||
@ -385,18 +438,14 @@ class Identity:
 | 
			
		||||
 | 
			
		||||
        :param message: The message to be signed as *bytes*.
 | 
			
		||||
        :returns: Signature as *bytes*.
 | 
			
		||||
        :raises: *KeyError* if the instance does not hold a private key
 | 
			
		||||
        :raises: *KeyError* if the instance does not hold a private key.
 | 
			
		||||
        """
 | 
			
		||||
        if self.prv != None:
 | 
			
		||||
            signature = self.prv.sign(
 | 
			
		||||
                message,
 | 
			
		||||
                padding.PSS(
 | 
			
		||||
                    mgf=padding.MGF1(hashes.SHA256()),
 | 
			
		||||
                    salt_length=padding.PSS.MAX_LENGTH
 | 
			
		||||
                ),
 | 
			
		||||
                hashes.SHA256()
 | 
			
		||||
            )
 | 
			
		||||
            return signature
 | 
			
		||||
        if self.sig_prv != None:
 | 
			
		||||
            try:
 | 
			
		||||
                return self.sig_prv.sign(message)    
 | 
			
		||||
            except Exception as e:
 | 
			
		||||
                RNS.log("The identity "+str(self)+" could not sign the requested message. The contained exception was: "+str(e), RNS.LOG_ERROR)
 | 
			
		||||
                raise e 
 | 
			
		||||
        else:
 | 
			
		||||
            raise KeyError("Signing failed because identity does not hold a private key")
 | 
			
		||||
 | 
			
		||||
@ -407,19 +456,11 @@ class Identity:
 | 
			
		||||
        :param signature: The signature to be validated as *bytes*.
 | 
			
		||||
        :param message: The message to be validated as *bytes*.
 | 
			
		||||
        :returns: True if the signature is valid, otherwise False.
 | 
			
		||||
        :raises: *KeyError* if the instance does not hold a public key
 | 
			
		||||
        :raises: *KeyError* if the instance does not hold a public key.
 | 
			
		||||
        """
 | 
			
		||||
        if self.pub != None:
 | 
			
		||||
            try:
 | 
			
		||||
                self.pub.verify(
 | 
			
		||||
                    signature,
 | 
			
		||||
                    message,
 | 
			
		||||
                    padding.PSS(
 | 
			
		||||
                        mgf=padding.MGF1(hashes.SHA256()),
 | 
			
		||||
                        salt_length=padding.PSS.MAX_LENGTH
 | 
			
		||||
                    ),
 | 
			
		||||
                    hashes.SHA256()
 | 
			
		||||
                )
 | 
			
		||||
                self.sig_pub.verify(signature, message)
 | 
			
		||||
                return True
 | 
			
		||||
            except Exception as e:
 | 
			
		||||
                return False
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										27
									
								
								RNS/Link.py
									
									
									
									
									
								
							
							
						
						
									
										27
									
								
								RNS/Link.py
									
									
									
									
									
								
							@ -33,17 +33,15 @@ class Link:
 | 
			
		||||
    :param peer_pub_bytes: Internal use, ignore this argument.
 | 
			
		||||
    :param peer_sig_pub_bytes: Internal use, ignore this argument.
 | 
			
		||||
    """
 | 
			
		||||
    CURVE = "Curve25519"
 | 
			
		||||
    CURVE = RNS.Identity.CURVE
 | 
			
		||||
    """
 | 
			
		||||
    The curve used for Elliptic Curve DH key exchanges
 | 
			
		||||
    """
 | 
			
		||||
 | 
			
		||||
    ECPUBSIZE = 32+32
 | 
			
		||||
    BLOCKSIZE = 16
 | 
			
		||||
    KEYSIZE   = 32
 | 
			
		||||
    ECPUBSIZE         = 32+32
 | 
			
		||||
    KEYSIZE           = 32
 | 
			
		||||
 | 
			
		||||
    AES_HMAC_OVERHEAD = 58
 | 
			
		||||
    MDU = math.floor((RNS.Reticulum.MDU-AES_HMAC_OVERHEAD)/BLOCKSIZE)*BLOCKSIZE - 1
 | 
			
		||||
    MDU = math.floor((RNS.Reticulum.MDU-RNS.Identity.AES_HMAC_OVERHEAD)/RNS.Identity.AES128_BLOCKSIZE)*RNS.Identity.AES128_BLOCKSIZE - 1
 | 
			
		||||
 | 
			
		||||
    # TODO: This should not be hardcoded,
 | 
			
		||||
    # but calculated from something like 
 | 
			
		||||
@ -90,11 +88,6 @@ class Link:
 | 
			
		||||
                link.last_inbound = time.time()
 | 
			
		||||
                link.start_watchdog()
 | 
			
		||||
                
 | 
			
		||||
                # TODO: Why was link_established callback here? Seems weird
 | 
			
		||||
                # to call this before RTT packet has been received
 | 
			
		||||
                #if self.owner.callbacks.link_established != None:
 | 
			
		||||
                #   self.owner.callbacks.link_established(link)
 | 
			
		||||
                
 | 
			
		||||
                RNS.log("Incoming link request "+str(link)+" accepted", RNS.LOG_VERBOSE)
 | 
			
		||||
                return link
 | 
			
		||||
 | 
			
		||||
@ -537,13 +530,13 @@ class Link:
 | 
			
		||||
        except Exception as e:
 | 
			
		||||
            return False
 | 
			
		||||
 | 
			
		||||
    def link_established_callback(self, callback):
 | 
			
		||||
    def set_link_established_callback(self, callback):
 | 
			
		||||
        self.callbacks.link_established = callback
 | 
			
		||||
 | 
			
		||||
    def link_closed_callback(self, callback):
 | 
			
		||||
    def set_link_closed_callback(self, callback):
 | 
			
		||||
        self.callbacks.link_closed = callback
 | 
			
		||||
 | 
			
		||||
    def packet_callback(self, callback):
 | 
			
		||||
    def set_packet_callback(self, callback):
 | 
			
		||||
        """
 | 
			
		||||
        Registers a function to be called when a packet has been
 | 
			
		||||
        received over this link.
 | 
			
		||||
@ -552,7 +545,7 @@ class Link:
 | 
			
		||||
        """
 | 
			
		||||
        self.callbacks.packet = callback
 | 
			
		||||
 | 
			
		||||
    def resource_callback(self, callback):
 | 
			
		||||
    def set_resource_callback(self, callback):
 | 
			
		||||
        """
 | 
			
		||||
        Registers a function to be called when a resource has been
 | 
			
		||||
        advertised over this link. If the function returns *True*
 | 
			
		||||
@ -563,7 +556,7 @@ class Link:
 | 
			
		||||
        """
 | 
			
		||||
        self.callbacks.resource = callback
 | 
			
		||||
 | 
			
		||||
    def resource_started_callback(self, callback):
 | 
			
		||||
    def set_resource_started_callback(self, callback):
 | 
			
		||||
        """
 | 
			
		||||
        Registers a function to be called when a resource has begun
 | 
			
		||||
        transferring over this link.
 | 
			
		||||
@ -572,7 +565,7 @@ class Link:
 | 
			
		||||
        """
 | 
			
		||||
        self.callbacks.resource_started = callback
 | 
			
		||||
 | 
			
		||||
    def resource_concluded_callback(self, callback):
 | 
			
		||||
    def set_resource_concluded_callback(self, callback):
 | 
			
		||||
        """
 | 
			
		||||
        Registers a function to be called when a resource has concluded
 | 
			
		||||
        transferring over this link.
 | 
			
		||||
 | 
			
		||||
@ -6,8 +6,16 @@ import RNS
 | 
			
		||||
 | 
			
		||||
class Packet:
 | 
			
		||||
    """
 | 
			
		||||
    The Packet class is used to create packet instances that can be
 | 
			
		||||
    sent over a Reticulum network.
 | 
			
		||||
    The Packet class is used to create packet instances that can be sent
 | 
			
		||||
    over a Reticulum network. Packets to will automatically be encrypted if
 | 
			
		||||
    they are adressed to a ``RNS.Destination.SINGLE`` destination,
 | 
			
		||||
    ``RNS.Destination.GROUP`` destination or a :ref:`RNS.Link<api-link>`.
 | 
			
		||||
 | 
			
		||||
    For ``RNS.Destination.GROUP`` destinations, Reticulum will use the
 | 
			
		||||
    pre-shared key configured for the destination.
 | 
			
		||||
 | 
			
		||||
    For ``RNS.Destination.SINGLE`` destinations and :ref:`RNS.Link<api-link>`
 | 
			
		||||
    destinations, reticulum will use ephemeral keys, and offers **Forward Secrecy**.
 | 
			
		||||
 | 
			
		||||
    :param destination: A :ref:`RNS.Destination<api-destination>` instance to which the packet will be sent.
 | 
			
		||||
    :param data: The data payload to be included in the packet as *bytes*.
 | 
			
		||||
@ -56,14 +64,21 @@ class Packet:
 | 
			
		||||
 | 
			
		||||
    # This is used to calculate allowable
 | 
			
		||||
    # payload sizes
 | 
			
		||||
    HEADER_MAXSIZE = 23
 | 
			
		||||
    HEADER_MAXSIZE = RNS.Reticulum.HEADER_MAXSIZE
 | 
			
		||||
    MDU            = RNS.Reticulum.MDU
 | 
			
		||||
 | 
			
		||||
    # With an MTU of 500, the maximum RSA-encrypted
 | 
			
		||||
    # amount of data we can send in a single packet
 | 
			
		||||
    # is given by the below calculation; 258 bytes.
 | 
			
		||||
    RSA_MDU   = math.floor(MDU/RNS.Identity.DECRYPT_CHUNKSIZE)*RNS.Identity.ENCRYPT_CHUNKSIZE
 | 
			
		||||
    PLAIN_MDU = MDU
 | 
			
		||||
    # TODO: Update this
 | 
			
		||||
    # With an MTU of 500, the maximum of data we can
 | 
			
		||||
    # send in a single encrypted packet is given by
 | 
			
		||||
    # the below calculation; 383 bytes.
 | 
			
		||||
    ENCRYPTED_MDU = math.floor((RNS.Reticulum.MDU-RNS.Identity.AES_HMAC_OVERHEAD-RNS.Identity.KEYSIZE//16)/RNS.Identity.AES128_BLOCKSIZE)*RNS.Identity.AES128_BLOCKSIZE - 1
 | 
			
		||||
    """
 | 
			
		||||
    The maximum size of the payload data in a single encrypted packet 
 | 
			
		||||
    """
 | 
			
		||||
    PLAIN_MDU     = MDU
 | 
			
		||||
    """
 | 
			
		||||
    The maximum size of the payload data in a single unencrypted packet 
 | 
			
		||||
    """
 | 
			
		||||
 | 
			
		||||
    # TODO: This should be calculated
 | 
			
		||||
    # more intelligently
 | 
			
		||||
@ -406,7 +421,7 @@ class PacketReceipt:
 | 
			
		||||
        else:
 | 
			
		||||
            return False
 | 
			
		||||
 | 
			
		||||
    def rtt(self):
 | 
			
		||||
    def get_rtt(self):
 | 
			
		||||
        """
 | 
			
		||||
        :returns: The round-trip-time in seconds
 | 
			
		||||
        """
 | 
			
		||||
@ -439,7 +454,7 @@ class PacketReceipt:
 | 
			
		||||
        """
 | 
			
		||||
        self.timeout = float(timeout)
 | 
			
		||||
 | 
			
		||||
    def delivery_callback(self, callback):
 | 
			
		||||
    def set_delivery_callback(self, callback):
 | 
			
		||||
        """
 | 
			
		||||
        Sets a function that gets called if a successfull delivery has been proven.
 | 
			
		||||
 | 
			
		||||
@ -449,7 +464,7 @@ class PacketReceipt:
 | 
			
		||||
 | 
			
		||||
    # Set a function that gets called if the
 | 
			
		||||
    # delivery times out
 | 
			
		||||
    def timeout_callback(self, callback):
 | 
			
		||||
    def set_timeout_callback(self, callback):
 | 
			
		||||
        """
 | 
			
		||||
        Sets a function that gets called if the delivery times out.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -17,7 +17,6 @@ class Resource:
 | 
			
		||||
    :param link: The :ref:`RNS.Link<api-link>` instance on which to transfer the data.
 | 
			
		||||
    :param advertise: Whether to automatically advertise the resource. Can be *True* or *False*.
 | 
			
		||||
    :param auto_compress: Whether to auto-compress the resource. Can be *True* or *False*.
 | 
			
		||||
    :param auto_compress: Whether the resource must be compressed. Can be *True* or *False*. Used for debugging, will disappear in the future.
 | 
			
		||||
    :param callback: A *callable* with the signature *callback(resource)*. Will be called when the resource transfer concludes.
 | 
			
		||||
    :param progress_callback: A *callable* with the signature *callback(resource)*. Will be called whenever the resource transfer progress is updated.
 | 
			
		||||
    :param segment_index: Internal use, ignore.
 | 
			
		||||
@ -134,7 +133,7 @@ class Resource:
 | 
			
		||||
    # Create a resource for transmission to a remote destination
 | 
			
		||||
    # The data passed can be either a bytes-array or a file opened
 | 
			
		||||
    # in binary read mode.
 | 
			
		||||
    def __init__(self, data, link, advertise=True, auto_compress=True, must_compress=False, callback=None, progress_callback=None, segment_index = 1, original_hash = None):
 | 
			
		||||
    def __init__(self, data, link, advertise=True, auto_compress=True, callback=None, progress_callback=None, segment_index = 1, original_hash = None):
 | 
			
		||||
        data_size = None
 | 
			
		||||
        resource_data = None
 | 
			
		||||
        if hasattr(data, "read"):
 | 
			
		||||
@ -198,7 +197,7 @@ class Resource:
 | 
			
		||||
            self.uncompressed_data = data
 | 
			
		||||
 | 
			
		||||
            compression_began = time.time()
 | 
			
		||||
            if must_compress or (auto_compress and len(self.uncompressed_data) < Resource.AUTO_COMPRESS_MAX_SIZE):
 | 
			
		||||
            if (auto_compress and len(self.uncompressed_data) < Resource.AUTO_COMPRESS_MAX_SIZE):
 | 
			
		||||
                RNS.log("Compressing resource data...", RNS.LOG_DEBUG)
 | 
			
		||||
                self.compressed_data   = bz2.compress(self.uncompressed_data)
 | 
			
		||||
                RNS.log("Compression completed in "+str(round(time.time()-compression_began, 3))+" seconds", RNS.LOG_DEBUG)
 | 
			
		||||
@ -748,8 +747,6 @@ class Resource:
 | 
			
		||||
        :returns: The current progress of the resource transfer as a *float* between 0.0 and 1.0.
 | 
			
		||||
        """
 | 
			
		||||
        if self.initiator:
 | 
			
		||||
            # TODO: Remove
 | 
			
		||||
            # progress = self.sent_parts / len(self.parts)
 | 
			
		||||
            self.processed_parts  = (self.segment_index-1)*math.ceil(Resource.MAX_EFFICIENT_SIZE/Resource.SDU)
 | 
			
		||||
            self.processed_parts += self.sent_parts
 | 
			
		||||
            self.progress_total_parts = float(self.grand_total_parts)
 | 
			
		||||
 | 
			
		||||
@ -108,7 +108,7 @@ class Transport:
 | 
			
		||||
 | 
			
		||||
        # Create transport-specific destinations
 | 
			
		||||
        Transport.path_request_destination = RNS.Destination(None, RNS.Destination.IN, RNS.Destination.PLAIN, Transport.APP_NAME, "path", "request")
 | 
			
		||||
        Transport.path_request_destination.packet_callback(Transport.path_request_handler)
 | 
			
		||||
        Transport.path_request_destination.set_packet_callback(Transport.path_request_handler)
 | 
			
		||||
        Transport.control_destinations.append(Transport.path_request_destination)
 | 
			
		||||
        Transport.control_hashes.append(Transport.path_request_destination.hash)
 | 
			
		||||
 | 
			
		||||
@ -652,7 +652,7 @@ class Transport:
 | 
			
		||||
                    # First, check that the announce is not for a destination
 | 
			
		||||
                    # local to this system, and that hops are less than the max
 | 
			
		||||
                    if (not any(packet.destination_hash == d.hash for d in Transport.destinations) and packet.hops < Transport.PATHFINDER_M+1):
 | 
			
		||||
                        random_blob = packet.data[RNS.Identity.DERKEYSIZE//8+10:RNS.Identity.DERKEYSIZE//8+20]
 | 
			
		||||
                        random_blob = packet.data[RNS.Identity.KEYSIZE//8+10:RNS.Identity.KEYSIZE//8+20]
 | 
			
		||||
                        random_blobs = []
 | 
			
		||||
                        if packet.destination_hash in Transport.destination_table:
 | 
			
		||||
                            random_blobs = Transport.destination_table[packet.destination_hash][4]
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user