# # ElGamal.py : ElGamal encryption/decryption and signatures # # 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: ElGamal.py,v 1.9 2003/04/04 19:44:26 akuchling Exp $" from Crypto.PublicKey.pubkey import * from Crypto.Util import number class error (Exception): pass # Generate an ElGamal key with N bits def generate(bits, randfunc, progress_func=None): """generate(bits:int, randfunc:callable, progress_func:callable) Generate an ElGamal key of length 'bits', using 'randfunc' to get random data and 'progress_func', if present, to display the progress of the key generation. """ obj=ElGamalobj() # Generate prime p if progress_func: progress_func('p\n') obj.p=bignum(getPrime(bits, randfunc)) # Generate random number g if progress_func: progress_func('g\n') size=bits-1-(ord(randfunc(1)) & 63) # g will be from 1--64 bits smaller than p if size<1: size=bits-1 while (1): obj.g=bignum(getPrime(size, randfunc)) if obj.g < obj.p: break size=(size+1) % bits if size==0: size=4 # Generate random number x if progress_func: progress_func('x\n') while (1): size=bits-1-ord(randfunc(1)) # x will be from 1 to 256 bits smaller than p if size>2: break while (1): obj.x=bignum(getPrime(size, randfunc)) if obj.x < obj.p: break size = (size+1) % bits if size==0: size=4 if progress_func: progress_func('y\n') obj.y = pow(obj.g, obj.x, obj.p) return obj def construct(tuple): """construct(tuple:(long,long,long,long)|(long,long,long,long,long))) : ElGamalobj Construct an ElGamal key from a 3- or 4-tuple of numbers. """ obj=ElGamalobj() if len(tuple) not in [3,4]: 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 ElGamalobj(pubkey): keydata=['p', 'g', 'y', 'x'] def _encrypt(self, M, K): a=pow(self.g, K, self.p) b=( M*pow(self.y, K, self.p) ) % self.p return ( a,b ) def _decrypt(self, M): if (not hasattr(self, 'x')): raise error, 'Private key not available in this object' ax=pow(M[0], self.x, self.p) plaintext=(M[1] * inverse(ax, self.p ) ) % self.p return plaintext def _sign(self, M, K): if (not hasattr(self, 'x')): raise error, 'Private key not available in this object' p1=self.p-1 if (GCD(K, p1)!=1): raise error, 'Bad K value: GCD(K,p-1)!=1' a=pow(self.g, K, self.p) t=(M-self.x*a) % p1 while t<0: t=t+p1 b=(t*inverse(K, p1)) % p1 return (a, b) def _verify(self, M, sig): v1=pow(self.y, sig[0], self.p) v1=(v1*pow(sig[0], sig[1], self.p)) % self.p v2=pow(self.g, M, self.p) if v1==v2: return 1 return 0 def size(self): "Return the maximum number of bits that can be handled by this key." return number.size(self.p) - 1 def has_private(self): """Return a Boolean denoting whether the object contains private components.""" if hasattr(self, 'x'): return 1 else: return 0 def publickey(self): """Return a new key object containing only the public information.""" return construct((self.p, self.g, self.y)) object=ElGamalobj