| 
									
										
										
										
											2008-09-18 21:42:28 -04:00
										 |  |  | # -*- coding: utf-8 -*- | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | #  PublicKey/RSA.py : RSA public key primitive | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # Copyright (C) 2008  Dwayne C. Litzenberger <dlitz@dlitz.net> | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # ======================================================================= | 
					
						
							|  |  |  | # Permission is hereby granted, free of charge, to any person obtaining | 
					
						
							|  |  |  | # a copy of this software and associated documentation files (the | 
					
						
							|  |  |  | # "Software"), to deal in the Software without restriction, including | 
					
						
							|  |  |  | # without limitation the rights to use, copy, modify, merge, publish, | 
					
						
							|  |  |  | # distribute, sublicense, and/or sell copies of the Software, and to | 
					
						
							|  |  |  | # permit persons to whom the Software is furnished to do so. | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | 
					
						
							|  |  |  | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | 
					
						
							|  |  |  | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | 
					
						
							|  |  |  | # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | 
					
						
							|  |  |  | # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 
					
						
							|  |  |  | # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 
					
						
							|  |  |  | # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 
					
						
							|  |  |  | # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 
					
						
							|  |  |  | # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 
					
						
							|  |  |  | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 
					
						
							|  |  |  | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 
					
						
							|  |  |  | # ======================================================================= | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | """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 | 
					
						
							|  |  |  | from Crypto.pct_warnings import PublicKey_KParam_DeprecationWarning | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 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, plaintext, K=None): | 
					
						
							|  |  |  |         if K: | 
					
						
							|  |  |  |             # New code should specify only one parameter to .encrypt | 
					
						
							|  |  |  |             warnings.warn("rsaObj.encrypt: unnecessray second parameter specified", PublicKey_KParam_DeprecationWarning) | 
					
						
							|  |  |  |         return pubkey.pubkey.encrypt(self, plaintext, "") | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-10-18 20:20:49 -04:00
										 |  |  |     def sign(self, message, K=None): | 
					
						
							|  |  |  |         if K: | 
					
						
							|  |  |  |             # New code should specify only one parameter to .encrypt | 
					
						
							|  |  |  |             warnings.warn("rsaObj.sign: unnecessray second parameter specified", PublicKey_KParam_DeprecationWarning) | 
					
						
							|  |  |  |         return pubkey.pubkey.sign(self, message, "") | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-09-18 21:42:28 -04:00
										 |  |  |     def _encrypt(self, c, K=None): | 
					
						
							|  |  |  |         return (self.key._encrypt(c),) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def _decrypt(self, c): | 
					
						
							|  |  |  |         (ciphertext,) = c | 
					
						
							|  |  |  |         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) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-10-18 20:20:49 -04:00
										 |  |  |     def _sign(self, m, K=None): | 
					
						
							|  |  |  |         return (self.key._sign(m),) | 
					
						
							| 
									
										
										
										
											2008-09-18 21:42:28 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def _verify(self, m, sig): | 
					
						
							| 
									
										
										
										
											2008-10-18 20:20:49 -04:00
										 |  |  |         (s,) = sig | 
					
						
							|  |  |  |         return self.key._verify(m, s) | 
					
						
							| 
									
										
										
										
											2008-09-18 21:42:28 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |     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: | 
					
						
							|  |  |  | 
 |