| 
									
										
										
										
											1998-12-13 19:19:48 -07:00
										 |  |  | # | 
					
						
							|  |  |  | #   ElGamal.py : ElGamal encryption/decryption and signatures | 
					
						
							|  |  |  | #  | 
					
						
							| 
									
										
										
										
											2002-04-22 21:24:27 -07:00
										 |  |  | #  Part of the Python Cryptography Toolkit | 
					
						
							| 
									
										
										
										
											1998-12-13 19:19:48 -07:00
										 |  |  | #  | 
					
						
							|  |  |  | # 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.  | 
					
						
							|  |  |  | #  | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | from pubkey import * | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-05-24 14:27:34 -07:00
										 |  |  | class error (Exception): | 
					
						
							|  |  |  |     pass | 
					
						
							| 
									
										
										
										
											1998-12-13 19:19:48 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | # Generate an ElGamal key with N bits | 
					
						
							|  |  |  | def generate(bits, randfunc, progress_func=None): | 
					
						
							| 
									
										
										
										
											2002-05-24 14:27:34 -07:00
										 |  |  |     """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. | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											1998-12-13 19:19:48 -07:00
										 |  |  |     obj=ElGamalobj() | 
					
						
							|  |  |  |     # Generate prime p | 
					
						
							| 
									
										
										
										
											2002-05-24 14:27:34 -07:00
										 |  |  |     if progress_func: progress_func('p\n') | 
					
						
							| 
									
										
										
										
											1998-12-13 19:19:48 -07:00
										 |  |  |     obj.p=bignum(getPrime(bits, randfunc)) | 
					
						
							|  |  |  |     # Generate random number g | 
					
						
							| 
									
										
										
										
											2002-05-24 14:27:34 -07:00
										 |  |  |     if progress_func: progress_func('g\n') | 
					
						
							| 
									
										
										
										
											1998-12-13 19:19:48 -07:00
										 |  |  |     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 | 
					
						
							| 
									
										
										
										
											2002-05-24 14:27:34 -07:00
										 |  |  |     if progress_func: progress_func('x\n') | 
					
						
							| 
									
										
										
										
											1998-12-13 19:19:48 -07:00
										 |  |  |     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 | 
					
						
							| 
									
										
										
										
											2002-05-24 14:27:34 -07:00
										 |  |  |     if progress_func: progress_func('y\n') | 
					
						
							| 
									
										
										
										
											1998-12-13 19:19:48 -07:00
										 |  |  |     obj.y=pow(obj.g, obj.x, obj.p) | 
					
						
							|  |  |  |     return obj | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  | def construct(tuple): | 
					
						
							| 
									
										
										
										
											2002-05-24 14:27:34 -07:00
										 |  |  |     """construct(tuple:(long,long,long,long)|(long,long,long,long,long)))
 | 
					
						
							|  |  |  |              : ElGamalobj | 
					
						
							|  |  |  |     Construct an ElGamal key from a 3- or 4-tuple of numbers. | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |      | 
					
						
							| 
									
										
										
										
											1998-12-13 19:19:48 -07:00
										 |  |  |     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 ) | 
					
						
							| 
									
										
										
										
											2002-05-24 14:27:34 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1998-12-13 19:19:48 -07:00
										 |  |  |     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 | 
					
						
							| 
									
										
										
										
											2002-05-24 14:27:34 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1998-12-13 19:19:48 -07:00
										 |  |  |     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) | 
					
						
							| 
									
										
										
										
											2002-05-24 14:27:34 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1998-12-13 19:19:48 -07:00
										 |  |  |     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." | 
					
						
							|  |  |  |         bits, power = 0,1L | 
					
						
							|  |  |  | 	while (power<self.p): bits, power = bits+1, power<<1 | 
					
						
							|  |  |  | 	return bits-1 | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  |     def hasprivate(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 |