# -*- coding: utf-8 -*- # # PublicKey/RSA.py : RSA public key primitive # # 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. # =================================================================== """RSA public-key cryptography algorithm.""" __revision__ = "$Id$" __all__ = ['generate', 'construct', 'error'] from Crypto.Util.python_compat import * from Crypto.PublicKey import _RSA, _slowmath, pubkey from Crypto import Random try: from Crypto.PublicKey import _fastmath except ImportError: _fastmath = None class _RSAobj(pubkey.pubkey): keydata = ['n', 'e', 'd', 'p', 'q', 'u'] def __init__(self, implementation, key): self.implementation = implementation self.key = key def __getattr__(self, attrname): if attrname in self.keydata: # For backward compatibility, allow the user to get (not set) the # RSA key parameters directly from this object. return getattr(self.key, attrname) else: raise AttributeError("%s object has no %r attribute" % (self.__class__.__name__, attrname,)) def _encrypt(self, c, K): return (self.key._encrypt(c),) def _decrypt(self, c): #(ciphertext,) = c (ciphertext,) = c[:1] # HACK - We should use the previous line # instead, but this is more compatible and we're # going to replace the Crypto.PublicKey API soon # anyway. return self.key._decrypt(ciphertext) def _blind(self, m, r): return self.key._blind(m, r) def _unblind(self, m, r): return self.key._unblind(m, r) def _sign(self, m, K=None): return (self.key._sign(m),) def _verify(self, m, sig): #(s,) = sig (s,) = sig[:1] # HACK - We should use the previous line instead, but # this is more compatible and we're going to replace # the Crypto.PublicKey API soon anyway. return self.key._verify(m, s) def has_private(self): return self.key.has_private() def size(self): return self.key.size() def can_blind(self): return True def can_encrypt(self): return True def can_sign(self): return True def publickey(self): return self.implementation.construct((self.key.n, self.key.e)) def __getstate__(self): d = {} for k in self.keydata: try: d[k] = getattr(self.key, k) except AttributeError: pass return d def __setstate__(self, d): if not hasattr(self, 'implementation'): self.implementation = RSAImplementation() t = [] for k in self.keydata: if not d.has_key(k): break t.append(d[k]) self.key = self.implementation._math.rsa_construct(*tuple(t)) def __repr__(self): attrs = [] for k in self.keydata: if k == 'n': attrs.append("n(%d)" % (self.size()+1,)) elif hasattr(self.key, k): attrs.append(k) if self.has_private(): attrs.append("private") return "<%s @0x%x %s>" % (self.__class__.__name__, id(self), ",".join(attrs)) class RSAImplementation(object): def __init__(self, **kwargs): # 'use_fast_math' parameter: # None (default) - Use fast math if available; Use slow math if not. # True - Use fast math, and raise RuntimeError if it's not available. # False - Use slow math. use_fast_math = kwargs.get('use_fast_math', None) if use_fast_math is None: # Automatic if _fastmath is not None: self._math = _fastmath else: self._math = _slowmath elif use_fast_math: # Explicitly select fast math if _fastmath is not None: self._math = _fastmath else: raise RuntimeError("fast math module not available") else: # Explicitly select slow math self._math = _slowmath self.error = self._math.error # 'default_randfunc' parameter: # None (default) - use Random.new().read # not None - use the specified function self._default_randfunc = kwargs.get('default_randfunc', None) self._current_randfunc = None def _get_randfunc(self, randfunc): if randfunc is not None: return randfunc elif self._current_randfunc is None: self._current_randfunc = Random.new().read return self._current_randfunc def generate(self, bits, randfunc=None, progress_func=None): rf = self._get_randfunc(randfunc) obj = _RSA.generate_py(bits, rf, progress_func) # TODO: Don't use legacy _RSA module key = self._math.rsa_construct(obj.n, obj.e, obj.d, obj.p, obj.q, obj.u) return _RSAobj(self, key) def construct(self, tup): key = self._math.rsa_construct(*tup) return _RSAobj(self, key) _impl = RSAImplementation() generate = _impl.generate construct = _impl.construct error = _impl.error # vim:set ts=4 sw=4 sts=4 expandtab: