257 lines
6.8 KiB
Python
257 lines
6.8 KiB
Python
#
|
|
# RSA.py : RSA encryption/decryption
|
|
#
|
|
# 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: RSA.py,v 1.20 2004/05/06 12:52:54 akuchling Exp $"
|
|
|
|
from Crypto.PublicKey import pubkey
|
|
from Crypto.Util import number
|
|
|
|
try:
|
|
from Crypto.PublicKey import _fastmath
|
|
except ImportError:
|
|
_fastmath = None
|
|
|
|
class error (Exception):
|
|
pass
|
|
|
|
def generate(bits, randfunc, progress_func=None):
|
|
"""generate(bits:int, randfunc:callable, progress_func:callable)
|
|
|
|
Generate an RSA key of length 'bits', using 'randfunc' to get
|
|
random data and 'progress_func', if present, to display
|
|
the progress of the key generation.
|
|
"""
|
|
obj=RSAobj()
|
|
|
|
# Generate the prime factors of n
|
|
if progress_func:
|
|
progress_func('p,q\n')
|
|
p = q = 1L
|
|
while number.size(p*q) < bits:
|
|
p = pubkey.getPrime(bits/2, randfunc)
|
|
q = pubkey.getPrime(bits/2, randfunc)
|
|
|
|
# p shall be smaller than q (for calc of u)
|
|
if p > q:
|
|
(p, q)=(q, p)
|
|
obj.p = p
|
|
obj.q = q
|
|
|
|
if progress_func:
|
|
progress_func('u\n')
|
|
obj.u = pubkey.inverse(obj.p, obj.q)
|
|
obj.n = obj.p*obj.q
|
|
|
|
obj.e = 65537L
|
|
if progress_func:
|
|
progress_func('d\n')
|
|
obj.d=pubkey.inverse(obj.e, (obj.p-1)*(obj.q-1))
|
|
|
|
assert bits <= 1+obj.size(), "Generated key is too small"
|
|
|
|
return obj
|
|
|
|
def construct(tuple):
|
|
"""construct(tuple:(long,) : RSAobj
|
|
Construct an RSA object from a 2-, 3-, 5-, or 6-tuple of numbers.
|
|
"""
|
|
|
|
obj=RSAobj()
|
|
if len(tuple) not in [2,3,5,6]:
|
|
raise error, 'argument for construct() wrong length'
|
|
for i in range(len(tuple)):
|
|
field = obj.keydata[i]
|
|
setattr(obj, field, tuple[i])
|
|
if len(tuple) >= 5:
|
|
# Ensure p is smaller than q
|
|
if obj.p>obj.q:
|
|
(obj.p, obj.q)=(obj.q, obj.p)
|
|
|
|
if len(tuple) == 5:
|
|
# u not supplied, so we're going to have to compute it.
|
|
obj.u=pubkey.inverse(obj.p, obj.q)
|
|
|
|
return obj
|
|
|
|
class RSAobj(pubkey.pubkey):
|
|
keydata = ['n', 'e', 'd', 'p', 'q', 'u']
|
|
def _encrypt(self, plaintext, K=''):
|
|
if self.n<=plaintext:
|
|
raise error, 'Plaintext too large'
|
|
return (pow(plaintext, self.e, self.n),)
|
|
|
|
def _decrypt(self, ciphertext):
|
|
if (not hasattr(self, 'd')):
|
|
raise error, 'Private key not available in this object'
|
|
if self.n<=ciphertext[0]:
|
|
raise error, 'Ciphertext too large'
|
|
return pow(ciphertext[0], self.d, self.n)
|
|
|
|
def _sign(self, M, K=''):
|
|
return (self._decrypt((M,)),)
|
|
|
|
def _verify(self, M, sig):
|
|
m2=self._encrypt(sig[0])
|
|
if m2[0]==M:
|
|
return 1
|
|
else: return 0
|
|
|
|
def _blind(self, M, B):
|
|
tmp = pow(B, self.e, self.n)
|
|
return (M * tmp) % self.n
|
|
|
|
def _unblind(self, M, B):
|
|
tmp = pubkey.inverse(B, self.n)
|
|
return (M * tmp) % self.n
|
|
|
|
def can_blind (self):
|
|
"""can_blind() : bool
|
|
Return a Boolean value recording whether this algorithm can
|
|
blind data. (This does not imply that this
|
|
particular key object has the private information required to
|
|
to blind a message.)
|
|
"""
|
|
return 1
|
|
|
|
def size(self):
|
|
"""size() : int
|
|
Return the maximum number of bits that can be handled by this key.
|
|
"""
|
|
return number.size(self.n) - 1
|
|
|
|
def has_private(self):
|
|
"""has_private() : bool
|
|
Return a Boolean denoting whether the object contains
|
|
private components.
|
|
"""
|
|
if hasattr(self, 'd'):
|
|
return 1
|
|
else: return 0
|
|
|
|
def publickey(self):
|
|
"""publickey(): RSAobj
|
|
Return a new key object containing only the public key information.
|
|
"""
|
|
return construct((self.n, self.e))
|
|
|
|
class RSAobj_c(pubkey.pubkey):
|
|
keydata = ['n', 'e', 'd', 'p', 'q', 'u']
|
|
|
|
def __init__(self, key):
|
|
self.key = key
|
|
|
|
def __getattr__(self, attr):
|
|
if attr in self.keydata:
|
|
return getattr(self.key, attr)
|
|
else:
|
|
if self.__dict__.has_key(attr):
|
|
self.__dict__[attr]
|
|
else:
|
|
raise AttributeError, '%s instance has no attribute %s' % (self.__class__, attr)
|
|
|
|
def __getstate__(self):
|
|
d = {}
|
|
for k in self.keydata:
|
|
if hasattr(self.key, k):
|
|
d[k]=getattr(self.key, k)
|
|
return d
|
|
|
|
def __setstate__(self, state):
|
|
n,e = state['n'], state['e']
|
|
if not state.has_key('d'):
|
|
self.key = _fastmath.rsa_construct(n,e)
|
|
else:
|
|
d = state['d']
|
|
if not state.has_key('q'):
|
|
self.key = _fastmath.rsa_construct(n,e,d)
|
|
else:
|
|
p, q, u = state['p'], state['q'], state['u']
|
|
self.key = _fastmath.rsa_construct(n,e,d,p,q,u)
|
|
|
|
def _encrypt(self, plain, K):
|
|
return (self.key._encrypt(plain),)
|
|
|
|
def _decrypt(self, cipher):
|
|
return self.key._decrypt(cipher[0])
|
|
|
|
def _sign(self, M, K):
|
|
return (self.key._sign(M),)
|
|
|
|
def _verify(self, M, sig):
|
|
return self.key._verify(M, sig[0])
|
|
|
|
def _blind(self, M, B):
|
|
return self.key._blind(M, B)
|
|
|
|
def _unblind(self, M, B):
|
|
return self.key._unblind(M, B)
|
|
|
|
def can_blind (self):
|
|
return 1
|
|
|
|
def size(self):
|
|
return self.key.size()
|
|
|
|
def has_private(self):
|
|
return self.key.has_private()
|
|
|
|
def publickey(self):
|
|
return construct_c((self.key.n, self.key.e))
|
|
|
|
def generate_c(bits, randfunc, progress_func = None):
|
|
# Generate the prime factors of n
|
|
if progress_func:
|
|
progress_func('p,q\n')
|
|
|
|
p = q = 1L
|
|
while number.size(p*q) < bits:
|
|
p = pubkey.getPrime(bits/2, randfunc)
|
|
q = pubkey.getPrime(bits/2, randfunc)
|
|
|
|
# p shall be smaller than q (for calc of u)
|
|
if p > q:
|
|
(p, q)=(q, p)
|
|
if progress_func:
|
|
progress_func('u\n')
|
|
u=pubkey.inverse(p, q)
|
|
n=p*q
|
|
|
|
e = 65537L
|
|
if progress_func:
|
|
progress_func('d\n')
|
|
d=pubkey.inverse(e, (p-1)*(q-1))
|
|
key = _fastmath.rsa_construct(n,e,d,p,q,u)
|
|
obj = RSAobj_c(key)
|
|
|
|
## print p
|
|
## print q
|
|
## print number.size(p), number.size(q), number.size(q*p),
|
|
## print obj.size(), bits
|
|
assert bits <= 1+obj.size(), "Generated key is too small"
|
|
return obj
|
|
|
|
|
|
def construct_c(tuple):
|
|
key = apply(_fastmath.rsa_construct, tuple)
|
|
return RSAobj_c(key)
|
|
|
|
object = RSAobj
|
|
|
|
generate_py = generate
|
|
construct_py = construct
|
|
|
|
if _fastmath:
|
|
#print "using C version of RSA"
|
|
generate = generate_c
|
|
construct = construct_c
|
|
error = _fastmath.error
|