Ticket #466: 2011-02-p1.diff
File 2011-02-p1.diff, 98.6 KB (added by warner, at 2011-02-07T18:29:02Z) |
---|
-
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 2 from keys import SigningKey, VerifyingKey, BadSignatureError, BadDigestError 3 from curves import NIST192p, NIST224p, NIST256p, NIST384p, NIST521p 4 5 _hush_pyflakes = [SigningKey, VerifyingKey, BadSignatureError, BadDigestError, 6 NIST192p, NIST224p, NIST256p, NIST384p, NIST521p] 7 del _hush_pyflakes 8 9 # This code comes from http://github.com/warner/python-ecdsa 10 11 try: 12 from _version import __version__ as v 13 __version__ = v 14 del v 15 except 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
- + 1 import der, ecdsa 2 3 class UnknownCurveError(Exception): 4 pass 5 6 def orderlen(order): 7 return (1+len("%x"%order))//2 # bytes 8 9 # the NIST curves 10 class 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 22 NIST192p = Curve("NIST192p", ecdsa.curve_192, ecdsa.generator_192, 23 (1, 2, 840, 10045, 3, 1, 1)) 24 NIST224p = Curve("NIST224p", ecdsa.curve_224, ecdsa.generator_224, 25 (1, 3, 132, 0, 33)) 26 NIST256p = Curve("NIST256p", ecdsa.curve_256, ecdsa.generator_256, 27 (1, 2, 840, 10045, 3, 1, 7)) 28 NIST384p = Curve("NIST384p", ecdsa.curve_384, ecdsa.generator_384, 29 (1, 3, 132, 0, 34)) 30 NIST521p = Curve("NIST521p", ecdsa.curve_521, ecdsa.generator_521, 31 (1, 3, 132, 0, 35)) 32 33 curves = [NIST192p, NIST224p, NIST256p, NIST384p, NIST521p] 34 35 def 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
- + 1 import binascii 2 import base64 3 4 class UnexpectedDER(Exception): 5 pass 6 7 def encode_constructed(tag, value): 8 return chr(0xa0+tag) + encode_length(len(value)) + value 9 def 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 23 def encode_bitstring(s): 24 return "\x03" + encode_length(len(s)) + s 25 def encode_octet_string(s): 26 return "\x04" + encode_length(len(s)) + s 27 def 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 34 def 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) 37 def 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 47 def 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 58 def 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 66 def 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 75 def 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 94 def 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 104 def 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 119 def 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 130 def 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 141 def 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 179 def 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) 183 def 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 """ 3 Implementation of Elliptic-Curve Digital Signatures. 4 5 Classes and methods for elliptic-curve signatures: 6 private keys, public keys, signatures, 7 NIST prime-modulus curves with modulus lengths of 8 192, 224, 256, 384, and 521 bits. 9 10 Example: 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 44 Version of 2009.05.16. 45 46 Revision 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 52 Written in 2005 by Peter Pearson and placed in the public domain. 53 """ 54 55 56 import ellipticcurve 57 import numbertheory 58 import random 59 60 61 62 class Signature( object ): 63 """ECDSA signature. 64 """ 65 def __init__( self, r, s ): 66 self.r = r 67 self.s = s 68 69 70 71 class 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 114 class 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 154 def 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 166 def 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 173 def 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 185 def 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 212 curve_192 = ellipticcurve.CurveFp( _p, -3, _b ) 213 generator_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 225 curve_224 = ellipticcurve.CurveFp( _p, -3, _b ) 226 generator_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 237 curve_256 = ellipticcurve.CurveFp( _p, -3, _b ) 238 generator_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 249 curve_384 = ellipticcurve.CurveFp( _p, -3, _b ) 250 generator_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 261 curve_521 = ellipticcurve.CurveFp( _p, -3, _b ) 262 generator_521 = ellipticcurve.Point( curve_521, _Gx, _Gy, _r ) 263 264 265 266 def __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 559 if __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 35 import numbertheory 36 37 class 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 60 class 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: 179 INFINITY = Point( None, None, None ) 180 181 def __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 289 if __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
- + 1 import binascii 2 3 import ecdsa 4 import der 5 from curves import NIST192p, find_curve 6 from util import string_to_number, number_to_string, randrange 7 from util import sigencode_string, sigdecode_string 8 from util import oid_ecPublicKey, encoded_oid_ecPublicKey 9 from hashlib import sha1 10 11 class BadSignatureError(Exception): 12 pass 13 class BadDigestError(Exception): 14 pass 15 16 class 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 105 class 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 14 import math 15 import types 16 17 18 class Error( Exception ): 19 """Base class for exceptions in this module.""" 20 pass 21 22 class SquareRootError( Error ): 23 pass 24 25 class NegativeExponentError( Error ): 26 pass 27 28 29 def 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 45 def 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 69 def 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 95 def 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 124 def 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 150 def 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 186 def 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 207 def 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 214 def 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 226 def lcm2(a,b): 227 """Least common multiple of two integers.""" 228 229 return (a*b)//gcd(a,b) 230 231 232 def 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 245 def 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 296 def 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 314 def 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 324 def 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 337 def 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 347 def 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 366 def 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 382 def 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 390 def 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 463 def 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 472 smallprimes = [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 493 miller_rabin_test_count = 0 494 495 def __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 613 if __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
- + 1 import unittest 2 import os 3 import time 4 import shutil 5 import subprocess 6 from binascii import hexlify, unhexlify 7 from hashlib import sha1 8 9 from keys import SigningKey, VerifyingKey 10 from keys import BadSignatureError 11 import util 12 from util import sigencode_der, sigencode_strings 13 from util import sigdecode_der, sigdecode_strings 14 from curves import Curve, UnknownCurveError 15 from curves import NIST192p, NIST224p, NIST256p, NIST384p, NIST521p 16 import der 17 18 class SubprocessError(Exception): 19 pass 20 21 def 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 32 BENCH = False 33 34 class 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 253 class 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 350 class 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 420 class 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 460 def __main__(): 461 unittest.main() 462 if __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 2 import os 3 import math 4 import binascii 5 from hashlib import sha256 6 import der 7 from 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 14 oid_ecPublicKey = (1, 2, 840, 10045, 2, 1) 15 encoded_oid_ecPublicKey = der.encode_oid(*oid_ecPublicKey) 16 17 def 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 57 class 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 76 def 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 88 def lsb_of_ones(numbits): 89 return (1 << numbits) - 1 90 def 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 107 def 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 120 def 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 134 def 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 153 def 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 160 def string_to_number(string): 161 return int(binascii.hexlify(string), 16) 162 163 def 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 172 def 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 177 def 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 183 def sigencode_der(r, s, order): 184 return der.encode_sequence(der.encode_integer(r), der.encode_integer(s)) 185 186 187 def 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 194 def 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 203 def 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