From d7791c60e28658359b776ad6b31000f02dd23693 Mon Sep 17 00:00:00 2001 From: Mark Qvist Date: Tue, 6 May 2025 12:08:17 +0200 Subject: [PATCH] Implemented compatibility handling for AES-256 migration --- RNS/Cryptography/Token.py | 56 +++++++++++++++++++++++++++++++-------- RNS/Destination.py | 5 +++- RNS/Identity.py | 8 +++--- RNS/Transport.py | 21 +++++++-------- 4 files changed, 64 insertions(+), 26 deletions(-) diff --git a/RNS/Cryptography/Token.py b/RNS/Cryptography/Token.py index 9434de5..1bb7bec 100644 --- a/RNS/Cryptography/Token.py +++ b/RNS/Cryptography/Token.py @@ -37,6 +37,8 @@ from RNS.Cryptography import AES from RNS.Cryptography.AES import AES_128_CBC from RNS.Cryptography.AES import AES_256_CBC +# import RNS # TODO: Remove + class Token(): """ This class provides a slightly modified implementation of the Fernet spec @@ -64,11 +66,23 @@ class Token(): self._signing_key = key[:16] self._encryption_key = key[16:] + #################################################################### + self.mode_legacy = AES_128_CBC # TODO: Remove after migration + self._signing_key_128 = key[:16] # TODO: Remove after migration + self._encryption_key_128 = key[16:] # TODO: Remove after migration + #################################################################### + elif len(key) == 64: self.mode = AES_256_CBC self._signing_key = key[:32] self._encryption_key = key[32:] + #################################################################### + self.mode_legacy = AES_128_CBC # TODO: Remove after migration + self._signing_key_128 = key[:16] # TODO: Remove after migration + self._encryption_key_128 = key[16:32] # TODO: Remove after migration + #################################################################### + else: raise ValueError("Token key must be 128 or 256 bits, not "+str(len(key)*8)) else: raise TypeError(f"Invalid token mode: {mode}") @@ -79,16 +93,17 @@ class Token(): else: received_hmac = token[-32:] expected_hmac = HMAC.new(self._signing_key, token[:-32]).digest() + expected_hmac_128 = HMAC.new(self._signing_key_128, token[:-32]).digest() # TODO: Remove after migration - if received_hmac == expected_hmac: return True + # TODO: Reset after migration + # if received_hmac == expected_hmac: return True + if received_hmac == expected_hmac or received_hmac == expected_hmac_128: return True else: return False def encrypt(self, data = None): - iv = os.urandom(16) - current_time = int(time.time()) - if not isinstance(data, bytes): raise TypeError("Token plaintext input must be bytes") + iv = os.urandom(16) ciphertext = self.mode.encrypt( plaintext = PKCS7.pad(data), @@ -108,12 +123,31 @@ class Token(): ciphertext = token[16:-32] try: - plaintext = PKCS7.unpad( - self.mode.decrypt( - ciphertext = ciphertext, - key = self._encryption_key, - iv = iv)) + try: + # RNS.log(f"Trying decryption with {self.mode}", RNS.LOG_DEBUG) # TODO: Remove + plaintext = PKCS7.unpad( + self.mode.decrypt( + ciphertext = ciphertext, + key = self._encryption_key, + iv = iv)) - return plaintext + # RNS.log(f"Decrypted packet with {self.mode}", RNS.LOG_DEBUG) # TODO: Remove + return plaintext - except Exception as e: raise ValueError("Could not decrypt token") \ No newline at end of file + # TODO: Remove after migration ############################ + except Exception as e: + # RNS.log(f"{self.mode} decryption failed", RNS.LOG_DEBUG) # TODO: Remove + # RNS.log(f"Trying decryption with {self.mode_legacy}", RNS.LOG_DEBUG) # TODO: Remove + plaintext = PKCS7.unpad( + self.mode_legacy.decrypt( + ciphertext = ciphertext, + key = self._encryption_key_128, + iv = iv)) + + # RNS.log(f"Decrypted packet with {self.mode_legacy}", RNS.LOG_DEBUG) # TODO: Remove + return plaintext + ########################################################### + + except Exception as e: + RNS.trace_exception(e) # TODO: Remove after migration + raise ValueError("Could not decrypt token") \ No newline at end of file diff --git a/RNS/Destination.py b/RNS/Destination.py index 7d4ffeb..00b7f68 100755 --- a/RNS/Destination.py +++ b/RNS/Destination.py @@ -418,7 +418,8 @@ class Destination: else: plaintext = self.decrypt(packet.data) packet.ratchet_id = self.latest_ratchet_id - if plaintext != None: + if plaintext == None: return False + else: if packet.packet_type == RNS.Packet.DATA: if self.callbacks.packet != None: try: @@ -426,6 +427,8 @@ class Destination: except Exception as e: RNS.log("Error while executing receive callback from "+str(self)+". The contained exception was: "+str(e), RNS.LOG_ERROR) + return True + def incoming_link_request(self, data, packet): if self.accept_link_requests: link = RNS.Link.validate_request(self, data, packet) diff --git a/RNS/Identity.py b/RNS/Identity.py index 9432813..148454c 100644 --- a/RNS/Identity.py +++ b/RNS/Identity.py @@ -544,6 +544,8 @@ class Identity: RNS.log("The contained exception was: "+str(e)) def __init__(self,create_keys=True): + self.derived_key_length = 64 + # Initialize keys to none self.prv = None self.prv_bytes = None @@ -677,7 +679,7 @@ class Identity: shared_key = ephemeral_key.exchange(target_public_key) derived_key = RNS.Cryptography.hkdf( - length=32, + length=self.derived_key_length, derive_from=shared_key, salt=self.get_salt(), context=self.get_context(), @@ -715,7 +717,7 @@ class Identity: ratchet_id = Identity._get_ratchet_id(ratchet_prv.public_key().public_bytes()) shared_key = ratchet_prv.exchange(peer_pub) derived_key = RNS.Cryptography.hkdf( - length=32, + length=self.derived_key_length, derive_from=shared_key, salt=self.get_salt(), context=self.get_context(), @@ -740,7 +742,7 @@ class Identity: if plaintext == None: shared_key = self.prv.exchange(peer_pub) derived_key = RNS.Cryptography.hkdf( - length=32, + length=self.derived_key_length, derive_from=shared_key, salt=self.get_salt(), context=self.get_context(), diff --git a/RNS/Transport.py b/RNS/Transport.py index 4a91e66..4eafe80 100755 --- a/RNS/Transport.py +++ b/RNS/Transport.py @@ -1879,18 +1879,17 @@ class Transport: for destination in Transport.destinations: if destination.hash == packet.destination_hash and destination.type == packet.destination_type: packet.destination = destination - destination.receive(packet) + if destination.receive(packet): + if destination.proof_strategy == RNS.Destination.PROVE_ALL: + packet.prove() - if destination.proof_strategy == RNS.Destination.PROVE_ALL: - packet.prove() - - elif destination.proof_strategy == RNS.Destination.PROVE_APP: - if destination.callbacks.proof_requested: - try: - if destination.callbacks.proof_requested(packet): - packet.prove() - except Exception as e: - RNS.log("Error while executing proof request callback. The contained exception was: "+str(e), RNS.LOG_ERROR) + elif destination.proof_strategy == RNS.Destination.PROVE_APP: + if destination.callbacks.proof_requested: + try: + if destination.callbacks.proof_requested(packet): + packet.prove() + except Exception as e: + RNS.log("Error while executing proof request callback. The contained exception was: "+str(e), RNS.LOG_ERROR) # Handling for proofs and link-request proofs elif packet.packet_type == RNS.Packet.PROOF: