# # 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