Ticket #466: 2011-02-p1.diff

File 2011-02-p1.diff, 98.6 KB (added by warner, at 2011-02-07T18:29:02Z)

copy python-ecdsa-0.7 into tree as allmydata.util.ecdsa

  • new file src/allmydata/util/ecdsa/__init__.py

    diff --git a/src/allmydata/util/ecdsa/__init__.py b/src/allmydata/util/ecdsa/__init__.py
    new file mode 100644
    index 0000000..0ba98be
    - +  
     1
     2from keys import SigningKey, VerifyingKey, BadSignatureError, BadDigestError
     3from curves import NIST192p, NIST224p, NIST256p, NIST384p, NIST521p
     4
     5_hush_pyflakes = [SigningKey, VerifyingKey, BadSignatureError, BadDigestError,
     6                  NIST192p, NIST224p, NIST256p, NIST384p, NIST521p]
     7del _hush_pyflakes
     8
     9# This code comes from http://github.com/warner/python-ecdsa
     10
     11try:
     12    from _version import __version__ as v
     13    __version__ = v
     14    del v
     15except ImportError:
     16    __version__ = "UNKNOWN"
  • new file src/allmydata/util/ecdsa/_version.py

    diff --git a/src/allmydata/util/ecdsa/_version.py b/src/allmydata/util/ecdsa/_version.py
    new file mode 100644
    index 0000000..327334e
    - +  
     1
     2# This file is originally generated from Git information by running 'setup.py
     3# version'. Distribution tarballs contain a pre-generated copy of this file.
     4
     5__version__ = '0.6'
  • new file src/allmydata/util/ecdsa/curves.py

    diff --git a/src/allmydata/util/ecdsa/curves.py b/src/allmydata/util/ecdsa/curves.py
    new file mode 100644
    index 0000000..2e4cc2c
    - +  
     1import der, ecdsa
     2
     3class UnknownCurveError(Exception):
     4    pass
     5
     6def orderlen(order):
     7    return (1+len("%x"%order))//2 # bytes
     8
     9# the NIST curves
     10class Curve:
     11    def __init__(self, name, curve, generator, oid):
     12        self.name = name
     13        self.curve = curve
     14        self.generator = generator
     15        self.order = generator.order()
     16        self.baselen = orderlen(self.order)
     17        self.verifying_key_length = 2*self.baselen
     18        self.signature_length = 2*self.baselen
     19        self.oid = oid
     20        self.encoded_oid = der.encode_oid(*oid)
     21
     22NIST192p = Curve("NIST192p", ecdsa.curve_192, ecdsa.generator_192,
     23                 (1, 2, 840, 10045, 3, 1, 1))
     24NIST224p = Curve("NIST224p", ecdsa.curve_224, ecdsa.generator_224,
     25                 (1, 3, 132, 0, 33))
     26NIST256p = Curve("NIST256p", ecdsa.curve_256, ecdsa.generator_256,
     27                 (1, 2, 840, 10045, 3, 1, 7))
     28NIST384p = Curve("NIST384p", ecdsa.curve_384, ecdsa.generator_384,
     29                 (1, 3, 132, 0, 34))
     30NIST521p = Curve("NIST521p", ecdsa.curve_521, ecdsa.generator_521,
     31                 (1, 3, 132, 0, 35))
     32
     33curves = [NIST192p, NIST224p, NIST256p, NIST384p, NIST521p]
     34
     35def find_curve(oid_curve):
     36    for c in curves:
     37        if c.oid == oid_curve:
     38            return c
     39    raise UnknownCurveError("I don't know about the curve with oid %s."
     40                            "I only know about these: %s" %
     41                            (oid_curve, [c.name for c in curves]))
  • new file src/allmydata/util/ecdsa/der.py

    diff --git a/src/allmydata/util/ecdsa/der.py b/src/allmydata/util/ecdsa/der.py
    new file mode 100644
    index 0000000..e03ad9c
    - +  
     1import binascii
     2import base64
     3
     4class UnexpectedDER(Exception):
     5    pass
     6
     7def encode_constructed(tag, value):
     8    return chr(0xa0+tag) + encode_length(len(value)) + value
     9def encode_integer(r):
     10    assert r >= 0 # can't support negative numbers yet
     11    h = "%x" % r
     12    if len(h)%2:
     13        h = "0" + h
     14    s = binascii.unhexlify(h)
     15    if ord(s[0]) <= 0x7f:
     16        return "\x02" + chr(len(s)) + s
     17    else:
     18        # DER integers are two's complement, so if the first byte is
     19        # 0x80-0xff then we need an extra 0x00 byte to prevent it from
     20        # looking negative.
     21        return "\x02" + chr(len(s)+1) + "\x00" + s
     22
     23def encode_bitstring(s):
     24    return "\x03" + encode_length(len(s)) + s
     25def encode_octet_string(s):
     26    return "\x04" + encode_length(len(s)) + s
     27def encode_oid(first, second, *pieces):
     28    assert first <= 2
     29    assert second <= 39
     30    encoded_pieces = [chr(40*first+second)] + [encode_number(p)
     31                                               for p in pieces]
     32    body = "".join(encoded_pieces)
     33    return "\x06" + encode_length(len(body)) + body
     34def encode_sequence(*encoded_pieces):
     35    total_len = sum([len(p) for p in encoded_pieces])
     36    return "\x30" + encode_length(total_len) + "".join(encoded_pieces)
     37def encode_number(n):
     38    b128_digits = []
     39    while n:
     40        b128_digits.insert(0, (n & 0x7f) | 0x80)
     41        n = n >> 7
     42    if not b128_digits:
     43        b128_digits.append(0)
     44    b128_digits[-1] &= 0x7f
     45    return "".join([chr(d) for d in b128_digits])
     46
     47def remove_constructed(string):
     48    s0 = ord(string[0])
     49    if (s0 & 0xe0) != 0xa0:
     50        raise UnexpectedDER("wanted constructed tag (0xa0-0xbf), got 0x%02x"
     51                            % s0)
     52    tag = s0 & 0x1f
     53    length, llen = read_length(string[1:])
     54    body = string[1+llen:1+llen+length]
     55    rest = string[1+llen+length:]
     56    return tag, body, rest
     57
     58def remove_sequence(string):
     59    if not string.startswith("\x30"):
     60        raise UnexpectedDER("wanted sequence (0x30), got 0x%02x" %
     61                            ord(string[0]))
     62    length, lengthlength = read_length(string[1:])
     63    endseq = 1+lengthlength+length
     64    return string[1+lengthlength:endseq], string[endseq:]
     65
     66def remove_octet_string(string):
     67    if not string.startswith("\x04"):
     68        raise UnexpectedDER("wanted octetstring (0x04), got 0x%02x" %
     69                            ord(string[0]))
     70    length, llen = read_length(string[1:])
     71    body = string[1+llen:1+llen+length]
     72    rest = string[1+llen+length:]
     73    return body, rest
     74
     75def remove_object(string):
     76    if not string.startswith("\x06"):
     77        raise UnexpectedDER("wanted object (0x06), got 0x%02x" %
     78                            ord(string[0]))
     79    length, lengthlength = read_length(string[1:])
     80    body = string[1+lengthlength:1+lengthlength+length]
     81    rest = string[1+lengthlength+length:]
     82    numbers = []
     83    while body:
     84        n, ll = read_number(body)
     85        numbers.append(n)
     86        body = body[ll:]
     87    n0 = numbers.pop(0)
     88    first = n0//40
     89    second = n0-(40*first)
     90    numbers.insert(0, first)
     91    numbers.insert(1, second)
     92    return tuple(numbers), rest
     93
     94def remove_integer(string):
     95    if not string.startswith("\x02"):
     96        raise UnexpectedDER("wanted integer (0x02), got 0x%02x" %
     97                            ord(string[0]))
     98    length, llen = read_length(string[1:])
     99    numberbytes = string[1+llen:1+llen+length]
     100    rest = string[1+llen+length:]
     101    assert ord(numberbytes[0]) < 0x80 # can't support negative numbers yet
     102    return int(binascii.hexlify(numberbytes), 16), rest
     103
     104def read_number(string):
     105    number = 0
     106    llen = 0
     107    # base-128 big endian, with b7 set in all but the last byte
     108    while True:
     109        if llen > len(string):
     110            raise UnexpectedDER("ran out of length bytes")
     111        number = number << 7
     112        d = ord(string[llen])
     113        number += (d & 0x7f)
     114        llen += 1
     115        if not d & 0x80:
     116            break
     117    return number, llen
     118
     119def encode_length(l):
     120    assert l >= 0
     121    if l < 0x80:
     122        return chr(l)
     123    s = "%x" % l
     124    if len(s)%2:
     125        s = "0"+s
     126    s = binascii.unhexlify(s)
     127    llen = len(s)
     128    return chr(0x80|llen) + s
     129
     130def read_length(string):
     131    if not (ord(string[0]) & 0x80):
     132        # short form
     133        return (ord(string[0]) & 0x7f), 1
     134    # else long-form: b0&0x7f is number of additional base256 length bytes,
     135    # big-endian
     136    llen = ord(string[0]) & 0x7f
     137    if llen > len(string)-1:
     138        raise UnexpectedDER("ran out of length bytes")
     139    return int(binascii.hexlify(string[1:1+llen]), 16), 1+llen
     140
     141def remove_bitstring(string):
     142    if not string.startswith("\x03"):
     143        raise UnexpectedDER("wanted bitstring (0x03), got 0x%02x" %
     144                            ord(string[0]))
     145    length, llen = read_length(string[1:])
     146    body = string[1+llen:1+llen+length]
     147    rest = string[1+llen+length:]
     148    return body, rest
     149
     150# SEQUENCE([1, STRING(secexp), cont[0], OBJECT(curvename), cont[1], BINTSTRING)
     151
     152
     153# signatures: (from RFC3279)
     154#  ansi-X9-62  OBJECT IDENTIFIER ::= {
     155#       iso(1) member-body(2) us(840) 10045 }
     156#
     157#  id-ecSigType OBJECT IDENTIFIER  ::=  {
     158#       ansi-X9-62 signatures(4) }
     159#  ecdsa-with-SHA1  OBJECT IDENTIFIER ::= {
     160#       id-ecSigType 1 }
     161## so 1,2,840,10045,4,1
     162## so 0x42, .. ..
     163
     164#  Ecdsa-Sig-Value  ::=  SEQUENCE  {
     165#       r     INTEGER,
     166#       s     INTEGER  }
     167
     168# id-public-key-type OBJECT IDENTIFIER  ::= { ansi-X9.62 2 }
     169#
     170# id-ecPublicKey OBJECT IDENTIFIER ::= { id-publicKeyType 1 }
     171
     172# I think the secp224r1 identifier is (t=06,l=05,v=2b81040021)
     173#  secp224r1 OBJECT IDENTIFIER ::= {
     174#  iso(1) identified-organization(3) certicom(132) curve(0) 33 }
     175# and the secp384r1 is (t=06,l=05,v=2b81040022)
     176#  secp384r1 OBJECT IDENTIFIER ::= {
     177#  iso(1) identified-organization(3) certicom(132) curve(0) 34 }
     178
     179def unpem(pem):
     180    d = "".join([l.strip() for l in pem.split("\n")
     181                 if l and not l.startswith("-----")])
     182    return base64.b64decode(d)
     183def topem(der, name):
     184    b64 = base64.b64encode(der)
     185    lines = ["-----BEGIN %s-----\n" % name]
     186    lines.extend([b64[start:start+64]+"\n"
     187                  for start in range(0, len(b64), 64)])
     188    lines.append("-----END %s-----\n" % name)
     189    return "".join(lines)
     190
  • new file src/allmydata/util/ecdsa/ecdsa.py

    diff --git a/src/allmydata/util/ecdsa/ecdsa.py b/src/allmydata/util/ecdsa/ecdsa.py
    new file mode 100644
    index 0000000..b9d1f31
    - +  
     1#! /usr/bin/env python
     2"""
     3Implementation of Elliptic-Curve Digital Signatures.
     4
     5Classes and methods for elliptic-curve signatures:
     6private keys, public keys, signatures,
     7NIST prime-modulus curves with modulus lengths of
     8192, 224, 256, 384, and 521 bits.
     9
     10Example:
     11
     12  # (In real-life applications, you would probably want to
     13  # protect against defects in SystemRandom.)
     14  from random import SystemRandom
     15  randrange = SystemRandom().randrange
     16
     17  # Generate a public/private key pair using the NIST Curve P-192:
     18
     19  g = generator_192
     20  n = g.order()
     21  secret = randrange( 1, n )
     22  pubkey = Public_key( g, g * secret )
     23  privkey = Private_key( pubkey, secret )
     24
     25  # Signing a hash value:
     26 
     27  hash = randrange( 1, n )
     28  signature = privkey.sign( hash, randrange( 1, n ) )
     29
     30  # Verifying a signature for a hash value:
     31
     32  if pubkey.verifies( hash, signature ):
     33    print "Demo verification succeeded."
     34  else:
     35    print "*** Demo verification failed."
     36
     37  # Verification fails if the hash value is modified:
     38
     39  if pubkey.verifies( hash-1, signature ):
     40    print "**** Demo verification failed to reject tampered hash."
     41  else:
     42    print "Demo verification correctly rejected tampered hash."
     43
     44Version of 2009.05.16.
     45
     46Revision history:
     47      2005.12.31 - Initial version.
     48      2008.11.25 - Substantial revisions introducing new classes.
     49      2009.05.16 - Warn against using random.randrange in real applications.
     50      2009.05.17 - Use random.SystemRandom by default.
     51
     52Written in 2005 by Peter Pearson and placed in the public domain.
     53"""
     54
     55
     56import ellipticcurve
     57import numbertheory
     58import random
     59
     60
     61
     62class Signature( object ):
     63  """ECDSA signature.
     64  """
     65  def __init__( self, r, s ):
     66    self.r = r
     67    self.s = s
     68
     69
     70
     71class Public_key( object ):
     72  """Public key for ECDSA.
     73  """
     74
     75  def __init__( self, generator, point ):
     76    """generator is the Point that generates the group,
     77    point is the Point that defines the public key.
     78    """
     79   
     80    self.curve = generator.curve()
     81    self.generator = generator
     82    self.point = point
     83    n = generator.order()
     84    if not n:
     85      raise RuntimeError, "Generator point must have order."
     86    if not n * point == ellipticcurve.INFINITY:
     87      raise RuntimeError, "Generator point order is bad."
     88    if point.x() < 0 or n <= point.x() or point.y() < 0 or n <= point.y():
     89      raise RuntimeError, "Generator point has x or y out of range."
     90
     91
     92  def verifies( self, hash, signature ):
     93    """Verify that signature is a valid signature of hash.
     94    Return True if the signature is valid.
     95    """
     96
     97    # From X9.62 J.3.1.
     98
     99    G = self.generator
     100    n = G.order()
     101    r = signature.r
     102    s = signature.s
     103    if r < 1 or r > n-1: return False
     104    if s < 1 or s > n-1: return False
     105    c = numbertheory.inverse_mod( s, n )
     106    u1 = ( hash * c ) % n
     107    u2 = ( r * c ) % n
     108    xy = u1 * G + u2 * self.point
     109    v = xy.x() % n
     110    return v == r
     111   
     112
     113
     114class Private_key( object ):
     115  """Private key for ECDSA.
     116  """
     117
     118  def __init__( self, public_key, secret_multiplier ):
     119    """public_key is of class Public_key;
     120    secret_multiplier is a large integer.
     121    """
     122   
     123    self.public_key = public_key
     124    self.secret_multiplier = secret_multiplier
     125
     126  def sign( self, hash, random_k ):
     127    """Return a signature for the provided hash, using the provided
     128    random nonce.  It is absolutely vital that random_k be an unpredictable
     129    number in the range [1, self.public_key.point.order()-1].  If
     130    an attacker can guess random_k, he can compute our private key from a
     131    single signature.  Also, if an attacker knows a few high-order
     132    bits (or a few low-order bits) of random_k, he can compute our private
     133    key from many signatures.  The generation of nonces with adequate
     134    cryptographic strength is very difficult and far beyond the scope
     135    of this comment.
     136
     137    May raise RuntimeError, in which case retrying with a new
     138    random value k is in order.
     139    """
     140
     141    G = self.public_key.generator
     142    n = G.order()
     143    k = random_k % n
     144    p1 = k * G
     145    r = p1.x()
     146    if r == 0: raise RuntimeError, "amazingly unlucky random number r"
     147    s = ( numbertheory.inverse_mod( k, n ) * \
     148          ( hash + ( self.secret_multiplier * r ) % n ) ) % n
     149    if s == 0: raise RuntimeError, "amazingly unlucky random number s"
     150    return Signature( r, s )
     151
     152
     153
     154def int_to_string( x ):
     155  """Convert integer x into a string of bytes, as per X9.62."""
     156  assert x >= 0
     157  if x == 0: return chr(0)
     158  result = ""
     159  while x > 0:
     160    q, r = divmod( x, 256 )
     161    result = chr( r ) + result
     162    x = q
     163  return result
     164
     165
     166def string_to_int( s ):
     167  """Convert a string of bytes into an integer, as per X9.62."""
     168  result = 0L
     169  for c in s: result = 256 * result + ord( c )
     170  return result
     171
     172
     173def digest_integer( m ):
     174  """Convert an integer into a string of bytes, compute
     175     its SHA-1 hash, and convert the result to an integer."""
     176  #
     177  # I don't expect this function to be used much. I wrote
     178  # it in order to be able to duplicate the examples
     179  # in ECDSAVS.
     180  #
     181  from hashlib import sha1
     182  return string_to_int( sha1( int_to_string( m ) ).digest() )
     183
     184
     185def point_is_valid( generator, x, y ):
     186  """Is (x,y) a valid public key based on the specified generator?"""
     187
     188  # These are the tests specified in X9.62.
     189
     190  n = generator.order()
     191  curve = generator.curve()
     192  if x < 0 or n <= x or y < 0 or n <= y:
     193    return False
     194  if not curve.contains_point( x, y ):
     195    return False
     196  if not n*ellipticcurve.Point( curve, x, y ) == \
     197     ellipticcurve.INFINITY:
     198    return False
     199  return True
     200
     201
     202
     203# NIST Curve P-192:
     204_p = 6277101735386680763835789423207666416083908700390324961279L
     205_r = 6277101735386680763835789423176059013767194773182842284081L
     206# s = 0x3045ae6fc8422f64ed579528d38120eae12196d5L
     207# c = 0x3099d2bbbfcb2538542dcd5fb078b6ef5f3d6fe2c745de65L
     208_b = 0x64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1L
     209_Gx = 0x188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012L
     210_Gy = 0x07192b95ffc8da78631011ed6b24cdd573f977a11e794811L
     211
     212curve_192 = ellipticcurve.CurveFp( _p, -3, _b )
     213generator_192 = ellipticcurve.Point( curve_192, _Gx, _Gy, _r )
     214
     215
     216# NIST Curve P-224:
     217_p = 26959946667150639794667015087019630673557916260026308143510066298881L
     218_r = 26959946667150639794667015087019625940457807714424391721682722368061L
     219# s = 0xbd71344799d5c7fcdc45b59fa3b9ab8f6a948bc5L
     220# c = 0x5b056c7e11dd68f40469ee7f3c7a7d74f7d121116506d031218291fbL
     221_b = 0xb4050a850c04b3abf54132565044b0b7d7bfd8ba270b39432355ffb4L
     222_Gx =0xb70e0cbd6bb4bf7f321390b94a03c1d356c21122343280d6115c1d21L
     223_Gy = 0xbd376388b5f723fb4c22dfe6cd4375a05a07476444d5819985007e34L
     224
     225curve_224 = ellipticcurve.CurveFp( _p, -3, _b )
     226generator_224 = ellipticcurve.Point( curve_224, _Gx, _Gy, _r )
     227
     228# NIST Curve P-256:
     229_p = 115792089210356248762697446949407573530086143415290314195533631308867097853951L
     230_r = 115792089210356248762697446949407573529996955224135760342422259061068512044369L
     231# s = 0xc49d360886e704936a6678e1139d26b7819f7e90L
     232# c = 0x7efba1662985be9403cb055c75d4f7e0ce8d84a9c5114abcaf3177680104fa0dL
     233_b = 0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604bL
     234_Gx = 0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296L
     235_Gy = 0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5L
     236
     237curve_256 = ellipticcurve.CurveFp( _p, -3, _b )
     238generator_256 = ellipticcurve.Point( curve_256, _Gx, _Gy, _r )
     239
     240# NIST Curve P-384:
     241_p = 39402006196394479212279040100143613805079739270465446667948293404245721771496870329047266088258938001861606973112319L
     242_r = 39402006196394479212279040100143613805079739270465446667946905279627659399113263569398956308152294913554433653942643L
     243# s = 0xa335926aa319a27a1d00896a6773a4827acdac73L
     244# c = 0x79d1e655f868f02fff48dcdee14151ddb80643c1406d0ca10dfe6fc52009540a495e8042ea5f744f6e184667cc722483L
     245_b = 0xb3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875ac656398d8a2ed19d2a85c8edd3ec2aefL
     246_Gx = 0xaa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e3872760ab7L
     247_Gy = 0x3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5fL
     248
     249curve_384 = ellipticcurve.CurveFp( _p, -3, _b )
     250generator_384 = ellipticcurve.Point( curve_384, _Gx, _Gy, _r )
     251
     252# NIST Curve P-521:
     253_p = 6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057151L
     254_r = 6864797660130609714981900799081393217269435300143305409394463459185543183397655394245057746333217197532963996371363321113864768612440380340372808892707005449L
     255# s = 0xd09e8800291cb85396cc6717393284aaa0da64baL
     256# c = 0x0b48bfa5f420a34949539d2bdfc264eeeeb077688e44fbf0ad8f6d0edb37bd6b533281000518e19f1b9ffbe0fe9ed8a3c2200b8f875e523868c70c1e5bf55bad637L
     257_b = 0x051953eb9618e1c9a1f929a21a0b68540eea2da725b99b315f3b8b489918ef109e156193951ec7e937b1652c0bd3bb1bf073573df883d2c34f1ef451fd46b503f00L
     258_Gx = 0xc6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f828af606b4d3dbaa14b5e77efe75928fe1dc127a2ffa8de3348b3c1856a429bf97e7e31c2e5bd66L
     259_Gy = 0x11839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd17273e662c97ee72995ef42640c550b9013fad0761353c7086a272c24088be94769fd16650L
     260
     261curve_521 = ellipticcurve.CurveFp( _p, -3, _b )
     262generator_521 = ellipticcurve.Point( curve_521, _Gx, _Gy, _r )
     263
     264 
     265
     266def __main__():
     267  class TestFailure(Exception): pass
     268
     269  def test_point_validity( generator, x, y, expected ):
     270    """generator defines the curve; is (x,y) a point on
     271       this curve? "expected" is True if the right answer is Yes."""
     272    if point_is_valid( generator, x, y ) == expected:
     273      print "Point validity tested as expected."
     274    else:
     275      raise TestFailure("*** Point validity test gave wrong result.")
     276
     277  def test_signature_validity( Msg, Qx, Qy, R, S, expected ):
     278    """Msg = message, Qx and Qy represent the base point on
     279       elliptic curve c192, R and S are the signature, and
     280       "expected" is True iff the signature is expected to be valid."""
     281    pubk = Public_key( generator_192,
     282                       ellipticcurve.Point( curve_192, Qx, Qy ) )
     283    got = pubk.verifies( digest_integer( Msg ), Signature( R, S ) )
     284    if got == expected:
     285      print "Signature tested as expected: got %s, expected %s." % \
     286            ( got, expected )
     287    else:
     288      raise TestFailure("*** Signature test failed: got %s, expected %s." % \
     289                        ( got, expected ))
     290
     291  print "NIST Curve P-192:"
     292
     293  p192 = generator_192
     294
     295  # From X9.62:
     296
     297  d = 651056770906015076056810763456358567190100156695615665659L
     298  Q = d * p192
     299  if Q.x() != 0x62B12D60690CDCF330BABAB6E69763B471F994DD702D16A5L:
     300    raise TestFailure("*** p192 * d came out wrong.")
     301  else:
     302    print "p192 * d came out right."
     303
     304  k = 6140507067065001063065065565667405560006161556565665656654L
     305  R = k * p192
     306  if R.x() != 0x885052380FF147B734C330C43D39B2C4A89F29B0F749FEADL \
     307     or R.y() != 0x9CF9FA1CBEFEFB917747A3BB29C072B9289C2547884FD835L:
     308    raise TestFailure("*** k * p192 came out wrong.")
     309  else:
     310    print "k * p192 came out right."
     311
     312  u1 = 2563697409189434185194736134579731015366492496392189760599L
     313  u2 = 6266643813348617967186477710235785849136406323338782220568L
     314  temp = u1 * p192 + u2 * Q
     315  if temp.x() != 0x885052380FF147B734C330C43D39B2C4A89F29B0F749FEADL \
     316     or temp.y() != 0x9CF9FA1CBEFEFB917747A3BB29C072B9289C2547884FD835L:
     317    raise TestFailure("*** u1 * p192 + u2 * Q came out wrong.")
     318  else:
     319    print "u1 * p192 + u2 * Q came out right."
     320
     321  e = 968236873715988614170569073515315707566766479517L
     322  pubk = Public_key( generator_192, generator_192 * d )
     323  privk = Private_key( pubk, d )
     324  sig = privk.sign( e, k )
     325  r, s = sig.r, sig.s
     326  if r != 3342403536405981729393488334694600415596881826869351677613L \
     327     or s != 5735822328888155254683894997897571951568553642892029982342L:
     328    raise TestFailure("*** r or s came out wrong.")
     329  else:
     330    print "r and s came out right."
     331
     332  valid = pubk.verifies( e, sig )
     333  if valid: print "Signature verified OK."
     334  else: raise TestFailure("*** Signature failed verification.")
     335
     336  valid = pubk.verifies( e-1, sig )
     337  if not valid: print "Forgery was correctly rejected."
     338  else: raise TestFailure("*** Forgery was erroneously accepted.")
     339
     340  print "Testing point validity, as per ECDSAVS.pdf B.2.2:"
     341
     342  test_point_validity( \
     343    p192, \
     344    0xcd6d0f029a023e9aaca429615b8f577abee685d8257cc83aL, \
     345    0x00019c410987680e9fb6c0b6ecc01d9a2647c8bae27721bacdfcL, \
     346    False )
     347
     348  test_point_validity(
     349    p192, \
     350    0x00017f2fce203639e9eaf9fb50b81fc32776b30e3b02af16c73bL, \
     351    0x95da95c5e72dd48e229d4748d4eee658a9a54111b23b2adbL, \
     352    False )
     353
     354  test_point_validity(
     355    p192, \
     356    0x4f77f8bc7fccbadd5760f4938746d5f253ee2168c1cf2792L, \
     357    0x000147156ff824d131629739817edb197717c41aab5c2a70f0f6L, \
     358    False )
     359
     360  test_point_validity(
     361    p192, \
     362    0xc58d61f88d905293bcd4cd0080bcb1b7f811f2ffa41979f6L, \
     363    0x8804dc7a7c4c7f8b5d437f5156f3312ca7d6de8a0e11867fL, \
     364    True )
     365
     366  test_point_validity(
     367    p192, \
     368    0xcdf56c1aa3d8afc53c521adf3ffb96734a6a630a4a5b5a70L, \
     369    0x97c1c44a5fb229007b5ec5d25f7413d170068ffd023caa4eL, \
     370    True )
     371
     372  test_point_validity(
     373    p192, \
     374    0x89009c0dc361c81e99280c8e91df578df88cdf4b0cdedcedL, \
     375    0x27be44a529b7513e727251f128b34262a0fd4d8ec82377b9L, \
     376    True )
     377
     378  test_point_validity(
     379    p192, \
     380    0x6a223d00bd22c52833409a163e057e5b5da1def2a197dd15L, \
     381    0x7b482604199367f1f303f9ef627f922f97023e90eae08abfL, \
     382    True )
     383 
     384  test_point_validity(
     385    p192, \
     386    0x6dccbde75c0948c98dab32ea0bc59fe125cf0fb1a3798edaL, \
     387    0x0001171a3e0fa60cf3096f4e116b556198de430e1fbd330c8835L, \
     388    False )
     389 
     390  test_point_validity(
     391    p192, \
     392    0xd266b39e1f491fc4acbbbc7d098430931cfa66d55015af12L, \
     393    0x193782eb909e391a3148b7764e6b234aa94e48d30a16dbb2L, \
     394    False )
     395 
     396  test_point_validity(
     397    p192, \
     398    0x9d6ddbcd439baa0c6b80a654091680e462a7d1d3f1ffeb43L, \
     399    0x6ad8efc4d133ccf167c44eb4691c80abffb9f82b932b8caaL, \
     400    False )
     401 
     402  test_point_validity(
     403    p192, \
     404    0x146479d944e6bda87e5b35818aa666a4c998a71f4e95edbcL, \
     405    0xa86d6fe62bc8fbd88139693f842635f687f132255858e7f6L, \
     406    False )
     407 
     408  test_point_validity(
     409    p192, \
     410    0xe594d4a598046f3598243f50fd2c7bd7d380edb055802253L, \
     411    0x509014c0c4d6b536e3ca750ec09066af39b4c8616a53a923L, \
     412    False )
     413
     414  print "Trying signature-verification tests from ECDSAVS.pdf B.2.4:"
     415  print "P-192:"
     416  Msg = 0x84ce72aa8699df436059f052ac51b6398d2511e49631bcb7e71f89c499b9ee425dfbc13a5f6d408471b054f2655617cbbaf7937b7c80cd8865cf02c8487d30d2b0fbd8b2c4e102e16d828374bbc47b93852f212d5043c3ea720f086178ff798cc4f63f787b9c2e419efa033e7644ea7936f54462dc21a6c4580725f7f0e7d158L
     417  Qx = 0xd9dbfb332aa8e5ff091e8ce535857c37c73f6250ffb2e7acL
     418  Qy = 0x282102e364feded3ad15ddf968f88d8321aa268dd483ebc4L
     419  R = 0x64dca58a20787c488d11d6dd96313f1b766f2d8efe122916L
     420  S = 0x1ecba28141e84ab4ecad92f56720e2cc83eb3d22dec72479L
     421  test_signature_validity( Msg, Qx, Qy, R, S, True )
     422
     423  Msg = 0x94bb5bacd5f8ea765810024db87f4224ad71362a3c28284b2b9f39fab86db12e8beb94aae899768229be8fdb6c4f12f28912bb604703a79ccff769c1607f5a91450f30ba0460d359d9126cbd6296be6d9c4bb96c0ee74cbb44197c207f6db326ab6f5a659113a9034e54be7b041ced9dcf6458d7fb9cbfb2744d999f7dfd63f4L
     424  Qx = 0x3e53ef8d3112af3285c0e74842090712cd324832d4277ae7L
     425  Qy = 0xcc75f8952d30aec2cbb719fc6aa9934590b5d0ff5a83adb7L
     426  R = 0x8285261607283ba18f335026130bab31840dcfd9c3e555afL
     427  S = 0x356d89e1b04541afc9704a45e9c535ce4a50929e33d7e06cL
     428  test_signature_validity( Msg, Qx, Qy, R, S, True )
     429
     430  Msg = 0xf6227a8eeb34afed1621dcc89a91d72ea212cb2f476839d9b4243c66877911b37b4ad6f4448792a7bbba76c63bdd63414b6facab7dc71c3396a73bd7ee14cdd41a659c61c99b779cecf07bc51ab391aa3252386242b9853ea7da67fd768d303f1b9b513d401565b6f1eb722dfdb96b519fe4f9bd5de67ae131e64b40e78c42ddL
     431  Qx = 0x16335dbe95f8e8254a4e04575d736befb258b8657f773cb7L
     432  Qy = 0x421b13379c59bc9dce38a1099ca79bbd06d647c7f6242336L
     433  R = 0x4141bd5d64ea36c5b0bd21ef28c02da216ed9d04522b1e91L
     434  S = 0x159a6aa852bcc579e821b7bb0994c0861fb08280c38daa09L
     435  test_signature_validity( Msg, Qx, Qy, R, S, False )
     436
     437  Msg = 0x16b5f93afd0d02246f662761ed8e0dd9504681ed02a253006eb36736b563097ba39f81c8e1bce7a16c1339e345efabbc6baa3efb0612948ae51103382a8ee8bc448e3ef71e9f6f7a9676694831d7f5dd0db5446f179bcb737d4a526367a447bfe2c857521c7f40b6d7d7e01a180d92431fb0bbd29c04a0c420a57b3ed26ccd8aL
     438  Qx = 0xfd14cdf1607f5efb7b1793037b15bdf4baa6f7c16341ab0bL
     439  Qy = 0x83fa0795cc6c4795b9016dac928fd6bac32f3229a96312c4L
     440  R = 0x8dfdb832951e0167c5d762a473c0416c5c15bc1195667dc1L
     441  S = 0x1720288a2dc13fa1ec78f763f8fe2ff7354a7e6fdde44520L
     442  test_signature_validity( Msg, Qx, Qy, R, S, False )
     443
     444  Msg = 0x08a2024b61b79d260e3bb43ef15659aec89e5b560199bc82cf7c65c77d39192e03b9a895d766655105edd9188242b91fbde4167f7862d4ddd61e5d4ab55196683d4f13ceb90d87aea6e07eb50a874e33086c4a7cb0273a8e1c4408f4b846bceae1ebaac1b2b2ea851a9b09de322efe34cebe601653efd6ddc876ce8c2f2072fbL
     445  Qx = 0x674f941dc1a1f8b763c9334d726172d527b90ca324db8828L
     446  Qy = 0x65adfa32e8b236cb33a3e84cf59bfb9417ae7e8ede57a7ffL
     447  R = 0x9508b9fdd7daf0d8126f9e2bc5a35e4c6d800b5b804d7796L
     448  S = 0x36f2bf6b21b987c77b53bb801b3435a577e3d493744bfab0L
     449  test_signature_validity( Msg, Qx, Qy, R, S, False )
     450
     451  Msg = 0x1843aba74b0789d4ac6b0b8923848023a644a7b70afa23b1191829bbe4397ce15b629bf21a8838298653ed0c19222b95fa4f7390d1b4c844d96e645537e0aae98afb5c0ac3bd0e4c37f8daaff25556c64e98c319c52687c904c4de7240a1cc55cd9756b7edaef184e6e23b385726e9ffcba8001b8f574987c1a3fedaaa83ca6dL
     452  Qx = 0x10ecca1aad7220b56a62008b35170bfd5e35885c4014a19fL
     453  Qy = 0x04eb61984c6c12ade3bc47f3c629ece7aa0a033b9948d686L
     454  R = 0x82bfa4e82c0dfe9274169b86694e76ce993fd83b5c60f325L
     455  S = 0xa97685676c59a65dbde002fe9d613431fb183e8006d05633L
     456  test_signature_validity( Msg, Qx, Qy, R, S, False )
     457
     458  Msg = 0x5a478f4084ddd1a7fea038aa9732a822106385797d02311aeef4d0264f824f698df7a48cfb6b578cf3da416bc0799425bb491be5b5ecc37995b85b03420a98f2c4dc5c31a69a379e9e322fbe706bbcaf0f77175e05cbb4fa162e0da82010a278461e3e974d137bc746d1880d6eb02aa95216014b37480d84b87f717bb13f76e1L
     459  Qx = 0x6636653cb5b894ca65c448277b29da3ad101c4c2300f7c04L
     460  Qy = 0xfdf1cbb3fc3fd6a4f890b59e554544175fa77dbdbeb656c1L
     461  R = 0xeac2ddecddfb79931a9c3d49c08de0645c783a24cb365e1cL
     462  S = 0x3549fee3cfa7e5f93bc47d92d8ba100e881a2a93c22f8d50L
     463  test_signature_validity( Msg, Qx, Qy, R, S, False )
     464
     465  Msg = 0xc598774259a058fa65212ac57eaa4f52240e629ef4c310722088292d1d4af6c39b49ce06ba77e4247b20637174d0bd67c9723feb57b5ead232b47ea452d5d7a089f17c00b8b6767e434a5e16c231ba0efa718a340bf41d67ea2d295812ff1b9277daacb8bc27b50ea5e6443bcf95ef4e9f5468fe78485236313d53d1c68f6ba2L
     466  Qx = 0xa82bd718d01d354001148cd5f69b9ebf38ff6f21898f8aaaL
     467  Qy = 0xe67ceede07fc2ebfafd62462a51e4b6c6b3d5b537b7caf3eL
     468  R = 0x4d292486c620c3de20856e57d3bb72fcde4a73ad26376955L
     469  S = 0xa85289591a6081d5728825520e62ff1c64f94235c04c7f95L
     470  test_signature_validity( Msg, Qx, Qy, R, S, False )
     471
     472  Msg = 0xca98ed9db081a07b7557f24ced6c7b9891269a95d2026747add9e9eb80638a961cf9c71a1b9f2c29744180bd4c3d3db60f2243c5c0b7cc8a8d40a3f9a7fc910250f2187136ee6413ffc67f1a25e1c4c204fa9635312252ac0e0481d89b6d53808f0c496ba87631803f6c572c1f61fa049737fdacce4adff757afed4f05beb658L
     473  Qx = 0x7d3b016b57758b160c4fca73d48df07ae3b6b30225126c2fL
     474  Qy = 0x4af3790d9775742bde46f8da876711be1b65244b2b39e7ecL
     475  R = 0x95f778f5f656511a5ab49a5d69ddd0929563c29cbc3a9e62L
     476  S = 0x75c87fc358c251b4c83d2dd979faad496b539f9f2ee7a289L
     477  test_signature_validity( Msg, Qx, Qy, R, S, False )
     478
     479  Msg = 0x31dd9a54c8338bea06b87eca813d555ad1850fac9742ef0bbe40dad400e10288acc9c11ea7dac79eb16378ebea9490e09536099f1b993e2653cd50240014c90a9c987f64545abc6a536b9bd2435eb5e911fdfde2f13be96ea36ad38df4ae9ea387b29cced599af777338af2794820c9cce43b51d2112380a35802ab7e396c97aL
     480  Qx = 0x9362f28c4ef96453d8a2f849f21e881cd7566887da8beb4aL
     481  Qy = 0xe64d26d8d74c48a024ae85d982ee74cd16046f4ee5333905L
     482  R = 0xf3923476a296c88287e8de914b0b324ad5a963319a4fe73bL
     483  S = 0xf0baeed7624ed00d15244d8ba2aede085517dbdec8ac65f5L
     484  test_signature_validity( Msg, Qx, Qy, R, S, True )
     485
     486  Msg = 0xb2b94e4432267c92f9fdb9dc6040c95ffa477652761290d3c7de312283f6450d89cc4aabe748554dfb6056b2d8e99c7aeaad9cdddebdee9dbc099839562d9064e68e7bb5f3a6bba0749ca9a538181fc785553a4000785d73cc207922f63e8ce1112768cb1de7b673aed83a1e4a74592f1268d8e2a4e9e63d414b5d442bd0456dL
     487  Qx = 0xcc6fc032a846aaac25533eb033522824f94e670fa997ecefL
     488  Qy = 0xe25463ef77a029eccda8b294fd63dd694e38d223d30862f1L
     489  R = 0x066b1d07f3a40e679b620eda7f550842a35c18b80c5ebe06L
     490  S = 0xa0b0fb201e8f2df65e2c4508ef303bdc90d934016f16b2dcL
     491  test_signature_validity( Msg, Qx, Qy, R, S, False )
     492
     493  Msg = 0x4366fcadf10d30d086911de30143da6f579527036937007b337f7282460eae5678b15cccda853193ea5fc4bc0a6b9d7a31128f27e1214988592827520b214eed5052f7775b750b0c6b15f145453ba3fee24a085d65287e10509eb5d5f602c440341376b95c24e5c4727d4b859bfe1483d20538acdd92c7997fa9c614f0f839d7L
     494  Qx = 0x955c908fe900a996f7e2089bee2f6376830f76a19135e753L
     495  Qy = 0xba0c42a91d3847de4a592a46dc3fdaf45a7cc709b90de520L
     496  R = 0x1f58ad77fc04c782815a1405b0925e72095d906cbf52a668L
     497  S = 0xf2e93758b3af75edf784f05a6761c9b9a6043c66b845b599L
     498  test_signature_validity( Msg, Qx, Qy, R, S, False )
     499
     500  Msg = 0x543f8af57d750e33aa8565e0cae92bfa7a1ff78833093421c2942cadf9986670a5ff3244c02a8225e790fbf30ea84c74720abf99cfd10d02d34377c3d3b41269bea763384f372bb786b5846f58932defa68023136cd571863b304886e95e52e7877f445b9364b3f06f3c28da12707673fecb4b8071de06b6e0a3c87da160cef3L
     501  Qx = 0x31f7fa05576d78a949b24812d4383107a9a45bb5fccdd835L
     502  Qy = 0x8dc0eb65994a90f02b5e19bd18b32d61150746c09107e76bL
     503  R = 0xbe26d59e4e883dde7c286614a767b31e49ad88789d3a78ffL
     504  S = 0x8762ca831c1ce42df77893c9b03119428e7a9b819b619068L
     505  test_signature_validity( Msg, Qx, Qy, R, S, False )
     506
     507  Msg = 0xd2e8454143ce281e609a9d748014dcebb9d0bc53adb02443a6aac2ffe6cb009f387c346ecb051791404f79e902ee333ad65e5c8cb38dc0d1d39a8dc90add5023572720e5b94b190d43dd0d7873397504c0c7aef2727e628eb6a74411f2e400c65670716cb4a815dc91cbbfeb7cfe8c929e93184c938af2c078584da045e8f8d1L
     508  Qx = 0x66aa8edbbdb5cf8e28ceb51b5bda891cae2df84819fe25c0L
     509  Qy = 0x0c6bc2f69030a7ce58d4a00e3b3349844784a13b8936f8daL
     510  R = 0xa4661e69b1734f4a71b788410a464b71e7ffe42334484f23L
     511  S = 0x738421cf5e049159d69c57a915143e226cac8355e149afe9L
     512  test_signature_validity( Msg, Qx, Qy, R, S, False )
     513
     514  Msg = 0x6660717144040f3e2f95a4e25b08a7079c702a8b29babad5a19a87654bc5c5afa261512a11b998a4fb36b5d8fe8bd942792ff0324b108120de86d63f65855e5461184fc96a0a8ffd2ce6d5dfb0230cbbdd98f8543e361b3205f5da3d500fdc8bac6db377d75ebef3cb8f4d1ff738071ad0938917889250b41dd1d98896ca06fbL
     515  Qx = 0xbcfacf45139b6f5f690a4c35a5fffa498794136a2353fc77L
     516  Qy = 0x6f4a6c906316a6afc6d98fe1f0399d056f128fe0270b0f22L
     517  R = 0x9db679a3dafe48f7ccad122933acfe9da0970b71c94c21c1L
     518  S = 0x984c2db99827576c0a41a5da41e07d8cc768bc82f18c9da9L
     519  test_signature_validity( Msg, Qx, Qy, R, S, False )
     520
     521
     522
     523  print "Testing the example code:"
     524
     525  # Building a public/private key pair from the NIST Curve P-192:
     526
     527  g = generator_192
     528  n = g.order()
     529
     530  # (random.SystemRandom is supposed to provide
     531  # crypto-quality random numbers, but as Debian recently
     532  # illustrated, a systems programmer can accidentally
     533  # demolish this security, so in serious applications
     534  # further precautions are appropriate.)
     535
     536  randrange = random.SystemRandom().randrange
     537 
     538  secret = randrange( 1, n )
     539  pubkey = Public_key( g, g * secret )
     540  privkey = Private_key( pubkey, secret )
     541
     542  # Signing a hash value:
     543 
     544  hash = randrange( 1, n )
     545  signature = privkey.sign( hash, randrange( 1, n ) )
     546
     547  # Verifying a signature for a hash value:
     548 
     549  if pubkey.verifies( hash, signature ):
     550    print "Demo verification succeeded."
     551  else:
     552    raise TestFailure("*** Demo verification failed.")
     553
     554  if pubkey.verifies( hash-1, signature ):
     555    raise TestFailure( "**** Demo verification failed to reject tampered hash.")
     556  else:
     557    print "Demo verification correctly rejected tampered hash."
     558
     559if __name__ == "__main__":
     560  __main__()
  • new file src/allmydata/util/ecdsa/ellipticcurve.py

    diff --git a/src/allmydata/util/ecdsa/ellipticcurve.py b/src/allmydata/util/ecdsa/ellipticcurve.py
    new file mode 100644
    index 0000000..c1eb361
    - +  
     1#! /usr/bin/env python
     2#
     3# Implementation of elliptic curves, for cryptographic applications.
     4#
     5# This module doesn't provide any way to choose a random elliptic
     6# curve, nor to verify that an elliptic curve was chosen randomly,
     7# because one can simply use NIST's standard curves.
     8#
     9# Notes from X9.62-1998 (draft):
     10#   Nomenclature:
     11#     - Q is a public key.
     12#     The "Elliptic Curve Domain Parameters" include:
     13#     - q is the "field size", which in our case equals p.
     14#     - p is a big prime.
     15#     - G is a point of prime order (5.1.1.1).
     16#     - n is the order of G (5.1.1.1).
     17#   Public-key validation (5.2.2):
     18#     - Verify that Q is not the point at infinity.
     19#     - Verify that X_Q and Y_Q are in [0,p-1].
     20#     - Verify that Q is on the curve.
     21#     - Verify that nQ is the point at infinity.
     22#   Signature generation (5.3):
     23#     - Pick random k from [1,n-1].
     24#   Signature checking (5.4.2):
     25#     - Verify that r and s are in [1,n-1].
     26#
     27# Version of 2008.11.25.
     28#
     29# Revision history:
     30#    2005.12.31 - Initial version.
     31#    2008.11.25 - Change CurveFp.is_on to contains_point.
     32#
     33# Written in 2005 by Peter Pearson and placed in the public domain.
     34
     35import numbertheory
     36
     37class CurveFp( object ):
     38  """Elliptic Curve over the field of integers modulo a prime."""
     39  def __init__( self, p, a, b ):
     40    """The curve of points satisfying y^2 = x^3 + a*x + b (mod p)."""
     41    self.__p = p
     42    self.__a = a
     43    self.__b = b
     44
     45  def p( self ):
     46    return self.__p
     47
     48  def a( self ):
     49    return self.__a
     50
     51  def b( self ):
     52    return self.__b
     53
     54  def contains_point( self, x, y ):
     55    """Is the point (x,y) on this curve?"""
     56    return ( y * y - ( x * x * x + self.__a * x + self.__b ) ) % self.__p == 0
     57
     58
     59
     60class Point( object ):
     61  """A point on an elliptic curve. Altering x and y is forbidding,
     62     but they can be read by the x() and y() methods."""
     63  def __init__( self, curve, x, y, order = None ):
     64    """curve, x, y, order; order (optional) is the order of this point."""
     65    self.__curve = curve
     66    self.__x = x
     67    self.__y = y
     68    self.__order = order
     69    # self.curve is allowed to be None only for INFINITY:
     70    if self.__curve: assert self.__curve.contains_point( x, y )
     71    if order: assert self * order == INFINITY
     72 
     73  def __cmp__( self, other ):
     74    """Return 0 if the points are identical, 1 otherwise."""
     75    if self.__curve == other.__curve \
     76       and self.__x == other.__x \
     77       and self.__y == other.__y:
     78      return 0
     79    else:
     80      return 1
     81
     82  def __add__( self, other ):
     83    """Add one point to another point."""
     84   
     85    # X9.62 B.3:
     86
     87    if other == INFINITY: return self
     88    if self == INFINITY: return other
     89    assert self.__curve == other.__curve
     90    if self.__x == other.__x:
     91      if ( self.__y + other.__y ) % self.__curve.p() == 0:
     92        return INFINITY
     93      else:
     94        return self.double()
     95
     96    p = self.__curve.p()
     97
     98    l = ( ( other.__y - self.__y ) * \
     99          numbertheory.inverse_mod( other.__x - self.__x, p ) ) % p
     100
     101    x3 = ( l * l - self.__x - other.__x ) % p
     102    y3 = ( l * ( self.__x - x3 ) - self.__y ) % p
     103   
     104    return Point( self.__curve, x3, y3 )
     105
     106  def __mul__( self, other ):
     107    """Multiply a point by an integer."""
     108
     109    def leftmost_bit( x ):
     110      assert x > 0
     111      result = 1L
     112      while result <= x: result = 2 * result
     113      return result // 2
     114
     115    e = other
     116    if self.__order: e = e % self.__order
     117    if e == 0: return INFINITY
     118    if self == INFINITY: return INFINITY
     119    assert e > 0
     120
     121    # From X9.62 D.3.2:
     122
     123    e3 = 3 * e
     124    negative_self = Point( self.__curve, self.__x, -self.__y, self.__order )
     125    i = leftmost_bit( e3 ) // 2
     126    result = self
     127    # print "Multiplying %s by %d (e3 = %d):" % ( self, other, e3 )
     128    while i > 1:
     129      result = result.double()
     130      if ( e3 & i ) != 0 and ( e & i ) == 0: result = result + self
     131      if ( e3 & i ) == 0 and ( e & i ) != 0: result = result + negative_self
     132      # print ". . . i = %d, result = %s" % ( i, result )
     133      i = i // 2
     134
     135    return result
     136
     137  def __rmul__( self, other ):
     138    """Multiply a point by an integer."""
     139   
     140    return self * other
     141
     142  def __str__( self ):
     143    if self == INFINITY: return "infinity"
     144    return "(%d,%d)" % ( self.__x, self.__y )
     145
     146  def double( self ):
     147    """Return a new point that is twice the old."""
     148
     149    if self == INFINITY:
     150      return INFINITY
     151
     152    # X9.62 B.3:
     153
     154    p = self.__curve.p()
     155    a = self.__curve.a()
     156
     157    l = ( ( 3 * self.__x * self.__x + a ) * \
     158          numbertheory.inverse_mod( 2 * self.__y, p ) ) % p
     159
     160    x3 = ( l * l - 2 * self.__x ) % p
     161    y3 = ( l * ( self.__x - x3 ) - self.__y ) % p
     162   
     163    return Point( self.__curve, x3, y3 )
     164
     165  def x( self ):
     166    return self.__x
     167
     168  def y( self ):
     169    return self.__y
     170
     171  def curve( self ):
     172    return self.__curve
     173 
     174  def order( self ):
     175    return self.__order
     176
     177
     178# This one point is the Point At Infinity for all purposes:
     179INFINITY = Point( None, None, None ) 
     180
     181def __main__():
     182
     183  class FailedTest(Exception): pass
     184  def test_add( c, x1, y1, x2,  y2, x3, y3 ):
     185    """We expect that on curve c, (x1,y1) + (x2, y2 ) = (x3, y3)."""
     186    p1 = Point( c, x1, y1 )
     187    p2 = Point( c, x2, y2 )
     188    p3 = p1 + p2
     189    print "%s + %s = %s" % ( p1, p2, p3 ),
     190    if p3.x() != x3 or p3.y() != y3:
     191      raise FailedTest("Failure: should give (%d,%d)." % ( x3, y3 ))
     192    else:
     193      print " Good."
     194
     195  def test_double( c, x1, y1, x3, y3 ):
     196    """We expect that on curve c, 2*(x1,y1) = (x3, y3)."""
     197    p1 = Point( c, x1, y1 )
     198    p3 = p1.double()
     199    print "%s doubled = %s" % ( p1, p3 ),
     200    if p3.x() != x3 or p3.y() != y3:
     201      raise FailedTest("Failure: should give (%d,%d)." % ( x3, y3 ))
     202    else:
     203      print " Good."
     204
     205  def test_double_infinity( c ):
     206    """We expect that on curve c, 2*INFINITY = INFINITY."""
     207    p1 = INFINITY
     208    p3 = p1.double()
     209    print "%s doubled = %s" % ( p1, p3 ),
     210    if p3.x() != INFINITY.x() or p3.y() != INFINITY.y():
     211      raise FailedTest("Failure: should give (%d,%d)." % ( INFINITY.x(), INFINITY.y() ))
     212    else:
     213      print " Good."
     214
     215  def test_multiply( c, x1, y1, m, x3, y3 ):
     216    """We expect that on curve c, m*(x1,y1) = (x3,y3)."""
     217    p1 = Point( c, x1, y1 )
     218    p3 = p1 * m
     219    print "%s * %d = %s" % ( p1, m, p3 ),
     220    if p3.x() != x3 or p3.y() != y3:
     221      raise FailedTest("Failure: should give (%d,%d)." % ( x3, y3 ))
     222    else:
     223      print " Good."
     224
     225
     226  # A few tests from X9.62 B.3:
     227
     228  c = CurveFp( 23, 1, 1 )
     229  test_add( c, 3, 10, 9, 7, 17, 20 )
     230  test_double( c, 3, 10, 7, 12 )
     231  test_add( c, 3, 10, 3, 10, 7, 12 )    # (Should just invoke double.)
     232  test_multiply( c, 3, 10, 2, 7, 12 )
     233
     234  test_double_infinity(c)
     235
     236  # From X9.62 I.1 (p. 96):
     237
     238  g = Point( c, 13, 7, 7 )
     239
     240  check = INFINITY
     241  for i in range( 7 + 1 ):
     242    p = ( i % 7 ) * g
     243    print "%s * %d = %s, expected %s . . ." % ( g, i, p, check ),
     244    if p == check:
     245      print " Good."
     246    else:
     247      raise FailedTest("Bad.")
     248    check = check + g
     249
     250  # NIST Curve P-192:
     251  p = 6277101735386680763835789423207666416083908700390324961279L
     252  r = 6277101735386680763835789423176059013767194773182842284081L
     253  #s = 0x3045ae6fc8422f64ed579528d38120eae12196d5L
     254  c = 0x3099d2bbbfcb2538542dcd5fb078b6ef5f3d6fe2c745de65L
     255  b = 0x64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1L
     256  Gx = 0x188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012L
     257  Gy = 0x07192b95ffc8da78631011ed6b24cdd573f977a11e794811L
     258
     259  c192 = CurveFp( p, -3, b )
     260  p192 = Point( c192, Gx, Gy, r )
     261
     262  # Checking against some sample computations presented
     263  # in X9.62:
     264
     265  d = 651056770906015076056810763456358567190100156695615665659L
     266  Q = d * p192
     267  if Q.x() != 0x62B12D60690CDCF330BABAB6E69763B471F994DD702D16A5L:
     268    raise FailedTest("p192 * d came out wrong.")
     269  else:
     270    print "p192 * d came out right."
     271
     272  k = 6140507067065001063065065565667405560006161556565665656654L
     273  R = k * p192
     274  if R.x() != 0x885052380FF147B734C330C43D39B2C4A89F29B0F749FEADL \
     275     or R.y() != 0x9CF9FA1CBEFEFB917747A3BB29C072B9289C2547884FD835L:
     276    raise FailedTest("k * p192 came out wrong.")
     277  else:
     278    print "k * p192 came out right."
     279
     280  u1 = 2563697409189434185194736134579731015366492496392189760599L
     281  u2 = 6266643813348617967186477710235785849136406323338782220568L
     282  temp = u1 * p192 + u2 * Q
     283  if temp.x() != 0x885052380FF147B734C330C43D39B2C4A89F29B0F749FEADL \
     284     or temp.y() != 0x9CF9FA1CBEFEFB917747A3BB29C072B9289C2547884FD835L:
     285    raise FailedTest("u1 * p192 + u2 * Q came out wrong.")
     286  else:
     287    print "u1 * p192 + u2 * Q came out right."
     288
     289if __name__ == "__main__":
     290  __main__()
  • new file src/allmydata/util/ecdsa/keys.py

    diff --git a/src/allmydata/util/ecdsa/keys.py b/src/allmydata/util/ecdsa/keys.py
    new file mode 100644
    index 0000000..6017f2c
    - +  
     1import binascii
     2
     3import ecdsa
     4import der
     5from curves import NIST192p, find_curve
     6from util import string_to_number, number_to_string, randrange
     7from util import sigencode_string, sigdecode_string
     8from util import oid_ecPublicKey, encoded_oid_ecPublicKey
     9from hashlib import sha1
     10
     11class BadSignatureError(Exception):
     12    pass
     13class BadDigestError(Exception):
     14    pass
     15
     16class VerifyingKey:
     17    @classmethod
     18    def from_public_point(klass, point, curve=NIST192p):
     19        self = klass()
     20        self.curve = curve
     21        self.pubkey = ecdsa.Public_key(curve.generator, point)
     22        self.pubkey.order = curve.order
     23        return self
     24
     25    @classmethod
     26    def from_string(klass, string, curve=NIST192p):
     27        order = curve.order
     28        assert len(string) == curve.verifying_key_length, \
     29               (len(string), curve.verifying_key_length)
     30        xs = string[:curve.baselen]
     31        ys = string[curve.baselen:]
     32        assert len(xs) == curve.baselen, (len(xs), curve.baselen)
     33        assert len(ys) == curve.baselen, (len(ys), curve.baselen)
     34        x = string_to_number(xs)
     35        y = string_to_number(ys)
     36        assert ecdsa.point_is_valid(curve.generator, x, y)
     37        import ellipticcurve
     38        point = ellipticcurve.Point(curve.curve, x, y, order)
     39        return klass.from_public_point(point, curve)
     40
     41    @classmethod
     42    def from_pem(klass, string):
     43        return klass.from_der(der.unpem(string))
     44
     45    @classmethod
     46    def from_der(klass, string):
     47        # [[oid_ecPublicKey,oid_curve], point_str_bitstring]
     48        s1,empty = der.remove_sequence(string)
     49        if empty != "":
     50            raise der.UnexpectedDER("trailing junk after DER pubkey: %s" %
     51                                    binascii.hexlify(empty))
     52        s2,point_str_bitstring = der.remove_sequence(s1)
     53        # s2 = oid_ecPublicKey,oid_curve
     54        oid_pk, rest = der.remove_object(s2)
     55        oid_curve, empty = der.remove_object(rest)
     56        if empty != "":
     57            raise der.UnexpectedDER("trailing junk after DER pubkey objects: %s" %
     58                                    binascii.hexlify(empty))
     59        assert oid_pk == oid_ecPublicKey, (oid_pk, oid_ecPublicKey)
     60        curve = find_curve(oid_curve)
     61        point_str, empty = der.remove_bitstring(point_str_bitstring)
     62        if empty != "":
     63            raise der.UnexpectedDER("trailing junk after pubkey pointstring: %s" %
     64                                    binascii.hexlify(empty))
     65        assert point_str.startswith("\x00\x04")
     66        return klass.from_string(point_str[2:], curve)
     67
     68    def to_string(self):
     69        # VerifyingKey.from_string(vk.to_string()) == vk as long as the
     70        # curves are the same: the curve itself is not included in the
     71        # serialized form
     72        order = self.pubkey.order
     73        x_str = number_to_string(self.pubkey.point.x(), order)
     74        y_str = number_to_string(self.pubkey.point.y(), order)
     75        return x_str + y_str
     76
     77    def to_pem(self):
     78        return der.topem(self.to_der(), "PUBLIC KEY")
     79
     80    def to_der(self):
     81        order = self.pubkey.order
     82        x_str = number_to_string(self.pubkey.point.x(), order)
     83        y_str = number_to_string(self.pubkey.point.y(), order)
     84        point_str = "\x00\x04" + x_str + y_str
     85        return der.encode_sequence(der.encode_sequence(encoded_oid_ecPublicKey,
     86                                                       self.curve.encoded_oid),
     87                                   der.encode_bitstring(point_str))
     88
     89    def verify(self, signature, data, hashfunc=sha1, sigdecode=sigdecode_string):
     90        digest = hashfunc(data).digest()
     91        return self.verify_digest(signature, digest, sigdecode)
     92
     93    def verify_digest(self, signature, digest, sigdecode=sigdecode_string):
     94        if len(digest) > self.curve.baselen:
     95            raise BadDigestError("this curve (%s) is too short "
     96                                 "for your digest (%d)" % (self.curve.name,
     97                                                           8*len(digest)))
     98        number = string_to_number(digest)
     99        r, s = sigdecode(signature, self.pubkey.order)
     100        sig = ecdsa.Signature(r, s)
     101        if self.pubkey.verifies(number, sig):
     102            return True
     103        raise BadSignatureError
     104
     105class SigningKey:
     106    @classmethod
     107    def generate(klass, curve=NIST192p, entropy=None):
     108        secexp = randrange(curve.order, entropy)
     109        return klass.from_secret_exponent(secexp, curve)
     110
     111    # to create a signing key from a short (arbitrary-length) seed, convert
     112    # that seed into an integer with something like
     113    # secexp=util.randrange_from_seed__X(seed, curve.order), and then pass
     114    # that integer into SigningKey.from_secret_exponent(secexp, curve)
     115
     116    @classmethod
     117    def from_secret_exponent(klass, secexp, curve=NIST192p):
     118        self = klass()
     119        self.curve = curve
     120        self.baselen = curve.baselen
     121        n = curve.order
     122        assert 1 <= secexp < n
     123        pubkey_point = curve.generator*secexp
     124        pubkey = ecdsa.Public_key(curve.generator, pubkey_point)
     125        pubkey.order = n
     126        self.verifying_key = VerifyingKey.from_public_point(pubkey_point, curve)
     127        self.privkey = ecdsa.Private_key(pubkey, secexp)
     128        self.privkey.order = n
     129        return self
     130
     131    @classmethod
     132    def from_string(klass, string, curve=NIST192p):
     133        assert len(string) == curve.baselen, (len(string), curve.baselen)
     134        secexp = string_to_number(string)
     135        return klass.from_secret_exponent(secexp, curve)
     136
     137    @classmethod
     138    def from_pem(klass, string):
     139        # the privkey pem file has two sections: "EC PARAMETERS" and "EC
     140        # PRIVATE KEY". The first is redundant.
     141        privkey_pem = string[string.index("-----BEGIN EC PRIVATE KEY-----"):]
     142        return klass.from_der(der.unpem(privkey_pem))
     143    @classmethod
     144    def from_der(klass, string):
     145        # SEQ([int(1), octetstring(privkey),cont[0], oid(secp224r1),
     146        #      cont[1],bitstring])
     147        s, empty = der.remove_sequence(string)
     148        if empty != "":
     149            raise der.UnexpectedDER("trailing junk after DER privkey: %s" %
     150                                    binascii.hexlify(empty))
     151        one, s = der.remove_integer(s)
     152        if one != 1:
     153            raise der.UnexpectedDER("expected '1' at start of DER privkey,"
     154                                    " got %d" % one)
     155        privkey_str, s = der.remove_octet_string(s)
     156        tag, curve_oid_str, s = der.remove_constructed(s)
     157        if tag != 0:
     158            raise der.UnexpectedDER("expected tag 0 in DER privkey,"
     159                                    " got %d" % tag)
     160        curve_oid, empty = der.remove_object(curve_oid_str)
     161        if empty != "":
     162            raise der.UnexpectedDER("trailing junk after DER privkey "
     163                                    "curve_oid: %s" % binascii.hexlify(empty))
     164        curve = find_curve(curve_oid)
     165
     166        # we don't actually care about the following fields
     167        #
     168        #tag, pubkey_bitstring, s = der.remove_constructed(s)
     169        #if tag != 1:
     170        #    raise der.UnexpectedDER("expected tag 1 in DER privkey, got %d"
     171        #                            % tag)
     172        #pubkey_str = der.remove_bitstring(pubkey_bitstring)
     173        #if empty != "":
     174        #    raise der.UnexpectedDER("trailing junk after DER privkey "
     175        #                            "pubkeystr: %s" % binascii.hexlify(empty))
     176
     177        # our from_string method likes fixed-length privkey strings
     178        if len(privkey_str) < curve.baselen:
     179            privkey_str = "\x00"*(curve.baselen-len(privkey_str)) + privkey_str
     180        return klass.from_string(privkey_str, curve)
     181
     182    def to_string(self):
     183        secexp = self.privkey.secret_multiplier
     184        s = number_to_string(secexp, self.privkey.order)
     185        return s
     186
     187    def to_pem(self):
     188        # TODO: "BEGIN ECPARAMETERS"
     189        return der.topem(self.to_der(), "EC PRIVATE KEY")
     190
     191    def to_der(self):
     192        # SEQ([int(1), octetstring(privkey),cont[0], oid(secp224r1),
     193        #      cont[1],bitstring])
     194        encoded_vk = "\x00\x04" + self.get_verifying_key().to_string()
     195        return der.encode_sequence(der.encode_integer(1),
     196                                   der.encode_octet_string(self.to_string()),
     197                                   der.encode_constructed(0, self.curve.encoded_oid),
     198                                   der.encode_constructed(1, der.encode_bitstring(encoded_vk)),
     199                                   )
     200
     201    def get_verifying_key(self):
     202        return self.verifying_key
     203
     204    def sign(self, data, entropy=None, hashfunc=sha1, sigencode=sigencode_string):
     205        """
     206        hashfunc= should behave like hashlib.sha1 . The output length of the
     207        hash (in bytes) must not be longer than the length of the curve order
     208        (rounded up to the nearest byte), so using SHA256 with nist256p is
     209        ok, but SHA256 with nist192p is not. (In the 2**-96ish unlikely event
     210        of a hash output larger than the curve order, the hash will
     211        effectively be wrapped mod n).
     212
     213        Use hashfunc=hashlib.sha1 to match openssl's -ecdsa-with-SHA1 mode,
     214        or hashfunc=hashlib.sha256 for openssl-1.0.0's -ecdsa-with-SHA256.
     215        """
     216
     217        h = hashfunc(data).digest()
     218        return self.sign_digest(h, entropy, sigencode)
     219
     220    def sign_digest(self, digest, entropy=None, sigencode=sigencode_string):
     221        if len(digest) > self.curve.baselen:
     222            raise BadDigestError("this curve (%s) is too short "
     223                                 "for your digest (%d)" % (self.curve.name,
     224                                                           8*len(digest)))
     225        number = string_to_number(digest)
     226        r, s = self.sign_number(number, entropy)
     227        return sigencode(r, s, self.privkey.order)
     228
     229    def sign_number(self, number, entropy=None):
     230        # returns a pair of numbers
     231        order = self.privkey.order
     232        # privkey.sign() may raise RuntimeError in the amazingly unlikely
     233        # (2**-192) event that r=0 or s=0, because that would leak the key.
     234        # We could re-try with a different 'k', but we couldn't test that
     235        # code, so I choose to allow the signature to fail instead.
     236        k = randrange(order, entropy)
     237        assert 1 <= k < order
     238        sig = self.privkey.sign(number, k)
     239        return sig.r, sig.s
  • new file src/allmydata/util/ecdsa/numbertheory.py

    diff --git a/src/allmydata/util/ecdsa/numbertheory.py b/src/allmydata/util/ecdsa/numbertheory.py
    new file mode 100644
    index 0000000..a07fb57
    - +  
     1#! /usr/bin/env python
     2#
     3# Provide some simple capabilities from number theory.
     4#
     5# Version of 2008.11.14.
     6#
     7# Written in 2005 and 2006 by Peter Pearson and placed in the public domain.
     8# Revision history:
     9#   2008.11.14: Use pow( base, exponent, modulus ) for modular_exp.
     10#               Make gcd and lcm accept arbitrarly many arguments.
     11
     12
     13
     14import math
     15import types
     16
     17
     18class Error( Exception ):
     19  """Base class for exceptions in this module."""
     20  pass
     21
     22class SquareRootError( Error ):
     23  pass
     24
     25class NegativeExponentError( Error ):
     26  pass
     27
     28
     29def modular_exp( base, exponent, modulus ):
     30  "Raise base to exponent, reducing by modulus"
     31  if exponent < 0:
     32    raise NegativeExponentError( "Negative exponents (%d) not allowed" \
     33                                 % exponent )
     34  return pow( base, exponent, modulus )
     35#   result = 1L
     36#   x = exponent
     37#   b = base + 0L
     38#   while x > 0:
     39#     if x % 2 > 0: result = (result * b) % modulus
     40#     x = x // 2
     41#     b = ( b * b ) % modulus
     42#   return result
     43
     44
     45def polynomial_reduce_mod( poly, polymod, p ):
     46  """Reduce poly by polymod, integer arithmetic modulo p.
     47
     48  Polynomials are represented as lists of coefficients
     49  of increasing powers of x."""
     50
     51  # This module has been tested only by extensive use
     52  # in calculating modular square roots.
     53
     54  # Just to make this easy, require a monic polynomial:
     55  assert polymod[-1] == 1
     56
     57  assert len( polymod ) > 1
     58
     59  while len( poly ) >= len( polymod ):
     60    if poly[-1] != 0:
     61      for i in range( 2, len( polymod ) + 1 ):
     62        poly[-i] = ( poly[-i] - poly[-1] * polymod[-i] ) % p
     63    poly = poly[0:-1]
     64
     65  return poly
     66
     67
     68
     69def polynomial_multiply_mod( m1, m2, polymod, p ):
     70  """Polynomial multiplication modulo a polynomial over ints mod p.
     71
     72  Polynomials are represented as lists of coefficients
     73  of increasing powers of x."""
     74
     75  # This is just a seat-of-the-pants implementation.
     76
     77  # This module has been tested only by extensive use
     78  # in calculating modular square roots.
     79
     80  # Initialize the product to zero:
     81
     82  prod = ( len( m1 ) + len( m2 ) - 1 ) * [0]
     83
     84  # Add together all the cross-terms:
     85
     86  for i in range( len( m1 ) ):
     87    for j in range( len( m2 ) ):
     88      prod[i+j] = ( prod[i+j] + m1[i] * m2[j] ) % p
     89
     90  return polynomial_reduce_mod( prod, polymod, p )
     91
     92 
     93
     94 
     95def polynomial_exp_mod( base, exponent, polymod, p ):
     96  """Polynomial exponentiation modulo a polynomial over ints mod p.
     97
     98  Polynomials are represented as lists of coefficients
     99  of increasing powers of x."""
     100
     101  # Based on the Handbook of Applied Cryptography, algorithm 2.227.
     102
     103  # This module has been tested only by extensive use
     104  # in calculating modular square roots.
     105
     106  assert exponent < p
     107
     108  if exponent == 0: return [ 1 ]
     109
     110  G = base
     111  k = exponent
     112  if k%2 == 1: s = G
     113  else:        s = [ 1 ]
     114
     115  while k > 1:
     116    k = k // 2
     117    G = polynomial_multiply_mod( G, G, polymod, p )
     118    if k%2 == 1: s = polynomial_multiply_mod( G, s, polymod, p )
     119
     120  return s
     121
     122
     123
     124def jacobi( a, n ):
     125  """Jacobi symbol"""
     126
     127  # Based on the Handbook of Applied Cryptography (HAC), algorithm 2.149.
     128
     129  # This function has been tested by comparison with a small
     130  # table printed in HAC, and by extensive use in calculating
     131  # modular square roots.
     132
     133  assert n >= 3
     134  assert n%2 == 1
     135  a = a % n
     136  if a == 0: return 0
     137  if a == 1: return 1
     138  a1, e = a, 0
     139  while a1%2 == 0:
     140    a1, e = a1//2, e+1
     141  if e%2 == 0 or n%8 == 1 or n%8 == 7: s = 1
     142  else: s = -1
     143  if a1 == 1: return s
     144  if n%4 == 3 and a1%4 == 3: s = -s
     145  return s * jacobi( n % a1, a1 )
     146 
     147
     148
     149
     150def square_root_mod_prime( a, p ):
     151  """Modular square root of a, mod p, p prime."""
     152
     153  # Based on the Handbook of Applied Cryptography, algorithms 3.34 to 3.39.
     154
     155  # This module has been tested for all values in [0,p-1] for
     156  # every prime p from 3 to 1229.
     157
     158  assert 0 <= a < p
     159  assert 1 < p
     160
     161  if a == 0: return 0
     162  if p == 2: return a
     163 
     164  jac = jacobi( a, p )
     165  if jac == -1: raise SquareRootError( "%d has no square root modulo %d" \
     166                                       % ( a, p ) )
     167
     168  if p % 4 == 3: return modular_exp( a, (p+1)//4, p )
     169
     170  if p % 8 == 5:
     171    d = modular_exp( a, (p-1)//4, p )
     172    if d == 1: return modular_exp( a, (p+3)//8, p )
     173    if d == p-1: return ( 2 * a * modular_exp( 4*a, (p-5)//8, p ) ) % p
     174    raise RuntimeError, "Shouldn't get here."
     175
     176  for b in range( 2, p ):
     177    if jacobi( b*b-4*a, p ) == -1:
     178      f = ( a, -b, 1 )
     179      ff = polynomial_exp_mod( ( 0, 1 ), (p+1)//2, f, p )
     180      assert ff[1] == 0
     181      return ff[0]
     182  raise RuntimeError, "No b found."
     183
     184
     185
     186def inverse_mod( a, m ):
     187  """Inverse of a mod m."""
     188
     189  if a < 0 or m <= a: a = a % m
     190
     191  # From Ferguson and Schneier, roughly:
     192
     193  c, d = a, m
     194  uc, vc, ud, vd = 1, 0, 0, 1
     195  while c != 0:
     196    q, c, d = divmod( d, c ) + ( c, )
     197    uc, vc, ud, vd = ud - q*uc, vd - q*vc, uc, vc
     198
     199  # At this point, d is the GCD, and ud*a+vd*m = d.
     200  # If d == 1, this means that ud is a inverse.
     201
     202  assert d == 1
     203  if ud > 0: return ud
     204  else: return ud + m
     205
     206
     207def gcd2(a, b):
     208  """Greatest common divisor using Euclid's algorithm."""
     209  while a:
     210    a, b = b%a, a
     211  return b
     212
     213
     214def gcd( *a ):
     215  """Greatest common divisor.
     216
     217  Usage: gcd( [ 2, 4, 6 ] )
     218  or:    gcd( 2, 4, 6 )
     219  """
     220
     221  if len( a ) > 1: return reduce( gcd2, a )
     222  if hasattr( a[0], "__iter__" ): return reduce( gcd2, a[0] )
     223  return a[0]
     224
     225
     226def lcm2(a,b):
     227  """Least common multiple of two integers."""
     228
     229  return (a*b)//gcd(a,b)
     230
     231
     232def lcm( *a ):
     233  """Least common multiple.
     234
     235  Usage: lcm( [ 3, 4, 5 ] )
     236  or:    lcm( 3, 4, 5 )
     237  """
     238
     239  if len( a ) > 1: return reduce( lcm2, a )
     240  if hasattr( a[0], "__iter__" ): return reduce( lcm2, a[0] )
     241  return a[0]
     242
     243
     244
     245def factorization( n ):
     246  """Decompose n into a list of (prime,exponent) pairs."""
     247
     248  assert isinstance( n, types.IntType ) or isinstance( n, types.LongType )
     249
     250  if n < 2: return []
     251
     252  result = []
     253  d = 2
     254
     255  # Test the small primes:
     256
     257  for d in smallprimes:
     258    if d > n: break
     259    q, r = divmod( n, d )
     260    if r == 0:
     261      count = 1
     262      while d <= n:
     263        n = q
     264        q, r = divmod( n, d )
     265        if r != 0: break
     266        count = count + 1
     267      result.append( ( d, count ) )
     268
     269  # If n is still greater than the last of our small primes,
     270  # it may require further work:
     271
     272  if n > smallprimes[-1]:
     273    if is_prime( n ):   # If what's left is prime, it's easy:
     274      result.append( ( n, 1 ) )
     275    else:               # Ugh. Search stupidly for a divisor:
     276      d = smallprimes[-1]
     277      while 1:
     278        d = d + 2               # Try the next divisor.
     279        q, r = divmod( n, d )
     280        if q < d: break         # n < d*d means we're done, n = 1 or prime.
     281        if r == 0:              # d divides n. How many times?
     282          count = 1
     283          n = q
     284          while d <= n:                 # As long as d might still divide n,
     285            q, r = divmod( n, d )       # see if it does.
     286            if r != 0: break
     287            n = q                       # It does. Reduce n, increase count.
     288            count = count + 1
     289          result.append( ( d, count ) )
     290      if n > 1: result.append( ( n, 1 ) )
     291       
     292  return result
     293
     294
     295
     296def phi( n ):
     297  """Return the Euler totient function of n."""
     298
     299  assert isinstance( n, types.IntType ) or isinstance( n, types.LongType )
     300
     301  if n < 3: return 1
     302
     303  result = 1
     304  ff = factorization( n )
     305  for f in ff:
     306    e = f[1]
     307    if e > 1:
     308      result = result * f[0] ** (e-1) * ( f[0] - 1 )
     309    else:
     310      result = result * ( f[0] - 1 )
     311  return result
     312
     313
     314def carmichael( n ):
     315  """Return Carmichael function of n.
     316
     317  Carmichael(n) is the smallest integer x such that
     318  m**x = 1 mod n for all m relatively prime to n.
     319  """
     320
     321  return carmichael_of_factorized( factorization( n ) )
     322
     323
     324def carmichael_of_factorized( f_list ):
     325  """Return the Carmichael function of a number that is
     326  represented as a list of (prime,exponent) pairs.
     327  """
     328
     329  if len( f_list ) < 1: return 1
     330
     331  result = carmichael_of_ppower( f_list[0] )
     332  for i in range( 1, len( f_list ) ):
     333    result = lcm( result, carmichael_of_ppower( f_list[i] ) )
     334
     335  return result
     336
     337def carmichael_of_ppower( pp ):
     338  """Carmichael function of the given power of the given prime.
     339  """
     340
     341  p, a = pp
     342  if p == 2 and a > 2: return 2**(a-2)
     343  else: return (p-1) * p**(a-1)
     344
     345
     346
     347def order_mod( x, m ):
     348  """Return the order of x in the multiplicative group mod m.
     349  """
     350
     351  # Warning: this implementation is not very clever, and will
     352  # take a long time if m is very large.
     353
     354  if m <= 1: return 0
     355
     356  assert gcd( x, m ) == 1
     357
     358  z = x
     359  result = 1
     360  while z != 1:
     361    z = ( z * x ) % m
     362    result = result + 1
     363  return result
     364
     365
     366def largest_factor_relatively_prime( a, b ):
     367  """Return the largest factor of a relatively prime to b.
     368  """
     369
     370  while 1:
     371    d = gcd( a, b )
     372    if d <= 1: break
     373    b = d
     374    while 1:
     375      q, r = divmod( a, d )
     376      if r > 0:
     377        break
     378      a = q
     379  return a
     380
     381
     382def kinda_order_mod( x, m ):
     383  """Return the order of x in the multiplicative group mod m',
     384  where m' is the largest factor of m relatively prime to x.
     385  """
     386
     387  return order_mod( x, largest_factor_relatively_prime( m, x ) )
     388
     389
     390def is_prime( n ):
     391  """Return True if x is prime, False otherwise.
     392
     393  We use the Miller-Rabin test, as given in Menezes et al. p. 138.
     394  This test is not exact: there are composite values n for which
     395  it returns True.
     396
     397  In testing the odd numbers from 10000001 to 19999999,
     398  about 66 composites got past the first test,
     399  5 got past the second test, and none got past the third.
     400  Since factors of 2, 3, 5, 7, and 11 were detected during
     401  preliminary screening, the number of numbers tested by
     402  Miller-Rabin was (19999999 - 10000001)*(2/3)*(4/5)*(6/7)
     403  = 4.57 million.
     404  """
     405 
     406  # (This is used to study the risk of false positives:)
     407  global miller_rabin_test_count
     408
     409  miller_rabin_test_count = 0
     410 
     411  if n <= smallprimes[-1]:
     412    if n in smallprimes: return True
     413    else: return False
     414
     415  if gcd( n, 2*3*5*7*11 ) != 1: return False
     416
     417  # Choose a number of iterations sufficient to reduce the
     418  # probability of accepting a composite below 2**-80
     419  # (from Menezes et al. Table 4.4):
     420
     421  t = 40
     422  n_bits = 1 + int( math.log( n, 2 ) )
     423  for k, tt in ( ( 100, 27 ),
     424                 ( 150, 18 ),
     425                 ( 200, 15 ),
     426                 ( 250, 12 ),
     427                 ( 300,  9 ),
     428                 ( 350,  8 ),
     429                 ( 400,  7 ),
     430                 ( 450,  6 ),
     431                 ( 550,  5 ),
     432                 ( 650,  4 ),
     433                 ( 850,  3 ),
     434                 ( 1300, 2 ),
     435                 ):
     436    if n_bits < k: break
     437    t = tt
     438
     439  # Run the test t times:
     440
     441  s = 0
     442  r = n - 1
     443  while ( r % 2 ) == 0:
     444    s = s + 1
     445    r = r // 2
     446  for i in xrange( t ):
     447    a = smallprimes[ i ]
     448    y = modular_exp( a, r, n )
     449    if y != 1 and y != n-1:
     450      j = 1
     451      while j <= s - 1 and y != n - 1:
     452        y = modular_exp( y, 2, n )
     453        if y == 1:
     454          miller_rabin_test_count = i + 1
     455          return False
     456        j = j + 1
     457      if y != n-1:
     458        miller_rabin_test_count = i + 1
     459        return False
     460  return True
     461
     462
     463def next_prime( starting_value ):
     464  "Return the smallest prime larger than the starting value."
     465
     466  if starting_value < 2: return 2
     467  result = ( starting_value + 1 ) | 1
     468  while not is_prime( result ): result = result + 2
     469  return result
     470
     471
     472smallprimes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41,
     473               43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97,
     474               101, 103, 107, 109, 113, 127, 131, 137, 139, 149,
     475               151, 157, 163, 167, 173, 179, 181, 191, 193, 197,
     476               199, 211, 223, 227, 229, 233, 239, 241, 251, 257,
     477               263, 269, 271, 277, 281, 283, 293, 307, 311, 313,
     478               317, 331, 337, 347, 349, 353, 359, 367, 373, 379,
     479               383, 389, 397, 401, 409, 419, 421, 431, 433, 439,
     480               443, 449, 457, 461, 463, 467, 479, 487, 491, 499,
     481               503, 509, 521, 523, 541, 547, 557, 563, 569, 571,
     482               577, 587, 593, 599, 601, 607, 613, 617, 619, 631,
     483               641, 643, 647, 653, 659, 661, 673, 677, 683, 691,
     484               701, 709, 719, 727, 733, 739, 743, 751, 757, 761,
     485               769, 773, 787, 797, 809, 811, 821, 823, 827, 829,
     486               839, 853, 857, 859, 863, 877, 881, 883, 887, 907,
     487               911, 919, 929, 937, 941, 947, 953, 967, 971, 977,
     488               983, 991, 997, 1009, 1013, 1019, 1021, 1031, 1033,
     489               1039, 1049, 1051, 1061, 1063, 1069, 1087, 1091, 1093,
     490               1097, 1103, 1109, 1117, 1123, 1129, 1151, 1153, 1163,
     491               1171, 1181, 1187, 1193, 1201, 1213, 1217, 1223, 1229]
     492
     493miller_rabin_test_count = 0
     494
     495def __main__():
     496 
     497  # Making sure locally defined exceptions work:
     498  # p = modular_exp( 2, -2, 3 )
     499  # p = square_root_mod_prime( 2, 3 )
     500
     501
     502  print "Testing gcd..."
     503  assert gcd( 3*5*7, 3*5*11, 3*5*13 )     == 3*5
     504  assert gcd( [ 3*5*7, 3*5*11, 3*5*13 ] ) == 3*5
     505  assert gcd( 3 ) == 3
     506
     507  print "Testing lcm..."
     508  assert lcm( 3, 5*3, 7*3 )     == 3*5*7
     509  assert lcm( [ 3, 5*3, 7*3 ] ) == 3*5*7
     510  assert lcm( 3 ) == 3
     511
     512  print "Testing next_prime..."
     513  bigprimes = ( 999671,
     514                999683,
     515                999721,
     516                999727,
     517                999749,
     518                999763,
     519                999769,
     520                999773,
     521                999809,
     522                999853,
     523                999863,
     524                999883,
     525                999907,
     526                999917,
     527                999931,
     528                999953,
     529                999959,
     530                999961,
     531                999979,
     532                999983 )
     533
     534  for i in xrange( len( bigprimes ) - 1 ):
     535    assert next_prime( bigprimes[i] ) == bigprimes[ i+1 ]
     536
     537  error_tally = 0
     538
     539  # Test the square_root_mod_prime function:
     540
     541  for p in smallprimes:
     542    print "Testing square_root_mod_prime for modulus p = %d." % p
     543    squares = []
     544
     545    for root in range( 0, 1+p//2 ):
     546      sq = ( root * root ) % p
     547      squares.append( sq )
     548      calculated = square_root_mod_prime( sq, p )
     549      if ( calculated * calculated ) % p != sq:
     550        error_tally = error_tally + 1
     551        print "Failed to find %d as sqrt( %d ) mod %d. Said %d." % \
     552              ( root, sq, p, calculated )
     553
     554    for nonsquare in range( 0, p ):
     555      if nonsquare not in squares:
     556        try:
     557          calculated = square_root_mod_prime( nonsquare, p )
     558        except SquareRootError:
     559          pass
     560        else:
     561          error_tally = error_tally + 1
     562          print "Failed to report no root for sqrt( %d ) mod %d." % \
     563                ( nonsquare, p )
     564
     565  # Test the jacobi function:
     566  for m in range( 3, 400, 2 ):
     567    print "Testing jacobi for modulus m = %d." % m
     568    if is_prime( m ):
     569      squares = []
     570      for root in range( 1, m ):
     571        if jacobi( root * root, m ) != 1:
     572          error_tally = error_tally + 1
     573          print "jacobi( %d * %d, %d ) != 1" % ( root, root, m )
     574        squares.append( root * root % m )
     575      for i in range( 1, m ):
     576        if not i in squares:
     577          if jacobi( i, m ) != -1:
     578            error_tally = error_tally + 1
     579            print "jacobi( %d, %d ) != -1" % ( i, m )
     580    else:       # m is not prime.
     581      f = factorization( m )
     582      for a in range( 1, m ):
     583        c = 1
     584        for i in f:
     585          c = c * jacobi( a, i[0] ) ** i[1]
     586        if c != jacobi( a, m ):
     587          error_tally = error_tally + 1
     588          print "%d != jacobi( %d, %d )" % ( c, a, m )
     589
     590
     591# Test the inverse_mod function:
     592  print "Testing inverse_mod . . ."
     593  import random
     594  n_tests = 0
     595  for i in range( 100 ):
     596    m = random.randint( 20, 10000 )
     597    for j in range( 100 ):
     598      a = random.randint( 1, m-1 )
     599      if gcd( a, m ) == 1:
     600        n_tests = n_tests + 1
     601        inv = inverse_mod( a, m )
     602        if inv <= 0 or inv >= m or ( a * inv ) % m != 1:
     603          error_tally = error_tally + 1
     604          print "%d = inverse_mod( %d, %d ) is wrong." % ( inv, a, m )
     605  assert n_tests > 1000
     606  print n_tests, " tests of inverse_mod completed."
     607
     608  class FailedTest(Exception): pass
     609  print error_tally, "errors detected."
     610  if error_tally != 0:
     611    raise FailedTest("%d errors detected" % error_tally)
     612
     613if __name__ == '__main__':
     614  __main__()
  • new file src/allmydata/util/ecdsa/test_pyecdsa.py

    diff --git a/src/allmydata/util/ecdsa/test_pyecdsa.py b/src/allmydata/util/ecdsa/test_pyecdsa.py
    new file mode 100644
    index 0000000..34176b9
    - +  
     1import unittest
     2import os
     3import time
     4import shutil
     5import subprocess
     6from binascii import hexlify, unhexlify
     7from hashlib import sha1
     8
     9from keys import SigningKey, VerifyingKey
     10from keys import BadSignatureError
     11import util
     12from util import sigencode_der, sigencode_strings
     13from util import sigdecode_der, sigdecode_strings
     14from curves import Curve, UnknownCurveError
     15from curves import NIST192p, NIST224p, NIST256p, NIST384p, NIST521p
     16import der
     17
     18class SubprocessError(Exception):
     19    pass
     20
     21def run_openssl(cmd):
     22    OPENSSL = "openssl"
     23    p = subprocess.Popen([OPENSSL] + cmd.split(),
     24                         stdout=subprocess.PIPE,
     25                         stderr=subprocess.STDOUT)
     26    stdout, ignored = p.communicate()
     27    if p.returncode != 0:
     28        raise SubprocessError("cmd '%s %s' failed: rc=%s, stdout/err was %s" %
     29                              (OPENSSL, cmd, p.returncode, stdout))
     30    return stdout
     31
     32BENCH = False
     33
     34class ECDSA(unittest.TestCase):
     35    def test_basic(self):
     36        priv = SigningKey.generate()
     37        pub = priv.get_verifying_key()
     38
     39        data = "blahblah"
     40        sig = priv.sign(data)
     41
     42        self.failUnless(pub.verify(sig, data))
     43        self.failUnlessRaises(BadSignatureError, pub.verify, sig, data+"bad")
     44
     45        pub2 = VerifyingKey.from_string(pub.to_string())
     46        self.failUnless(pub2.verify(sig, data))
     47
     48    def test_lengths(self):
     49        default = NIST192p
     50        priv = SigningKey.generate()
     51        pub = priv.get_verifying_key()
     52        self.failUnlessEqual(len(pub.to_string()), default.verifying_key_length)
     53        sig = priv.sign("data")
     54        self.failUnlessEqual(len(sig), default.signature_length)
     55        if BENCH:
     56            print
     57        for curve in (NIST192p, NIST224p, NIST256p, NIST384p, NIST521p):
     58            start = time.time()
     59            priv = SigningKey.generate(curve=curve)
     60            pub1 = priv.get_verifying_key()
     61            keygen_time = time.time() - start
     62            pub2 = VerifyingKey.from_string(pub1.to_string(), curve)
     63            self.failUnlessEqual(pub1.to_string(), pub2.to_string())
     64            self.failUnlessEqual(len(pub1.to_string()),
     65                                 curve.verifying_key_length)
     66            start = time.time()
     67            sig = priv.sign("data")
     68            sign_time = time.time() - start
     69            self.failUnlessEqual(len(sig), curve.signature_length)
     70            if BENCH:
     71                start = time.time()
     72                pub1.verify(sig, "data")
     73                verify_time = time.time() - start
     74                print "%s: siglen=%d, keygen=%0.3fs, sign=%0.3f, verify=%0.3f" \
     75                      % (curve.name, curve.signature_length,
     76                         keygen_time, sign_time, verify_time)
     77
     78    def test_serialize(self):
     79        seed = "secret"
     80        curve = NIST192p
     81        secexp1 = util.randrange_from_seed__trytryagain(seed, curve.order)
     82        secexp2 = util.randrange_from_seed__trytryagain(seed, curve.order)
     83        self.failUnlessEqual(secexp1, secexp2)
     84        priv1 = SigningKey.from_secret_exponent(secexp1, curve)
     85        priv2 = SigningKey.from_secret_exponent(secexp2, curve)
     86        self.failUnlessEqual(hexlify(priv1.to_string()),
     87                             hexlify(priv2.to_string()))
     88        self.failUnlessEqual(priv1.to_pem(), priv2.to_pem())
     89        pub1 = priv1.get_verifying_key()
     90        pub2 = priv2.get_verifying_key()
     91        data = "data"
     92        sig1 = priv1.sign(data)
     93        sig2 = priv2.sign(data)
     94        self.failUnless(pub1.verify(sig1, data))
     95        self.failUnless(pub2.verify(sig1, data))
     96        self.failUnless(pub1.verify(sig2, data))
     97        self.failUnless(pub2.verify(sig2, data))
     98        self.failUnlessEqual(hexlify(pub1.to_string()),
     99                             hexlify(pub2.to_string()))
     100
     101    def test_nonrandom(self):
     102        s = "all the entropy in the entire world, compressed into one line"
     103        def not_much_entropy(numbytes):
     104            return s[:numbytes]
     105        # we control the entropy source, these two keys should be identical:
     106        priv1 = SigningKey.generate(entropy=not_much_entropy)
     107        priv2 = SigningKey.generate(entropy=not_much_entropy)
     108        self.failUnlessEqual(hexlify(priv1.get_verifying_key().to_string()),
     109                             hexlify(priv2.get_verifying_key().to_string()))
     110        # likewise, signatures should be identical. Obviously you'd never
     111        # want to do this with keys you care about, because the secrecy of
     112        # the private key depends upon using different random numbers for
     113        # each signature
     114        sig1 = priv1.sign("data", entropy=not_much_entropy)
     115        sig2 = priv2.sign("data", entropy=not_much_entropy)
     116        self.failUnlessEqual(hexlify(sig1), hexlify(sig2))
     117
     118    def failUnlessPrivkeysEqual(self, priv1, priv2):
     119        self.failUnlessEqual(priv1.privkey.secret_multiplier,
     120                             priv2.privkey.secret_multiplier)
     121        self.failUnlessEqual(priv1.privkey.public_key.generator,
     122                             priv2.privkey.public_key.generator)
     123
     124    def failIfPrivkeysEqual(self, priv1, priv2):
     125        self.failIfEqual(priv1.privkey.secret_multiplier,
     126                         priv2.privkey.secret_multiplier)
     127
     128    def test_privkey_creation(self):
     129        s = "all the entropy in the entire world, compressed into one line"
     130        def not_much_entropy(numbytes):
     131            return s[:numbytes]
     132        priv1 = SigningKey.generate()
     133        self.failUnlessEqual(priv1.baselen, NIST192p.baselen)
     134
     135        priv1 = SigningKey.generate(curve=NIST224p)
     136        self.failUnlessEqual(priv1.baselen, NIST224p.baselen)
     137
     138        priv1 = SigningKey.generate(entropy=not_much_entropy)
     139        self.failUnlessEqual(priv1.baselen, NIST192p.baselen)
     140        priv2 = SigningKey.generate(entropy=not_much_entropy)
     141        self.failUnlessEqual(priv2.baselen, NIST192p.baselen)
     142        self.failUnlessPrivkeysEqual(priv1, priv2)
     143
     144        priv1 = SigningKey.from_secret_exponent(secexp=3)
     145        self.failUnlessEqual(priv1.baselen, NIST192p.baselen)
     146        priv2 = SigningKey.from_secret_exponent(secexp=3)
     147        self.failUnlessPrivkeysEqual(priv1, priv2)
     148
     149        priv1 = SigningKey.from_secret_exponent(secexp=4, curve=NIST224p)
     150        self.failUnlessEqual(priv1.baselen, NIST224p.baselen)
     151
     152    def test_privkey_strings(self):
     153        priv1 = SigningKey.generate()
     154        s1 = priv1.to_string()
     155        self.failUnlessEqual(type(s1), str)
     156        self.failUnlessEqual(len(s1), NIST192p.baselen)
     157        priv2 = SigningKey.from_string(s1)
     158        self.failUnlessPrivkeysEqual(priv1, priv2)
     159
     160        s1 = priv1.to_pem()
     161        self.failUnlessEqual(type(s1), str)
     162        self.failUnless(s1.startswith("-----BEGIN EC PRIVATE KEY-----"))
     163        self.failUnless(s1.strip().endswith("-----END EC PRIVATE KEY-----"))
     164        priv2 = SigningKey.from_pem(s1)
     165        self.failUnlessPrivkeysEqual(priv1, priv2)
     166
     167        s1 = priv1.to_der()
     168        self.failUnlessEqual(type(s1), str)
     169        priv2 = SigningKey.from_der(s1)
     170        self.failUnlessPrivkeysEqual(priv1, priv2)
     171
     172        priv1 = SigningKey.generate(curve=NIST256p)
     173        s1 = priv1.to_pem()
     174        self.failUnlessEqual(type(s1), str)
     175        self.failUnless(s1.startswith("-----BEGIN EC PRIVATE KEY-----"))
     176        self.failUnless(s1.strip().endswith("-----END EC PRIVATE KEY-----"))
     177        priv2 = SigningKey.from_pem(s1)
     178        self.failUnlessPrivkeysEqual(priv1, priv2)
     179
     180        s1 = priv1.to_der()
     181        self.failUnlessEqual(type(s1), str)
     182        priv2 = SigningKey.from_der(s1)
     183        self.failUnlessPrivkeysEqual(priv1, priv2)
     184
     185    def failUnlessPubkeysEqual(self, pub1, pub2):
     186        self.failUnlessEqual(pub1.pubkey.point, pub2.pubkey.point)
     187        self.failUnlessEqual(pub1.pubkey.generator, pub2.pubkey.generator)
     188        self.failUnlessEqual(pub1.curve, pub2.curve)
     189
     190    def test_pubkey_strings(self):
     191        priv1 = SigningKey.generate()
     192        pub1 = priv1.get_verifying_key()
     193        s1 = pub1.to_string()
     194        self.failUnlessEqual(type(s1), str)
     195        self.failUnlessEqual(len(s1), NIST192p.verifying_key_length)
     196        pub2 = VerifyingKey.from_string(s1)
     197        self.failUnlessPubkeysEqual(pub1, pub2)
     198
     199        priv1 = SigningKey.generate(curve=NIST256p)
     200        pub1 = priv1.get_verifying_key()
     201        s1 = pub1.to_string()
     202        self.failUnlessEqual(type(s1), str)
     203        self.failUnlessEqual(len(s1), NIST256p.verifying_key_length)
     204        pub2 = VerifyingKey.from_string(s1, curve=NIST256p)
     205        self.failUnlessPubkeysEqual(pub1, pub2)
     206
     207        pub1_der = pub1.to_der()
     208        self.failUnlessEqual(type(pub1_der), str)
     209        pub2 = VerifyingKey.from_der(pub1_der)
     210        self.failUnlessPubkeysEqual(pub1, pub2)
     211
     212        self.failUnlessRaises(der.UnexpectedDER,
     213                              VerifyingKey.from_der, pub1_der+"junk")
     214        badpub = VerifyingKey.from_der(pub1_der)
     215        class FakeGenerator:
     216            def order(self): return 123456789
     217        badcurve = Curve("unknown", None, FakeGenerator(), (1,2,3,4,5,6))
     218        badpub.curve = badcurve
     219        badder = badpub.to_der()
     220        self.failUnlessRaises(UnknownCurveError, VerifyingKey.from_der, badder)
     221
     222        pem = pub1.to_pem()
     223        self.failUnlessEqual(type(pem), str)
     224        self.failUnless(pem.startswith("-----BEGIN PUBLIC KEY-----"), pem)
     225        self.failUnless(pem.strip().endswith("-----END PUBLIC KEY-----"), pem)
     226        pub2 = VerifyingKey.from_pem(pem)
     227        self.failUnlessPubkeysEqual(pub1, pub2)
     228
     229    def test_signature_strings(self):
     230        priv1 = SigningKey.generate()
     231        pub1 = priv1.get_verifying_key()
     232        data = "data"
     233
     234        sig = priv1.sign(data)
     235        self.failUnlessEqual(type(sig), str)
     236        self.failUnlessEqual(len(sig), NIST192p.signature_length)
     237        self.failUnless(pub1.verify(sig, data))
     238
     239        sig = priv1.sign(data, sigencode=sigencode_strings)
     240        self.failUnlessEqual(type(sig), tuple)
     241        self.failUnlessEqual(len(sig), 2)
     242        self.failUnlessEqual(type(sig[0]), str)
     243        self.failUnlessEqual(type(sig[1]), str)
     244        self.failUnlessEqual(len(sig[0]), NIST192p.baselen)
     245        self.failUnlessEqual(len(sig[1]), NIST192p.baselen)
     246        self.failUnless(pub1.verify(sig, data, sigdecode=sigdecode_strings))
     247
     248        sig_der = priv1.sign(data, sigencode=sigencode_der)
     249        self.failUnlessEqual(type(sig_der), str)
     250        self.failUnless(pub1.verify(sig_der, data, sigdecode=sigdecode_der))
     251       
     252
     253class OpenSSL(unittest.TestCase):
     254    # test interoperability with OpenSSL tools. Note that openssl's ECDSA
     255    # sign/verify arguments changed between 0.9.8 and 1.0.0: the early
     256    # versions require "-ecdsa-with-SHA1", the later versions want just
     257    # "-SHA1" (or to leave out that argument entirely, which means the
     258    # signature will use some default digest algorithm, probably determined
     259    # by the key, probably always SHA1).
     260    #
     261    # openssl ecparam -name secp224r1 -genkey -out privkey.pem
     262    # openssl ec -in privkey.pem -text -noout # get the priv/pub keys
     263    # openssl dgst -ecdsa-with-SHA1 -sign privkey.pem -out data.sig data.txt
     264    # openssl asn1parse -in data.sig -inform DER
     265    #  data.sig is 64 bytes, probably 56b plus ASN1 overhead
     266    # openssl dgst -ecdsa-with-SHA1 -prverify privkey.pem -signature data.sig data.txt ; echo $?
     267    # openssl ec -in privkey.pem -pubout -out pubkey.pem
     268    # openssl ec -in privkey.pem -pubout -outform DER -out pubkey.der
     269
     270    def get_openssl_messagedigest_arg(self):
     271        v = run_openssl("version")
     272        # e.g. "OpenSSL 1.0.0 29 Mar 2010", or "OpenSSL 1.0.0a 1 Jun 2010",
     273        # or "OpenSSL 0.9.8o 01 Jun 2010"
     274        vs = v.split()[1].split(".")
     275        if vs >=  ["1","0","0"]:
     276            return "-SHA1"
     277        else:
     278            return "-ecdsa-with-SHA1"
     279
     280    # sk: 1:OpenSSL->python  2:python->OpenSSL
     281    # vk: 3:OpenSSL->python  4:python->OpenSSL
     282    # sig: 5:OpenSSL->python 6:python->OpenSSL
     283
     284    def test_from_openssl_nist192p(self):
     285        return self.do_test_from_openssl(NIST192p, "prime192v1")
     286    def test_from_openssl_nist224p(self):
     287        return self.do_test_from_openssl(NIST224p, "secp224r1")
     288    def test_from_openssl_nist384p(self):
     289        return self.do_test_from_openssl(NIST384p, "secp384r1")
     290    def test_from_openssl_nist521p(self):
     291        return self.do_test_from_openssl(NIST521p, "secp521r1")
     292
     293    def do_test_from_openssl(self, curve, curvename):
     294        # OpenSSL: create sk, vk, sign.
     295        # Python: read vk(3), checksig(5), read sk(1), sign, check
     296        mdarg = self.get_openssl_messagedigest_arg()
     297        if os.path.isdir("t"):
     298            shutil.rmtree("t")
     299        os.mkdir("t")
     300        run_openssl("ecparam -name %s -genkey -out t/privkey.pem" % curvename)
     301        run_openssl("ec -in t/privkey.pem -pubout -out t/pubkey.pem")
     302        data = "data"
     303        open("t/data.txt","wb").write(data)
     304        run_openssl("dgst %s -sign t/privkey.pem -out t/data.sig t/data.txt" % mdarg)
     305        run_openssl("dgst %s -verify t/pubkey.pem -signature t/data.sig t/data.txt" % mdarg)
     306        pubkey_pem = open("t/pubkey.pem").read()
     307        vk = VerifyingKey.from_pem(pubkey_pem) # 3
     308        sig_der = open("t/data.sig","rb").read()
     309        self.failUnless(vk.verify(sig_der, data, # 5
     310                                  hashfunc=sha1, sigdecode=sigdecode_der))
     311
     312        sk = SigningKey.from_pem(open("t/privkey.pem").read()) # 1
     313        sig = sk.sign(data)
     314        self.failUnless(vk.verify(sig, data))
     315
     316    def test_to_openssl_nist192p(self):
     317        self.do_test_to_openssl(NIST192p, "prime192v1")
     318    def test_to_openssl_nist224p(self):
     319        self.do_test_to_openssl(NIST224p, "secp224r1")
     320    def test_to_openssl_nist384p(self):
     321        self.do_test_to_openssl(NIST384p, "secp384r1")
     322    def test_to_openssl_nist521p(self):
     323        self.do_test_to_openssl(NIST521p, "secp521r1")
     324
     325    def do_test_to_openssl(self, curve, curvename):
     326        # Python: create sk, vk, sign.
     327        # OpenSSL: read vk(4), checksig(6), read sk(2), sign, check
     328        mdarg = self.get_openssl_messagedigest_arg()
     329        if os.path.isdir("t"):
     330            shutil.rmtree("t")
     331        os.mkdir("t")
     332        sk = SigningKey.generate(curve=curve)
     333        vk = sk.get_verifying_key()
     334        data = "data"
     335        open("t/pubkey.der","wb").write(vk.to_der()) # 4
     336        open("t/pubkey.pem","wb").write(vk.to_pem()) # 4
     337        sig_der = sk.sign(data, hashfunc=sha1, sigencode=sigencode_der)
     338        open("t/data.sig","wb").write(sig_der) # 6
     339        open("t/data.txt","wb").write(data)
     340        open("t/baddata.txt","wb").write(data+"corrupt")
     341
     342        self.failUnlessRaises(SubprocessError, run_openssl,
     343                              "dgst %s -verify t/pubkey.der -keyform DER -signature t/data.sig t/baddata.txt" % mdarg)
     344        run_openssl("dgst %s -verify t/pubkey.der -keyform DER -signature t/data.sig t/data.txt" % mdarg)
     345
     346        open("t/privkey.pem","wb").write(sk.to_pem()) # 2
     347        run_openssl("dgst %s -sign t/privkey.pem -out t/data.sig2 t/data.txt" % mdarg)
     348        run_openssl("dgst %s -verify t/pubkey.pem -signature t/data.sig2 t/data.txt" % mdarg)
     349
     350class DER(unittest.TestCase):
     351    def test_oids(self):
     352        oid_ecPublicKey = der.encode_oid(1, 2, 840, 10045, 2, 1)
     353        self.failUnlessEqual(hexlify(oid_ecPublicKey), "06072a8648ce3d0201")
     354        self.failUnlessEqual(hexlify(NIST224p.encoded_oid), "06052b81040021")
     355        self.failUnlessEqual(hexlify(NIST256p.encoded_oid),
     356                             "06082a8648ce3d030107")
     357        x = oid_ecPublicKey + "more"
     358        x1, rest = der.remove_object(x)
     359        self.failUnlessEqual(x1, (1, 2, 840, 10045, 2, 1))
     360        self.failUnlessEqual(rest, "more")
     361
     362    def test_integer(self):
     363        self.failUnlessEqual(der.encode_integer(0), "\x02\x01\x00")
     364        self.failUnlessEqual(der.encode_integer(1), "\x02\x01\x01")
     365        self.failUnlessEqual(der.encode_integer(127), "\x02\x01\x7f")
     366        self.failUnlessEqual(der.encode_integer(128), "\x02\x02\x00\x80")
     367        self.failUnlessEqual(der.encode_integer(256), "\x02\x02\x01\x00")
     368        #self.failUnlessEqual(der.encode_integer(-1), "\x02\x01\xff")
     369
     370        def s(n): return der.remove_integer(der.encode_integer(n) + "junk")
     371        self.failUnlessEqual(s(0), (0, "junk"))
     372        self.failUnlessEqual(s(1), (1, "junk"))
     373        self.failUnlessEqual(s(127), (127, "junk"))
     374        self.failUnlessEqual(s(128), (128, "junk"))
     375        self.failUnlessEqual(s(256), (256, "junk"))
     376        self.failUnlessEqual(s(1234567890123456789012345678901234567890),
     377                             ( 1234567890123456789012345678901234567890,"junk"))
     378
     379    def test_number(self):
     380        self.failUnlessEqual(der.encode_number(0), "\x00")
     381        self.failUnlessEqual(der.encode_number(127), "\x7f")
     382        self.failUnlessEqual(der.encode_number(128), "\x81\x00")
     383        self.failUnlessEqual(der.encode_number(3*128+7), "\x83\x07")
     384        #self.failUnlessEqual(der.read_number("\x81\x9b"+"more"), (155, 2))
     385        #self.failUnlessEqual(der.encode_number(155), "\x81\x9b")
     386        for n in (0, 1, 2, 127, 128, 3*128+7, 840, 10045): #, 155):
     387            x = der.encode_number(n) + "more"
     388            n1, llen = der.read_number(x)
     389            self.failUnlessEqual(n1, n)
     390            self.failUnlessEqual(x[llen:], "more")
     391
     392    def test_length(self):
     393        self.failUnlessEqual(der.encode_length(0), "\x00")
     394        self.failUnlessEqual(der.encode_length(127), "\x7f")
     395        self.failUnlessEqual(der.encode_length(128), "\x81\x80")
     396        self.failUnlessEqual(der.encode_length(255), "\x81\xff")
     397        self.failUnlessEqual(der.encode_length(256), "\x82\x01\x00")
     398        self.failUnlessEqual(der.encode_length(3*256+7), "\x82\x03\x07")
     399        self.failUnlessEqual(der.read_length("\x81\x9b"+"more"), (155, 2))
     400        self.failUnlessEqual(der.encode_length(155), "\x81\x9b")
     401        for n in (0, 1, 2, 127, 128, 255, 256, 3*256+7, 155):
     402            x = der.encode_length(n) + "more"
     403            n1, llen = der.read_length(x)
     404            self.failUnlessEqual(n1, n)
     405            self.failUnlessEqual(x[llen:], "more")
     406
     407    def test_sequence(self):
     408        x = der.encode_sequence("ABC", "DEF") + "GHI"
     409        self.failUnlessEqual(x, "\x30\x06ABCDEFGHI")
     410        x1, rest = der.remove_sequence(x)
     411        self.failUnlessEqual(x1, "ABCDEF")
     412        self.failUnlessEqual(rest, "GHI")
     413
     414    def test_constructed(self):
     415        x = der.encode_constructed(0, NIST224p.encoded_oid)
     416        self.failUnlessEqual(hexlify(x), "a007" + "06052b81040021")
     417        x = der.encode_constructed(1, unhexlify("0102030a0b0c"))
     418        self.failUnlessEqual(hexlify(x), "a106" + "0102030a0b0c")
     419
     420class Util(unittest.TestCase):
     421    def test_trytryagain(self):
     422        tta = util.randrange_from_seed__trytryagain
     423        for i in range(1000):
     424            seed = "seed-%d" % i
     425            for order in (2**8-2, 2**8-1, 2**8, 2**8+1, 2**8+2,
     426                          2**16-1, 2**16+1):
     427                n = tta(seed, order)
     428                self.failUnless(1 <= n < order, (1, n, order))
     429        # this trytryagain *does* provide long-term stability
     430        self.failUnlessEqual("%x"%(tta("seed", NIST224p.order)),
     431                             "6fa59d73bf0446ae8743cf748fc5ac11d5585a90356417e97155c3bc")
     432
     433    def test_randrange(self):
     434        # util.randrange does not provide long-term stability: we might
     435        # change the algorithm in the future.
     436        for i in range(1000):
     437            entropy = util.PRNG("seed-%d" % i)
     438            for order in (2**8-2, 2**8-1, 2**8,
     439                          2**16-1, 2**16+1,
     440                          ):
     441                # that oddball 2**16+1 takes half our runtime
     442                n = util.randrange(order, entropy=entropy)
     443                self.failUnless(1 <= n < order, (1, n, order))
     444
     445    def OFF_test_prove_uniformity(self):
     446        order = 2**8-2
     447        counts = dict([(i, 0) for i in range(1, order)])
     448        assert 0 not in counts
     449        assert order not in counts
     450        for i in range(1000000):
     451            seed = "seed-%d" % i
     452            n = util.randrange_from_seed__trytryagain(seed, order)
     453            counts[n] += 1
     454        # this technique should use the full range
     455        self.failUnless(counts[order-1])
     456        for i in range(1, order):
     457            print "%3d: %s" % (i, "*"*(counts[i]//100))
     458           
     459
     460def __main__():
     461    unittest.main()
     462if __name__ == "__main__":
     463    __main__()
  • new file src/allmydata/util/ecdsa/util.py

    diff --git a/src/allmydata/util/ecdsa/util.py b/src/allmydata/util/ecdsa/util.py
    new file mode 100644
    index 0000000..6d37891
    - +  
     1
     2import os
     3import math
     4import binascii
     5from hashlib import sha256
     6import der
     7from curves import orderlen
     8
     9# RFC5480:
     10#   The "unrestricted" algorithm identifier is:
     11#     id-ecPublicKey OBJECT IDENTIFIER ::= {
     12#       iso(1) member-body(2) us(840) ansi-X9-62(10045) keyType(2) 1 }
     13
     14oid_ecPublicKey = (1, 2, 840, 10045, 2, 1)
     15encoded_oid_ecPublicKey = der.encode_oid(*oid_ecPublicKey)
     16
     17def randrange(order, entropy=None):
     18    """Return a random integer k such that 1 <= k < order, uniformly
     19    distributed across that range. For simplicity, this only behaves well if
     20    'order' is fairly close (but below) a power of 256. The try-try-again
     21    algorithm we use takes longer and longer time (on average) to complete as
     22    'order' falls, rising to a maximum of avg=512 loops for the worst-case
     23    (256**k)+1 . All of the standard curves behave well. There is a cutoff at
     24    10k loops (which raises RuntimeError) to prevent an infinite loop when
     25    something is really broken like the entropy function not working.
     26
     27    Note that this function is not declared to be forwards-compatible: we may
     28    change the behavior in future releases. The entropy= argument (which
     29    should get a callable that behaves like os.entropy) can be used to
     30    achieve stability within a given release (for repeatable unit tests), but
     31    should not be used as a long-term-compatible key generation algorithm.
     32    """
     33    # we could handle arbitrary orders (even 256**k+1) better if we created
     34    # candidates bit-wise instead of byte-wise, which would reduce the
     35    # worst-case behavior to avg=2 loops, but that would be more complex. The
     36    # change would be to round the order up to a power of 256, subtract one
     37    # (to get 0xffff..), use that to get a byte-long mask for the top byte,
     38    # generate the len-1 entropy bytes, generate one extra byte and mask off
     39    # the top bits, then combine it with the rest. Requires jumping back and
     40    # forth between strings and integers a lot.
     41
     42    if entropy is None:
     43        entropy = os.urandom
     44    assert order > 1
     45    bytes = orderlen(order)
     46    dont_try_forever = 10000 # gives about 2**-60 failures for worst case
     47    while dont_try_forever > 0:
     48        dont_try_forever -= 1
     49        candidate = string_to_number(entropy(bytes)) + 1
     50        if 1 <= candidate < order:
     51            return candidate
     52        continue
     53    raise RuntimeError("randrange() tried hard but gave up, either something"
     54                       " is very wrong or you got realllly unlucky. Order was"
     55                       " %x" % order)
     56
     57class PRNG:
     58    # this returns a callable which, when invoked with an integer N, will
     59    # return N pseudorandom bytes. Note: this is a short-term PRNG, meant
     60    # primarily for the needs of randrange_from_seed__trytryagain(), which
     61    # only needs to run it a few times per seed. It does not provide
     62    # protection against state compromise (forward security).
     63    def __init__(self, seed):
     64        self.generator = self.block_generator(seed)
     65
     66    def __call__(self, numbytes):
     67        return "".join([self.generator.next() for i in range(numbytes)])
     68
     69    def block_generator(self, seed):
     70        counter = 0
     71        while True:
     72            for byte in sha256("prng-%d-%s" % (counter, seed)).digest():
     73                yield byte
     74            counter += 1
     75
     76def randrange_from_seed__overshoot_modulo(seed, order):
     77    # hash the data, then turn the digest into a number in [1,order).
     78    #
     79    # We use David-Sarah Hopwood's suggestion: turn it into a number that's
     80    # sufficiently larger than the group order, then modulo it down to fit.
     81    # This should give adequate (but not perfect) uniformity, and simple
     82    # code. There are other choices: try-try-again is the main one.
     83    base = PRNG(seed)(2*orderlen(order))
     84    number = (int(binascii.hexlify(base), 16) % (order-1)) + 1
     85    assert 1 <= number < order, (1, number, order)
     86    return number
     87
     88def lsb_of_ones(numbits):
     89    return (1 << numbits) - 1
     90def bits_and_bytes(order):
     91    bits = int(math.log(order-1, 2)+1)
     92    bytes = bits // 8
     93    extrabits = bits % 8
     94    return bits, bytes, extrabits
     95
     96# the following randrange_from_seed__METHOD() functions take an
     97# arbitrarily-sized secret seed and turn it into a number that obeys the same
     98# range limits as randrange() above. They are meant for deriving consistent
     99# signing keys from a secret rather than generating them randomly, for
     100# example a protocol in which three signing keys are derived from a master
     101# secret. You should use a uniformly-distributed unguessable seed with about
     102# curve.baselen bytes of entropy. To use one, do this:
     103#   seed = os.urandom(curve.baselen) # or other starting point
     104#   secexp = ecdsa.util.randrange_from_seed__trytryagain(sed, curve.order)
     105#   sk = SigningKey.from_secret_exponent(secexp, curve)
     106
     107def randrange_from_seed__truncate_bytes(seed, order, hashmod=sha256):
     108    # hash the seed, then turn the digest into a number in [1,order), but
     109    # don't worry about trying to uniformly fill the range. This will lose,
     110    # on average, four bits of entropy.
     111    bits, bytes, extrabits = bits_and_bytes(order)
     112    if extrabits:
     113        bytes += 1
     114    base = hashmod(seed).digest()[:bytes]
     115    base = "\x00"*(bytes-len(base)) + base
     116    number = 1+int(binascii.hexlify(base), 16)
     117    assert 1 <= number < order
     118    return number
     119
     120def randrange_from_seed__truncate_bits(seed, order, hashmod=sha256):
     121    # like string_to_randrange_truncate_bytes, but only lose an average of
     122    # half a bit
     123    bits = int(math.log(order-1, 2)+1)
     124    maxbytes = (bits+7) // 8
     125    base = hashmod(seed).digest()[:maxbytes]
     126    base = "\x00"*(maxbytes-len(base)) + base
     127    topbits = 8*maxbytes - bits
     128    if topbits:
     129        base = chr(ord(base[0]) & lsb_of_ones(topbits)) + base[1:]
     130    number = 1+int(binascii.hexlify(base), 16)
     131    assert 1 <= number < order
     132    return number
     133
     134def randrange_from_seed__trytryagain(seed, order):
     135    # figure out exactly how many bits we need (rounded up to the nearest
     136    # bit), so we can reduce the chance of looping to less than 0.5 . This is
     137    # specified to feed from a byte-oriented PRNG, and discards the
     138    # high-order bits of the first byte as necessary to get the right number
     139    # of bits. The average number of loops will range from 1.0 (when
     140    # order=2**k-1) to 2.0 (when order=2**k+1).
     141    assert order > 1
     142    bits, bytes, extrabits = bits_and_bytes(order)
     143    generate = PRNG(seed)
     144    while True:
     145        extrabyte = ""
     146        if extrabits:
     147            extrabyte = chr(ord(generate(1)) & lsb_of_ones(extrabits))
     148        guess = string_to_number(extrabyte + generate(bytes)) + 1
     149        if 1 <= guess < order:
     150            return guess
     151
     152
     153def number_to_string(num, order):
     154    l = orderlen(order)
     155    fmt_str = "%0" + str(2*l) + "x"
     156    string = binascii.unhexlify(fmt_str % num)
     157    assert len(string) == l, (len(string), l)
     158    return string
     159
     160def string_to_number(string):
     161    return int(binascii.hexlify(string), 16)
     162
     163def string_to_number_fixedlen(string, order):
     164    l = orderlen(order)
     165    assert len(string) == l, (len(string), l)
     166    return int(binascii.hexlify(string), 16)
     167
     168# these methods are useful for the sigencode= argument to SK.sign() and the
     169# sigdecode= argument to VK.verify(), and control how the signature is packed
     170# or unpacked.
     171
     172def sigencode_strings(r, s, order):
     173    r_str = number_to_string(r, order)
     174    s_str = number_to_string(s, order)
     175    return (r_str, s_str)
     176
     177def sigencode_string(r, s, order):
     178    # for any given curve, the size of the signature numbers is
     179    # fixed, so just use simple concatenation
     180    r_str, s_str = sigencode_strings(r, s, order)
     181    return r_str + s_str
     182
     183def sigencode_der(r, s, order):
     184    return der.encode_sequence(der.encode_integer(r), der.encode_integer(s))
     185
     186
     187def sigdecode_string(signature, order):
     188    l = orderlen(order)
     189    assert len(signature) == 2*l, (len(signature), 2*l)
     190    r = string_to_number_fixedlen(signature[:l], order)
     191    s = string_to_number_fixedlen(signature[l:], order)
     192    return r, s
     193
     194def sigdecode_strings(rs_strings, order):
     195    (r_str, s_str) = rs_strings
     196    l = orderlen(order)
     197    assert len(r_str) == l, (len(r_str), l)
     198    assert len(s_str) == l, (len(s_str), l)
     199    r = string_to_number_fixedlen(r_str, order)
     200    s = string_to_number_fixedlen(s_str, order)
     201    return r, s
     202
     203def sigdecode_der(sig_der, order):
     204    #return der.encode_sequence(der.encode_integer(r), der.encode_integer(s))
     205    rs_strings, empty = der.remove_sequence(sig_der)
     206    if empty != "":
     207        raise der.UnexpectedDER("trailing junk after DER sig: %s" %
     208                                binascii.hexlify(empty))
     209    r, rest = der.remove_integer(rs_strings)
     210    s, empty = der.remove_integer(rest)
     211    if empty != "":
     212        raise der.UnexpectedDER("trailing junk after DER numbers: %s" %
     213                                binascii.hexlify(empty))
     214    return r, s
     215