diff options
author | Nick Mathewson <nickm@torproject.org> | 2014-02-03 11:34:13 -0500 |
---|---|---|
committer | Nick Mathewson <nickm@torproject.org> | 2014-02-03 11:34:13 -0500 |
commit | 27d81c756b0e28266e75cf4cf897e486d11040b2 (patch) | |
tree | 6cf89e33791e946c36fc56364839379c5ef165e2 /src/test | |
parent | c6c87fb6d172abc7838694e4175f09f60c2ebf87 (diff) | |
download | tor-27d81c756b0e28266e75cf4cf897e486d11040b2.tar tor-27d81c756b0e28266e75cf4cf897e486d11040b2.tar.gz |
slownacl's pure-python curve25519 lets us test ntor everywhere.
Improvement on f308adf8382bc7e61ea05a172, where we made the ntor
unit tests run everywhere... so long as a python curve25519 module
was installed. Now the unit tests don't require that module.
Diffstat (limited to 'src/test')
-rwxr-xr-x | src/test/ntor_ref.py | 19 | ||||
-rw-r--r-- | src/test/slownacl_curve25519.py | 98 |
2 files changed, 108 insertions, 9 deletions
diff --git a/src/test/ntor_ref.py b/src/test/ntor_ref.py index 2a5f98460..12eb00742 100755 --- a/src/test/ntor_ref.py +++ b/src/test/ntor_ref.py @@ -30,11 +30,12 @@ commands: import binascii try: import curve25519 + curve25519mod = curve25519.keys except ImportError: curve25519 = None - print "SKIPPING: No Python curve25519 module installed" - import sys - sys.exit(0) + import slownacl_curve25519 + curve25519mod = slownacl_curve25519 + import hashlib import hmac import subprocess @@ -74,17 +75,17 @@ T_VERIFY = PROTOID + ":verify" def H_mac(msg): return H(msg, tweak=T_MAC) def H_verify(msg): return H(msg, tweak=T_VERIFY) -class PrivateKey(curve25519.keys.Private): - """As curve25519.keys.Private, but doesn't regenerate its public key +class PrivateKey(curve25519mod.Private): + """As curve25519mod.Private, but doesn't regenerate its public key every time you ask for it. """ def __init__(self): - curve25519.keys.Private.__init__(self) + curve25519mod.Private.__init__(self) self._memo_public = None def get_public(self): if self._memo_public is None: - self._memo_public = curve25519.keys.Private.get_public(self) + self._memo_public = curve25519mod.Private.get_public(self) return self._memo_public @@ -184,7 +185,7 @@ def server(seckey_b, my_node_id, message, keyBytes=72): badness = (keyid(seckey_b.get_public()) != message[NODE_ID_LENGTH:NODE_ID_LENGTH+H_LENGTH]) - pubkey_X = curve25519.keys.Public(message[NODE_ID_LENGTH+H_LENGTH:]) + pubkey_X = curve25519mod.Public(message[NODE_ID_LENGTH+H_LENGTH:]) seckey_y = PrivateKey() pubkey_Y = seckey_y.get_public() pubkey_B = seckey_b.get_public() @@ -247,7 +248,7 @@ def client_part2(seckey_x, msg, node_id, pubkey_B, keyBytes=72): """ assert len(msg) == G_LENGTH + H_LENGTH - pubkey_Y = curve25519.keys.Public(msg[:G_LENGTH]) + pubkey_Y = curve25519mod.Public(msg[:G_LENGTH]) their_auth = msg[G_LENGTH:] pubkey_X = seckey_x.get_public() diff --git a/src/test/slownacl_curve25519.py b/src/test/slownacl_curve25519.py new file mode 100644 index 000000000..25244fb12 --- /dev/null +++ b/src/test/slownacl_curve25519.py @@ -0,0 +1,98 @@ +# This is the curve25519 implementation from Matthew Dempsky's "Slownacl" +# library. It is in the public domain. +# +# It isn't constant-time. Don't use it except for testing. +# +# Nick got the slownacl source from: +# https://github.com/mdempsky/dnscurve/tree/master/slownacl + +__all__ = ['smult_curve25519_base', 'smult_curve25519'] + +P = 2 ** 255 - 19 +A = 486662 + +def expmod(b, e, m): + if e == 0: return 1 + t = expmod(b, e / 2, m) ** 2 % m + if e & 1: t = (t * b) % m + return t + +def inv(x): + return expmod(x, P - 2, P) + +# Addition and doubling formulas taken from Appendix D of "Curve25519: +# new Diffie-Hellman speed records". + +def add((xn,zn), (xm,zm), (xd,zd)): + x = 4 * (xm * xn - zm * zn) ** 2 * zd + z = 4 * (xm * zn - zm * xn) ** 2 * xd + return (x % P, z % P) + +def double((xn,zn)): + x = (xn ** 2 - zn ** 2) ** 2 + z = 4 * xn * zn * (xn ** 2 + A * xn * zn + zn ** 2) + return (x % P, z % P) + +def curve25519(n, base): + one = (base,1) + two = double(one) + # f(m) evaluates to a tuple containing the mth multiple and the + # (m+1)th multiple of base. + def f(m): + if m == 1: return (one, two) + (pm, pm1) = f(m / 2) + if (m & 1): + return (add(pm, pm1, one), double(pm1)) + return (double(pm), add(pm, pm1, one)) + ((x,z), _) = f(n) + return (x * inv(z)) % P + +def unpack(s): + if len(s) != 32: raise ValueError('Invalid Curve25519 argument') + return sum(ord(s[i]) << (8 * i) for i in range(32)) + +def pack(n): + return ''.join([chr((n >> (8 * i)) & 255) for i in range(32)]) + +def clamp(n): + n &= ~7 + n &= ~(128 << 8 * 31) + n |= 64 << 8 * 31 + return n + +def smult_curve25519(n, p): + n = clamp(unpack(n)) + p = unpack(p) + return pack(curve25519(n, p)) + +def smult_curve25519_base(n): + n = clamp(unpack(n)) + return pack(curve25519(n, 9)) + + +# +# This part I'm adding in for compatibility with the curve25519 python +# module. -Nick +# +import os + +class Private: + def __init__(self, secret=None, seed=None): + self.private = pack(clamp(unpack(os.urandom(32)))) + + def get_public(self): + return Public(smult_curve25519_base(self.private)) + + def get_shared_key(self, public, hashfn): + return hashfn(smult_curve25519(self.private, public.public)) + + def serialize(self): + return self.private + +class Public: + def __init__(self, public): + self.public = public + + def serialize(self): + return self.public + |