mirror of
https://github.com/apprenticeharper/DeDRM_tools
synced 2025-02-08 08:46:21 +01:00
184 lines
6 KiB
Python
184 lines
6 KiB
Python
# -*- coding: utf-8 -*-
|
|
#
|
|
# PublicKey/RSA.py : RSA public key primitive
|
|
#
|
|
# Written in 2008 by Dwayne C. Litzenberger <dlitz@dlitz.net>
|
|
#
|
|
# ===================================================================
|
|
# 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:
|
|
|