Source code for tlslite.utils.python_rsakey

# Author: Trevor Perrin
# See the LICENSE file for legal information regarding use of this file.

"""Pure-Python RSA implementation."""
import threading
from .cryptomath import *
from .rsakey import *
from .pem import *
from .deprecations import deprecated_params
if GMPY2_LOADED:
    from gmpy2 import mpz
elif gmpyLoaded:
    from gmpy import mpz

[docs] class Python_RSAKey(RSAKey):
[docs] def __init__(self, n=0, e=0, d=0, p=0, q=0, dP=0, dQ=0, qInv=0, key_type="rsa"): """Initialise key directly from integers. see also generate() and parsePEM().""" if (n and not e) or (e and not n): raise AssertionError() if gmpyLoaded or GMPY2_LOADED: n = mpz(n) e = mpz(e) d = mpz(d) p = mpz(p) q = mpz(q) dP = mpz(dP) dQ = mpz(dQ) qInv = mpz(qInv) self.n = n self.e = e if p and not q or not p and q: raise ValueError("p and q must be set or left unset together") if not d and p and q: t = lcm(p - 1, q - 1) d = invMod(e, t) self.d = d self.p = p self.q = q if not dP and p: dP = d % (p - 1) self.dP = dP if not dQ and q: dQ = d % (q - 1) self.dQ = dQ if not qInv: qInv = invMod(q, p) self.qInv = qInv self.blinder = 0 self.unblinder = 0 self._lock = threading.Lock() self.key_type = key_type
[docs] def hasPrivateKey(self): """ Does the key has the associated private key (True) or is it only the public part (False). """ return self.d != 0
def _rawPrivateKeyOp(self, message): n = self.n with self._lock: # Create blinding values, on the first pass: if not self.blinder: self.unblinder = getRandomNumber(2, n) self.blinder = powMod(invMod(self.unblinder, n), self.e, n) unblinder = self.unblinder blinder = self.blinder # Update blinding values self.blinder = (blinder * blinder) % n self.unblinder = (unblinder * unblinder) % n # Blind the input message = (message * blinder) % n # Perform the RSA operation cipher = self._rawPrivateKeyOpHelper(message) # Unblind the output cipher = (cipher * unblinder) % n # Return the output return cipher def _rawPrivateKeyOpHelper(self, m): #Non-CRT version #c = pow(m, self.d, self.n) #CRT version (~3x faster). p, q = self.p, self.q s1 = pow(m, self.dP, p) s2 = pow(m, self.dQ, q) h = ((s1 - s2) * self.qInv) % p c = s2 + q * h return c def _rawPublicKeyOp(self, ciphertext): msg = pow(ciphertext, self.e, self.n) return msg
[docs] def acceptsPassword(self): """Does it support encrypted key files.""" return False
[docs] @staticmethod def generate(bits, key_type="rsa"): """Generate a private key with modulus 'bits' bit big. key_type can be "rsa" for a universal rsaEncryption key or "rsa-pss" for a key that can be used only for RSASSA-PSS.""" # p, q, and t are standard names for the variables in RSA, so # ignore the fact those are one character long variable names # pylint: disable=invalid-name key = Python_RSAKey() while True: p = getRandomPrime(bits//2, False) q = getRandomPrime(bits//2, False) if gmpyLoaded or GMPY2_LOADED: p = mpz(p) q = mpz(q) t = lcm(p-1, q-1) # since we need to calculate inverse of 65537 mod t, they # must be relatively prime (coprime) if gcd(t, 65537) == 1: break key.n = p * q if gmpyLoaded or GMPY2_LOADED: key.e = mpz(65537) else: key.e = 65537 key.d = invMod(key.e, t) key.p = p key.q = q key.dP = key.d % (p-1) key.dQ = key.d % (q-1) key.qInv = invMod(q, p) key.key_type = key_type # pylint: enable=invalid-name return key
[docs] @staticmethod @deprecated_params({"data": "s", "password_callback": "passwordCallback"}) def parsePEM(data, password_callback=None): """Parse a string containing a PEM-encoded <privateKey>.""" from .python_key import Python_Key return Python_Key.parsePEM(data, password_callback)