# # qNEW.py : The q-NEW signature algorithm. # # Part of the Python Cryptography Toolkit # # Distribute and use freely; there are no restrictions on further # dissemination and usage except those imposed by the laws of your # country of residence. This software is provided "as is" without # warranty of fitness for use or suitability for any purpose, express # or implied. Use at your own risk or not at all. # __revision__ = "$Id: qNEW.py,v 1.8 2003/04/04 15:13:35 akuchling Exp $" from Crypto.PublicKey import pubkey from Crypto.Util.number import * from Crypto.Hash import SHA class error (Exception): pass HASHBITS = 160 # Size of SHA digests def generate(bits, randfunc, progress_func=None): """generate(bits:int, randfunc:callable, progress_func:callable) Generate a qNEW key of length 'bits', using 'randfunc' to get random data and 'progress_func', if present, to display the progress of the key generation. """ obj=qNEWobj() # Generate prime numbers p and q. q is a 160-bit prime # number. p is another prime number (the modulus) whose bit # size is chosen by the caller, and is generated so that p-1 # is a multiple of q. # # Note that only a single seed is used to # generate p and q; if someone generates a key for you, you can # use the seed to duplicate the key generation. This can # protect you from someone generating values of p,q that have # some special form that's easy to break. if progress_func: progress_func('p,q\n') while (1): obj.q = getPrime(160, randfunc) # assert pow(2, 159L)1. g is kept; h can be discarded. if progress_func: progress_func('h,g\n') while (1): h=bytes_to_long(randfunc(bits)) % (p-1) g=pow(h, power, p) if 11: break obj.g=g # x is the private key information, and is # just a random number between 0 and q. # y=g**x mod p, and is part of the public information. if progress_func: progress_func('x,y\n') while (1): x=bytes_to_long(randfunc(20)) if 0 < x < obj.q: break obj.x, obj.y=x, pow(g, x, p) return obj # Construct a qNEW object def construct(tuple): """construct(tuple:(long,long,long,long)|(long,long,long,long,long) Construct a qNEW object from a 4- or 5-tuple of numbers. """ obj=qNEWobj() if len(tuple) not in [4,5]: raise error, 'argument for construct() wrong length' for i in range(len(tuple)): field = obj.keydata[i] setattr(obj, field, tuple[i]) return obj class qNEWobj(pubkey.pubkey): keydata=['p', 'q', 'g', 'y', 'x'] def _sign(self, M, K=''): if (self.q<=K): raise error, 'K is greater than q' if M<0: raise error, 'Illegal value of M (<0)' if M>=pow(2,161L): raise error, 'Illegal value of M (too large)' r=pow(self.g, K, self.p) % self.q s=(K- (r*M*self.x % self.q)) % self.q return (r,s) def _verify(self, M, sig): r, s = sig if r<=0 or r>=self.q or s<=0 or s>=self.q: return 0 if M<0: raise error, 'Illegal value of M (<0)' if M<=0 or M>=pow(2,161L): return 0 v1 = pow(self.g, s, self.p) v2 = pow(self.y, M*r, self.p) v = ((v1*v2) % self.p) v = v % self.q if v==r: return 1 return 0 def size(self): "Return the maximum number of bits that can be handled by this key." return 160 def has_private(self): """Return a Boolean denoting whether the object contains private components.""" return hasattr(self, 'x') def can_sign(self): """Return a Boolean value recording whether this algorithm can generate signatures.""" return 1 def can_encrypt(self): """Return a Boolean value recording whether this algorithm can encrypt data.""" return 0 def publickey(self): """Return a new key object containing only the public information.""" return construct((self.p, self.q, self.g, self.y)) object = qNEWobj