mirror of
https://github.com/Legrandin/pycryptodome.git
synced 2025-10-27 03:34:37 +00:00
187 lines
6.3 KiB
Python
187 lines
6.3 KiB
Python
|
|
# -*- 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, "")
|
||
|
|
|
||
|
|
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)
|
||
|
|
|
||
|
|
def _sign(self, m):
|
||
|
|
return self.key._sign(m)
|
||
|
|
|
||
|
|
def _verify(self, m, sig):
|
||
|
|
return self.key._verify(m, sig)
|
||
|
|
|
||
|
|
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:
|
||
|
|
|