mirror of
https://github.com/markqvist/Reticulum.git
synced 2024-12-25 15:39:32 -05:00
Moved Reticulum to Curve25519 for ECDH exchanges and signatures
This commit is contained in:
parent
4109cbc33d
commit
8478782c18
51
RNS/Link.py
51
RNS/Link.py
@ -1,7 +1,8 @@
|
|||||||
from cryptography.hazmat.backends import default_backend
|
from cryptography.hazmat.backends import default_backend
|
||||||
from cryptography.hazmat.primitives import hashes
|
from cryptography.hazmat.primitives import hashes
|
||||||
from cryptography.hazmat.primitives import serialization
|
from cryptography.hazmat.primitives import serialization
|
||||||
from cryptography.hazmat.primitives.asymmetric import ec
|
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.hazmat.primitives.kdf.hkdf import HKDF
|
||||||
from cryptography.fernet import Fernet
|
from cryptography.fernet import Fernet
|
||||||
from time import sleep
|
from time import sleep
|
||||||
@ -31,13 +32,15 @@ class Link:
|
|||||||
:param owner: Internal use by :ref:`RNS.Transport<api-Transport>`, ignore this argument.
|
:param owner: Internal use by :ref:`RNS.Transport<api-Transport>`, ignore this argument.
|
||||||
:param peer_pub_bytes: Internal use by :ref:`RNS.Transport<api-Transport>`, ignore this argument.
|
:param peer_pub_bytes: Internal use by :ref:`RNS.Transport<api-Transport>`, ignore this argument.
|
||||||
"""
|
"""
|
||||||
CURVE = ec.SECP256R1()
|
CURVE = "Curve25519"
|
||||||
"""
|
"""
|
||||||
The curve used for Elliptic Curve DH key exchanges
|
The curve used for Elliptic Curve DH key exchanges
|
||||||
"""
|
"""
|
||||||
|
|
||||||
ECPUBSIZE = 91
|
ECPUBSIZE = 32
|
||||||
BLOCKSIZE = 16
|
BLOCKSIZE = 16
|
||||||
|
KEYSIZE = 32
|
||||||
|
|
||||||
AES_HMAC_OVERHEAD = 58
|
AES_HMAC_OVERHEAD = 58
|
||||||
MDU = math.floor((RNS.Reticulum.MDU-AES_HMAC_OVERHEAD)/BLOCKSIZE)*BLOCKSIZE - 1
|
MDU = math.floor((RNS.Reticulum.MDU-AES_HMAC_OVERHEAD)/BLOCKSIZE)*BLOCKSIZE - 1
|
||||||
|
|
||||||
@ -133,12 +136,22 @@ class Link:
|
|||||||
self.initiator = False
|
self.initiator = False
|
||||||
else:
|
else:
|
||||||
self.initiator = True
|
self.initiator = True
|
||||||
|
|
||||||
|
self.fernet = None
|
||||||
|
|
||||||
self.prv = ec.generate_private_key(Link.CURVE, default_backend())
|
self.prv = X25519PrivateKey.generate()
|
||||||
|
self.sig_prv = Ed25519PrivateKey.from_private_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 = self.prv.public_key()
|
||||||
self.pub_bytes = self.pub.public_bytes(
|
self.pub_bytes = self.pub.public_bytes(
|
||||||
encoding=serialization.Encoding.DER,
|
encoding=serialization.Encoding.Raw,
|
||||||
format=serialization.PublicFormat.SubjectPublicKeyInfo
|
format=serialization.PublicFormat.Raw
|
||||||
)
|
)
|
||||||
|
|
||||||
if peer_pub_bytes == None:
|
if peer_pub_bytes == None:
|
||||||
@ -162,7 +175,11 @@ class Link:
|
|||||||
|
|
||||||
def load_peer(self, peer_pub_bytes):
|
def load_peer(self, peer_pub_bytes):
|
||||||
self.peer_pub_bytes = peer_pub_bytes
|
self.peer_pub_bytes = peer_pub_bytes
|
||||||
self.peer_pub = serialization.load_der_public_key(peer_pub_bytes, backend=default_backend())
|
self.peer_pub = X25519PublicKey.from_public_bytes(self.peer_pub_bytes)
|
||||||
|
|
||||||
|
self.peer_sig_pub_bytes = peer_pub_bytes
|
||||||
|
self.peer_sig_pub = Ed25519PublicKey.from_public_bytes(self.peer_sig_pub_bytes)
|
||||||
|
|
||||||
if not hasattr(self.peer_pub, "curve"):
|
if not hasattr(self.peer_pub, "curve"):
|
||||||
self.peer_pub.curve = Link.CURVE
|
self.peer_pub.curve = Link.CURVE
|
||||||
|
|
||||||
@ -172,13 +189,12 @@ class Link:
|
|||||||
|
|
||||||
def handshake(self):
|
def handshake(self):
|
||||||
self.status = Link.HANDSHAKE
|
self.status = Link.HANDSHAKE
|
||||||
self.shared_key = self.prv.exchange(ec.ECDH(), self.peer_pub)
|
self.shared_key = self.prv.exchange(self.peer_pub)
|
||||||
self.derived_key = HKDF(
|
self.derived_key = HKDF(
|
||||||
algorithm=hashes.SHA256(),
|
algorithm=hashes.SHA256(),
|
||||||
length=32,
|
length=32,
|
||||||
salt=self.get_salt(),
|
salt=self.get_salt(),
|
||||||
info=self.get_context(),
|
info=self.get_context(),
|
||||||
backend=default_backend()
|
|
||||||
).derive(self.shared_key)
|
).derive(self.shared_key)
|
||||||
|
|
||||||
def prove(self):
|
def prove(self):
|
||||||
@ -487,9 +503,10 @@ class Link:
|
|||||||
if self.__encryption_disabled:
|
if self.__encryption_disabled:
|
||||||
return plaintext
|
return plaintext
|
||||||
try:
|
try:
|
||||||
# TODO: Optimise this re-allocation
|
if not self.fernet:
|
||||||
fernet = Fernet(base64.urlsafe_b64encode(self.derived_key))
|
self.fernet = Fernet(base64.urlsafe_b64encode(self.derived_key))
|
||||||
ciphertext = base64.urlsafe_b64decode(fernet.encrypt(plaintext))
|
|
||||||
|
ciphertext = base64.urlsafe_b64decode(self.fernet.encrypt(plaintext))
|
||||||
return ciphertext
|
return ciphertext
|
||||||
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)
|
||||||
@ -499,8 +516,10 @@ class Link:
|
|||||||
if self.__encryption_disabled:
|
if self.__encryption_disabled:
|
||||||
return ciphertext
|
return ciphertext
|
||||||
try:
|
try:
|
||||||
fernet = Fernet(base64.urlsafe_b64encode(self.derived_key))
|
if not self.fernet:
|
||||||
plaintext = fernet.decrypt(base64.urlsafe_b64encode(ciphertext))
|
self.fernet = Fernet(base64.urlsafe_b64encode(self.derived_key))
|
||||||
|
|
||||||
|
plaintext = self.fernet.decrypt(base64.urlsafe_b64encode(ciphertext))
|
||||||
return plaintext
|
return plaintext
|
||||||
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)
|
||||||
@ -510,11 +529,11 @@ class Link:
|
|||||||
|
|
||||||
|
|
||||||
def sign(self, message):
|
def sign(self, message):
|
||||||
return self.prv.sign(message, ec.ECDSA(hashes.SHA256()))
|
return self.sig_prv.sign(message)
|
||||||
|
|
||||||
def validate(self, signature, message):
|
def validate(self, signature, message):
|
||||||
try:
|
try:
|
||||||
self.peer_pub.verify(signature, message, ec.ECDSA(hashes.SHA256()))
|
self.peer_sig_pub.verify(signature, message)
|
||||||
return True
|
return True
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
return False
|
return False
|
||||||
|
2
setup.py
2
setup.py
@ -18,6 +18,6 @@ setuptools.setup(
|
|||||||
"License :: OSI Approved :: MIT License",
|
"License :: OSI Approved :: MIT License",
|
||||||
"Operating System :: OS Independent",
|
"Operating System :: OS Independent",
|
||||||
],
|
],
|
||||||
install_requires=['cryptography', 'pyserial'],
|
install_requires=['cryptography>=3.4.7', 'pyserial'],
|
||||||
python_requires='>=3.5',
|
python_requires='>=3.5',
|
||||||
)
|
)
|
Loading…
Reference in New Issue
Block a user