pycryptodome/lib/Crypto/PublicKey/RSA.py

188 lines
6.4 KiB
Python
Raw Normal View History

# -*- 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
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)
2008-10-18 20:20:49 -04:00
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.
2008-10-18 20:20:49 -04:00
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: