mirror of
https://github.com/markqvist/Reticulum.git
synced 2024-11-05 13:50:14 +00:00
Constant time X25519 exchange
This commit is contained in:
parent
06fffe5a94
commit
9a4325ce8e
@ -1,33 +1,18 @@
|
|||||||
"""A pure Python implementation of Curve25519
|
|
||||||
This module supports both a low-level interface through curve25519(base_point, secret)
|
|
||||||
and curve25519_base(secret) that take 32-byte blocks of data as inputs and a higher
|
|
||||||
level interface using the X25519PrivateKey and X25519PublicKey classes that are
|
|
||||||
compatible with the classes in cryptography.hazmat.primitives.asymmetric.x25519 with
|
|
||||||
the same names.
|
|
||||||
"""
|
|
||||||
|
|
||||||
# By Nicko van Someren, 2021. This code is released into the public domain.
|
# By Nicko van Someren, 2021. This code is released into the public domain.
|
||||||
|
# Small modifications for use in Reticulum, and constant time key exchange
|
||||||
|
# added by Mark Qvist in 2022.
|
||||||
|
|
||||||
# #### WARNING ####
|
# WARNING! Only the X25519PrivateKey.exchange() method attempts to hide execution time.
|
||||||
|
# In the context of Reticulum, this is sufficient, but it may not be in other systems. If
|
||||||
|
# this code is to be used to provide cryptographic security in an environment where the
|
||||||
|
# start and end times of the execution can be guessed, inferred or measured then it is
|
||||||
|
# critical that steps are taken to hide the execution time, for instance by adding a
|
||||||
|
# delay so that encrypted packets are not sent until a fixed time after the _start_ of
|
||||||
|
# execution.
|
||||||
|
|
||||||
# Since this code makes use of Python's built-in large integer types, it is NOT EXPECTED
|
|
||||||
# to run in constant time. While some effort is made to minimise the time variations,
|
|
||||||
# the underlying math functions are likely to have running times that are highly
|
|
||||||
# value-dependent, leaving this code potentially vulnerable to timing attacks. If this
|
|
||||||
# code is to be used to provide cryptographic security in an environment where the start
|
|
||||||
# and end times of the execution can be guessed, inferred or measured then it is critical
|
|
||||||
# that steps are taken to hide the execution time, for instance by adding a delay so that
|
|
||||||
# encrypted packets are not sent until a fixed time after the _start_ of execution.
|
|
||||||
|
|
||||||
|
|
||||||
# Implements ladder multiplication as described in "Montgomery curves and the Montgomery
|
|
||||||
# ladder" by Daniel J. Bernstein and Tanja Lange. https://eprint.iacr.org/2017/293.pdf
|
|
||||||
|
|
||||||
# Curve25519 is a Montgomery curve defined by:
|
|
||||||
# y**2 = x**3 + A * x**2 + x mod P
|
|
||||||
# where P = 2**255-19 and A = 486662
|
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
import time
|
||||||
|
|
||||||
P = 2 ** 255 - 19
|
P = 2 ** 255 - 19
|
||||||
_A = 486662
|
_A = 486662
|
||||||
@ -124,6 +109,13 @@ class X25519PublicKey:
|
|||||||
|
|
||||||
|
|
||||||
class X25519PrivateKey:
|
class X25519PrivateKey:
|
||||||
|
MIN_EXEC_TIME = 0.002
|
||||||
|
MAX_EXEC_TIME = 0.5
|
||||||
|
DELAY_WINDOW = 10
|
||||||
|
|
||||||
|
T_CLEAR = None
|
||||||
|
T_MAX = 0
|
||||||
|
|
||||||
def __init__(self, a):
|
def __init__(self, a):
|
||||||
self.a = a
|
self.a = a
|
||||||
|
|
||||||
@ -145,4 +137,35 @@ class X25519PrivateKey:
|
|||||||
if isinstance(peer_public_key, bytes):
|
if isinstance(peer_public_key, bytes):
|
||||||
peer_public_key = X25519PublicKey.from_public_bytes(peer_public_key)
|
peer_public_key = X25519PublicKey.from_public_bytes(peer_public_key)
|
||||||
|
|
||||||
return _pack_number(_raw_curve25519(peer_public_key.x, self.a))
|
start = time.time()
|
||||||
|
|
||||||
|
shared = _pack_number(_raw_curve25519(peer_public_key.x, self.a))
|
||||||
|
|
||||||
|
end = time.time()
|
||||||
|
duration = end-start
|
||||||
|
|
||||||
|
if X25519PrivateKey.T_CLEAR == None:
|
||||||
|
X25519PrivateKey.T_CLEAR = end + X25519PrivateKey.DELAY_WINDOW
|
||||||
|
|
||||||
|
if end > X25519PrivateKey.T_CLEAR:
|
||||||
|
X25519PrivateKey.T_CLEAR = end + X25519PrivateKey.DELAY_WINDOW
|
||||||
|
X25519PrivateKey.T_MAX = 0
|
||||||
|
|
||||||
|
if duration < X25519PrivateKey.T_MAX or duration < X25519PrivateKey.MIN_EXEC_TIME:
|
||||||
|
target = start+X25519PrivateKey.T_MAX
|
||||||
|
|
||||||
|
if target > start+X25519PrivateKey.MAX_EXEC_TIME:
|
||||||
|
target = start+X25519PrivateKey.MAX_EXEC_TIME
|
||||||
|
|
||||||
|
if target < start+X25519PrivateKey.MIN_EXEC_TIME:
|
||||||
|
target = start+X25519PrivateKey.MIN_EXEC_TIME
|
||||||
|
|
||||||
|
try:
|
||||||
|
time.sleep(target-time.time())
|
||||||
|
except Exception as e:
|
||||||
|
pass
|
||||||
|
|
||||||
|
elif duration > X25519PrivateKey.T_MAX:
|
||||||
|
X25519PrivateKey.T_MAX = duration
|
||||||
|
|
||||||
|
return shared
|
Loading…
Reference in New Issue
Block a user