Commit 27d81c75 authored by Nick Mathewson's avatar Nick Mathewson 🦀
Browse files

slownacl's pure-python curve25519 lets us test ntor everywhere.

Improvement on f308adf8, 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.
parent c6c87fb6
Loading
Loading
Loading
Loading
+10 −9
Original line number Diff line number Diff line
@@ -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()
+98 −0
Original line number Diff line number Diff line
# 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