Refactored fernet to token

This commit is contained in:
Mark Qvist 2024-11-22 15:19:12 +01:00
parent 04d2626809
commit aabb763cea
8 changed files with 38 additions and 34 deletions

View File

@ -325,12 +325,12 @@ In the default installation configuration, the `X25519`, `Ed25519` and
(via the [PyCA/cryptography](https://github.com/pyca/cryptography) package). (via the [PyCA/cryptography](https://github.com/pyca/cryptography) package).
The hashing functions `SHA-256` and `SHA-512` are provided by the standard The hashing functions `SHA-256` and `SHA-512` are provided by the standard
Python [hashlib](https://docs.python.org/3/library/hashlib.html). The `HKDF`, Python [hashlib](https://docs.python.org/3/library/hashlib.html). The `HKDF`,
`HMAC`, `Fernet` primitives, and the `PKCS7` padding function are always `HMAC`, `Token` primitives, and the `PKCS7` padding function are always
provided by the following internal implementations: provided by the following internal implementations:
- [HKDF.py](RNS/Cryptography/HKDF.py) - [HKDF.py](RNS/Cryptography/HKDF.py)
- [HMAC.py](RNS/Cryptography/HMAC.py) - [HMAC.py](RNS/Cryptography/HMAC.py)
- [Fernet.py](RNS/Cryptography/Fernet.py) - [Token.py](RNS/Cryptography/Token.py)
- [PKCS7.py](RNS/Cryptography/PKCS7.py) - [PKCS7.py](RNS/Cryptography/PKCS7.py)

View File

@ -27,7 +27,7 @@ from RNS.Cryptography import HMAC
from RNS.Cryptography import PKCS7 from RNS.Cryptography import PKCS7
from RNS.Cryptography.AES import AES_128_CBC from RNS.Cryptography.AES import AES_128_CBC
class Fernet(): class Token():
""" """
This class provides a slightly modified implementation of the Fernet spec This class provides a slightly modified implementation of the Fernet spec
found at: https://github.com/fernet/spec/blob/master/Spec.md found at: https://github.com/fernet/spec/blob/master/Spec.md
@ -37,7 +37,7 @@ class Fernet():
not relevant to Reticulum. They are therefore stripped from this not relevant to Reticulum. They are therefore stripped from this
implementation, since they incur overhead and leak initiator metadata. implementation, since they incur overhead and leak initiator metadata.
""" """
FERNET_OVERHEAD = 48 # Bytes TOKEN_OVERHEAD = 48 # Bytes
@staticmethod @staticmethod
def generate_key(): def generate_key():

View File

@ -5,7 +5,7 @@ from .Hashes import sha256
from .Hashes import sha512 from .Hashes import sha512
from .HKDF import hkdf from .HKDF import hkdf
from .PKCS7 import PKCS7 from .PKCS7 import PKCS7
from .Fernet import Fernet from .Token import Token
from .Provider import backend from .Provider import backend
import RNS.Cryptography.Provider as cp import RNS.Cryptography.Provider as cp

View File

@ -26,7 +26,7 @@ import time
import threading import threading
import RNS import RNS
from RNS.Cryptography import Fernet from RNS.Cryptography import Token
from .vendor import umsgpack as umsgpack from .vendor import umsgpack as umsgpack
class Callbacks: class Callbacks:
@ -525,8 +525,8 @@ class Destination:
raise TypeError("A single destination holds keys through an Identity instance") raise TypeError("A single destination holds keys through an Identity instance")
if self.type == Destination.GROUP: if self.type == Destination.GROUP:
self.prv_bytes = Fernet.generate_key() self.prv_bytes = Token.generate_key()
self.prv = Fernet(self.prv_bytes) self.prv = Token(self.prv_bytes)
def get_private_key(self): def get_private_key(self):
""" """
@ -556,7 +556,7 @@ class Destination:
if self.type == Destination.GROUP: if self.type == Destination.GROUP:
self.prv_bytes = key self.prv_bytes = key
self.prv = Fernet(self.prv_bytes) self.prv = Token(self.prv_bytes)
def load_public_key(self, key): def load_public_key(self, key):
if self.type != Destination.SINGLE: if self.type != Destination.SINGLE:

View File

@ -31,7 +31,7 @@ import threading
from .vendor import umsgpack as umsgpack from .vendor import umsgpack as umsgpack
from RNS.Cryptography import X25519PrivateKey, X25519PublicKey, Ed25519PrivateKey, Ed25519PublicKey from RNS.Cryptography import X25519PrivateKey, X25519PublicKey, Ed25519PrivateKey, Ed25519PublicKey
from RNS.Cryptography import Fernet from RNS.Cryptography import Token
class Identity: class Identity:
@ -66,7 +66,7 @@ class Identity:
""" """
# Non-configurable constants # Non-configurable constants
FERNET_OVERHEAD = RNS.Cryptography.Fernet.FERNET_OVERHEAD TOKEN_OVERHEAD = RNS.Cryptography.Token.TOKEN_OVERHEAD
AES128_BLOCKSIZE = 16 # In bytes AES128_BLOCKSIZE = 16 # In bytes
HASHLENGTH = 256 # In bits HASHLENGTH = 256 # In bits
SIGLENGTH = KEYSIZE # In bits SIGLENGTH = KEYSIZE # In bits
@ -646,8 +646,8 @@ class Identity:
context=self.get_context(), context=self.get_context(),
) )
fernet = Fernet(derived_key) token = Token(derived_key)
ciphertext = fernet.encrypt(plaintext) ciphertext = token.encrypt(plaintext)
token = ephemeral_pub_bytes+ciphertext token = ephemeral_pub_bytes+ciphertext
return token return token
@ -684,8 +684,8 @@ class Identity:
context=self.get_context(), context=self.get_context(),
) )
fernet = Fernet(derived_key) token = Token(derived_key)
plaintext = fernet.decrypt(ciphertext) plaintext = token.decrypt(ciphertext)
if ratchet_id_receiver: if ratchet_id_receiver:
ratchet_id_receiver.latest_ratchet_id = ratchet_id ratchet_id_receiver.latest_ratchet_id = ratchet_id
@ -709,8 +709,8 @@ class Identity:
context=self.get_context(), context=self.get_context(),
) )
fernet = Fernet(derived_key) token = Token(derived_key)
plaintext = fernet.decrypt(ciphertext) plaintext = token.decrypt(ciphertext)
if ratchet_id_receiver: if ratchet_id_receiver:
ratchet_id_receiver.latest_ratchet_id = None ratchet_id_receiver.latest_ratchet_id = None

View File

@ -21,7 +21,7 @@
# SOFTWARE. # SOFTWARE.
from RNS.Cryptography import X25519PrivateKey, X25519PublicKey, Ed25519PrivateKey, Ed25519PublicKey from RNS.Cryptography import X25519PrivateKey, X25519PublicKey, Ed25519PrivateKey, Ed25519PublicKey
from RNS.Cryptography import Fernet from RNS.Cryptography import Token
from RNS.Channel import Channel, LinkChannelOutlet from RNS.Channel import Channel, LinkChannelOutlet
from time import sleep from time import sleep
@ -61,7 +61,7 @@ class Link:
ECPUBSIZE = 32+32 ECPUBSIZE = 32+32
KEYSIZE = 32 KEYSIZE = 32
MDU = math.floor((RNS.Reticulum.MTU-RNS.Reticulum.IFAC_MIN_SIZE-RNS.Reticulum.HEADER_MINSIZE-RNS.Identity.FERNET_OVERHEAD)/RNS.Identity.AES128_BLOCKSIZE)*RNS.Identity.AES128_BLOCKSIZE - 1 MDU = math.floor((RNS.Reticulum.MTU-RNS.Reticulum.IFAC_MIN_SIZE-RNS.Reticulum.HEADER_MINSIZE-RNS.Identity.TOKEN_OVERHEAD)/RNS.Identity.AES128_BLOCKSIZE)*RNS.Identity.AES128_BLOCKSIZE - 1
ESTABLISHMENT_TIMEOUT_PER_HOP = RNS.Reticulum.DEFAULT_PER_HOP_TIMEOUT ESTABLISHMENT_TIMEOUT_PER_HOP = RNS.Reticulum.DEFAULT_PER_HOP_TIMEOUT
""" """
@ -188,7 +188,7 @@ class Link:
self.prv = X25519PrivateKey.generate() self.prv = X25519PrivateKey.generate()
self.sig_prv = Ed25519PrivateKey.generate() self.sig_prv = Ed25519PrivateKey.generate()
self.fernet = None self.token = None
self.pub = self.prv.public_key() self.pub = self.prv.public_key()
self.pub_bytes = self.pub.public_bytes() self.pub_bytes = self.pub.public_bytes()
@ -979,14 +979,14 @@ class Link:
def encrypt(self, plaintext): def encrypt(self, plaintext):
try: try:
if not self.fernet: if not self.token:
try: try:
self.fernet = Fernet(self.derived_key) self.token = Token(self.derived_key)
except Exception as e: except Exception as e:
RNS.log("Could not instantiate Fernet while performin encryption on link "+str(self)+". The contained exception was: "+str(e), RNS.LOG_ERROR) RNS.log("Could not instantiate token while performing encryption on link "+str(self)+". The contained exception was: "+str(e), RNS.LOG_ERROR)
raise e raise e
return self.fernet.encrypt(plaintext) return self.token.encrypt(plaintext)
except Exception as e: except Exception as e:
RNS.log("Encryption on link "+str(self)+" failed. The contained exception was: "+str(e), RNS.LOG_ERROR) RNS.log("Encryption on link "+str(self)+" failed. The contained exception was: "+str(e), RNS.LOG_ERROR)
@ -995,10 +995,10 @@ class Link:
def decrypt(self, ciphertext): def decrypt(self, ciphertext):
try: try:
if not self.fernet: if not self.token:
self.fernet = Fernet(self.derived_key) self.token = Token(self.derived_key)
return self.fernet.decrypt(ciphertext) return self.token.decrypt(ciphertext)
except Exception as e: except Exception as e:
RNS.log("Decryption failed on link "+str(self)+". The contained exception was: "+str(e), RNS.LOG_ERROR) RNS.log("Decryption failed on link "+str(self)+". The contained exception was: "+str(e), RNS.LOG_ERROR)

View File

@ -95,7 +95,7 @@ class Packet:
# With an MTU of 500, the maximum of data we can # With an MTU of 500, the maximum of data we can
# send in a single encrypted packet is given by # send in a single encrypted packet is given by
# the below calculation; 383 bytes. # the below calculation; 383 bytes.
ENCRYPTED_MDU = math.floor((RNS.Reticulum.MDU-RNS.Identity.FERNET_OVERHEAD-RNS.Identity.KEYSIZE//16)/RNS.Identity.AES128_BLOCKSIZE)*RNS.Identity.AES128_BLOCKSIZE - 1 ENCRYPTED_MDU = math.floor((RNS.Reticulum.MDU-RNS.Identity.TOKEN_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 The maximum size of the payload data in a single encrypted packet
""" """

View File

@ -868,13 +868,17 @@ both on general-purpose CPUs and on microcontrollers. The necessary primitives a
* HKDF for key derivation * HKDF for key derivation
* Modified Fernet for encrypted tokens * Encrypted tokens are based on the Fernet spec
* AES-128 in CBC mode * Ephemeral keys derived from an ECDH key exchange on Curve25519
* HMAC for message authentication * AES-128 in CBC mode with PKCS7 padding
* No Version and Timestamp metadata included * HMAC using SHA256 for message authentication
* IVs are generated through os.urandom()
* No Fernet version and timestamp metadata fields
* SHA-256 * SHA-256
@ -884,12 +888,12 @@ In the default installation configuration, the ``X25519``, ``Ed25519`` and ``AES
primitives are provided by `OpenSSL <https://www.openssl.org/>`_ (via the `PyCA/cryptography <https://github.com/pyca/cryptography>`_ primitives are provided by `OpenSSL <https://www.openssl.org/>`_ (via the `PyCA/cryptography <https://github.com/pyca/cryptography>`_
package). The hashing functions ``SHA-256`` and ``SHA-512`` are provided by the standard package). The hashing functions ``SHA-256`` and ``SHA-512`` are provided by the standard
Python `hashlib <https://docs.python.org/3/library/hashlib.html>`_. The ``HKDF``, ``HMAC``, Python `hashlib <https://docs.python.org/3/library/hashlib.html>`_. The ``HKDF``, ``HMAC``,
``Fernet`` primitives, and the ``PKCS7`` padding function are always provided by the ``Token`` primitives, and the ``PKCS7`` padding function are always provided by the
following internal implementations: following internal implementations:
- ``RNS/Cryptography/HKDF.py`` - ``RNS/Cryptography/HKDF.py``
- ``RNS/Cryptography/HMAC.py`` - ``RNS/Cryptography/HMAC.py``
- ``RNS/Cryptography/Fernet.py`` - ``RNS/Cryptography/Token.py``
- ``RNS/Cryptography/PKCS7.py`` - ``RNS/Cryptography/PKCS7.py``