1*f0865ec9SKyle Evans#/* 2*f0865ec9SKyle Evans# * Copyright (C) 2017 - This file is part of libecc project 3*f0865ec9SKyle Evans# * 4*f0865ec9SKyle Evans# * Authors: 5*f0865ec9SKyle Evans# * Ryad BENADJILA <ryadbenadjila@gmail.com> 6*f0865ec9SKyle Evans# * Arnaud EBALARD <arnaud.ebalard@ssi.gouv.fr> 7*f0865ec9SKyle Evans# * Jean-Pierre FLORI <jean-pierre.flori@ssi.gouv.fr> 8*f0865ec9SKyle Evans# * 9*f0865ec9SKyle Evans# * Contributors: 10*f0865ec9SKyle Evans# * Nicolas VIVET <nicolas.vivet@ssi.gouv.fr> 11*f0865ec9SKyle Evans# * Karim KHALFALLAH <karim.khalfallah@ssi.gouv.fr> 12*f0865ec9SKyle Evans# * 13*f0865ec9SKyle Evans# * This software is licensed under a dual BSD and GPL v2 license. 14*f0865ec9SKyle Evans# * See LICENSE file at the root folder of the project. 15*f0865ec9SKyle Evans# */ 16*f0865ec9SKyle Evans#! /usr/bin/env python 17*f0865ec9SKyle Evans 18*f0865ec9SKyle Evansimport random, sys, re, math, os, getopt, glob, copy, hashlib, binascii, string, signal, base64 19*f0865ec9SKyle Evans 20*f0865ec9SKyle Evans# External dependecy for SHA-3 21*f0865ec9SKyle Evans# It is an independent module, since hashlib has no support 22*f0865ec9SKyle Evans# for SHA-3 functions for now 23*f0865ec9SKyle Evansimport sha3 24*f0865ec9SKyle Evans 25*f0865ec9SKyle Evans# Handle Python 2/3 issues 26*f0865ec9SKyle Evansdef is_python_2(): 27*f0865ec9SKyle Evans if sys.version_info[0] < 3: 28*f0865ec9SKyle Evans return True 29*f0865ec9SKyle Evans else: 30*f0865ec9SKyle Evans return False 31*f0865ec9SKyle Evans 32*f0865ec9SKyle Evans### Ctrl-C handler 33*f0865ec9SKyle Evansdef handler(signal, frame): 34*f0865ec9SKyle Evans print("\nSIGINT caught: exiting ...") 35*f0865ec9SKyle Evans exit(0) 36*f0865ec9SKyle Evans 37*f0865ec9SKyle Evans# Helper to ask the user for something 38*f0865ec9SKyle Evansdef get_user_input(prompt): 39*f0865ec9SKyle Evans # Handle the Python 2/3 issue 40*f0865ec9SKyle Evans if is_python_2() == False: 41*f0865ec9SKyle Evans return input(prompt) 42*f0865ec9SKyle Evans else: 43*f0865ec9SKyle Evans return raw_input(prompt) 44*f0865ec9SKyle Evans 45*f0865ec9SKyle Evans########################################################## 46*f0865ec9SKyle Evans#### Math helpers 47*f0865ec9SKyle Evansdef egcd(b, n): 48*f0865ec9SKyle Evans x0, x1, y0, y1 = 1, 0, 0, 1 49*f0865ec9SKyle Evans while n != 0: 50*f0865ec9SKyle Evans q, b, n = b // n, n, b % n 51*f0865ec9SKyle Evans x0, x1 = x1, x0 - q * x1 52*f0865ec9SKyle Evans y0, y1 = y1, y0 - q * y1 53*f0865ec9SKyle Evans return b, x0, y0 54*f0865ec9SKyle Evans 55*f0865ec9SKyle Evansdef modinv(a, m): 56*f0865ec9SKyle Evans g, x, y = egcd(a, m) 57*f0865ec9SKyle Evans if g != 1: 58*f0865ec9SKyle Evans raise Exception("Error: modular inverse does not exist") 59*f0865ec9SKyle Evans else: 60*f0865ec9SKyle Evans return x % m 61*f0865ec9SKyle Evans 62*f0865ec9SKyle Evansdef compute_monty_coef(prime, pbitlen, wlen): 63*f0865ec9SKyle Evans """ 64*f0865ec9SKyle Evans Compute montgomery coeff r, r^2 and mpinv. pbitlen is the size 65*f0865ec9SKyle Evans of p in bits. It is expected to be a multiple of word 66*f0865ec9SKyle Evans bit size. 67*f0865ec9SKyle Evans """ 68*f0865ec9SKyle Evans r = (1 << int(pbitlen)) % prime 69*f0865ec9SKyle Evans r_square = (1 << (2 * int(pbitlen))) % prime 70*f0865ec9SKyle Evans mpinv = 2**wlen - (modinv(prime, 2**wlen)) 71*f0865ec9SKyle Evans return r, r_square, mpinv 72*f0865ec9SKyle Evans 73*f0865ec9SKyle Evansdef compute_div_coef(prime, pbitlen, wlen): 74*f0865ec9SKyle Evans """ 75*f0865ec9SKyle Evans Compute division coeffs p_normalized, p_shift and p_reciprocal. 76*f0865ec9SKyle Evans """ 77*f0865ec9SKyle Evans tmp = prime 78*f0865ec9SKyle Evans cnt = 0 79*f0865ec9SKyle Evans while tmp != 0: 80*f0865ec9SKyle Evans tmp = tmp >> 1 81*f0865ec9SKyle Evans cnt += 1 82*f0865ec9SKyle Evans pshift = int(pbitlen - cnt) 83*f0865ec9SKyle Evans primenorm = prime << pshift 84*f0865ec9SKyle Evans B = 2**wlen 85*f0865ec9SKyle Evans prec = B**3 // ((primenorm >> int(pbitlen - 2*wlen)) + 1) - B 86*f0865ec9SKyle Evans return pshift, primenorm, prec 87*f0865ec9SKyle Evans 88*f0865ec9SKyle Evansdef is_probprime(n): 89*f0865ec9SKyle Evans # ensure n is odd 90*f0865ec9SKyle Evans if n % 2 == 0: 91*f0865ec9SKyle Evans return False 92*f0865ec9SKyle Evans # write n-1 as 2**s * d 93*f0865ec9SKyle Evans # repeatedly try to divide n-1 by 2 94*f0865ec9SKyle Evans s = 0 95*f0865ec9SKyle Evans d = n-1 96*f0865ec9SKyle Evans while True: 97*f0865ec9SKyle Evans quotient, remainder = divmod(d, 2) 98*f0865ec9SKyle Evans if remainder == 1: 99*f0865ec9SKyle Evans break 100*f0865ec9SKyle Evans s += 1 101*f0865ec9SKyle Evans d = quotient 102*f0865ec9SKyle Evans assert(2**s * d == n-1) 103*f0865ec9SKyle Evans # test the base a to see whether it is a witness for the compositeness of n 104*f0865ec9SKyle Evans def try_composite(a): 105*f0865ec9SKyle Evans if pow(a, d, n) == 1: 106*f0865ec9SKyle Evans return False 107*f0865ec9SKyle Evans for i in range(s): 108*f0865ec9SKyle Evans if pow(a, 2**i * d, n) == n-1: 109*f0865ec9SKyle Evans return False 110*f0865ec9SKyle Evans return True # n is definitely composite 111*f0865ec9SKyle Evans for i in range(5): 112*f0865ec9SKyle Evans a = random.randrange(2, n) 113*f0865ec9SKyle Evans if try_composite(a): 114*f0865ec9SKyle Evans return False 115*f0865ec9SKyle Evans return True # no base tested showed n as composite 116*f0865ec9SKyle Evans 117*f0865ec9SKyle Evansdef legendre_symbol(a, p): 118*f0865ec9SKyle Evans ls = pow(a, (p - 1) // 2, p) 119*f0865ec9SKyle Evans return -1 if ls == p - 1 else ls 120*f0865ec9SKyle Evans 121*f0865ec9SKyle Evans# Tonelli-Shanks algorithm to find square roots 122*f0865ec9SKyle Evans# over prime fields 123*f0865ec9SKyle Evansdef mod_sqrt(a, p): 124*f0865ec9SKyle Evans # Square root of 0 is 0 125*f0865ec9SKyle Evans if a == 0: 126*f0865ec9SKyle Evans return 0 127*f0865ec9SKyle Evans # Simple cases 128*f0865ec9SKyle Evans if legendre_symbol(a, p) != 1: 129*f0865ec9SKyle Evans # No square residue 130*f0865ec9SKyle Evans return None 131*f0865ec9SKyle Evans elif p == 2: 132*f0865ec9SKyle Evans return a 133*f0865ec9SKyle Evans elif p % 4 == 3: 134*f0865ec9SKyle Evans return pow(a, (p + 1) // 4, p) 135*f0865ec9SKyle Evans s = p - 1 136*f0865ec9SKyle Evans e = 0 137*f0865ec9SKyle Evans while s % 2 == 0: 138*f0865ec9SKyle Evans s = s // 2 139*f0865ec9SKyle Evans e += 1 140*f0865ec9SKyle Evans n = 2 141*f0865ec9SKyle Evans while legendre_symbol(n, p) != -1: 142*f0865ec9SKyle Evans n += 1 143*f0865ec9SKyle Evans x = pow(a, (s + 1) // 2, p) 144*f0865ec9SKyle Evans b = pow(a, s, p) 145*f0865ec9SKyle Evans g = pow(n, s, p) 146*f0865ec9SKyle Evans r = e 147*f0865ec9SKyle Evans while True: 148*f0865ec9SKyle Evans t = b 149*f0865ec9SKyle Evans m = 0 150*f0865ec9SKyle Evans if is_python_2(): 151*f0865ec9SKyle Evans for m in xrange(r): 152*f0865ec9SKyle Evans if t == 1: 153*f0865ec9SKyle Evans break 154*f0865ec9SKyle Evans t = pow(t, 2, p) 155*f0865ec9SKyle Evans else: 156*f0865ec9SKyle Evans for m in range(r): 157*f0865ec9SKyle Evans if t == 1: 158*f0865ec9SKyle Evans break 159*f0865ec9SKyle Evans t = pow(t, 2, p) 160*f0865ec9SKyle Evans if m == 0: 161*f0865ec9SKyle Evans return x 162*f0865ec9SKyle Evans gs = pow(g, 2 ** (r - m - 1), p) 163*f0865ec9SKyle Evans g = (gs * gs) % p 164*f0865ec9SKyle Evans x = (x * gs) % p 165*f0865ec9SKyle Evans b = (b * g) % p 166*f0865ec9SKyle Evans r = m 167*f0865ec9SKyle Evans 168*f0865ec9SKyle Evans########################################################## 169*f0865ec9SKyle Evans### Math elliptic curves basic blocks 170*f0865ec9SKyle Evans 171*f0865ec9SKyle Evans# WARNING: these blocks are only here for testing purpose and 172*f0865ec9SKyle Evans# are not intended to be used in a security oriented library! 173*f0865ec9SKyle Evans# This explains the usage of naive affine coordinates fomulas 174*f0865ec9SKyle Evansclass Curve(object): 175*f0865ec9SKyle Evans def __init__(self, a, b, prime, order, cofactor, gx, gy, npoints, name, oid): 176*f0865ec9SKyle Evans self.a = a 177*f0865ec9SKyle Evans self.b = b 178*f0865ec9SKyle Evans self.p = prime 179*f0865ec9SKyle Evans self.q = order 180*f0865ec9SKyle Evans self.c = cofactor 181*f0865ec9SKyle Evans self.gx = gx 182*f0865ec9SKyle Evans self.gy = gy 183*f0865ec9SKyle Evans self.n = npoints 184*f0865ec9SKyle Evans self.name = name 185*f0865ec9SKyle Evans self.oid = oid 186*f0865ec9SKyle Evans # Equality testing 187*f0865ec9SKyle Evans def __eq__(self, other): 188*f0865ec9SKyle Evans return self.__dict__ == other.__dict__ 189*f0865ec9SKyle Evans # Deep copy is implemented using the ~X operator 190*f0865ec9SKyle Evans def __invert__(self): 191*f0865ec9SKyle Evans return copy.deepcopy(self) 192*f0865ec9SKyle Evans 193*f0865ec9SKyle Evans 194*f0865ec9SKyle Evansclass Point(object): 195*f0865ec9SKyle Evans # Affine coordinates (x, y), infinity point is (None, None) 196*f0865ec9SKyle Evans def __init__(self, curve, x, y): 197*f0865ec9SKyle Evans self.curve = curve 198*f0865ec9SKyle Evans if x != None: 199*f0865ec9SKyle Evans self.x = (x % curve.p) 200*f0865ec9SKyle Evans else: 201*f0865ec9SKyle Evans self.x = None 202*f0865ec9SKyle Evans if y != None: 203*f0865ec9SKyle Evans self.y = (y % curve.p) 204*f0865ec9SKyle Evans else: 205*f0865ec9SKyle Evans self.y = None 206*f0865ec9SKyle Evans # Check that the point is indeed on the curve 207*f0865ec9SKyle Evans if (x != None): 208*f0865ec9SKyle Evans if (pow(y, 2, curve.p) != ((pow(x, 3, curve.p) + (curve.a * x) + curve.b ) % curve.p)): 209*f0865ec9SKyle Evans raise Exception("Error: point is not on curve!") 210*f0865ec9SKyle Evans # Addition 211*f0865ec9SKyle Evans def __add__(self, Q): 212*f0865ec9SKyle Evans x1 = self.x 213*f0865ec9SKyle Evans y1 = self.y 214*f0865ec9SKyle Evans x2 = Q.x 215*f0865ec9SKyle Evans y2 = Q.y 216*f0865ec9SKyle Evans curve = self.curve 217*f0865ec9SKyle Evans # Check that we are on the same curve 218*f0865ec9SKyle Evans if Q.curve != curve: 219*f0865ec9SKyle Evans raise Exception("Point add error: two point don't have the same curve") 220*f0865ec9SKyle Evans # If Q is infinity point, return ourself 221*f0865ec9SKyle Evans if Q.x == None: 222*f0865ec9SKyle Evans return Point(self.curve, self.x, self.y) 223*f0865ec9SKyle Evans # If we are the infinity point return Q 224*f0865ec9SKyle Evans if self.x == None: 225*f0865ec9SKyle Evans return Q 226*f0865ec9SKyle Evans # Infinity point or Doubling 227*f0865ec9SKyle Evans if (x1 == x2): 228*f0865ec9SKyle Evans if (((y1 + y2) % curve.p) == 0): 229*f0865ec9SKyle Evans # Return infinity point 230*f0865ec9SKyle Evans return Point(self.curve, None, None) 231*f0865ec9SKyle Evans else: 232*f0865ec9SKyle Evans # Doubling 233*f0865ec9SKyle Evans L = ((3*pow(x1, 2, curve.p) + curve.a) * modinv(2*y1, curve.p)) % curve.p 234*f0865ec9SKyle Evans # Addition 235*f0865ec9SKyle Evans else: 236*f0865ec9SKyle Evans L = ((y2 - y1) * modinv((x2 - x1) % curve.p, curve.p)) % curve.p 237*f0865ec9SKyle Evans resx = (pow(L, 2, curve.p) - x1 - x2) % curve.p 238*f0865ec9SKyle Evans resy = ((L * (x1 - resx)) - y1) % curve.p 239*f0865ec9SKyle Evans # Return the point 240*f0865ec9SKyle Evans return Point(self.curve, resx, resy) 241*f0865ec9SKyle Evans # Negation 242*f0865ec9SKyle Evans def __neg__(self): 243*f0865ec9SKyle Evans if (self.x == None): 244*f0865ec9SKyle Evans return Point(self.curve, None, None) 245*f0865ec9SKyle Evans else: 246*f0865ec9SKyle Evans return Point(self.curve, self.x, -self.y) 247*f0865ec9SKyle Evans # Subtraction 248*f0865ec9SKyle Evans def __sub__(self, other): 249*f0865ec9SKyle Evans return self + (-other) 250*f0865ec9SKyle Evans # Scalar mul 251*f0865ec9SKyle Evans def __rmul__(self, scalar): 252*f0865ec9SKyle Evans # Implement simple double and add algorithm 253*f0865ec9SKyle Evans P = self 254*f0865ec9SKyle Evans Q = Point(P.curve, None, None) 255*f0865ec9SKyle Evans for i in range(getbitlen(scalar), 0, -1): 256*f0865ec9SKyle Evans Q = Q + Q 257*f0865ec9SKyle Evans if (scalar >> (i-1)) & 0x1 == 0x1: 258*f0865ec9SKyle Evans Q = Q + P 259*f0865ec9SKyle Evans return Q 260*f0865ec9SKyle Evans # Equality testing 261*f0865ec9SKyle Evans def __eq__(self, other): 262*f0865ec9SKyle Evans return self.__dict__ == other.__dict__ 263*f0865ec9SKyle Evans # Deep copy is implemented using the ~X operator 264*f0865ec9SKyle Evans def __invert__(self): 265*f0865ec9SKyle Evans return copy.deepcopy(self) 266*f0865ec9SKyle Evans def __str__(self): 267*f0865ec9SKyle Evans if self.x == None: 268*f0865ec9SKyle Evans return "Inf" 269*f0865ec9SKyle Evans else: 270*f0865ec9SKyle Evans return ("(x = %s, y = %s)" % (hex(self.x), hex(self.y))) 271*f0865ec9SKyle Evans 272*f0865ec9SKyle Evans########################################################## 273*f0865ec9SKyle Evans### Private and public keys structures 274*f0865ec9SKyle Evansclass PrivKey(object): 275*f0865ec9SKyle Evans def __init__(self, curve, x): 276*f0865ec9SKyle Evans self.curve = curve 277*f0865ec9SKyle Evans self.x = x 278*f0865ec9SKyle Evans 279*f0865ec9SKyle Evansclass PubKey(object): 280*f0865ec9SKyle Evans def __init__(self, curve, Y): 281*f0865ec9SKyle Evans # Sanity check 282*f0865ec9SKyle Evans if Y.curve != curve: 283*f0865ec9SKyle Evans raise Exception("Error: curve and point curve differ in public key!") 284*f0865ec9SKyle Evans self.curve = curve 285*f0865ec9SKyle Evans self.Y = Y 286*f0865ec9SKyle Evans 287*f0865ec9SKyle Evansclass KeyPair(object): 288*f0865ec9SKyle Evans def __init__(self, pubkey, privkey): 289*f0865ec9SKyle Evans self.pubkey = pubkey 290*f0865ec9SKyle Evans self.privkey = privkey 291*f0865ec9SKyle Evans 292*f0865ec9SKyle Evans 293*f0865ec9SKyle Evansdef fromprivkey(privkey, is_eckcdsa=False): 294*f0865ec9SKyle Evans curve = privkey.curve 295*f0865ec9SKyle Evans q = curve.q 296*f0865ec9SKyle Evans gx = curve.gx 297*f0865ec9SKyle Evans gy = curve.gy 298*f0865ec9SKyle Evans G = Point(curve, gx, gy) 299*f0865ec9SKyle Evans if is_eckcdsa == False: 300*f0865ec9SKyle Evans return PubKey(curve, privkey.x * G) 301*f0865ec9SKyle Evans else: 302*f0865ec9SKyle Evans return PubKey(curve, modinv(privkey.x, q) * G) 303*f0865ec9SKyle Evans 304*f0865ec9SKyle Evansdef genKeyPair(curve, is_eckcdsa=False): 305*f0865ec9SKyle Evans p = curve.p 306*f0865ec9SKyle Evans q = curve.q 307*f0865ec9SKyle Evans gx = curve.gx 308*f0865ec9SKyle Evans gy = curve.gy 309*f0865ec9SKyle Evans G = Point(curve, gx, gy) 310*f0865ec9SKyle Evans OK = False 311*f0865ec9SKyle Evans while OK == False: 312*f0865ec9SKyle Evans x = getrandomint(q) 313*f0865ec9SKyle Evans if x == 0: 314*f0865ec9SKyle Evans continue 315*f0865ec9SKyle Evans OK = True 316*f0865ec9SKyle Evans privkey = PrivKey(curve, x) 317*f0865ec9SKyle Evans pubkey = fromprivkey(privkey, is_eckcdsa) 318*f0865ec9SKyle Evans return KeyPair(pubkey, privkey) 319*f0865ec9SKyle Evans 320*f0865ec9SKyle Evans########################################################## 321*f0865ec9SKyle Evans### Signature algorithms helpers 322*f0865ec9SKyle Evansdef getrandomint(modulo): 323*f0865ec9SKyle Evans return random.randrange(0, modulo+1) 324*f0865ec9SKyle Evans 325*f0865ec9SKyle Evansdef getbitlen(bint): 326*f0865ec9SKyle Evans """ 327*f0865ec9SKyle Evans Returns the number of bits encoding an integer 328*f0865ec9SKyle Evans """ 329*f0865ec9SKyle Evans if bint == None: 330*f0865ec9SKyle Evans return 0 331*f0865ec9SKyle Evans if bint == 0: 332*f0865ec9SKyle Evans # Zero is encoded on one bit 333*f0865ec9SKyle Evans return 1 334*f0865ec9SKyle Evans else: 335*f0865ec9SKyle Evans return int(bint).bit_length() 336*f0865ec9SKyle Evans 337*f0865ec9SKyle Evansdef getbytelen(bint): 338*f0865ec9SKyle Evans """ 339*f0865ec9SKyle Evans Returns the number of bytes encoding an integer 340*f0865ec9SKyle Evans """ 341*f0865ec9SKyle Evans bitsize = getbitlen(bint) 342*f0865ec9SKyle Evans bytesize = int(bitsize // 8) 343*f0865ec9SKyle Evans if bitsize % 8 != 0: 344*f0865ec9SKyle Evans bytesize += 1 345*f0865ec9SKyle Evans return bytesize 346*f0865ec9SKyle Evans 347*f0865ec9SKyle Evansdef stringtoint(bitstring): 348*f0865ec9SKyle Evans acc = 0 349*f0865ec9SKyle Evans size = len(bitstring) 350*f0865ec9SKyle Evans for i in range(0, size): 351*f0865ec9SKyle Evans acc = acc + (ord(bitstring[i]) * (2**(8*(size - 1 - i)))) 352*f0865ec9SKyle Evans return acc 353*f0865ec9SKyle Evans 354*f0865ec9SKyle Evansdef inttostring(a): 355*f0865ec9SKyle Evans size = int(getbytelen(a)) 356*f0865ec9SKyle Evans outstr = "" 357*f0865ec9SKyle Evans for i in range(0, size): 358*f0865ec9SKyle Evans outstr = outstr + chr((a >> (8*(size - 1 - i))) & 0xFF) 359*f0865ec9SKyle Evans return outstr 360*f0865ec9SKyle Evans 361*f0865ec9SKyle Evansdef expand(bitstring, bitlen, direction): 362*f0865ec9SKyle Evans bytelen = int(math.ceil(bitlen / 8.)) 363*f0865ec9SKyle Evans if len(bitstring) >= bytelen: 364*f0865ec9SKyle Evans return bitstring 365*f0865ec9SKyle Evans else: 366*f0865ec9SKyle Evans if direction == "LEFT": 367*f0865ec9SKyle Evans return ((bytelen-len(bitstring))*"\x00") + bitstring 368*f0865ec9SKyle Evans elif direction == "RIGHT": 369*f0865ec9SKyle Evans return bitstring + ((bytelen-len(bitstring))*"\x00") 370*f0865ec9SKyle Evans else: 371*f0865ec9SKyle Evans raise Exception("Error: unknown direction "+direction+" in expand") 372*f0865ec9SKyle Evans 373*f0865ec9SKyle Evansdef truncate(bitstring, bitlen, keep): 374*f0865ec9SKyle Evans """ 375*f0865ec9SKyle Evans Takes a bit string and truncates it to keep the left 376*f0865ec9SKyle Evans most or the right most bits 377*f0865ec9SKyle Evans """ 378*f0865ec9SKyle Evans strbitlen = 8*len(bitstring) 379*f0865ec9SKyle Evans # Check if truncation is needed 380*f0865ec9SKyle Evans if strbitlen > bitlen: 381*f0865ec9SKyle Evans if keep == "LEFT": 382*f0865ec9SKyle Evans return expand(inttostring(stringtoint(bitstring) >> int(strbitlen - bitlen)), bitlen, "LEFT") 383*f0865ec9SKyle Evans elif keep == "RIGHT": 384*f0865ec9SKyle Evans mask = (2**bitlen)-1 385*f0865ec9SKyle Evans return expand(inttostring(stringtoint(bitstring) & mask), bitlen, "LEFT") 386*f0865ec9SKyle Evans else: 387*f0865ec9SKyle Evans raise Exception("Error: unknown direction "+keep+" in truncate") 388*f0865ec9SKyle Evans else: 389*f0865ec9SKyle Evans # No need to truncate! 390*f0865ec9SKyle Evans return bitstring 391*f0865ec9SKyle Evans 392*f0865ec9SKyle Evans########################################################## 393*f0865ec9SKyle Evans### Hash algorithms 394*f0865ec9SKyle Evansdef sha224(message): 395*f0865ec9SKyle Evans ctx = hashlib.sha224() 396*f0865ec9SKyle Evans if(is_python_2() == True): 397*f0865ec9SKyle Evans ctx.update(message) 398*f0865ec9SKyle Evans digest = ctx.digest() 399*f0865ec9SKyle Evans else: 400*f0865ec9SKyle Evans ctx.update(message.encode('latin-1')) 401*f0865ec9SKyle Evans digest = ctx.digest().decode('latin-1') 402*f0865ec9SKyle Evans return (digest, ctx.digest_size, ctx.block_size) 403*f0865ec9SKyle Evans 404*f0865ec9SKyle Evansdef sha256(message): 405*f0865ec9SKyle Evans ctx = hashlib.sha256() 406*f0865ec9SKyle Evans if(is_python_2() == True): 407*f0865ec9SKyle Evans ctx.update(message) 408*f0865ec9SKyle Evans digest = ctx.digest() 409*f0865ec9SKyle Evans else: 410*f0865ec9SKyle Evans ctx.update(message.encode('latin-1')) 411*f0865ec9SKyle Evans digest = ctx.digest().decode('latin-1') 412*f0865ec9SKyle Evans return (digest, ctx.digest_size, ctx.block_size) 413*f0865ec9SKyle Evans 414*f0865ec9SKyle Evansdef sha384(message): 415*f0865ec9SKyle Evans ctx = hashlib.sha384() 416*f0865ec9SKyle Evans if(is_python_2() == True): 417*f0865ec9SKyle Evans ctx.update(message) 418*f0865ec9SKyle Evans digest = ctx.digest() 419*f0865ec9SKyle Evans else: 420*f0865ec9SKyle Evans ctx.update(message.encode('latin-1')) 421*f0865ec9SKyle Evans digest = ctx.digest().decode('latin-1') 422*f0865ec9SKyle Evans return (digest, ctx.digest_size, ctx.block_size) 423*f0865ec9SKyle Evans 424*f0865ec9SKyle Evansdef sha512(message): 425*f0865ec9SKyle Evans ctx = hashlib.sha512() 426*f0865ec9SKyle Evans if(is_python_2() == True): 427*f0865ec9SKyle Evans ctx.update(message) 428*f0865ec9SKyle Evans digest = ctx.digest() 429*f0865ec9SKyle Evans else: 430*f0865ec9SKyle Evans ctx.update(message.encode('latin-1')) 431*f0865ec9SKyle Evans digest = ctx.digest().decode('latin-1') 432*f0865ec9SKyle Evans return (digest, ctx.digest_size, ctx.block_size) 433*f0865ec9SKyle Evans 434*f0865ec9SKyle Evansdef sha3_224(message): 435*f0865ec9SKyle Evans ctx = sha3.Sha3_ctx(224) 436*f0865ec9SKyle Evans if(is_python_2() == True): 437*f0865ec9SKyle Evans ctx.update(message) 438*f0865ec9SKyle Evans digest = ctx.digest() 439*f0865ec9SKyle Evans else: 440*f0865ec9SKyle Evans ctx.update(message.encode('latin-1')) 441*f0865ec9SKyle Evans digest = ctx.digest().decode('latin-1') 442*f0865ec9SKyle Evans return (digest, ctx.digest_size, ctx.block_size) 443*f0865ec9SKyle Evans 444*f0865ec9SKyle Evansdef sha3_256(message): 445*f0865ec9SKyle Evans ctx = sha3.Sha3_ctx(256) 446*f0865ec9SKyle Evans if(is_python_2() == True): 447*f0865ec9SKyle Evans ctx.update(message) 448*f0865ec9SKyle Evans digest = ctx.digest() 449*f0865ec9SKyle Evans else: 450*f0865ec9SKyle Evans ctx.update(message.encode('latin-1')) 451*f0865ec9SKyle Evans digest = ctx.digest().decode('latin-1') 452*f0865ec9SKyle Evans return (digest, ctx.digest_size, ctx.block_size) 453*f0865ec9SKyle Evans 454*f0865ec9SKyle Evansdef sha3_384(message): 455*f0865ec9SKyle Evans ctx = sha3.Sha3_ctx(384) 456*f0865ec9SKyle Evans if(is_python_2() == True): 457*f0865ec9SKyle Evans ctx.update(message) 458*f0865ec9SKyle Evans digest = ctx.digest() 459*f0865ec9SKyle Evans else: 460*f0865ec9SKyle Evans ctx.update(message.encode('latin-1')) 461*f0865ec9SKyle Evans digest = ctx.digest().decode('latin-1') 462*f0865ec9SKyle Evans return (digest, ctx.digest_size, ctx.block_size) 463*f0865ec9SKyle Evans 464*f0865ec9SKyle Evansdef sha3_512(message): 465*f0865ec9SKyle Evans ctx = sha3.Sha3_ctx(512) 466*f0865ec9SKyle Evans if(is_python_2() == True): 467*f0865ec9SKyle Evans ctx.update(message) 468*f0865ec9SKyle Evans digest = ctx.digest() 469*f0865ec9SKyle Evans else: 470*f0865ec9SKyle Evans ctx.update(message.encode('latin-1')) 471*f0865ec9SKyle Evans digest = ctx.digest().decode('latin-1') 472*f0865ec9SKyle Evans return (digest, ctx.digest_size, ctx.block_size) 473*f0865ec9SKyle Evans 474*f0865ec9SKyle Evans########################################################## 475*f0865ec9SKyle Evans### Signature algorithms 476*f0865ec9SKyle Evans 477*f0865ec9SKyle Evans# *| IUF - ECDSA signature 478*f0865ec9SKyle Evans# *| 479*f0865ec9SKyle Evans# *| UF 1. Compute h = H(m) 480*f0865ec9SKyle Evans# *| F 2. If |h| > bitlen(q), set h to bitlen(q) 481*f0865ec9SKyle Evans# *| leftmost (most significant) bits of h 482*f0865ec9SKyle Evans# *| F 3. e = OS2I(h) mod q 483*f0865ec9SKyle Evans# *| F 4. Get a random value k in ]0,q[ 484*f0865ec9SKyle Evans# *| F 5. Compute W = (W_x,W_y) = kG 485*f0865ec9SKyle Evans# *| F 6. Compute r = W_x mod q 486*f0865ec9SKyle Evans# *| F 7. If r is 0, restart the process at step 4. 487*f0865ec9SKyle Evans# *| F 8. If e == rx, restart the process at step 4. 488*f0865ec9SKyle Evans# *| F 9. Compute s = k^-1 * (xr + e) mod q 489*f0865ec9SKyle Evans# *| F 10. If s is 0, restart the process at step 4. 490*f0865ec9SKyle Evans# *| F 11. Return (r,s) 491*f0865ec9SKyle Evansdef ecdsa_sign(hashfunc, keypair, message, k=None): 492*f0865ec9SKyle Evans privkey = keypair.privkey 493*f0865ec9SKyle Evans # Get important parameters from the curve 494*f0865ec9SKyle Evans p = privkey.curve.p 495*f0865ec9SKyle Evans q = privkey.curve.q 496*f0865ec9SKyle Evans gx = privkey.curve.gx 497*f0865ec9SKyle Evans gy = privkey.curve.gy 498*f0865ec9SKyle Evans G = Point(privkey.curve, gx, gy) 499*f0865ec9SKyle Evans q_limit_len = getbitlen(q) 500*f0865ec9SKyle Evans # Compute the hash 501*f0865ec9SKyle Evans (h, _, _) = hashfunc(message) 502*f0865ec9SKyle Evans # Truncate hash value 503*f0865ec9SKyle Evans h = truncate(h, q_limit_len, "LEFT") 504*f0865ec9SKyle Evans # Convert the hash value to an int 505*f0865ec9SKyle Evans e = stringtoint(h) % q 506*f0865ec9SKyle Evans OK = False 507*f0865ec9SKyle Evans while OK == False: 508*f0865ec9SKyle Evans if k == None: 509*f0865ec9SKyle Evans k = getrandomint(q) 510*f0865ec9SKyle Evans if k == 0: 511*f0865ec9SKyle Evans continue 512*f0865ec9SKyle Evans W = k * G 513*f0865ec9SKyle Evans r = W.x % q 514*f0865ec9SKyle Evans if r == 0: 515*f0865ec9SKyle Evans continue 516*f0865ec9SKyle Evans if e == r * privkey.x: 517*f0865ec9SKyle Evans continue 518*f0865ec9SKyle Evans s = (modinv(k, q) * ((privkey.x * r) + e)) % q 519*f0865ec9SKyle Evans if s == 0: 520*f0865ec9SKyle Evans continue 521*f0865ec9SKyle Evans OK = True 522*f0865ec9SKyle Evans return ((expand(inttostring(r), 8*getbytelen(q), "LEFT") + expand(inttostring(s), 8*getbytelen(q), "LEFT")), k) 523*f0865ec9SKyle Evans 524*f0865ec9SKyle Evans# *| IUF - ECDSA verification 525*f0865ec9SKyle Evans# *| 526*f0865ec9SKyle Evans# *| I 1. Reject the signature if r or s is 0. 527*f0865ec9SKyle Evans# *| UF 2. Compute h = H(m) 528*f0865ec9SKyle Evans# *| F 3. If |h| > bitlen(q), set h to bitlen(q) 529*f0865ec9SKyle Evans# *| leftmost (most significant) bits of h 530*f0865ec9SKyle Evans# *| F 4. Compute e = OS2I(h) mod q 531*f0865ec9SKyle Evans# *| F 5. Compute u = (s^-1)e mod q 532*f0865ec9SKyle Evans# *| F 6. Compute v = (s^-1)r mod q 533*f0865ec9SKyle Evans# *| F 7. Compute W' = uG + vY 534*f0865ec9SKyle Evans# *| F 8. If W' is the point at infinity, reject the signature. 535*f0865ec9SKyle Evans# *| F 9. Compute r' = W'_x mod q 536*f0865ec9SKyle Evans# *| F 10. Accept the signature if and only if r equals r' 537*f0865ec9SKyle Evansdef ecdsa_verify(hashfunc, keypair, message, sig): 538*f0865ec9SKyle Evans pubkey = keypair.pubkey 539*f0865ec9SKyle Evans # Get important parameters from the curve 540*f0865ec9SKyle Evans p = pubkey.curve.p 541*f0865ec9SKyle Evans q = pubkey.curve.q 542*f0865ec9SKyle Evans gx = pubkey.curve.gx 543*f0865ec9SKyle Evans gy = pubkey.curve.gy 544*f0865ec9SKyle Evans q_limit_len = getbitlen(q) 545*f0865ec9SKyle Evans G = Point(pubkey.curve, gx, gy) 546*f0865ec9SKyle Evans # Extract r and s 547*f0865ec9SKyle Evans if len(sig) != 2*getbytelen(q): 548*f0865ec9SKyle Evans raise Exception("ECDSA verify: bad signature length!") 549*f0865ec9SKyle Evans r = stringtoint(sig[0:int(len(sig)/2)]) 550*f0865ec9SKyle Evans s = stringtoint(sig[int(len(sig)/2):]) 551*f0865ec9SKyle Evans if r == 0 or s == 0: 552*f0865ec9SKyle Evans return False 553*f0865ec9SKyle Evans # Compute the hash 554*f0865ec9SKyle Evans (h, _, _) = hashfunc(message) 555*f0865ec9SKyle Evans # Truncate hash value 556*f0865ec9SKyle Evans h = truncate(h, q_limit_len, "LEFT") 557*f0865ec9SKyle Evans # Convert the hash value to an int 558*f0865ec9SKyle Evans e = stringtoint(h) % q 559*f0865ec9SKyle Evans u = (modinv(s, q) * e) % q 560*f0865ec9SKyle Evans v = (modinv(s, q) * r) % q 561*f0865ec9SKyle Evans W_ = (u * G) + (v * pubkey.Y) 562*f0865ec9SKyle Evans if W_.x == None: 563*f0865ec9SKyle Evans return False 564*f0865ec9SKyle Evans r_ = W_.x % q 565*f0865ec9SKyle Evans if r == r_: 566*f0865ec9SKyle Evans return True 567*f0865ec9SKyle Evans else: 568*f0865ec9SKyle Evans return False 569*f0865ec9SKyle Evans 570*f0865ec9SKyle Evansdef eckcdsa_genKeyPair(curve): 571*f0865ec9SKyle Evans return genKeyPair(curve, True) 572*f0865ec9SKyle Evans 573*f0865ec9SKyle Evans# *| IUF - ECKCDSA signature 574*f0865ec9SKyle Evans# *| 575*f0865ec9SKyle Evans# *| IUF 1. Compute h = H(z||m) 576*f0865ec9SKyle Evans# *| F 2. If hsize > bitlen(q), set h to bitlen(q) 577*f0865ec9SKyle Evans# *| rightmost (less significant) bits of h. 578*f0865ec9SKyle Evans# *| F 3. Get a random value k in ]0,q[ 579*f0865ec9SKyle Evans# *| F 4. Compute W = (W_x,W_y) = kG 580*f0865ec9SKyle Evans# *| F 5. Compute r = h(FE2OS(W_x)). 581*f0865ec9SKyle Evans# *| F 6. If hsize > bitlen(q), set r to bitlen(q) 582*f0865ec9SKyle Evans# *| rightmost (less significant) bits of r. 583*f0865ec9SKyle Evans# *| F 7. Compute e = OS2I(r XOR h) mod q 584*f0865ec9SKyle Evans# *| F 8. Compute s = x(k - e) mod q 585*f0865ec9SKyle Evans# *| F 9. if s == 0, restart at step 3. 586*f0865ec9SKyle Evans# *| F 10. return (r,s) 587*f0865ec9SKyle Evansdef eckcdsa_sign(hashfunc, keypair, message, k=None): 588*f0865ec9SKyle Evans privkey = keypair.privkey 589*f0865ec9SKyle Evans # Get important parameters from the curve 590*f0865ec9SKyle Evans p = privkey.curve.p 591*f0865ec9SKyle Evans q = privkey.curve.q 592*f0865ec9SKyle Evans gx = privkey.curve.gx 593*f0865ec9SKyle Evans gy = privkey.curve.gy 594*f0865ec9SKyle Evans G = Point(privkey.curve, gx, gy) 595*f0865ec9SKyle Evans q_limit_len = getbitlen(q) 596*f0865ec9SKyle Evans # Compute the certificate data 597*f0865ec9SKyle Evans (_, _, hblocksize) = hashfunc("") 598*f0865ec9SKyle Evans z = expand(inttostring(keypair.pubkey.Y.x), 8*getbytelen(p), "LEFT") 599*f0865ec9SKyle Evans z = z + expand(inttostring(keypair.pubkey.Y.y), 8*getbytelen(p), "LEFT") 600*f0865ec9SKyle Evans if len(z) > hblocksize: 601*f0865ec9SKyle Evans # Truncate 602*f0865ec9SKyle Evans z = truncate(z, 8*hblocksize, "LEFT") 603*f0865ec9SKyle Evans else: 604*f0865ec9SKyle Evans # Expand 605*f0865ec9SKyle Evans z = expand(z, 8*hblocksize, "RIGHT") 606*f0865ec9SKyle Evans # Compute the hash 607*f0865ec9SKyle Evans (h, _, _) = hashfunc(z + message) 608*f0865ec9SKyle Evans # Truncate hash value 609*f0865ec9SKyle Evans h = truncate(h, 8 * int(math.ceil(q_limit_len / 8)), "RIGHT") 610*f0865ec9SKyle Evans OK = False 611*f0865ec9SKyle Evans while OK == False: 612*f0865ec9SKyle Evans if k == None: 613*f0865ec9SKyle Evans k = getrandomint(q) 614*f0865ec9SKyle Evans if k == 0: 615*f0865ec9SKyle Evans continue 616*f0865ec9SKyle Evans W = k * G 617*f0865ec9SKyle Evans (r, _, _) = hashfunc(expand(inttostring(W.x), 8*getbytelen(p), "LEFT")) 618*f0865ec9SKyle Evans r = truncate(r, 8 * int(math.ceil(q_limit_len / 8)), "RIGHT") 619*f0865ec9SKyle Evans e = (stringtoint(r) ^ stringtoint(h)) % q 620*f0865ec9SKyle Evans s = (privkey.x * (k - e)) % q 621*f0865ec9SKyle Evans if s == 0: 622*f0865ec9SKyle Evans continue 623*f0865ec9SKyle Evans OK = True 624*f0865ec9SKyle Evans return (r + expand(inttostring(s), 8*getbytelen(q), "LEFT"), k) 625*f0865ec9SKyle Evans 626*f0865ec9SKyle Evans# *| IUF - ECKCDSA verification 627*f0865ec9SKyle Evans# *| 628*f0865ec9SKyle Evans# *| I 1. Check the length of r: 629*f0865ec9SKyle Evans# *| - if hsize > bitlen(q), r must be of 630*f0865ec9SKyle Evans# *| length bitlen(q) 631*f0865ec9SKyle Evans# *| - if hsize <= bitlen(q), r must be of 632*f0865ec9SKyle Evans# *| length hsize 633*f0865ec9SKyle Evans# *| I 2. Check that s is in ]0,q[ 634*f0865ec9SKyle Evans# *| IUF 3. Compute h = H(z||m) 635*f0865ec9SKyle Evans# *| F 4. If hsize > bitlen(q), set h to bitlen(q) 636*f0865ec9SKyle Evans# *| rightmost (less significant) bits of h. 637*f0865ec9SKyle Evans# *| F 5. Compute e = OS2I(r XOR h) mod q 638*f0865ec9SKyle Evans# *| F 6. Compute W' = sY + eG, where Y is the public key 639*f0865ec9SKyle Evans# *| F 7. Compute r' = h(FE2OS(W'x)) 640*f0865ec9SKyle Evans# *| F 8. If hsize > bitlen(q), set r' to bitlen(q) 641*f0865ec9SKyle Evans# *| rightmost (less significant) bits of r'. 642*f0865ec9SKyle Evans# *| F 9. Check if r == r' 643*f0865ec9SKyle Evansdef eckcdsa_verify(hashfunc, keypair, message, sig): 644*f0865ec9SKyle Evans pubkey = keypair.pubkey 645*f0865ec9SKyle Evans # Get important parameters from the curve 646*f0865ec9SKyle Evans p = pubkey.curve.p 647*f0865ec9SKyle Evans q = pubkey.curve.q 648*f0865ec9SKyle Evans gx = pubkey.curve.gx 649*f0865ec9SKyle Evans gy = pubkey.curve.gy 650*f0865ec9SKyle Evans G = Point(pubkey.curve, gx, gy) 651*f0865ec9SKyle Evans q_limit_len = getbitlen(q) 652*f0865ec9SKyle Evans (_, hsize, hblocksize) = hashfunc("") 653*f0865ec9SKyle Evans # Extract r and s 654*f0865ec9SKyle Evans if (8*hsize) > q_limit_len: 655*f0865ec9SKyle Evans r_len = int(math.ceil(q_limit_len / 8.)) 656*f0865ec9SKyle Evans else: 657*f0865ec9SKyle Evans r_len = hsize 658*f0865ec9SKyle Evans r = stringtoint(sig[0:int(r_len)]) 659*f0865ec9SKyle Evans s = stringtoint(sig[int(r_len):]) 660*f0865ec9SKyle Evans if (s >= q) or (s < 0): 661*f0865ec9SKyle Evans return False 662*f0865ec9SKyle Evans # Compute the certificate data 663*f0865ec9SKyle Evans z = expand(inttostring(keypair.pubkey.Y.x), 8*getbytelen(p), "LEFT") 664*f0865ec9SKyle Evans z = z + expand(inttostring(keypair.pubkey.Y.y), 8*getbytelen(p), "LEFT") 665*f0865ec9SKyle Evans if len(z) > hblocksize: 666*f0865ec9SKyle Evans # Truncate 667*f0865ec9SKyle Evans z = truncate(z, 8*hblocksize, "LEFT") 668*f0865ec9SKyle Evans else: 669*f0865ec9SKyle Evans # Expand 670*f0865ec9SKyle Evans z = expand(z, 8*hblocksize, "RIGHT") 671*f0865ec9SKyle Evans # Compute the hash 672*f0865ec9SKyle Evans (h, _, _) = hashfunc(z + message) 673*f0865ec9SKyle Evans # Truncate hash value 674*f0865ec9SKyle Evans h = truncate(h, 8 * int(math.ceil(q_limit_len / 8)), "RIGHT") 675*f0865ec9SKyle Evans e = (r ^ stringtoint(h)) % q 676*f0865ec9SKyle Evans W_ = (s * pubkey.Y) + (e * G) 677*f0865ec9SKyle Evans (h, _, _) = hashfunc(expand(inttostring(W_.x), 8*getbytelen(p), "LEFT")) 678*f0865ec9SKyle Evans r_ = truncate(h, 8 * int(math.ceil(q_limit_len / 8)), "RIGHT") 679*f0865ec9SKyle Evans if stringtoint(r_) == r: 680*f0865ec9SKyle Evans return True 681*f0865ec9SKyle Evans else: 682*f0865ec9SKyle Evans return False 683*f0865ec9SKyle Evans 684*f0865ec9SKyle Evans# *| IUF - ECFSDSA signature 685*f0865ec9SKyle Evans# *| 686*f0865ec9SKyle Evans# *| I 1. Get a random value k in ]0,q[ 687*f0865ec9SKyle Evans# *| I 2. Compute W = (W_x,W_y) = kG 688*f0865ec9SKyle Evans# *| I 3. Compute r = FE2OS(W_x)||FE2OS(W_y) 689*f0865ec9SKyle Evans# *| I 4. If r is an all zero string, restart the process at step 1. 690*f0865ec9SKyle Evans# *| IUF 5. Compute h = H(r||m) 691*f0865ec9SKyle Evans# *| F 6. Compute e = OS2I(h) mod q 692*f0865ec9SKyle Evans# *| F 7. Compute s = (k + ex) mod q 693*f0865ec9SKyle Evans# *| F 8. If s is 0, restart the process at step 1 (see c. below) 694*f0865ec9SKyle Evans# *| F 9. Return (r,s) 695*f0865ec9SKyle Evansdef ecfsdsa_sign(hashfunc, keypair, message, k=None): 696*f0865ec9SKyle Evans privkey = keypair.privkey 697*f0865ec9SKyle Evans # Get important parameters from the curve 698*f0865ec9SKyle Evans p = privkey.curve.p 699*f0865ec9SKyle Evans q = privkey.curve.q 700*f0865ec9SKyle Evans gx = privkey.curve.gx 701*f0865ec9SKyle Evans gy = privkey.curve.gy 702*f0865ec9SKyle Evans G = Point(privkey.curve, gx, gy) 703*f0865ec9SKyle Evans OK = False 704*f0865ec9SKyle Evans while OK == False: 705*f0865ec9SKyle Evans if k == None: 706*f0865ec9SKyle Evans k = getrandomint(q) 707*f0865ec9SKyle Evans if k == 0: 708*f0865ec9SKyle Evans continue 709*f0865ec9SKyle Evans W = k * G 710*f0865ec9SKyle Evans r = expand(inttostring(W.x), 8*getbytelen(p), "LEFT") + expand(inttostring(W.y), 8*getbytelen(p), "LEFT") 711*f0865ec9SKyle Evans if stringtoint(r) == 0: 712*f0865ec9SKyle Evans continue 713*f0865ec9SKyle Evans (h, _, _) = hashfunc(r + message) 714*f0865ec9SKyle Evans e = stringtoint(h) % q 715*f0865ec9SKyle Evans s = (k + e * privkey.x) % q 716*f0865ec9SKyle Evans if s == 0: 717*f0865ec9SKyle Evans continue 718*f0865ec9SKyle Evans OK = True 719*f0865ec9SKyle Evans return (r + expand(inttostring(s), 8*getbytelen(q), "LEFT"), k) 720*f0865ec9SKyle Evans 721*f0865ec9SKyle Evans 722*f0865ec9SKyle Evans# *| IUF - ECFSDSA verification 723*f0865ec9SKyle Evans# *| 724*f0865ec9SKyle Evans# *| I 1. Reject the signature if r is not a valid point on the curve. 725*f0865ec9SKyle Evans# *| I 2. Reject the signature if s is not in ]0,q[ 726*f0865ec9SKyle Evans# *| IUF 3. Compute h = H(r||m) 727*f0865ec9SKyle Evans# *| F 4. Convert h to an integer and then compute e = -h mod q 728*f0865ec9SKyle Evans# *| F 5. compute W' = sG + eY, where Y is the public key 729*f0865ec9SKyle Evans# *| F 6. Compute r' = FE2OS(W'_x)||FE2OS(W'_y) 730*f0865ec9SKyle Evans# *| F 7. Accept the signature if and only if r equals r' 731*f0865ec9SKyle Evansdef ecfsdsa_verify(hashfunc, keypair, message, sig): 732*f0865ec9SKyle Evans pubkey = keypair.pubkey 733*f0865ec9SKyle Evans # Get important parameters from the curve 734*f0865ec9SKyle Evans p = pubkey.curve.p 735*f0865ec9SKyle Evans q = pubkey.curve.q 736*f0865ec9SKyle Evans gx = pubkey.curve.gx 737*f0865ec9SKyle Evans gy = pubkey.curve.gy 738*f0865ec9SKyle Evans G = Point(pubkey.curve, gx, gy) 739*f0865ec9SKyle Evans # Extract coordinates from r and s from signature 740*f0865ec9SKyle Evans if len(sig) != (2*getbytelen(p)) + getbytelen(q): 741*f0865ec9SKyle Evans raise Exception("ECFSDSA verify: bad signature length!") 742*f0865ec9SKyle Evans wx = sig[:int(getbytelen(p))] 743*f0865ec9SKyle Evans wy = sig[int(getbytelen(p)):int(2*getbytelen(p))] 744*f0865ec9SKyle Evans r = wx + wy 745*f0865ec9SKyle Evans s = stringtoint(sig[int(2*getbytelen(p)):int((2*getbytelen(p))+getbytelen(q))]) 746*f0865ec9SKyle Evans # Check r is on the curve 747*f0865ec9SKyle Evans W = Point(pubkey.curve, stringtoint(wx), stringtoint(wy)) 748*f0865ec9SKyle Evans # Check s is in ]0,q[ 749*f0865ec9SKyle Evans if s == 0 or s > q: 750*f0865ec9SKyle Evans raise Exception("ECFSDSA verify: s not in ]0,q[") 751*f0865ec9SKyle Evans (h, _, _) = hashfunc(r + message) 752*f0865ec9SKyle Evans e = (-stringtoint(h)) % q 753*f0865ec9SKyle Evans W_ = s * G + e * pubkey.Y 754*f0865ec9SKyle Evans r_ = expand(inttostring(W_.x), 8*getbytelen(p), "LEFT") + expand(inttostring(W_.y), 8*getbytelen(p), "LEFT") 755*f0865ec9SKyle Evans if r == r_: 756*f0865ec9SKyle Evans return True 757*f0865ec9SKyle Evans else: 758*f0865ec9SKyle Evans return False 759*f0865ec9SKyle Evans 760*f0865ec9SKyle Evans 761*f0865ec9SKyle Evans# NOTE: ISO/IEC 14888-3 standard seems to diverge from the existing implementations 762*f0865ec9SKyle Evans# of ECRDSA when treating the message hash, and from the examples of certificates provided 763*f0865ec9SKyle Evans# in RFC 7091 and draft-deremin-rfc4491-bis. While in ISO/IEC 14888-3 it is explicitely asked 764*f0865ec9SKyle Evans# to proceed with the hash of the message as big endian, the RFCs derived from the Russian 765*f0865ec9SKyle Evans# standard expect the hash value to be treated as little endian when importing it as an integer 766*f0865ec9SKyle Evans# (this discrepancy is exhibited and confirmed by test vectors present in ISO/IEC 14888-3, and 767*f0865ec9SKyle Evans# by X.509 certificates present in the RFCs). This seems (to be confirmed) to be a discrepancy of 768*f0865ec9SKyle Evans# ISO/IEC 14888-3 algorithm description that must be fixed there. 769*f0865ec9SKyle Evans# 770*f0865ec9SKyle Evans# In order to be conservative, libecc uses the Russian standard behavior as expected to be in line with 771*f0865ec9SKyle Evans# other implemetations, but keeps the ISO/IEC 14888-3 behavior if forced/asked by the user using 772*f0865ec9SKyle Evans# the USE_ISO14888_3_ECRDSA toggle. This allows to keep backward compatibility with previous versions of the 773*f0865ec9SKyle Evans# library if needed. 774*f0865ec9SKyle Evans 775*f0865ec9SKyle Evans# *| IUF - ECRDSA signature 776*f0865ec9SKyle Evans# *| 777*f0865ec9SKyle Evans# *| UF 1. Compute h = H(m) 778*f0865ec9SKyle Evans# *| F 2. Get a random value k in ]0,q[ 779*f0865ec9SKyle Evans# *| F 3. Compute W = (W_x,W_y) = kG 780*f0865ec9SKyle Evans# *| F 4. Compute r = W_x mod q 781*f0865ec9SKyle Evans# *| F 5. If r is 0, restart the process at step 2. 782*f0865ec9SKyle Evans# *| F 6. Compute e = OS2I(h) mod q. If e is 0, set e to 1. 783*f0865ec9SKyle Evans# *| NOTE: here, ISO/IEC 14888-3 and RFCs differ in the way e treated. 784*f0865ec9SKyle Evans# *| e = OS2I(h) for ISO/IEC 14888-3, or e = OS2I(reversed(h)) when endianness of h 785*f0865ec9SKyle Evans# *| is reversed for RFCs. 786*f0865ec9SKyle Evans# *| F 7. Compute s = (rx + ke) mod q 787*f0865ec9SKyle Evans# *| F 8. If s is 0, restart the process at step 2. 788*f0865ec9SKyle Evans# *| F 11. Return (r,s) 789*f0865ec9SKyle Evansdef ecrdsa_sign(hashfunc, keypair, message, k=None, use_iso14888_divergence=False): 790*f0865ec9SKyle Evans privkey = keypair.privkey 791*f0865ec9SKyle Evans # Get important parameters from the curve 792*f0865ec9SKyle Evans p = privkey.curve.p 793*f0865ec9SKyle Evans q = privkey.curve.q 794*f0865ec9SKyle Evans gx = privkey.curve.gx 795*f0865ec9SKyle Evans gy = privkey.curve.gy 796*f0865ec9SKyle Evans G = Point(privkey.curve, gx, gy) 797*f0865ec9SKyle Evans (h, _, _) = hashfunc(message) 798*f0865ec9SKyle Evans if use_iso14888_divergence == False: 799*f0865ec9SKyle Evans # Reverse the endianness for Russian standard RFC ECRDSA (contrary to ISO/IEC 14888-3 case) 800*f0865ec9SKyle Evans h = h[::-1] 801*f0865ec9SKyle Evans OK = False 802*f0865ec9SKyle Evans while OK == False: 803*f0865ec9SKyle Evans if k == None: 804*f0865ec9SKyle Evans k = getrandomint(q) 805*f0865ec9SKyle Evans if k == 0: 806*f0865ec9SKyle Evans continue 807*f0865ec9SKyle Evans W = k * G 808*f0865ec9SKyle Evans r = W.x % q 809*f0865ec9SKyle Evans if r == 0: 810*f0865ec9SKyle Evans continue 811*f0865ec9SKyle Evans e = stringtoint(h) % q 812*f0865ec9SKyle Evans if e == 0: 813*f0865ec9SKyle Evans e = 1 814*f0865ec9SKyle Evans s = ((r * privkey.x) + (k * e)) % q 815*f0865ec9SKyle Evans if s == 0: 816*f0865ec9SKyle Evans continue 817*f0865ec9SKyle Evans OK = True 818*f0865ec9SKyle Evans return (expand(inttostring(r), 8*getbytelen(q), "LEFT") + expand(inttostring(s), 8*getbytelen(q), "LEFT"), k) 819*f0865ec9SKyle Evans 820*f0865ec9SKyle Evans# *| IUF - ECRDSA verification 821*f0865ec9SKyle Evans# *| 822*f0865ec9SKyle Evans# *| UF 1. Check that r and s are both in ]0,q[ 823*f0865ec9SKyle Evans# *| F 2. Compute h = H(m) 824*f0865ec9SKyle Evans# *| F 3. Compute e = OS2I(h)^-1 mod q 825*f0865ec9SKyle Evans# *| NOTE: here, ISO/IEC 14888-3 and RFCs differ in the way e treated. 826*f0865ec9SKyle Evans# *| e = OS2I(h) for ISO/IEC 14888-3, or e = OS2I(reversed(h)) when endianness of h 827*f0865ec9SKyle Evans# *| is reversed for RFCs. 828*f0865ec9SKyle Evans# *| F 4. Compute u = es mod q 829*f0865ec9SKyle Evans# *| F 4. Compute v = -er mod q 830*f0865ec9SKyle Evans# *| F 5. Compute W' = uG + vY = (W'_x, W'_y) 831*f0865ec9SKyle Evans# *| F 6. Let's now compute r' = W'_x mod q 832*f0865ec9SKyle Evans# *| F 7. Check r and r' are the same 833*f0865ec9SKyle Evansdef ecrdsa_verify(hashfunc, keypair, message, sig, use_iso14888_divergence=False): 834*f0865ec9SKyle Evans pubkey = keypair.pubkey 835*f0865ec9SKyle Evans # Get important parameters from the curve 836*f0865ec9SKyle Evans p = pubkey.curve.p 837*f0865ec9SKyle Evans q = pubkey.curve.q 838*f0865ec9SKyle Evans gx = pubkey.curve.gx 839*f0865ec9SKyle Evans gy = pubkey.curve.gy 840*f0865ec9SKyle Evans G = Point(pubkey.curve, gx, gy) 841*f0865ec9SKyle Evans # Extract coordinates from r and s from signature 842*f0865ec9SKyle Evans if len(sig) != 2*getbytelen(q): 843*f0865ec9SKyle Evans raise Exception("ECRDSA verify: bad signature length!") 844*f0865ec9SKyle Evans r = stringtoint(sig[:int(getbytelen(q))]) 845*f0865ec9SKyle Evans s = stringtoint(sig[int(getbytelen(q)):int(2*getbytelen(q))]) 846*f0865ec9SKyle Evans if r == 0 or r > q: 847*f0865ec9SKyle Evans raise Exception("ECRDSA verify: r not in ]0,q[") 848*f0865ec9SKyle Evans if s == 0 or s > q: 849*f0865ec9SKyle Evans raise Exception("ECRDSA verify: s not in ]0,q[") 850*f0865ec9SKyle Evans (h, _, _) = hashfunc(message) 851*f0865ec9SKyle Evans if use_iso14888_divergence == False: 852*f0865ec9SKyle Evans # Reverse the endianness for Russian standard RFC ECRDSA (contrary to ISO/IEC 14888-3 case) 853*f0865ec9SKyle Evans h = h[::-1] 854*f0865ec9SKyle Evans e = modinv(stringtoint(h) % q, q) 855*f0865ec9SKyle Evans u = (e * s) % q 856*f0865ec9SKyle Evans v = (-e * r) % q 857*f0865ec9SKyle Evans W_ = u * G + v * pubkey.Y 858*f0865ec9SKyle Evans r_ = W_.x % q 859*f0865ec9SKyle Evans if r == r_: 860*f0865ec9SKyle Evans return True 861*f0865ec9SKyle Evans else: 862*f0865ec9SKyle Evans return False 863*f0865ec9SKyle Evans 864*f0865ec9SKyle Evans 865*f0865ec9SKyle Evans# *| IUF - ECGDSA signature 866*f0865ec9SKyle Evans# *| 867*f0865ec9SKyle Evans# *| UF 1. Compute h = H(m). If |h| > bitlen(q), set h to bitlen(q) 868*f0865ec9SKyle Evans# *| leftmost (most significant) bits of h 869*f0865ec9SKyle Evans# *| F 2. Convert e = - OS2I(h) mod q 870*f0865ec9SKyle Evans# *| F 3. Get a random value k in ]0,q[ 871*f0865ec9SKyle Evans# *| F 4. Compute W = (W_x,W_y) = kG 872*f0865ec9SKyle Evans# *| F 5. Compute r = W_x mod q 873*f0865ec9SKyle Evans# *| F 6. If r is 0, restart the process at step 4. 874*f0865ec9SKyle Evans# *| F 7. Compute s = x(kr + e) mod q 875*f0865ec9SKyle Evans# *| F 8. If s is 0, restart the process at step 4. 876*f0865ec9SKyle Evans# *| F 9. Return (r,s) 877*f0865ec9SKyle Evansdef ecgdsa_sign(hashfunc, keypair, message, k=None): 878*f0865ec9SKyle Evans privkey = keypair.privkey 879*f0865ec9SKyle Evans # Get important parameters from the curve 880*f0865ec9SKyle Evans p = privkey.curve.p 881*f0865ec9SKyle Evans q = privkey.curve.q 882*f0865ec9SKyle Evans gx = privkey.curve.gx 883*f0865ec9SKyle Evans gy = privkey.curve.gy 884*f0865ec9SKyle Evans G = Point(privkey.curve, gx, gy) 885*f0865ec9SKyle Evans (h, _, _) = hashfunc(message) 886*f0865ec9SKyle Evans q_limit_len = getbitlen(q) 887*f0865ec9SKyle Evans # Truncate hash value 888*f0865ec9SKyle Evans h = truncate(h, q_limit_len, "LEFT") 889*f0865ec9SKyle Evans e = (-stringtoint(h)) % q 890*f0865ec9SKyle Evans OK = False 891*f0865ec9SKyle Evans while OK == False: 892*f0865ec9SKyle Evans if k == None: 893*f0865ec9SKyle Evans k = getrandomint(q) 894*f0865ec9SKyle Evans if k == 0: 895*f0865ec9SKyle Evans continue 896*f0865ec9SKyle Evans W = k * G 897*f0865ec9SKyle Evans r = W.x % q 898*f0865ec9SKyle Evans if r == 0: 899*f0865ec9SKyle Evans continue 900*f0865ec9SKyle Evans s = (privkey.x * ((k * r) + e)) % q 901*f0865ec9SKyle Evans if s == 0: 902*f0865ec9SKyle Evans continue 903*f0865ec9SKyle Evans OK = True 904*f0865ec9SKyle Evans return (expand(inttostring(r), 8*getbytelen(q), "LEFT") + expand(inttostring(s), 8*getbytelen(q), "LEFT"), k) 905*f0865ec9SKyle Evans 906*f0865ec9SKyle Evans# *| IUF - ECGDSA verification 907*f0865ec9SKyle Evans# *| 908*f0865ec9SKyle Evans# *| I 1. Reject the signature if r or s is 0. 909*f0865ec9SKyle Evans# *| UF 2. Compute h = H(m). If |h| > bitlen(q), set h to bitlen(q) 910*f0865ec9SKyle Evans# *| leftmost (most significant) bits of h 911*f0865ec9SKyle Evans# *| F 3. Compute e = OS2I(h) mod q 912*f0865ec9SKyle Evans# *| F 4. Compute u = ((r^-1)e mod q) 913*f0865ec9SKyle Evans# *| F 5. Compute v = ((r^-1)s mod q) 914*f0865ec9SKyle Evans# *| F 6. Compute W' = uG + vY 915*f0865ec9SKyle Evans# *| F 7. Compute r' = W'_x mod q 916*f0865ec9SKyle Evans# *| F 8. Accept the signature if and only if r equals r' 917*f0865ec9SKyle Evansdef ecgdsa_verify(hashfunc, keypair, message, sig): 918*f0865ec9SKyle Evans pubkey = keypair.pubkey 919*f0865ec9SKyle Evans # Get important parameters from the curve 920*f0865ec9SKyle Evans p = pubkey.curve.p 921*f0865ec9SKyle Evans q = pubkey.curve.q 922*f0865ec9SKyle Evans gx = pubkey.curve.gx 923*f0865ec9SKyle Evans gy = pubkey.curve.gy 924*f0865ec9SKyle Evans G = Point(pubkey.curve, gx, gy) 925*f0865ec9SKyle Evans # Extract coordinates from r and s from signature 926*f0865ec9SKyle Evans if len(sig) != 2*getbytelen(q): 927*f0865ec9SKyle Evans raise Exception("ECGDSA verify: bad signature length!") 928*f0865ec9SKyle Evans r = stringtoint(sig[:int(getbytelen(q))]) 929*f0865ec9SKyle Evans s = stringtoint(sig[int(getbytelen(q)):int(2*getbytelen(q))]) 930*f0865ec9SKyle Evans if r == 0 or r > q: 931*f0865ec9SKyle Evans raise Exception("ECGDSA verify: r not in ]0,q[") 932*f0865ec9SKyle Evans if s == 0 or s > q: 933*f0865ec9SKyle Evans raise Exception("ECGDSA verify: s not in ]0,q[") 934*f0865ec9SKyle Evans (h, _, _) = hashfunc(message) 935*f0865ec9SKyle Evans q_limit_len = getbitlen(q) 936*f0865ec9SKyle Evans # Truncate hash value 937*f0865ec9SKyle Evans h = truncate(h, q_limit_len, "LEFT") 938*f0865ec9SKyle Evans e = stringtoint(h) % q 939*f0865ec9SKyle Evans r_inv = modinv(r, q) 940*f0865ec9SKyle Evans u = (r_inv * e) % q 941*f0865ec9SKyle Evans v = (r_inv * s) % q 942*f0865ec9SKyle Evans W_ = u * G + v * pubkey.Y 943*f0865ec9SKyle Evans r_ = W_.x % q 944*f0865ec9SKyle Evans if r == r_: 945*f0865ec9SKyle Evans return True 946*f0865ec9SKyle Evans else: 947*f0865ec9SKyle Evans return False 948*f0865ec9SKyle Evans 949*f0865ec9SKyle Evans# *| IUF - ECSDSA/ECOSDSA signature 950*f0865ec9SKyle Evans# *| 951*f0865ec9SKyle Evans# *| I 1. Get a random value k in ]0, q[ 952*f0865ec9SKyle Evans# *| I 2. Compute W = kG = (Wx, Wy) 953*f0865ec9SKyle Evans# *| IUF 3. Compute r = H(Wx [|| Wy] || m) 954*f0865ec9SKyle Evans# *| - In the normal version (ECSDSA), r = h(Wx || Wy || m). 955*f0865ec9SKyle Evans# *| - In the optimized version (ECOSDSA), r = h(Wx || m). 956*f0865ec9SKyle Evans# *| F 4. Compute e = OS2I(r) mod q 957*f0865ec9SKyle Evans# *| F 5. if e == 0, restart at step 1. 958*f0865ec9SKyle Evans# *| F 6. Compute s = (k + ex) mod q. 959*f0865ec9SKyle Evans# *| F 7. if s == 0, restart at step 1. 960*f0865ec9SKyle Evans# *| F 8. Return (r, s) 961*f0865ec9SKyle Evansdef ecsdsa_common_sign(hashfunc, keypair, message, optimized, k=None): 962*f0865ec9SKyle Evans privkey = keypair.privkey 963*f0865ec9SKyle Evans # Get important parameters from the curve 964*f0865ec9SKyle Evans p = privkey.curve.p 965*f0865ec9SKyle Evans q = privkey.curve.q 966*f0865ec9SKyle Evans gx = privkey.curve.gx 967*f0865ec9SKyle Evans gy = privkey.curve.gy 968*f0865ec9SKyle Evans G = Point(privkey.curve, gx, gy) 969*f0865ec9SKyle Evans OK = False 970*f0865ec9SKyle Evans while OK == False: 971*f0865ec9SKyle Evans if k == None: 972*f0865ec9SKyle Evans k = getrandomint(q) 973*f0865ec9SKyle Evans if k == 0: 974*f0865ec9SKyle Evans continue 975*f0865ec9SKyle Evans W = k * G 976*f0865ec9SKyle Evans if optimized == False: 977*f0865ec9SKyle Evans (r, _, _) = hashfunc(expand(inttostring(W.x), 8*getbytelen(p), "LEFT") + expand(inttostring(W.y), 8*getbytelen(p), "LEFT") + message) 978*f0865ec9SKyle Evans else: 979*f0865ec9SKyle Evans (r, _, _) = hashfunc(expand(inttostring(W.x), 8*getbytelen(p), "LEFT") + message) 980*f0865ec9SKyle Evans e = stringtoint(r) % q 981*f0865ec9SKyle Evans if e == 0: 982*f0865ec9SKyle Evans continue 983*f0865ec9SKyle Evans s = (k + (e * privkey.x)) % q 984*f0865ec9SKyle Evans if s == 0: 985*f0865ec9SKyle Evans continue 986*f0865ec9SKyle Evans OK = True 987*f0865ec9SKyle Evans return (r + expand(inttostring(s), 8*getbytelen(q), "LEFT"), k) 988*f0865ec9SKyle Evans 989*f0865ec9SKyle Evansdef ecsdsa_sign(hashfunc, keypair, message, k=None): 990*f0865ec9SKyle Evans return ecsdsa_common_sign(hashfunc, keypair, message, False, k) 991*f0865ec9SKyle Evans 992*f0865ec9SKyle Evansdef ecosdsa_sign(hashfunc, keypair, message, k=None): 993*f0865ec9SKyle Evans return ecsdsa_common_sign(hashfunc, keypair, message, True, k) 994*f0865ec9SKyle Evans 995*f0865ec9SKyle Evans# *| IUF - ECSDSA/ECOSDSA verification 996*f0865ec9SKyle Evans# *| 997*f0865ec9SKyle Evans# *| I 1. if s is not in ]0,q[, reject the signature.x 998*f0865ec9SKyle Evans# *| I 2. Compute e = -r mod q 999*f0865ec9SKyle Evans# *| I 3. If e == 0, reject the signature. 1000*f0865ec9SKyle Evans# *| I 4. Compute W' = sG + eY 1001*f0865ec9SKyle Evans# *| IUF 5. Compute r' = H(W'x [|| W'y] || m) 1002*f0865ec9SKyle Evans# *| - In the normal version (ECSDSA), r = h(W'x || W'y || m). 1003*f0865ec9SKyle Evans# *| - In the optimized version (ECOSDSA), r = h(W'x || m). 1004*f0865ec9SKyle Evans# *| F 6. Accept the signature if and only if r and r' are the same 1005*f0865ec9SKyle Evansdef ecsdsa_common_verify(hashfunc, keypair, message, sig, optimized): 1006*f0865ec9SKyle Evans pubkey = keypair.pubkey 1007*f0865ec9SKyle Evans # Get important parameters from the curve 1008*f0865ec9SKyle Evans p = pubkey.curve.p 1009*f0865ec9SKyle Evans q = pubkey.curve.q 1010*f0865ec9SKyle Evans gx = pubkey.curve.gx 1011*f0865ec9SKyle Evans gy = pubkey.curve.gy 1012*f0865ec9SKyle Evans G = Point(pubkey.curve, gx, gy) 1013*f0865ec9SKyle Evans (_, hlen, _) = hashfunc("") 1014*f0865ec9SKyle Evans # Extract coordinates from r and s from signature 1015*f0865ec9SKyle Evans if len(sig) != hlen + getbytelen(q): 1016*f0865ec9SKyle Evans raise Exception("EC[O]SDSA verify: bad signature length!") 1017*f0865ec9SKyle Evans r = stringtoint(sig[:int(hlen)]) 1018*f0865ec9SKyle Evans s = stringtoint(sig[int(hlen):int(hlen+getbytelen(q))]) 1019*f0865ec9SKyle Evans if s == 0 or s > q: 1020*f0865ec9SKyle Evans raise Exception("EC[O]DSA verify: s not in ]0,q[") 1021*f0865ec9SKyle Evans e = (-r) % q 1022*f0865ec9SKyle Evans if e == 0: 1023*f0865ec9SKyle Evans raise Exception("EC[O]DSA verify: e is null") 1024*f0865ec9SKyle Evans W_ = s * G + e * pubkey.Y 1025*f0865ec9SKyle Evans if optimized == False: 1026*f0865ec9SKyle Evans (r_, _, _) = hashfunc(expand(inttostring(W_.x), 8*getbytelen(p), "LEFT") + expand(inttostring(W_.y), 8*getbytelen(p), "LEFT") + message) 1027*f0865ec9SKyle Evans else: 1028*f0865ec9SKyle Evans (r_, _, _) = hashfunc(expand(inttostring(W_.x), 8*getbytelen(p), "LEFT") + message) 1029*f0865ec9SKyle Evans if sig[:int(hlen)] == r_: 1030*f0865ec9SKyle Evans return True 1031*f0865ec9SKyle Evans else: 1032*f0865ec9SKyle Evans return False 1033*f0865ec9SKyle Evans 1034*f0865ec9SKyle Evansdef ecsdsa_verify(hashfunc, keypair, message, sig): 1035*f0865ec9SKyle Evans return ecsdsa_common_verify(hashfunc, keypair, message, sig, False) 1036*f0865ec9SKyle Evans 1037*f0865ec9SKyle Evansdef ecosdsa_verify(hashfunc, keypair, message, sig): 1038*f0865ec9SKyle Evans return ecsdsa_common_verify(hashfunc, keypair, message, sig, True) 1039*f0865ec9SKyle Evans 1040*f0865ec9SKyle Evans 1041*f0865ec9SKyle Evans########################################################## 1042*f0865ec9SKyle Evans### Generate self-tests for all the algorithms 1043*f0865ec9SKyle Evans 1044*f0865ec9SKyle Evansall_hash_funcs = [ (sha224, "SHA224"), (sha256, "SHA256"), (sha384, "SHA384"), (sha512, "SHA512"), (sha3_224, "SHA3_224"), (sha3_256, "SHA3_256"), (sha3_384, "SHA3_384"), (sha3_512, "SHA3_512") ] 1045*f0865ec9SKyle Evans 1046*f0865ec9SKyle Evansall_sig_algs = [ (ecdsa_sign, ecdsa_verify, genKeyPair, "ECDSA"), 1047*f0865ec9SKyle Evans (eckcdsa_sign, eckcdsa_verify, eckcdsa_genKeyPair, "ECKCDSA"), 1048*f0865ec9SKyle Evans (ecfsdsa_sign, ecfsdsa_verify, genKeyPair, "ECFSDSA"), 1049*f0865ec9SKyle Evans (ecrdsa_sign, ecrdsa_verify, genKeyPair, "ECRDSA"), 1050*f0865ec9SKyle Evans (ecgdsa_sign, ecgdsa_verify, eckcdsa_genKeyPair, "ECGDSA"), 1051*f0865ec9SKyle Evans (ecsdsa_sign, ecsdsa_verify, genKeyPair, "ECSDSA"), 1052*f0865ec9SKyle Evans (ecosdsa_sign, ecosdsa_verify, genKeyPair, "ECOSDSA"), ] 1053*f0865ec9SKyle Evans 1054*f0865ec9SKyle Evans 1055*f0865ec9SKyle Evanscurr_test = 0 1056*f0865ec9SKyle Evansdef pretty_print_curr_test(num_test, total_gen_tests): 1057*f0865ec9SKyle Evans num_decimal = int(math.log10(total_gen_tests))+1 1058*f0865ec9SKyle Evans format_buf = "%0"+str(num_decimal)+"d/%0"+str(num_decimal)+"d" 1059*f0865ec9SKyle Evans sys.stdout.write('\b'*((2*num_decimal)+1)) 1060*f0865ec9SKyle Evans sys.stdout.flush() 1061*f0865ec9SKyle Evans sys.stdout.write(format_buf % (num_test, total_gen_tests)) 1062*f0865ec9SKyle Evans if num_test == total_gen_tests: 1063*f0865ec9SKyle Evans print("") 1064*f0865ec9SKyle Evans return 1065*f0865ec9SKyle Evans 1066*f0865ec9SKyle Evansdef gen_self_test(curve, hashfunc, sig_alg_sign, sig_alg_verify, sig_alg_genkeypair, num, hashfunc_name, sig_alg_name, total_gen_tests): 1067*f0865ec9SKyle Evans global curr_test 1068*f0865ec9SKyle Evans curr_test = curr_test + 1 1069*f0865ec9SKyle Evans if num != 0: 1070*f0865ec9SKyle Evans pretty_print_curr_test(curr_test, total_gen_tests) 1071*f0865ec9SKyle Evans output_list = [] 1072*f0865ec9SKyle Evans for test_num in range(0, num): 1073*f0865ec9SKyle Evans out_vectors = "" 1074*f0865ec9SKyle Evans # Generate a random key pair 1075*f0865ec9SKyle Evans keypair = sig_alg_genkeypair(curve) 1076*f0865ec9SKyle Evans # Generate a random message with a random size 1077*f0865ec9SKyle Evans size = getrandomint(256) 1078*f0865ec9SKyle Evans if is_python_2(): 1079*f0865ec9SKyle Evans message = ''.join([random.choice(string.ascii_letters + string.digits) for n in xrange(size)]) 1080*f0865ec9SKyle Evans else: 1081*f0865ec9SKyle Evans message = ''.join([random.choice(string.ascii_letters + string.digits) for n in range(size)]) 1082*f0865ec9SKyle Evans test_name = sig_alg_name + "_" + hashfunc_name + "_" + curve.name.upper() + "_" + str(test_num) 1083*f0865ec9SKyle Evans # Sign the message 1084*f0865ec9SKyle Evans (sig, k) = sig_alg_sign(hashfunc, keypair, message) 1085*f0865ec9SKyle Evans # Check that everything is OK with a verify 1086*f0865ec9SKyle Evans if sig_alg_verify(hashfunc, keypair, message, sig) != True: 1087*f0865ec9SKyle Evans raise Exception("Error during self test generation: sig verify failed! "+test_name+ " / msg="+message+" / sig="+binascii.hexlify(sig)+" / k="+hex(k)+" / privkey.x="+hex(keypair.privkey.x)) 1088*f0865ec9SKyle Evans if sig_alg_name == "ECRDSA": 1089*f0865ec9SKyle Evans out_vectors += "#ifndef USE_ISO14888_3_ECRDSA\n" 1090*f0865ec9SKyle Evans # Now generate the test vector 1091*f0865ec9SKyle Evans out_vectors += "#ifdef WITH_HASH_"+hashfunc_name.upper()+"\n" 1092*f0865ec9SKyle Evans out_vectors += "#ifdef WITH_CURVE_"+curve.name.upper()+"\n" 1093*f0865ec9SKyle Evans out_vectors += "#ifdef WITH_SIG_"+sig_alg_name.upper()+"\n" 1094*f0865ec9SKyle Evans out_vectors += "/* "+test_name+" known test vectors */\n" 1095*f0865ec9SKyle Evans out_vectors += "static int "+test_name+"_test_vectors_get_random(nn_t out, nn_src_t q)\n{\n" 1096*f0865ec9SKyle Evans # k_buf MUST be exported padded to the length of q 1097*f0865ec9SKyle Evans out_vectors += "\tconst u8 k_buf[] = "+bigint_to_C_array(k, getbytelen(curve.q)) 1098*f0865ec9SKyle Evans out_vectors += "\tint ret, cmp;\n\tret = nn_init_from_buf(out, k_buf, sizeof(k_buf)); EG(ret, err);\n\tret = nn_cmp(out, q, &cmp); EG(ret, err);\n\tret = (cmp >= 0) ? -1 : 0;\nerr:\n\treturn ret;\n}\n" 1099*f0865ec9SKyle Evans out_vectors += "static const u8 "+test_name+"_test_vectors_priv_key[] = \n"+bigint_to_C_array(keypair.privkey.x, getbytelen(keypair.privkey.x)) 1100*f0865ec9SKyle Evans out_vectors += "static const u8 "+test_name+"_test_vectors_expected_sig[] = \n"+bigint_to_C_array(stringtoint(sig), len(sig)) 1101*f0865ec9SKyle Evans out_vectors += "static const ec_test_case "+test_name+"_test_case = {\n" 1102*f0865ec9SKyle Evans out_vectors += "\t.name = \""+test_name+"\",\n" 1103*f0865ec9SKyle Evans out_vectors += "\t.ec_str_p = &"+curve.name+"_str_params,\n" 1104*f0865ec9SKyle Evans out_vectors += "\t.priv_key = "+test_name+"_test_vectors_priv_key,\n" 1105*f0865ec9SKyle Evans out_vectors += "\t.priv_key_len = sizeof("+test_name+"_test_vectors_priv_key),\n" 1106*f0865ec9SKyle Evans out_vectors += "\t.nn_random = "+test_name+"_test_vectors_get_random,\n" 1107*f0865ec9SKyle Evans out_vectors += "\t.hash_type = "+hashfunc_name+",\n" 1108*f0865ec9SKyle Evans out_vectors += "\t.msg = \""+message+"\",\n" 1109*f0865ec9SKyle Evans out_vectors += "\t.msglen = "+str(len(message))+",\n" 1110*f0865ec9SKyle Evans out_vectors += "\t.sig_type = "+sig_alg_name+",\n" 1111*f0865ec9SKyle Evans out_vectors += "\t.exp_sig = "+test_name+"_test_vectors_expected_sig,\n" 1112*f0865ec9SKyle Evans out_vectors += "\t.exp_siglen = sizeof("+test_name+"_test_vectors_expected_sig),\n};\n" 1113*f0865ec9SKyle Evans out_vectors += "#endif /* WITH_HASH_"+hashfunc_name+" */\n" 1114*f0865ec9SKyle Evans out_vectors += "#endif /* WITH_CURVE_"+curve.name+" */\n" 1115*f0865ec9SKyle Evans out_vectors += "#endif /* WITH_SIG_"+sig_alg_name+" */\n" 1116*f0865ec9SKyle Evans if sig_alg_name == "ECRDSA": 1117*f0865ec9SKyle Evans out_vectors += "#endif /* !USE_ISO14888_3_ECRDSA */\n" 1118*f0865ec9SKyle Evans out_name = "" 1119*f0865ec9SKyle Evans if sig_alg_name == "ECRDSA": 1120*f0865ec9SKyle Evans out_name += "#ifndef USE_ISO14888_3_ECRDSA"+"/* For "+test_name+" */\n" 1121*f0865ec9SKyle Evans out_name += "#ifdef WITH_HASH_"+hashfunc_name.upper()+"/* For "+test_name+" */\n" 1122*f0865ec9SKyle Evans out_name += "#ifdef WITH_CURVE_"+curve.name.upper()+"/* For "+test_name+" */\n" 1123*f0865ec9SKyle Evans out_name += "#ifdef WITH_SIG_"+sig_alg_name.upper()+"/* For "+test_name+" */\n" 1124*f0865ec9SKyle Evans out_name += "\t&"+test_name+"_test_case,\n" 1125*f0865ec9SKyle Evans out_name += "#endif /* WITH_HASH_"+hashfunc_name+" for "+test_name+" */\n" 1126*f0865ec9SKyle Evans out_name += "#endif /* WITH_CURVE_"+curve.name+" for "+test_name+" */\n" 1127*f0865ec9SKyle Evans out_name += "#endif /* WITH_SIG_"+sig_alg_name+" for "+test_name+" */" 1128*f0865ec9SKyle Evans if sig_alg_name == "ECRDSA": 1129*f0865ec9SKyle Evans out_name += "\n#endif /* !USE_ISO14888_3_ECRDSA */"+"/* For "+test_name+" */" 1130*f0865ec9SKyle Evans output_list.append((out_name, out_vectors)) 1131*f0865ec9SKyle Evans # In the specific case of ECRDSA, we also generate an ISO/IEC compatible test vector 1132*f0865ec9SKyle Evans if sig_alg_name == "ECRDSA": 1133*f0865ec9SKyle Evans out_vectors = "" 1134*f0865ec9SKyle Evans (sig, k) = sig_alg_sign(hashfunc, keypair, message, use_iso14888_divergence=True) 1135*f0865ec9SKyle Evans # Check that everything is OK with a verify 1136*f0865ec9SKyle Evans if sig_alg_verify(hashfunc, keypair, message, sig, use_iso14888_divergence=True) != True: 1137*f0865ec9SKyle Evans raise Exception("Error during self test generation: sig verify failed! "+test_name+ " / msg="+message+" / sig="+binascii.hexlify(sig)+" / k="+hex(k)+" / privkey.x="+hex(keypair.privkey.x)) 1138*f0865ec9SKyle Evans out_vectors += "#ifdef USE_ISO14888_3_ECRDSA\n" 1139*f0865ec9SKyle Evans # Now generate the test vector 1140*f0865ec9SKyle Evans out_vectors += "#ifdef WITH_HASH_"+hashfunc_name.upper()+"\n" 1141*f0865ec9SKyle Evans out_vectors += "#ifdef WITH_CURVE_"+curve.name.upper()+"\n" 1142*f0865ec9SKyle Evans out_vectors += "#ifdef WITH_SIG_"+sig_alg_name.upper()+"\n" 1143*f0865ec9SKyle Evans out_vectors += "/* "+test_name+" known test vectors */\n" 1144*f0865ec9SKyle Evans out_vectors += "static int "+test_name+"_test_vectors_get_random(nn_t out, nn_src_t q)\n{\n" 1145*f0865ec9SKyle Evans # k_buf MUST be exported padded to the length of q 1146*f0865ec9SKyle Evans out_vectors += "\tconst u8 k_buf[] = "+bigint_to_C_array(k, getbytelen(curve.q)) 1147*f0865ec9SKyle Evans out_vectors += "\tint ret, cmp;\n\tret = nn_init_from_buf(out, k_buf, sizeof(k_buf)); EG(ret, err);\n\tret = nn_cmp(out, q, &cmp); EG(ret, err);\n\tret = (cmp >= 0) ? -1 : 0;\nerr:\n\treturn ret;\n}\n" 1148*f0865ec9SKyle Evans out_vectors += "static const u8 "+test_name+"_test_vectors_priv_key[] = \n"+bigint_to_C_array(keypair.privkey.x, getbytelen(keypair.privkey.x)) 1149*f0865ec9SKyle Evans out_vectors += "static const u8 "+test_name+"_test_vectors_expected_sig[] = \n"+bigint_to_C_array(stringtoint(sig), len(sig)) 1150*f0865ec9SKyle Evans out_vectors += "static const ec_test_case "+test_name+"_test_case = {\n" 1151*f0865ec9SKyle Evans out_vectors += "\t.name = \""+test_name+"\",\n" 1152*f0865ec9SKyle Evans out_vectors += "\t.ec_str_p = &"+curve.name+"_str_params,\n" 1153*f0865ec9SKyle Evans out_vectors += "\t.priv_key = "+test_name+"_test_vectors_priv_key,\n" 1154*f0865ec9SKyle Evans out_vectors += "\t.priv_key_len = sizeof("+test_name+"_test_vectors_priv_key),\n" 1155*f0865ec9SKyle Evans out_vectors += "\t.nn_random = "+test_name+"_test_vectors_get_random,\n" 1156*f0865ec9SKyle Evans out_vectors += "\t.hash_type = "+hashfunc_name+",\n" 1157*f0865ec9SKyle Evans out_vectors += "\t.msg = \""+message+"\",\n" 1158*f0865ec9SKyle Evans out_vectors += "\t.msglen = "+str(len(message))+",\n" 1159*f0865ec9SKyle Evans out_vectors += "\t.sig_type = "+sig_alg_name+",\n" 1160*f0865ec9SKyle Evans out_vectors += "\t.exp_sig = "+test_name+"_test_vectors_expected_sig,\n" 1161*f0865ec9SKyle Evans out_vectors += "\t.exp_siglen = sizeof("+test_name+"_test_vectors_expected_sig),\n};\n" 1162*f0865ec9SKyle Evans out_vectors += "#endif /* WITH_HASH_"+hashfunc_name+" */\n" 1163*f0865ec9SKyle Evans out_vectors += "#endif /* WITH_CURVE_"+curve.name+" */\n" 1164*f0865ec9SKyle Evans out_vectors += "#endif /* WITH_SIG_"+sig_alg_name+" */\n" 1165*f0865ec9SKyle Evans out_vectors += "#endif /* USE_ISO14888_3_ECRDSA */\n" 1166*f0865ec9SKyle Evans out_name = "" 1167*f0865ec9SKyle Evans out_name += "#ifdef USE_ISO14888_3_ECRDSA"+"/* For "+test_name+" */\n" 1168*f0865ec9SKyle Evans out_name += "#ifdef WITH_HASH_"+hashfunc_name.upper()+"/* For "+test_name+" */\n" 1169*f0865ec9SKyle Evans out_name += "#ifdef WITH_CURVE_"+curve.name.upper()+"/* For "+test_name+" */\n" 1170*f0865ec9SKyle Evans out_name += "#ifdef WITH_SIG_"+sig_alg_name.upper()+"/* For "+test_name+" */\n" 1171*f0865ec9SKyle Evans out_name += "\t&"+test_name+"_test_case,\n" 1172*f0865ec9SKyle Evans out_name += "#endif /* WITH_HASH_"+hashfunc_name+" for "+test_name+" */\n" 1173*f0865ec9SKyle Evans out_name += "#endif /* WITH_CURVE_"+curve.name+" for "+test_name+" */\n" 1174*f0865ec9SKyle Evans out_name += "#endif /* WITH_SIG_"+sig_alg_name+" for "+test_name+" */\n" 1175*f0865ec9SKyle Evans out_name += "#endif /* USE_ISO14888_3_ECRDSA */"+"/* For "+test_name+" */" 1176*f0865ec9SKyle Evans output_list.append((out_name, out_vectors)) 1177*f0865ec9SKyle Evans 1178*f0865ec9SKyle Evans return output_list 1179*f0865ec9SKyle Evans 1180*f0865ec9SKyle Evansdef gen_self_tests(curve, num): 1181*f0865ec9SKyle Evans global curr_test 1182*f0865ec9SKyle Evans curr_test = 0 1183*f0865ec9SKyle Evans total_gen_tests = len(all_hash_funcs) * len(all_sig_algs) 1184*f0865ec9SKyle Evans vectors = [[ gen_self_test(curve, hashf, sign, verify, genkp, num, hash_name, sig_alg_name, total_gen_tests) 1185*f0865ec9SKyle Evans for (hashf, hash_name) in all_hash_funcs ] for (sign, verify, genkp, sig_alg_name) in all_sig_algs ] 1186*f0865ec9SKyle Evans return vectors 1187*f0865ec9SKyle Evans 1188*f0865ec9SKyle Evans########################################################## 1189*f0865ec9SKyle Evans### ASN.1 stuff 1190*f0865ec9SKyle Evansdef parse_DER_extract_size(derbuf): 1191*f0865ec9SKyle Evans # Extract the size 1192*f0865ec9SKyle Evans if ord(derbuf[0]) & 0x80 != 0: 1193*f0865ec9SKyle Evans encoding_len_bytes = ord(derbuf[0]) & ~0x80 1194*f0865ec9SKyle Evans # Skip 1195*f0865ec9SKyle Evans base = 1 1196*f0865ec9SKyle Evans else: 1197*f0865ec9SKyle Evans encoding_len_bytes = 1 1198*f0865ec9SKyle Evans base = 0 1199*f0865ec9SKyle Evans if len(derbuf) < encoding_len_bytes+1: 1200*f0865ec9SKyle Evans return (False, 0, 0) 1201*f0865ec9SKyle Evans else: 1202*f0865ec9SKyle Evans length = stringtoint(derbuf[base:base+encoding_len_bytes]) 1203*f0865ec9SKyle Evans if len(derbuf) < length+encoding_len_bytes: 1204*f0865ec9SKyle Evans return (False, 0, 0) 1205*f0865ec9SKyle Evans else: 1206*f0865ec9SKyle Evans return (True, encoding_len_bytes+base, length) 1207*f0865ec9SKyle Evans 1208*f0865ec9SKyle Evansdef extract_DER_object(derbuf, object_tag): 1209*f0865ec9SKyle Evans # Check type 1210*f0865ec9SKyle Evans if ord(derbuf[0]) != object_tag: 1211*f0865ec9SKyle Evans # Not the type we expect ... 1212*f0865ec9SKyle Evans return (False, 0, "") 1213*f0865ec9SKyle Evans else: 1214*f0865ec9SKyle Evans derbuf = derbuf[1:] 1215*f0865ec9SKyle Evans # Extract the size 1216*f0865ec9SKyle Evans (check, encoding_len, size) = parse_DER_extract_size(derbuf) 1217*f0865ec9SKyle Evans if check == False: 1218*f0865ec9SKyle Evans return (False, 0, "") 1219*f0865ec9SKyle Evans else: 1220*f0865ec9SKyle Evans if len(derbuf) < encoding_len + size: 1221*f0865ec9SKyle Evans return (False, 0, "") 1222*f0865ec9SKyle Evans else: 1223*f0865ec9SKyle Evans return (True, size+encoding_len+1, derbuf[encoding_len:encoding_len+size]) 1224*f0865ec9SKyle Evans 1225*f0865ec9SKyle Evansdef extract_DER_sequence(derbuf): 1226*f0865ec9SKyle Evans return extract_DER_object(derbuf, 0x30) 1227*f0865ec9SKyle Evans 1228*f0865ec9SKyle Evansdef extract_DER_integer(derbuf): 1229*f0865ec9SKyle Evans return extract_DER_object(derbuf, 0x02) 1230*f0865ec9SKyle Evans 1231*f0865ec9SKyle Evansdef extract_DER_octetstring(derbuf): 1232*f0865ec9SKyle Evans return extract_DER_object(derbuf, 0x04) 1233*f0865ec9SKyle Evans 1234*f0865ec9SKyle Evansdef extract_DER_bitstring(derbuf): 1235*f0865ec9SKyle Evans return extract_DER_object(derbuf, 0x03) 1236*f0865ec9SKyle Evans 1237*f0865ec9SKyle Evansdef extract_DER_oid(derbuf): 1238*f0865ec9SKyle Evans return extract_DER_object(derbuf, 0x06) 1239*f0865ec9SKyle Evans 1240*f0865ec9SKyle Evans# See ECParameters sequence in RFC 3279 1241*f0865ec9SKyle Evansdef parse_DER_ECParameters(derbuf): 1242*f0865ec9SKyle Evans # XXX: this is a very ugly way of extracting the information 1243*f0865ec9SKyle Evans # regarding an EC curve, but since the ASN.1 structure is quite 1244*f0865ec9SKyle Evans # "static", this might be sufficient without embedding a full 1245*f0865ec9SKyle Evans # ASN.1 parser ... 1246*f0865ec9SKyle Evans # Default return (a, b, prime, order, cofactor, gx, gy) 1247*f0865ec9SKyle Evans default_ret = (0, 0, 0, 0, 0, 0, 0) 1248*f0865ec9SKyle Evans # Get ECParameters wrapping sequence 1249*f0865ec9SKyle Evans (check, size_ECParameters, ECParameters) = extract_DER_sequence(derbuf) 1250*f0865ec9SKyle Evans if check == False: 1251*f0865ec9SKyle Evans return (False, default_ret) 1252*f0865ec9SKyle Evans # Get integer 1253*f0865ec9SKyle Evans (check, size_ECPVer, ECPVer) = extract_DER_integer(ECParameters) 1254*f0865ec9SKyle Evans if check == False: 1255*f0865ec9SKyle Evans return (False, default_ret) 1256*f0865ec9SKyle Evans # Get sequence 1257*f0865ec9SKyle Evans (check, size_FieldID, FieldID) = extract_DER_sequence(ECParameters[size_ECPVer:]) 1258*f0865ec9SKyle Evans if check == False: 1259*f0865ec9SKyle Evans return (False, default_ret) 1260*f0865ec9SKyle Evans # Get OID 1261*f0865ec9SKyle Evans (check, size_Oid, Oid) = extract_DER_oid(FieldID) 1262*f0865ec9SKyle Evans if check == False: 1263*f0865ec9SKyle Evans return (False, default_ret) 1264*f0865ec9SKyle Evans # Does the OID correspond to a prime field? 1265*f0865ec9SKyle Evans if(Oid != "\x2A\x86\x48\xCE\x3D\x01\x01"): 1266*f0865ec9SKyle Evans print("DER parse error: only prime fields are supported ...") 1267*f0865ec9SKyle Evans return (False, default_ret) 1268*f0865ec9SKyle Evans # Get prime p of prime field 1269*f0865ec9SKyle Evans (check, size_P, P) = extract_DER_integer(FieldID[size_Oid:]) 1270*f0865ec9SKyle Evans if check == False: 1271*f0865ec9SKyle Evans return (False, default_ret) 1272*f0865ec9SKyle Evans # Get curve (sequence) 1273*f0865ec9SKyle Evans (check, size_Curve, Curve) = extract_DER_sequence(ECParameters[size_ECPVer+size_FieldID:]) 1274*f0865ec9SKyle Evans if check == False: 1275*f0865ec9SKyle Evans return (False, default_ret) 1276*f0865ec9SKyle Evans # Get A in curve 1277*f0865ec9SKyle Evans (check, size_A, A) = extract_DER_octetstring(Curve) 1278*f0865ec9SKyle Evans if check == False: 1279*f0865ec9SKyle Evans return (False, default_ret) 1280*f0865ec9SKyle Evans # Get B in curve 1281*f0865ec9SKyle Evans (check, size_B, B) = extract_DER_octetstring(Curve[size_A:]) 1282*f0865ec9SKyle Evans if check == False: 1283*f0865ec9SKyle Evans return (False, default_ret) 1284*f0865ec9SKyle Evans # Get ECPoint 1285*f0865ec9SKyle Evans (check, size_ECPoint, ECPoint) = extract_DER_octetstring(ECParameters[size_ECPVer+size_FieldID+size_Curve:]) 1286*f0865ec9SKyle Evans if check == False: 1287*f0865ec9SKyle Evans return (False, default_ret) 1288*f0865ec9SKyle Evans # Get Order 1289*f0865ec9SKyle Evans (check, size_Order, Order) = extract_DER_integer(ECParameters[size_ECPVer+size_FieldID+size_Curve+size_ECPoint:]) 1290*f0865ec9SKyle Evans if check == False: 1291*f0865ec9SKyle Evans return (False, default_ret) 1292*f0865ec9SKyle Evans # Get Cofactor 1293*f0865ec9SKyle Evans (check, size_Cofactor, Cofactor) = extract_DER_integer(ECParameters[size_ECPVer+size_FieldID+size_Curve+size_ECPoint+size_Order:]) 1294*f0865ec9SKyle Evans if check == False: 1295*f0865ec9SKyle Evans return (False, default_ret) 1296*f0865ec9SKyle Evans # If we end up here, everything is OK, we can extract all our elements 1297*f0865ec9SKyle Evans prime = stringtoint(P) 1298*f0865ec9SKyle Evans a = stringtoint(A) 1299*f0865ec9SKyle Evans b = stringtoint(B) 1300*f0865ec9SKyle Evans order = stringtoint(Order) 1301*f0865ec9SKyle Evans cofactor = stringtoint(Cofactor) 1302*f0865ec9SKyle Evans # Extract Gx and Gy, see X9.62-1998 1303*f0865ec9SKyle Evans if len(ECPoint) < 1: 1304*f0865ec9SKyle Evans return (False, default_ret) 1305*f0865ec9SKyle Evans ECPoint_type = ord(ECPoint[0]) 1306*f0865ec9SKyle Evans if (ECPoint_type == 0x04) or (ECPoint_type == 0x06) or (ECPoint_type == 0x07): 1307*f0865ec9SKyle Evans # Uncompressed and hybrid points 1308*f0865ec9SKyle Evans if len(ECPoint[1:]) % 2 != 0: 1309*f0865ec9SKyle Evans return (False, default_ret) 1310*f0865ec9SKyle Evans ECPoint = ECPoint[1:] 1311*f0865ec9SKyle Evans gx = stringtoint(ECPoint[:int(len(ECPoint)/2)]) 1312*f0865ec9SKyle Evans gy = stringtoint(ECPoint[int(len(ECPoint)/2):]) 1313*f0865ec9SKyle Evans elif (ECPoint_type == 0x02) or (ECPoint_type == 0x03): 1314*f0865ec9SKyle Evans # Compressed point: uncompress it, see X9.62-1998 section 4.2.1 1315*f0865ec9SKyle Evans ECPoint = ECPoint[1:] 1316*f0865ec9SKyle Evans gx = stringtoint(ECPoint) 1317*f0865ec9SKyle Evans alpha = (pow(gx, 3, prime) + (a * gx) + b) % prime 1318*f0865ec9SKyle Evans beta = mod_sqrt(alpha, prime) 1319*f0865ec9SKyle Evans if (beta == None) or ((beta == 0) and (alpha != 0)): 1320*f0865ec9SKyle Evans return (False, 0) 1321*f0865ec9SKyle Evans if (beta & 0x1) == (ECPoint_type & 0x1): 1322*f0865ec9SKyle Evans gy = beta 1323*f0865ec9SKyle Evans else: 1324*f0865ec9SKyle Evans gy = prime - beta 1325*f0865ec9SKyle Evans else: 1326*f0865ec9SKyle Evans print("DER parse error: hybrid points are unsupported!") 1327*f0865ec9SKyle Evans return (False, default_ret) 1328*f0865ec9SKyle Evans return (True, (a, b, prime, order, cofactor, gx, gy)) 1329*f0865ec9SKyle Evans 1330*f0865ec9SKyle Evans########################################################## 1331*f0865ec9SKyle Evans### Text and format helpers 1332*f0865ec9SKyle Evansdef bigint_to_C_array(bint, size): 1333*f0865ec9SKyle Evans """ 1334*f0865ec9SKyle Evans Format a python big int to a C hex array 1335*f0865ec9SKyle Evans """ 1336*f0865ec9SKyle Evans hexstr = format(int(bint), 'x') 1337*f0865ec9SKyle Evans # Left pad to the size! 1338*f0865ec9SKyle Evans hexstr = ("0"*int((2*size)-len(hexstr)))+hexstr 1339*f0865ec9SKyle Evans hexstr = ("0"*(len(hexstr) % 2))+hexstr 1340*f0865ec9SKyle Evans out_str = "{\n" 1341*f0865ec9SKyle Evans for i in range(0, len(hexstr) - 1, 2): 1342*f0865ec9SKyle Evans if (i%16 == 0): 1343*f0865ec9SKyle Evans if(i!=0): 1344*f0865ec9SKyle Evans out_str += "\n" 1345*f0865ec9SKyle Evans out_str += "\t" 1346*f0865ec9SKyle Evans out_str += "0x"+hexstr[i:i+2]+", " 1347*f0865ec9SKyle Evans out_str += "\n};\n" 1348*f0865ec9SKyle Evans return out_str 1349*f0865ec9SKyle Evans 1350*f0865ec9SKyle Evansdef check_in_file(fname, pat): 1351*f0865ec9SKyle Evans # See if the pattern is in the file. 1352*f0865ec9SKyle Evans with open(fname) as f: 1353*f0865ec9SKyle Evans if not any(re.search(pat, line) for line in f): 1354*f0865ec9SKyle Evans return False # pattern does not occur in file so we are done. 1355*f0865ec9SKyle Evans else: 1356*f0865ec9SKyle Evans return True 1357*f0865ec9SKyle Evans 1358*f0865ec9SKyle Evansdef num_patterns_in_file(fname, pat): 1359*f0865ec9SKyle Evans num_pat = 0 1360*f0865ec9SKyle Evans with open(fname) as f: 1361*f0865ec9SKyle Evans for line in f: 1362*f0865ec9SKyle Evans if re.search(pat, line): 1363*f0865ec9SKyle Evans num_pat = num_pat+1 1364*f0865ec9SKyle Evans return num_pat 1365*f0865ec9SKyle Evans 1366*f0865ec9SKyle Evansdef file_replace_pattern(fname, pat, s_after): 1367*f0865ec9SKyle Evans # first, see if the pattern is even in the file. 1368*f0865ec9SKyle Evans with open(fname) as f: 1369*f0865ec9SKyle Evans if not any(re.search(pat, line) for line in f): 1370*f0865ec9SKyle Evans return # pattern does not occur in file so we are done. 1371*f0865ec9SKyle Evans 1372*f0865ec9SKyle Evans # pattern is in the file, so perform replace operation. 1373*f0865ec9SKyle Evans with open(fname) as f: 1374*f0865ec9SKyle Evans out_fname = fname + ".tmp" 1375*f0865ec9SKyle Evans out = open(out_fname, "w") 1376*f0865ec9SKyle Evans for line in f: 1377*f0865ec9SKyle Evans out.write(re.sub(pat, s_after, line)) 1378*f0865ec9SKyle Evans out.close() 1379*f0865ec9SKyle Evans os.rename(out_fname, fname) 1380*f0865ec9SKyle Evans 1381*f0865ec9SKyle Evansdef file_remove_pattern(fname, pat): 1382*f0865ec9SKyle Evans # first, see if the pattern is even in the file. 1383*f0865ec9SKyle Evans with open(fname) as f: 1384*f0865ec9SKyle Evans if not any(re.search(pat, line) for line in f): 1385*f0865ec9SKyle Evans return # pattern does not occur in file so we are done. 1386*f0865ec9SKyle Evans 1387*f0865ec9SKyle Evans # pattern is in the file, so perform remove operation. 1388*f0865ec9SKyle Evans with open(fname) as f: 1389*f0865ec9SKyle Evans out_fname = fname + ".tmp" 1390*f0865ec9SKyle Evans out = open(out_fname, "w") 1391*f0865ec9SKyle Evans for line in f: 1392*f0865ec9SKyle Evans if not re.search(pat, line): 1393*f0865ec9SKyle Evans out.write(line) 1394*f0865ec9SKyle Evans out.close() 1395*f0865ec9SKyle Evans 1396*f0865ec9SKyle Evans if os.path.exists(fname): 1397*f0865ec9SKyle Evans remove_file(fname) 1398*f0865ec9SKyle Evans os.rename(out_fname, fname) 1399*f0865ec9SKyle Evans 1400*f0865ec9SKyle Evansdef remove_file(fname): 1401*f0865ec9SKyle Evans # Remove file 1402*f0865ec9SKyle Evans os.remove(fname) 1403*f0865ec9SKyle Evans 1404*f0865ec9SKyle Evansdef remove_files_pattern(fpattern): 1405*f0865ec9SKyle Evans [remove_file(x) for x in glob.glob(fpattern)] 1406*f0865ec9SKyle Evans 1407*f0865ec9SKyle Evansdef buffer_remove_pattern(buff, pat): 1408*f0865ec9SKyle Evans if is_python_2() == False: 1409*f0865ec9SKyle Evans buff = buff.decode('latin-1') 1410*f0865ec9SKyle Evans if re.search(pat, buff) == None: 1411*f0865ec9SKyle Evans return (False, buff) # pattern does not occur in file so we are done. 1412*f0865ec9SKyle Evans # Remove the pattern 1413*f0865ec9SKyle Evans buff = re.sub(pat, "", buff) 1414*f0865ec9SKyle Evans return (True, buff) 1415*f0865ec9SKyle Evans 1416*f0865ec9SKyle Evansdef is_base64(s): 1417*f0865ec9SKyle Evans s = ''.join([s.strip() for s in s.split("\n")]) 1418*f0865ec9SKyle Evans try: 1419*f0865ec9SKyle Evans enc = base64.b64encode(base64.b64decode(s)).strip() 1420*f0865ec9SKyle Evans if type(enc) is bytes: 1421*f0865ec9SKyle Evans return enc == s.encode('latin-1') 1422*f0865ec9SKyle Evans else: 1423*f0865ec9SKyle Evans return enc == s 1424*f0865ec9SKyle Evans except TypeError: 1425*f0865ec9SKyle Evans return False 1426*f0865ec9SKyle Evans 1427*f0865ec9SKyle Evans### Curve helpers 1428*f0865ec9SKyle Evansdef export_curve_int(curvename, intname, bigint, size): 1429*f0865ec9SKyle Evans if bigint == None: 1430*f0865ec9SKyle Evans out = "static const u8 "+curvename+"_"+intname+"[] = {\n\t0x00,\n};\n" 1431*f0865ec9SKyle Evans out += "TO_EC_STR_PARAM_FIXED_SIZE("+curvename+"_"+intname+", 0);\n\n" 1432*f0865ec9SKyle Evans else: 1433*f0865ec9SKyle Evans out = "static const u8 "+curvename+"_"+intname+"[] = "+bigint_to_C_array(bigint, size)+"\n" 1434*f0865ec9SKyle Evans out += "TO_EC_STR_PARAM("+curvename+"_"+intname+");\n\n" 1435*f0865ec9SKyle Evans return out 1436*f0865ec9SKyle Evans 1437*f0865ec9SKyle Evansdef export_curve_string(curvename, stringname, stringvalue): 1438*f0865ec9SKyle Evans out = "static const u8 "+curvename+"_"+stringname+"[] = \""+stringvalue+"\";\n" 1439*f0865ec9SKyle Evans out += "TO_EC_STR_PARAM("+curvename+"_"+stringname+");\n\n" 1440*f0865ec9SKyle Evans return out 1441*f0865ec9SKyle Evans 1442*f0865ec9SKyle Evansdef export_curve_struct(curvename, paramname, paramnamestr): 1443*f0865ec9SKyle Evans return "\t."+paramname+" = &"+curvename+"_"+paramnamestr+"_str_param, \n" 1444*f0865ec9SKyle Evans 1445*f0865ec9SKyle Evansdef curve_params(name, prime, pbitlen, a, b, gx, gy, order, cofactor, oid, alpha_montgomery, gamma_montgomery, alpha_edwards): 1446*f0865ec9SKyle Evans """ 1447*f0865ec9SKyle Evans Take as input some elliptic curve parameters and generate the 1448*f0865ec9SKyle Evans C parameters in a string 1449*f0865ec9SKyle Evans """ 1450*f0865ec9SKyle Evans bytesize = int(pbitlen / 8) 1451*f0865ec9SKyle Evans if pbitlen % 8 != 0: 1452*f0865ec9SKyle Evans bytesize += 1 1453*f0865ec9SKyle Evans # Compute the rounded word size for each word size 1454*f0865ec9SKyle Evans if bytesize % 8 != 0: 1455*f0865ec9SKyle Evans wordsbitsize64 = 8*((int(bytesize/8)+1)*8) 1456*f0865ec9SKyle Evans else: 1457*f0865ec9SKyle Evans wordsbitsize64 = 8*bytesize 1458*f0865ec9SKyle Evans if bytesize % 4 != 0: 1459*f0865ec9SKyle Evans wordsbitsize32 = 8*((int(bytesize/4)+1)*4) 1460*f0865ec9SKyle Evans else: 1461*f0865ec9SKyle Evans wordsbitsize32 = 8*bytesize 1462*f0865ec9SKyle Evans if bytesize % 2 != 0: 1463*f0865ec9SKyle Evans wordsbitsize16 = 8*((int(bytesize/2)+1)*2) 1464*f0865ec9SKyle Evans else: 1465*f0865ec9SKyle Evans wordsbitsize16 = 8*bytesize 1466*f0865ec9SKyle Evans # Compute some parameters 1467*f0865ec9SKyle Evans (r64, r_square64, mpinv64) = compute_monty_coef(prime, wordsbitsize64, 64) 1468*f0865ec9SKyle Evans (r32, r_square32, mpinv32) = compute_monty_coef(prime, wordsbitsize32, 32) 1469*f0865ec9SKyle Evans (r16, r_square16, mpinv16) = compute_monty_coef(prime, wordsbitsize16, 16) 1470*f0865ec9SKyle Evans # Compute p_reciprocal for each word size 1471*f0865ec9SKyle Evans (pshift64, primenorm64, p_reciprocal64) = compute_div_coef(prime, wordsbitsize64, 64) 1472*f0865ec9SKyle Evans (pshift32, primenorm32, p_reciprocal32) = compute_div_coef(prime, wordsbitsize32, 32) 1473*f0865ec9SKyle Evans (pshift16, primenorm16, p_reciprocal16) = compute_div_coef(prime, wordsbitsize16, 16) 1474*f0865ec9SKyle Evans # Compute the number of points on the curve 1475*f0865ec9SKyle Evans npoints = order * cofactor 1476*f0865ec9SKyle Evans 1477*f0865ec9SKyle Evans # Now output the parameters 1478*f0865ec9SKyle Evans ec_params_string = "#include <libecc/lib_ecc_config.h>\n" 1479*f0865ec9SKyle Evans ec_params_string += "#ifdef WITH_CURVE_"+name.upper()+"\n\n" 1480*f0865ec9SKyle Evans ec_params_string += "#ifndef __EC_PARAMS_"+name.upper()+"_H__\n" 1481*f0865ec9SKyle Evans ec_params_string += "#define __EC_PARAMS_"+name.upper()+"_H__\n" 1482*f0865ec9SKyle Evans ec_params_string += "#include <libecc/curves/known/ec_params_external.h>\n" 1483*f0865ec9SKyle Evans ec_params_string += export_curve_int(name, "p", prime, bytesize) 1484*f0865ec9SKyle Evans 1485*f0865ec9SKyle Evans ec_params_string += "#define CURVE_"+name.upper()+"_P_BITLEN "+str(pbitlen)+"\n" 1486*f0865ec9SKyle Evans ec_params_string += export_curve_int(name, "p_bitlen", pbitlen, getbytelen(pbitlen)) 1487*f0865ec9SKyle Evans 1488*f0865ec9SKyle Evans ec_params_string += "#if (WORD_BYTES == 8) /* 64-bit words */\n" 1489*f0865ec9SKyle Evans ec_params_string += export_curve_int(name, "r", r64, getbytelen(r64)) 1490*f0865ec9SKyle Evans ec_params_string += export_curve_int(name, "r_square", r_square64, getbytelen(r_square64)) 1491*f0865ec9SKyle Evans ec_params_string += export_curve_int(name, "mpinv", mpinv64, getbytelen(mpinv64)) 1492*f0865ec9SKyle Evans ec_params_string += export_curve_int(name, "p_shift", pshift64, getbytelen(pshift64)) 1493*f0865ec9SKyle Evans ec_params_string += export_curve_int(name, "p_normalized", primenorm64, getbytelen(primenorm64)) 1494*f0865ec9SKyle Evans ec_params_string += export_curve_int(name, "p_reciprocal", p_reciprocal64, getbytelen(p_reciprocal64)) 1495*f0865ec9SKyle Evans ec_params_string += "#elif (WORD_BYTES == 4) /* 32-bit words */\n" 1496*f0865ec9SKyle Evans ec_params_string += export_curve_int(name, "r", r32, getbytelen(r32)) 1497*f0865ec9SKyle Evans ec_params_string += export_curve_int(name, "r_square", r_square32, getbytelen(r_square32)) 1498*f0865ec9SKyle Evans ec_params_string += export_curve_int(name, "mpinv", mpinv32, getbytelen(mpinv32)) 1499*f0865ec9SKyle Evans ec_params_string += export_curve_int(name, "p_shift", pshift32, getbytelen(pshift32)) 1500*f0865ec9SKyle Evans ec_params_string += export_curve_int(name, "p_normalized", primenorm32, getbytelen(primenorm32)) 1501*f0865ec9SKyle Evans ec_params_string += export_curve_int(name, "p_reciprocal", p_reciprocal32, getbytelen(p_reciprocal32)) 1502*f0865ec9SKyle Evans ec_params_string += "#elif (WORD_BYTES == 2) /* 16-bit words */\n" 1503*f0865ec9SKyle Evans ec_params_string += export_curve_int(name, "r", r16, getbytelen(r16)) 1504*f0865ec9SKyle Evans ec_params_string += export_curve_int(name, "r_square", r_square16, getbytelen(r_square16)) 1505*f0865ec9SKyle Evans ec_params_string += export_curve_int(name, "mpinv", mpinv16, getbytelen(mpinv16)) 1506*f0865ec9SKyle Evans ec_params_string += export_curve_int(name, "p_shift", pshift16, getbytelen(pshift16)) 1507*f0865ec9SKyle Evans ec_params_string += export_curve_int(name, "p_normalized", primenorm16, getbytelen(primenorm16)) 1508*f0865ec9SKyle Evans ec_params_string += export_curve_int(name, "p_reciprocal", p_reciprocal16, getbytelen(p_reciprocal16)) 1509*f0865ec9SKyle Evans ec_params_string += "#else /* unknown word size */\n" 1510*f0865ec9SKyle Evans ec_params_string += "#error \"Unsupported word size\"\n" 1511*f0865ec9SKyle Evans ec_params_string += "#endif\n\n" 1512*f0865ec9SKyle Evans 1513*f0865ec9SKyle Evans ec_params_string += export_curve_int(name, "a", a, bytesize) 1514*f0865ec9SKyle Evans ec_params_string += export_curve_int(name, "b", b, bytesize) 1515*f0865ec9SKyle Evans 1516*f0865ec9SKyle Evans curve_order_bitlen = getbitlen(npoints) 1517*f0865ec9SKyle Evans ec_params_string += "#define CURVE_"+name.upper()+"_CURVE_ORDER_BITLEN "+str(curve_order_bitlen)+"\n" 1518*f0865ec9SKyle Evans ec_params_string += export_curve_int(name, "curve_order", npoints, getbytelen(npoints)) 1519*f0865ec9SKyle Evans 1520*f0865ec9SKyle Evans ec_params_string += export_curve_int(name, "gx", gx, bytesize) 1521*f0865ec9SKyle Evans ec_params_string += export_curve_int(name, "gy", gy, bytesize) 1522*f0865ec9SKyle Evans ec_params_string += export_curve_int(name, "gz", 0x01, bytesize) 1523*f0865ec9SKyle Evans 1524*f0865ec9SKyle Evans qbitlen = getbitlen(order) 1525*f0865ec9SKyle Evans 1526*f0865ec9SKyle Evans ec_params_string += export_curve_int(name, "gen_order", order, getbytelen(order)) 1527*f0865ec9SKyle Evans ec_params_string += "#define CURVE_"+name.upper()+"_Q_BITLEN "+str(qbitlen)+"\n" 1528*f0865ec9SKyle Evans ec_params_string += export_curve_int(name, "gen_order_bitlen", qbitlen, getbytelen(qbitlen)) 1529*f0865ec9SKyle Evans 1530*f0865ec9SKyle Evans ec_params_string += export_curve_int(name, "cofactor", cofactor, getbytelen(cofactor)) 1531*f0865ec9SKyle Evans 1532*f0865ec9SKyle Evans ec_params_string += export_curve_int(name, "alpha_montgomery", alpha_montgomery, getbytelen(alpha_montgomery)) 1533*f0865ec9SKyle Evans ec_params_string += export_curve_int(name, "gamma_montgomery", gamma_montgomery, getbytelen(gamma_montgomery)) 1534*f0865ec9SKyle Evans ec_params_string += export_curve_int(name, "alpha_edwards", alpha_edwards, getbytelen(alpha_edwards)) 1535*f0865ec9SKyle Evans 1536*f0865ec9SKyle Evans ec_params_string += export_curve_string(name, "name", name.upper()); 1537*f0865ec9SKyle Evans 1538*f0865ec9SKyle Evans if oid == None: 1539*f0865ec9SKyle Evans oid = "" 1540*f0865ec9SKyle Evans ec_params_string += export_curve_string(name, "oid", oid); 1541*f0865ec9SKyle Evans 1542*f0865ec9SKyle Evans ec_params_string += "static const ec_str_params "+name+"_str_params = {\n"+\ 1543*f0865ec9SKyle Evans export_curve_struct(name, "p", "p") +\ 1544*f0865ec9SKyle Evans export_curve_struct(name, "p_bitlen", "p_bitlen") +\ 1545*f0865ec9SKyle Evans export_curve_struct(name, "r", "r") +\ 1546*f0865ec9SKyle Evans export_curve_struct(name, "r_square", "r_square") +\ 1547*f0865ec9SKyle Evans export_curve_struct(name, "mpinv", "mpinv") +\ 1548*f0865ec9SKyle Evans export_curve_struct(name, "p_shift", "p_shift") +\ 1549*f0865ec9SKyle Evans export_curve_struct(name, "p_normalized", "p_normalized") +\ 1550*f0865ec9SKyle Evans export_curve_struct(name, "p_reciprocal", "p_reciprocal") +\ 1551*f0865ec9SKyle Evans export_curve_struct(name, "a", "a") +\ 1552*f0865ec9SKyle Evans export_curve_struct(name, "b", "b") +\ 1553*f0865ec9SKyle Evans export_curve_struct(name, "curve_order", "curve_order") +\ 1554*f0865ec9SKyle Evans export_curve_struct(name, "gx", "gx") +\ 1555*f0865ec9SKyle Evans export_curve_struct(name, "gy", "gy") +\ 1556*f0865ec9SKyle Evans export_curve_struct(name, "gz", "gz") +\ 1557*f0865ec9SKyle Evans export_curve_struct(name, "gen_order", "gen_order") +\ 1558*f0865ec9SKyle Evans export_curve_struct(name, "gen_order_bitlen", "gen_order_bitlen") +\ 1559*f0865ec9SKyle Evans export_curve_struct(name, "cofactor", "cofactor") +\ 1560*f0865ec9SKyle Evans export_curve_struct(name, "alpha_montgomery", "alpha_montgomery") +\ 1561*f0865ec9SKyle Evans export_curve_struct(name, "gamma_montgomery", "gamma_montgomery") +\ 1562*f0865ec9SKyle Evans export_curve_struct(name, "alpha_edwards", "alpha_edwards") +\ 1563*f0865ec9SKyle Evans export_curve_struct(name, "oid", "oid") +\ 1564*f0865ec9SKyle Evans export_curve_struct(name, "name", "name") 1565*f0865ec9SKyle Evans ec_params_string += "};\n\n" 1566*f0865ec9SKyle Evans 1567*f0865ec9SKyle Evans ec_params_string += "/*\n"+\ 1568*f0865ec9SKyle Evans " * Compute max bit length of all curves for p and q\n"+\ 1569*f0865ec9SKyle Evans " */\n"+\ 1570*f0865ec9SKyle Evans "#ifndef CURVES_MAX_P_BIT_LEN\n"+\ 1571*f0865ec9SKyle Evans "#define CURVES_MAX_P_BIT_LEN 0\n"+\ 1572*f0865ec9SKyle Evans "#endif\n"+\ 1573*f0865ec9SKyle Evans "#if (CURVES_MAX_P_BIT_LEN < CURVE_"+name.upper()+"_P_BITLEN)\n"+\ 1574*f0865ec9SKyle Evans "#undef CURVES_MAX_P_BIT_LEN\n"+\ 1575*f0865ec9SKyle Evans "#define CURVES_MAX_P_BIT_LEN CURVE_"+name.upper()+"_P_BITLEN\n"+\ 1576*f0865ec9SKyle Evans "#endif\n"+\ 1577*f0865ec9SKyle Evans "#ifndef CURVES_MAX_Q_BIT_LEN\n"+\ 1578*f0865ec9SKyle Evans "#define CURVES_MAX_Q_BIT_LEN 0\n"+\ 1579*f0865ec9SKyle Evans "#endif\n"+\ 1580*f0865ec9SKyle Evans "#if (CURVES_MAX_Q_BIT_LEN < CURVE_"+name.upper()+"_Q_BITLEN)\n"+\ 1581*f0865ec9SKyle Evans "#undef CURVES_MAX_Q_BIT_LEN\n"+\ 1582*f0865ec9SKyle Evans "#define CURVES_MAX_Q_BIT_LEN CURVE_"+name.upper()+"_Q_BITLEN\n"+\ 1583*f0865ec9SKyle Evans "#endif\n"+\ 1584*f0865ec9SKyle Evans "#ifndef CURVES_MAX_CURVE_ORDER_BIT_LEN\n"+\ 1585*f0865ec9SKyle Evans "#define CURVES_MAX_CURVE_ORDER_BIT_LEN 0\n"+\ 1586*f0865ec9SKyle Evans "#endif\n"+\ 1587*f0865ec9SKyle Evans "#if (CURVES_MAX_CURVE_ORDER_BIT_LEN < CURVE_"+name.upper()+"_CURVE_ORDER_BITLEN)\n"+\ 1588*f0865ec9SKyle Evans "#undef CURVES_MAX_CURVE_ORDER_BIT_LEN\n"+\ 1589*f0865ec9SKyle Evans "#define CURVES_MAX_CURVE_ORDER_BIT_LEN CURVE_"+name.upper()+"_CURVE_ORDER_BITLEN\n"+\ 1590*f0865ec9SKyle Evans "#endif\n\n" 1591*f0865ec9SKyle Evans 1592*f0865ec9SKyle Evans ec_params_string += "/*\n"+\ 1593*f0865ec9SKyle Evans " * Compute and adapt max name and oid length\n"+\ 1594*f0865ec9SKyle Evans " */\n"+\ 1595*f0865ec9SKyle Evans "#ifndef MAX_CURVE_OID_LEN\n"+\ 1596*f0865ec9SKyle Evans "#define MAX_CURVE_OID_LEN 0\n"+\ 1597*f0865ec9SKyle Evans "#endif\n"+\ 1598*f0865ec9SKyle Evans "#ifndef MAX_CURVE_NAME_LEN\n"+\ 1599*f0865ec9SKyle Evans "#define MAX_CURVE_NAME_LEN 0\n"+\ 1600*f0865ec9SKyle Evans "#endif\n"+\ 1601*f0865ec9SKyle Evans "#if (MAX_CURVE_OID_LEN < "+str(len(oid)+1)+")\n"+\ 1602*f0865ec9SKyle Evans "#undef MAX_CURVE_OID_LEN\n"+\ 1603*f0865ec9SKyle Evans "#define MAX_CURVE_OID_LEN "+str(len(oid)+1)+"\n"+\ 1604*f0865ec9SKyle Evans "#endif\n"+\ 1605*f0865ec9SKyle Evans "#if (MAX_CURVE_NAME_LEN < "+str(len(name.upper())+1)+")\n"+\ 1606*f0865ec9SKyle Evans "#undef MAX_CURVE_NAME_LEN\n"+\ 1607*f0865ec9SKyle Evans "#define MAX_CURVE_NAME_LEN "+str(len(name.upper())+1)+"\n"+\ 1608*f0865ec9SKyle Evans "#endif\n\n" 1609*f0865ec9SKyle Evans 1610*f0865ec9SKyle Evans ec_params_string += "#endif /* __EC_PARAMS_"+name.upper()+"_H__ */\n\n"+"#endif /* WITH_CURVE_"+name.upper()+" */\n" 1611*f0865ec9SKyle Evans 1612*f0865ec9SKyle Evans return ec_params_string 1613*f0865ec9SKyle Evans 1614*f0865ec9SKyle Evansdef usage(): 1615*f0865ec9SKyle Evans print("This script is intented to *statically* expand the ECC library with user defined curves.") 1616*f0865ec9SKyle Evans print("By statically we mean that the source code of libecc is expanded with new curves parameters through") 1617*f0865ec9SKyle Evans print("automatic code generation filling place holders in the existing code base of the library. Though the") 1618*f0865ec9SKyle Evans print("choice of static code generation versus dynamic curves import (such as what OpenSSL does) might be") 1619*f0865ec9SKyle Evans print("argued, this choice has been driven by simplicity and security design decisions: we want libecc to have") 1620*f0865ec9SKyle Evans print("all its parameters (such as memory consumption) set at compile time and statically adapted to the curves.") 1621*f0865ec9SKyle Evans print("Since libecc only supports curves over prime fields, the script can only add this kind of curves.") 1622*f0865ec9SKyle Evans print("This script implements elliptic curves and ISO signature algorithms from scratch over Python's multi-precision") 1623*f0865ec9SKyle Evans print("big numbers library. Addition and doubling over curves use naive formulas. Please DO NOT use the functions of this") 1624*f0865ec9SKyle Evans print("script for production code: they are not securely implemented and are very inefficient. Their only purpose is to expand") 1625*f0865ec9SKyle Evans print("libecc and produce test vectors.") 1626*f0865ec9SKyle Evans print("") 1627*f0865ec9SKyle Evans print("In order to add a curve, there are two ways:") 1628*f0865ec9SKyle Evans print("Adding a user defined curve with explicit parameters:") 1629*f0865ec9SKyle Evans print("-----------------------------------------------------") 1630*f0865ec9SKyle Evans print(sys.argv[0]+" --name=\"YOURCURVENAME\" --prime=... --order=... --a=... --b=... --gx=... --gy=... --cofactor=... --oid=THEOID") 1631*f0865ec9SKyle Evans print("\t> name: name of the curve in the form of a string") 1632*f0865ec9SKyle Evans print("\t> prime: prime number representing the curve prime field") 1633*f0865ec9SKyle Evans print("\t> order: prime number representing the generator order") 1634*f0865ec9SKyle Evans print("\t> cofactor: cofactor of the curve") 1635*f0865ec9SKyle Evans print("\t> a: 'a' coefficient of the short Weierstrass equation of the curve") 1636*f0865ec9SKyle Evans print("\t> b: 'b' coefficient of the short Weierstrass equation of the curve") 1637*f0865ec9SKyle Evans print("\t> gx: x coordinate of the generator G") 1638*f0865ec9SKyle Evans print("\t> gy: y coordinate of the generator G") 1639*f0865ec9SKyle Evans print("\t> oid: optional OID of the curve") 1640*f0865ec9SKyle Evans print(" Notes:") 1641*f0865ec9SKyle Evans print(" ******") 1642*f0865ec9SKyle Evans print("\t1) These elements are verified to indeed satisfy the curve equation.") 1643*f0865ec9SKyle Evans print("\t2) All the numbers can be given either in decimal or hexadecimal format with a prepending '0x'.") 1644*f0865ec9SKyle Evans print("\t3) The script automatically generates all the necessary files for the curve to be included in the library." ) 1645*f0865ec9SKyle Evans print("\tYou will find the new curve definition in the usual 'lib_ecc_config.h' file (one can activate it or not at compile time).") 1646*f0865ec9SKyle Evans print("") 1647*f0865ec9SKyle Evans print("Adding a user defined curve through RFC3279 ASN.1 parameters:") 1648*f0865ec9SKyle Evans print("-------------------------------------------------------------") 1649*f0865ec9SKyle Evans print(sys.argv[0]+" --name=\"YOURCURVENAME\" --ECfile=... --oid=THEOID") 1650*f0865ec9SKyle Evans print("\t> ECfile: the DER or PEM encoded file containing the curve parameters (see RFC3279)") 1651*f0865ec9SKyle Evans print(" Notes:") 1652*f0865ec9SKyle Evans print("\tCurve parameters encoded in DER or PEM format can be generated with tools like OpenSSL (among others). As an illustrative example,") 1653*f0865ec9SKyle Evans print("\tone can list all the supported curves under OpenSSL with:") 1654*f0865ec9SKyle Evans print("\t $ openssl ecparam -list_curves") 1655*f0865ec9SKyle Evans print("\tOnly the listed so called \"prime\" curves are supported. Then, one can extract an explicit curve representation in ASN.1") 1656*f0865ec9SKyle Evans print("\tas defined in RFC3279, for example for BRAINPOOLP320R1:") 1657*f0865ec9SKyle Evans print("\t $ openssl ecparam -param_enc explicit -outform DER -name brainpoolP320r1 -out brainpoolP320r1.der") 1658*f0865ec9SKyle Evans print("") 1659*f0865ec9SKyle Evans print("Removing user defined curves:") 1660*f0865ec9SKyle Evans print("-----------------------------") 1661*f0865ec9SKyle Evans print("\t*All the user defined curves can be removed with the --remove-all toggle.") 1662*f0865ec9SKyle Evans print("\t*A specific named user define curve can be removed with the --remove toggle: in this case the --name option is used to ") 1663*f0865ec9SKyle Evans print("\tlocate which named curve must be deleted.") 1664*f0865ec9SKyle Evans print("") 1665*f0865ec9SKyle Evans print("Test vectors:") 1666*f0865ec9SKyle Evans print("-------------") 1667*f0865ec9SKyle Evans print("\tTest vectors can be automatically generated and added to the library self tests when providing the --add-test-vectors=X toggle.") 1668*f0865ec9SKyle Evans print("\tIn this case, X test vectors will be generated for *each* (curve, sign algorithm, hash algorithm) 3-uplet (beware of combinatorial") 1669*f0865ec9SKyle Evans print("\tissues when X is big!). These tests are transparently added and compiled with the self tests.") 1670*f0865ec9SKyle Evans return 1671*f0865ec9SKyle Evans 1672*f0865ec9SKyle Evansdef get_int(instring): 1673*f0865ec9SKyle Evans if len(instring) == 0: 1674*f0865ec9SKyle Evans return 0 1675*f0865ec9SKyle Evans if len(instring) >= 2: 1676*f0865ec9SKyle Evans if instring[:2] == "0x": 1677*f0865ec9SKyle Evans return int(instring, 16) 1678*f0865ec9SKyle Evans return int(instring) 1679*f0865ec9SKyle Evans 1680*f0865ec9SKyle Evansdef parse_cmd_line(args): 1681*f0865ec9SKyle Evans """ 1682*f0865ec9SKyle Evans Get elliptic curve parameters from command line 1683*f0865ec9SKyle Evans """ 1684*f0865ec9SKyle Evans name = oid = prime = a = b = gx = gy = g = order = cofactor = ECfile = remove = remove_all = add_test_vectors = None 1685*f0865ec9SKyle Evans alpha_montgomery = gamma_montgomery = alpha_edwards = None 1686*f0865ec9SKyle Evans try: 1687*f0865ec9SKyle Evans opts, args = getopt.getopt(sys.argv[1:], ":h", ["help", "remove", "remove-all", "name=", "prime=", "a=", "b=", "generator=", "gx=", "gy=", "order=", "cofactor=", "alpha_montgomery=","gamma_montgomery=", "alpha_edwards=", "ECfile=", "oid=", "add-test-vectors="]) 1688*f0865ec9SKyle Evans except getopt.GetoptError as err: 1689*f0865ec9SKyle Evans # print help information and exit: 1690*f0865ec9SKyle Evans print(err) # will print something like "option -a not recognized" 1691*f0865ec9SKyle Evans usage() 1692*f0865ec9SKyle Evans return False 1693*f0865ec9SKyle Evans for o, arg in opts: 1694*f0865ec9SKyle Evans if o in ("-h", "--help"): 1695*f0865ec9SKyle Evans usage() 1696*f0865ec9SKyle Evans return True 1697*f0865ec9SKyle Evans elif o in ("--name"): 1698*f0865ec9SKyle Evans name = arg 1699*f0865ec9SKyle Evans # Prepend the custom string before name to avoid any collision 1700*f0865ec9SKyle Evans name = "user_defined_"+name 1701*f0865ec9SKyle Evans # Replace any unwanted name char 1702*f0865ec9SKyle Evans name = re.sub("\-", "_", name) 1703*f0865ec9SKyle Evans elif o in ("--oid="): 1704*f0865ec9SKyle Evans oid = arg 1705*f0865ec9SKyle Evans elif o in ("--prime"): 1706*f0865ec9SKyle Evans prime = get_int(arg.replace(' ', '')) 1707*f0865ec9SKyle Evans elif o in ("--a"): 1708*f0865ec9SKyle Evans a = get_int(arg.replace(' ', '')) 1709*f0865ec9SKyle Evans elif o in ("--b"): 1710*f0865ec9SKyle Evans b = get_int(arg.replace(' ', '')) 1711*f0865ec9SKyle Evans elif o in ("--gx"): 1712*f0865ec9SKyle Evans gx = get_int(arg.replace(' ', '')) 1713*f0865ec9SKyle Evans elif o in ("--gy"): 1714*f0865ec9SKyle Evans gy = get_int(arg.replace(' ', '')) 1715*f0865ec9SKyle Evans elif o in ("--generator"): 1716*f0865ec9SKyle Evans g = arg.replace(' ', '') 1717*f0865ec9SKyle Evans elif o in ("--order"): 1718*f0865ec9SKyle Evans order = get_int(arg.replace(' ', '')) 1719*f0865ec9SKyle Evans elif o in ("--cofactor"): 1720*f0865ec9SKyle Evans cofactor = get_int(arg.replace(' ', '')) 1721*f0865ec9SKyle Evans elif o in ("--alpha_montgomery"): 1722*f0865ec9SKyle Evans alpha_montgomery = get_int(arg.replace(' ', '')) 1723*f0865ec9SKyle Evans elif o in ("--gamma_montgomery"): 1724*f0865ec9SKyle Evans gamma_montgomery = get_int(arg.replace(' ', '')) 1725*f0865ec9SKyle Evans elif o in ("--alpha_edwards"): 1726*f0865ec9SKyle Evans alpha_edwards = get_int(arg.replace(' ', '')) 1727*f0865ec9SKyle Evans elif o in ("--remove"): 1728*f0865ec9SKyle Evans remove = True 1729*f0865ec9SKyle Evans elif o in ("--remove-all"): 1730*f0865ec9SKyle Evans remove_all = True 1731*f0865ec9SKyle Evans elif o in ("--add-test-vectors"): 1732*f0865ec9SKyle Evans add_test_vectors = get_int(arg.replace(' ', '')) 1733*f0865ec9SKyle Evans elif o in ("--ECfile"): 1734*f0865ec9SKyle Evans ECfile = arg 1735*f0865ec9SKyle Evans else: 1736*f0865ec9SKyle Evans print("unhandled option") 1737*f0865ec9SKyle Evans usage() 1738*f0865ec9SKyle Evans return False 1739*f0865ec9SKyle Evans 1740*f0865ec9SKyle Evans # File paths 1741*f0865ec9SKyle Evans script_path = os.path.abspath(os.path.dirname(sys.argv[0])) + "/" 1742*f0865ec9SKyle Evans ec_params_path = script_path + "../include/libecc/curves/user_defined/" 1743*f0865ec9SKyle Evans curves_list_path = script_path + "../include/libecc/curves/" 1744*f0865ec9SKyle Evans lib_ecc_types_path = script_path + "../include/libecc/" 1745*f0865ec9SKyle Evans lib_ecc_config_path = script_path + "../include/libecc/" 1746*f0865ec9SKyle Evans ec_self_tests_path = script_path + "../src/tests/" 1747*f0865ec9SKyle Evans meson_options_path = script_path + "../" 1748*f0865ec9SKyle Evans 1749*f0865ec9SKyle Evans # If remove is True, we have been asked to remove already existing user defined curves 1750*f0865ec9SKyle Evans if remove == True: 1751*f0865ec9SKyle Evans if name == None: 1752*f0865ec9SKyle Evans print("--remove option expects a curve name provided with --name") 1753*f0865ec9SKyle Evans return False 1754*f0865ec9SKyle Evans asked = "" 1755*f0865ec9SKyle Evans while asked != "y" and asked != "n": 1756*f0865ec9SKyle Evans asked = get_user_input("You asked to remove everything related to user defined "+name.replace("user_defined_", "")+" curve. Enter y to confirm, n to cancel [y/n]. ") 1757*f0865ec9SKyle Evans if asked == "n": 1758*f0865ec9SKyle Evans print("NOT removing curve "+name.replace("user_defined_", "")+" (cancelled).") 1759*f0865ec9SKyle Evans return True 1760*f0865ec9SKyle Evans # Remove any user defined stuff with given name 1761*f0865ec9SKyle Evans print("Removing user defined curve "+name.replace("user_defined_", "")+" ...") 1762*f0865ec9SKyle Evans if name == None: 1763*f0865ec9SKyle Evans print("Error: you must provide a curve name with --remove") 1764*f0865ec9SKyle Evans return False 1765*f0865ec9SKyle Evans file_remove_pattern(curves_list_path + "curves_list.h", ".*"+name+".*") 1766*f0865ec9SKyle Evans file_remove_pattern(curves_list_path + "curves_list.h", ".*"+name.upper()+".*") 1767*f0865ec9SKyle Evans file_remove_pattern(lib_ecc_types_path + "lib_ecc_types.h", ".*"+name.upper()+".*") 1768*f0865ec9SKyle Evans file_remove_pattern(lib_ecc_config_path + "lib_ecc_config.h", ".*"+name.upper()+".*") 1769*f0865ec9SKyle Evans file_remove_pattern(ec_self_tests_path + "ec_self_tests_core.h", ".*"+name+".*") 1770*f0865ec9SKyle Evans file_remove_pattern(ec_self_tests_path + "ec_self_tests_core.h", ".*"+name.upper()+".*") 1771*f0865ec9SKyle Evans file_remove_pattern(meson_options_path + "meson.options", ".*"+name.lower()+".*") 1772*f0865ec9SKyle Evans try: 1773*f0865ec9SKyle Evans remove_file(ec_params_path + "ec_params_"+name+".h") 1774*f0865ec9SKyle Evans except: 1775*f0865ec9SKyle Evans print("Error: curve name "+name+" does not seem to be present in the sources!") 1776*f0865ec9SKyle Evans return False 1777*f0865ec9SKyle Evans try: 1778*f0865ec9SKyle Evans remove_file(ec_self_tests_path + "ec_self_tests_core_"+name+".h") 1779*f0865ec9SKyle Evans except: 1780*f0865ec9SKyle Evans print("Warning: curve name "+name+" self tests do not seem to be present ...") 1781*f0865ec9SKyle Evans return True 1782*f0865ec9SKyle Evans return True 1783*f0865ec9SKyle Evans if remove_all == True: 1784*f0865ec9SKyle Evans asked = "" 1785*f0865ec9SKyle Evans while asked != "y" and asked != "n": 1786*f0865ec9SKyle Evans asked = get_user_input("You asked to remove everything related to ALL user defined curves. Enter y to confirm, n to cancel [y/n]. ") 1787*f0865ec9SKyle Evans if asked == "n": 1788*f0865ec9SKyle Evans print("NOT removing user defined curves (cancelled).") 1789*f0865ec9SKyle Evans return True 1790*f0865ec9SKyle Evans # Remove any user defined stuff with given name 1791*f0865ec9SKyle Evans print("Removing ALL user defined curves ...") 1792*f0865ec9SKyle Evans # Remove any user defined stuff (whatever name) 1793*f0865ec9SKyle Evans file_remove_pattern(curves_list_path + "curves_list.h", ".*user_defined.*") 1794*f0865ec9SKyle Evans file_remove_pattern(curves_list_path + "curves_list.h", ".*USER_DEFINED.*") 1795*f0865ec9SKyle Evans file_remove_pattern(lib_ecc_types_path + "lib_ecc_types.h", ".*USER_DEFINED.*") 1796*f0865ec9SKyle Evans file_remove_pattern(lib_ecc_config_path + "lib_ecc_config.h", ".*USER_DEFINED.*") 1797*f0865ec9SKyle Evans file_remove_pattern(ec_self_tests_path + "ec_self_tests_core.h", ".*USER_DEFINED.*") 1798*f0865ec9SKyle Evans file_remove_pattern(ec_self_tests_path + "ec_self_tests_core.h", ".*user_defined.*") 1799*f0865ec9SKyle Evans file_remove_pattern(meson_options_path + "meson.options", ".*user_defined.*") 1800*f0865ec9SKyle Evans remove_files_pattern(ec_params_path + "ec_params_user_defined_*.h") 1801*f0865ec9SKyle Evans remove_files_pattern(ec_self_tests_path + "ec_self_tests_core_user_defined_*.h") 1802*f0865ec9SKyle Evans return True 1803*f0865ec9SKyle Evans 1804*f0865ec9SKyle Evans # If a g is provided, split it in two gx and gy 1805*f0865ec9SKyle Evans if g != None: 1806*f0865ec9SKyle Evans if (len(g)/2)%2 == 0: 1807*f0865ec9SKyle Evans gx = get_int(g[:len(g)/2]) 1808*f0865ec9SKyle Evans gy = get_int(g[len(g)/2:]) 1809*f0865ec9SKyle Evans else: 1810*f0865ec9SKyle Evans # This is probably a generator encapsulated in a bit string 1811*f0865ec9SKyle Evans if g[0:2] != "04": 1812*f0865ec9SKyle Evans print("Error: provided generator g is not conforming!") 1813*f0865ec9SKyle Evans return False 1814*f0865ec9SKyle Evans else: 1815*f0865ec9SKyle Evans g = g[2:] 1816*f0865ec9SKyle Evans gx = get_int(g[:len(g)/2]) 1817*f0865ec9SKyle Evans gy = get_int(g[len(g)/2:]) 1818*f0865ec9SKyle Evans if ECfile != None: 1819*f0865ec9SKyle Evans # ASN.1 DER input incompatible with other options 1820*f0865ec9SKyle Evans if (prime != None) or (a != None) or (b != None) or (gx != None) or (gy != None) or (order != None) or (cofactor != None): 1821*f0865ec9SKyle Evans print("Error: option ECfile incompatible with explicit (prime, a, b, gx, gy, order, cofactor) options!") 1822*f0865ec9SKyle Evans return False 1823*f0865ec9SKyle Evans # We need at least a name 1824*f0865ec9SKyle Evans if (name == None): 1825*f0865ec9SKyle Evans print("Error: option ECfile needs a curve name!") 1826*f0865ec9SKyle Evans return False 1827*f0865ec9SKyle Evans # Open the file 1828*f0865ec9SKyle Evans try: 1829*f0865ec9SKyle Evans buf = open(ECfile, 'rb').read() 1830*f0865ec9SKyle Evans except: 1831*f0865ec9SKyle Evans print("Error: cannot open ECfile file "+ECfile) 1832*f0865ec9SKyle Evans return False 1833*f0865ec9SKyle Evans # Check if we have a PEM or a DER file 1834*f0865ec9SKyle Evans (check, derbuf) = buffer_remove_pattern(buf, "-----.*-----") 1835*f0865ec9SKyle Evans if (check == True): 1836*f0865ec9SKyle Evans # This a PEM file, proceed with base64 decoding 1837*f0865ec9SKyle Evans if(is_base64(derbuf) == False): 1838*f0865ec9SKyle Evans print("Error: error when decoding ECfile file "+ECfile+" (seems to be PEM, but failed to decode)") 1839*f0865ec9SKyle Evans return False 1840*f0865ec9SKyle Evans derbuf = base64.b64decode(derbuf) 1841*f0865ec9SKyle Evans (check, (a, b, prime, order, cofactor, gx, gy)) = parse_DER_ECParameters(derbuf) 1842*f0865ec9SKyle Evans if (check == False): 1843*f0865ec9SKyle Evans print("Error: error when parsing ECfile file "+ECfile+" (malformed or unsupported ASN.1)") 1844*f0865ec9SKyle Evans return False 1845*f0865ec9SKyle Evans 1846*f0865ec9SKyle Evans else: 1847*f0865ec9SKyle Evans if (prime == None) or (a == None) or (b == None) or (gx == None) or (gy == None) or (order == None) or (cofactor == None) or (name == None): 1848*f0865ec9SKyle Evans err_string = (prime == None)*"prime "+(a == None)*"a "+(b == None)*"b "+(gx == None)*"gx "+(gy == None)*"gy "+(order == None)*"order "+(cofactor == None)*"cofactor "+(name == None)*"name " 1849*f0865ec9SKyle Evans print("Error: missing "+err_string+" in explicit curve definition (name, prime, a, b, gx, gy, order, cofactor)!") 1850*f0865ec9SKyle Evans print("See the help with -h or --help") 1851*f0865ec9SKyle Evans return False 1852*f0865ec9SKyle Evans 1853*f0865ec9SKyle Evans # Some sanity checks here 1854*f0865ec9SKyle Evans # Check that prime is indeed a prime 1855*f0865ec9SKyle Evans if is_probprime(prime) == False: 1856*f0865ec9SKyle Evans print("Error: given prime is *NOT* prime!") 1857*f0865ec9SKyle Evans return False 1858*f0865ec9SKyle Evans if is_probprime(order) == False: 1859*f0865ec9SKyle Evans print("Error: given order is *NOT* prime!") 1860*f0865ec9SKyle Evans return False 1861*f0865ec9SKyle Evans if (a > prime) or (b > prime) or (gx > prime) or (gy > prime): 1862*f0865ec9SKyle Evans err_string = (a > prime)*"a "+(b > prime)*"b "+(gx > prime)*"gx "+(gy > prime)*"gy " 1863*f0865ec9SKyle Evans print("Error: "+err_string+"is > prime") 1864*f0865ec9SKyle Evans return False 1865*f0865ec9SKyle Evans # Check that the provided generator is on the curve 1866*f0865ec9SKyle Evans if pow(gy, 2, prime) != ((pow(gx, 3, prime) + (a*gx) + b) % prime): 1867*f0865ec9SKyle Evans print("Error: the given parameters (prime, a, b, gx, gy) do not verify the elliptic curve equation!") 1868*f0865ec9SKyle Evans return False 1869*f0865ec9SKyle Evans 1870*f0865ec9SKyle Evans # Check Montgomery and Edwards transfer coefficients 1871*f0865ec9SKyle Evans if ((alpha_montgomery != None) and (gamma_montgomery == None)) or ((alpha_montgomery == None) and (gamma_montgomery != None)): 1872*f0865ec9SKyle Evans print("Error: alpha_montgomery and gamma_montgomery must be both defined if used!") 1873*f0865ec9SKyle Evans return False 1874*f0865ec9SKyle Evans if (alpha_edwards != None): 1875*f0865ec9SKyle Evans if (alpha_montgomery == None) or (gamma_montgomery == None): 1876*f0865ec9SKyle Evans print("Error: alpha_edwards needs alpha_montgomery and gamma_montgomery to be both defined if used!") 1877*f0865ec9SKyle Evans return False 1878*f0865ec9SKyle Evans 1879*f0865ec9SKyle Evans # Now that we have our parameters, call the function to get bitlen 1880*f0865ec9SKyle Evans pbitlen = getbitlen(prime) 1881*f0865ec9SKyle Evans ec_params = curve_params(name, prime, pbitlen, a, b, gx, gy, order, cofactor, oid, alpha_montgomery, gamma_montgomery, alpha_edwards) 1882*f0865ec9SKyle Evans # Check if there is a name collision somewhere 1883*f0865ec9SKyle Evans if os.path.exists(ec_params_path + "ec_params_"+name+".h") == True : 1884*f0865ec9SKyle Evans print("Error: file %s already exists!" % (ec_params_path + "ec_params_"+name+".h")) 1885*f0865ec9SKyle Evans return False 1886*f0865ec9SKyle Evans if (check_in_file(curves_list_path + "curves_list.h", "ec_params_"+name+"_str_params") == True) or (check_in_file(curves_list_path + "curves_list.h", "WITH_CURVE_"+name.upper()+"\n") == True) or (check_in_file(lib_ecc_types_path + "lib_ecc_types.h", "WITH_CURVE_"+name.upper()+"\n") == True): 1887*f0865ec9SKyle Evans print("Error: name %s already exists in files" % ("ec_params_"+name)) 1888*f0865ec9SKyle Evans return False 1889*f0865ec9SKyle Evans # Create a new file with the parameters 1890*f0865ec9SKyle Evans if not os.path.exists(ec_params_path): 1891*f0865ec9SKyle Evans # Create the "user_defined" folder if it does not exist 1892*f0865ec9SKyle Evans os.mkdir(ec_params_path) 1893*f0865ec9SKyle Evans f = open(ec_params_path + "ec_params_"+name+".h", 'w') 1894*f0865ec9SKyle Evans f.write(ec_params) 1895*f0865ec9SKyle Evans f.close() 1896*f0865ec9SKyle Evans # Include the file in curves_list.h 1897*f0865ec9SKyle Evans magic = "ADD curves header here" 1898*f0865ec9SKyle Evans magic_re = "\/\* "+magic+" \*\/" 1899*f0865ec9SKyle Evans magic_back = "/* "+magic+" */" 1900*f0865ec9SKyle Evans file_replace_pattern(curves_list_path + "curves_list.h", magic_re, "#include <libecc/curves/user_defined/ec_params_"+name+".h>\n"+magic_back) 1901*f0865ec9SKyle Evans # Add the curve mapping 1902*f0865ec9SKyle Evans magic = "ADD curves mapping here" 1903*f0865ec9SKyle Evans magic_re = "\/\* "+magic+" \*\/" 1904*f0865ec9SKyle Evans magic_back = "/* "+magic+" */" 1905*f0865ec9SKyle Evans file_replace_pattern(curves_list_path + "curves_list.h", magic_re, "#ifdef WITH_CURVE_"+name.upper()+"\n\t{ .type = "+name.upper()+", .params = &"+name+"_str_params },\n#endif /* WITH_CURVE_"+name.upper()+" */\n"+magic_back) 1906*f0865ec9SKyle Evans # Add the new curve type in the enum 1907*f0865ec9SKyle Evans # First we get the number of already defined curves so that we increment the enum counter 1908*f0865ec9SKyle Evans num_with_curve = num_patterns_in_file(lib_ecc_types_path + "lib_ecc_types.h", "#ifdef WITH_CURVE_") 1909*f0865ec9SKyle Evans magic = "ADD curves type here" 1910*f0865ec9SKyle Evans magic_re = "\/\* "+magic+" \*\/" 1911*f0865ec9SKyle Evans magic_back = "/* "+magic+" */" 1912*f0865ec9SKyle Evans file_replace_pattern(lib_ecc_types_path + "lib_ecc_types.h", magic_re, "#ifdef WITH_CURVE_"+name.upper()+"\n\t"+name.upper()+" = "+str(num_with_curve+1)+",\n#endif /* WITH_CURVE_"+name.upper()+" */\n"+magic_back) 1913*f0865ec9SKyle Evans # Add the new curve define in the config 1914*f0865ec9SKyle Evans magic = "ADD curves define here" 1915*f0865ec9SKyle Evans magic_re = "\/\* "+magic+" \*\/" 1916*f0865ec9SKyle Evans magic_back = "/* "+magic+" */" 1917*f0865ec9SKyle Evans file_replace_pattern(lib_ecc_config_path + "lib_ecc_config.h", magic_re, "#define WITH_CURVE_"+name.upper()+"\n"+magic_back) 1918*f0865ec9SKyle Evans # Add the new curve meson option in the meson.options file 1919*f0865ec9SKyle Evans magic = "ADD curves meson option here" 1920*f0865ec9SKyle Evans magic_re = "# " + magic 1921*f0865ec9SKyle Evans magic_back = "# " + magic 1922*f0865ec9SKyle Evans file_replace_pattern(meson_options_path + "meson.options", magic_re, "\t'"+name.lower()+"',\n"+magic_back) 1923*f0865ec9SKyle Evans 1924*f0865ec9SKyle Evans # Do we need to add some test vectors? 1925*f0865ec9SKyle Evans if add_test_vectors != None: 1926*f0865ec9SKyle Evans print("Test vectors generation asked: this can take some time! Please wait ...") 1927*f0865ec9SKyle Evans # Create curve 1928*f0865ec9SKyle Evans c = Curve(a, b, prime, order, cofactor, gx, gy, cofactor * order, name, oid) 1929*f0865ec9SKyle Evans # Generate key pair for the algorithm 1930*f0865ec9SKyle Evans vectors = gen_self_tests(c, add_test_vectors) 1931*f0865ec9SKyle Evans # Iterate through all the tests 1932*f0865ec9SKyle Evans f = open(ec_self_tests_path + "ec_self_tests_core_"+name+".h", 'w') 1933*f0865ec9SKyle Evans for l in vectors: 1934*f0865ec9SKyle Evans for v in l: 1935*f0865ec9SKyle Evans for case in v: 1936*f0865ec9SKyle Evans (case_name, case_vector) = case 1937*f0865ec9SKyle Evans # Add the new test case 1938*f0865ec9SKyle Evans magic = "ADD curve test case here" 1939*f0865ec9SKyle Evans magic_re = "\/\* "+magic+" \*\/" 1940*f0865ec9SKyle Evans magic_back = "/* "+magic+" */" 1941*f0865ec9SKyle Evans file_replace_pattern(ec_self_tests_path + "ec_self_tests_core.h", magic_re, case_name+"\n"+magic_back) 1942*f0865ec9SKyle Evans # Create/Increment the header file 1943*f0865ec9SKyle Evans f.write(case_vector) 1944*f0865ec9SKyle Evans f.close() 1945*f0865ec9SKyle Evans # Add the new test cases header 1946*f0865ec9SKyle Evans magic = "ADD curve test vectors header here" 1947*f0865ec9SKyle Evans magic_re = "\/\* "+magic+" \*\/" 1948*f0865ec9SKyle Evans magic_back = "/* "+magic+" */" 1949*f0865ec9SKyle Evans file_replace_pattern(ec_self_tests_path + "ec_self_tests_core.h", magic_re, "#include \"ec_self_tests_core_"+name+".h\"\n"+magic_back) 1950*f0865ec9SKyle Evans return True 1951*f0865ec9SKyle Evans 1952*f0865ec9SKyle Evans 1953*f0865ec9SKyle Evans#### Main 1954*f0865ec9SKyle Evansif __name__ == "__main__": 1955*f0865ec9SKyle Evans signal.signal(signal.SIGINT, handler) 1956*f0865ec9SKyle Evans parse_cmd_line(sys.argv[1:]) 1957