# -*- coding: utf-8 -*- # # PubKey/RSA/_slowmath.py : Pure Python implementation of the RSA portions of _fastmath # # Written in 2008 by Dwayne C. Litzenberger # # =================================================================== # 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. # =================================================================== """Pure Python implementation of the RSA-related portions of Crypto.PublicKey._fastmath.""" __revision__ = "$Id$" __all__ = ['rsa_construct'] import sys if sys.version_info[0] == 2 and sys.version_info[1] == 1: from Crypto.Util.py21compat import * from Crypto.Util.number import size, inverse, GCD class error(Exception): pass class _RSAKey(object): def _blind(self, m, r): # compute r**e * m (mod n) return m * pow(r, self.e, self.n) def _unblind(self, m, r): # compute m / r (mod n) return inverse(r, self.n) * m % self.n def _decrypt(self, c): # compute c**d (mod n) if not self.has_private(): raise TypeError("No private key") if (hasattr(self,'p') and hasattr(self,'q') and hasattr(self,'u')): m1 = pow(c, self.d % (self.p-1), self.p) m2 = pow(c, self.d % (self.q-1), self.q) h = m2 - m1 if (h<0): h = h + self.q h = h*self.u % self.q return h*self.p+m1 return pow(c, self.d, self.n) def _encrypt(self, m): # compute m**d (mod n) return pow(m, self.e, self.n) def _sign(self, m): # alias for _decrypt if not self.has_private(): raise TypeError("No private key") return self._decrypt(m) def _verify(self, m, sig): return self._encrypt(sig) == m def has_private(self): return hasattr(self, 'd') def size(self): """Return the maximum number of bits that can be encrypted""" return size(self.n) - 1 def rsa_construct(n, e, d=None, p=None, q=None, u=None): """Construct an RSAKey object""" assert isinstance(n, long) assert isinstance(e, long) assert isinstance(d, (long, type(None))) assert isinstance(p, (long, type(None))) assert isinstance(q, (long, type(None))) assert isinstance(u, (long, type(None))) obj = _RSAKey() obj.n = n obj.e = e if d is None: return obj obj.d = d if p is not None and q is not None: obj.p = p obj.q = q else: # Compute factors p and q from the private exponent d. # We assume that n has no more than two factors. # See 8.2.2(i) in Handbook of Applied Cryptography. ktot = d*e-1 # The quantity d*e-1 is a multiple of phi(n), even, # and can be represented as t*2^s. t = ktot while t%2==0: t=divmod(t,2)[0] # Cycle through all multiplicative inverses in Zn. # The algorithm is non-deterministic, but there is a 50% chance # any candidate a leads to successful factoring. # See "Digitalized Signatures and Public Key Functions as Intractable # as Factorization", M. Rabin, 1979 spotted = 0 a = 2 while not spotted and a<100: k = t # Cycle through all values a^{t*2^i}=a^k while k