1998-12-13 19:19:48 -07:00
|
|
|
#
|
|
|
|
|
# ElGamal.py : ElGamal encryption/decryption and signatures
|
2003-02-28 16:28:35 -07:00
|
|
|
#
|
2002-04-22 21:24:27 -07:00
|
|
|
# Part of the Python Cryptography Toolkit
|
2003-02-28 16:28:35 -07:00
|
|
|
#
|
2009-08-02 22:46:19 -04:00
|
|
|
# Originally written by: A.M. Kuchling
|
2003-02-28 16:28:35 -07:00
|
|
|
#
|
2009-08-02 22:46:19 -04:00
|
|
|
# ===================================================================
|
|
|
|
|
# The contents of this file are dedicated to the public domain. To
|
|
|
|
|
# the extent that dedication to the public domain is not available,
|
|
|
|
|
# everyone is granted a worldwide, perpetual, royalty-free,
|
|
|
|
|
# non-exclusive license to exercise all rights associated with the
|
|
|
|
|
# contents of this file for any purpose whatsoever.
|
|
|
|
|
# No rights are reserved.
|
|
|
|
|
#
|
|
|
|
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
|
|
|
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
|
|
|
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
|
|
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
|
|
|
|
# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
|
|
|
|
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
|
|
|
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
|
|
|
# SOFTWARE.
|
|
|
|
|
# ===================================================================
|
1998-12-13 19:19:48 -07:00
|
|
|
|
2012-04-12 23:16:52 +02:00
|
|
|
"""ElGamal public-key algorithm (encryption and signature)."""
|
|
|
|
|
|
2008-08-06 21:27:50 -04:00
|
|
|
__revision__ = "$Id$"
|
2002-07-11 14:31:19 -07:00
|
|
|
|
2002-07-11 14:33:05 -07:00
|
|
|
from Crypto.PublicKey.pubkey import *
|
2003-04-04 20:44:26 -07:00
|
|
|
from Crypto.Util import number
|
1998-12-13 19:19:48 -07:00
|
|
|
|
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
|
2003-04-04 16:15:13 -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
|
2003-04-04 16:15:13 -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
|
2003-04-04 16:15:13 -07:00
|
|
|
if size<1:
|
|
|
|
|
size=bits-1
|
1998-12-13 19:19:48 -07:00
|
|
|
while (1):
|
|
|
|
|
obj.g=bignum(getPrime(size, randfunc))
|
2003-04-04 16:15:13 -07:00
|
|
|
if obj.g < obj.p:
|
|
|
|
|
break
|
1998-12-13 19:19:48 -07:00
|
|
|
size=(size+1) % bits
|
2003-04-04 16:15:13 -07:00
|
|
|
if size==0:
|
|
|
|
|
size=4
|
1998-12-13 19:19:48 -07:00
|
|
|
# Generate random number x
|
2003-04-04 16:15:13 -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
|
2003-04-04 16:15:13 -07:00
|
|
|
if size>2:
|
|
|
|
|
break
|
1998-12-13 19:19:48 -07:00
|
|
|
while (1):
|
|
|
|
|
obj.x=bignum(getPrime(size, randfunc))
|
2003-04-04 16:15:13 -07:00
|
|
|
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)
|
1998-12-13 19:19:48 -07:00
|
|
|
return obj
|
2003-02-28 16:28:35 -07:00
|
|
|
|
1998-12-13 19:19:48 -07:00
|
|
|
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.
|
|
|
|
|
"""
|
2003-02-28 16:28:35 -07:00
|
|
|
|
1998-12-13 19:19:48 -07:00
|
|
|
obj=ElGamalobj()
|
|
|
|
|
if len(tuple) not in [3,4]:
|
2009-04-25 13:57:55 -04:00
|
|
|
raise ValueError('argument for construct() wrong length')
|
1998-12-13 19:19:48 -07:00
|
|
|
for i in range(len(tuple)):
|
2003-02-28 16:28:35 -07:00
|
|
|
field = obj.keydata[i]
|
|
|
|
|
setattr(obj, field, tuple[i])
|
1998-12-13 19:19:48 -07:00
|
|
|
return obj
|
2003-02-28 16:28:35 -07:00
|
|
|
|
1998-12-13 19:19:48 -07:00
|
|
|
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
|
2003-02-28 16:28:35 -07:00
|
|
|
return ( a,b )
|
2002-05-24 14:27:34 -07:00
|
|
|
|
1998-12-13 19:19:48 -07:00
|
|
|
def _decrypt(self, M):
|
2003-02-28 16:28:35 -07:00
|
|
|
if (not hasattr(self, 'x')):
|
2009-04-25 13:57:55 -04:00
|
|
|
raise TypeError('Private key not available in this object')
|
1998-12-13 19:19:48 -07:00
|
|
|
ax=pow(M[0], self.x, self.p)
|
|
|
|
|
plaintext=(M[1] * inverse(ax, self.p ) ) % self.p
|
2003-02-28 16:28:35 -07:00
|
|
|
return plaintext
|
2002-05-24 14:27:34 -07:00
|
|
|
|
1998-12-13 19:19:48 -07:00
|
|
|
def _sign(self, M, K):
|
2003-02-28 16:28:35 -07:00
|
|
|
if (not hasattr(self, 'x')):
|
2009-04-25 13:57:55 -04:00
|
|
|
raise TypeError('Private key not available in this object')
|
1998-12-13 19:19:48 -07:00
|
|
|
p1=self.p-1
|
|
|
|
|
if (GCD(K, p1)!=1):
|
2009-04-25 13:57:55 -04:00
|
|
|
raise ValueError('Bad K value: GCD(K,p-1)!=1')
|
1998-12-13 19:19:48 -07:00
|
|
|
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)
|
2003-04-04 16:15:13 -07:00
|
|
|
if v1==v2:
|
|
|
|
|
return 1
|
1998-12-13 19:19:48 -07:00
|
|
|
return 0
|
2003-02-28 16:28:35 -07:00
|
|
|
|
1998-12-13 19:19:48 -07:00
|
|
|
def size(self):
|
2003-02-28 16:28:35 -07:00
|
|
|
"Return the maximum number of bits that can be handled by this key."
|
2003-04-04 20:44:26 -07:00
|
|
|
return number.size(self.p) - 1
|
2003-02-28 16:28:35 -07:00
|
|
|
|
2003-04-03 21:36:15 -07:00
|
|
|
def has_private(self):
|
2003-02-28 16:28:35 -07:00
|
|
|
"""Return a Boolean denoting whether the object contains
|
|
|
|
|
private components."""
|
2003-04-04 16:15:13 -07:00
|
|
|
if hasattr(self, 'x'):
|
|
|
|
|
return 1
|
|
|
|
|
else:
|
|
|
|
|
return 0
|
1998-12-13 19:19:48 -07:00
|
|
|
|
|
|
|
|
def publickey(self):
|
2003-02-28 16:28:35 -07:00
|
|
|
"""Return a new key object containing only the public information."""
|
1998-12-13 19:19:48 -07:00
|
|
|
return construct((self.p, self.g, self.y))
|
|
|
|
|
|
2003-02-28 16:28:35 -07:00
|
|
|
|
1998-12-13 19:19:48 -07:00
|
|
|
object=ElGamalobj
|