about summary refs log tree commit diff
path: root/.venv/lib/python3.12/site-packages/rsa/key.py
diff options
context:
space:
mode:
Diffstat (limited to '.venv/lib/python3.12/site-packages/rsa/key.py')
-rw-r--r--.venv/lib/python3.12/site-packages/rsa/key.py858
1 files changed, 858 insertions, 0 deletions
diff --git a/.venv/lib/python3.12/site-packages/rsa/key.py b/.venv/lib/python3.12/site-packages/rsa/key.py
new file mode 100644
index 00000000..b6b17f91
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/rsa/key.py
@@ -0,0 +1,858 @@
+#  Copyright 2011 Sybren A. Stüvel <sybren@stuvel.eu>

+#

+#  Licensed under the Apache License, Version 2.0 (the "License");

+#  you may not use this file except in compliance with the License.

+#  You may obtain a copy of the License at

+#

+#      https://www.apache.org/licenses/LICENSE-2.0

+#

+#  Unless required by applicable law or agreed to in writing, software

+#  distributed under the License is distributed on an "AS IS" BASIS,

+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+#  See the License for the specific language governing permissions and

+#  limitations under the License.

+

+"""RSA key generation code.

+

+Create new keys with the newkeys() function. It will give you a PublicKey and a

+PrivateKey object.

+

+Loading and saving keys requires the pyasn1 module. This module is imported as

+late as possible, such that other functionality will remain working in absence

+of pyasn1.

+

+.. note::

+

+    Storing public and private keys via the `pickle` module is possible.

+    However, it is insecure to load a key from an untrusted source.

+    The pickle module is not secure against erroneous or maliciously

+    constructed data. Never unpickle data received from an untrusted

+    or unauthenticated source.

+

+"""

+

+import threading

+import typing

+import warnings

+

+import rsa.prime

+import rsa.pem

+import rsa.common

+import rsa.randnum

+import rsa.core

+

+

+DEFAULT_EXPONENT = 65537

+

+

+T = typing.TypeVar("T", bound="AbstractKey")

+

+

+class AbstractKey:

+    """Abstract superclass for private and public keys."""

+

+    __slots__ = ("n", "e", "blindfac", "blindfac_inverse", "mutex")

+

+    def __init__(self, n: int, e: int) -> None:

+        self.n = n

+        self.e = e

+

+        # These will be computed properly on the first call to blind().

+        self.blindfac = self.blindfac_inverse = -1

+

+        # Used to protect updates to the blinding factor in multi-threaded

+        # environments.

+        self.mutex = threading.Lock()

+

+    @classmethod

+    def _load_pkcs1_pem(cls: typing.Type[T], keyfile: bytes) -> T:

+        """Loads a key in PKCS#1 PEM format, implement in a subclass.

+

+        :param keyfile: contents of a PEM-encoded file that contains

+            the public key.

+        :type keyfile: bytes

+

+        :return: the loaded key

+        :rtype: AbstractKey

+        """

+

+    @classmethod

+    def _load_pkcs1_der(cls: typing.Type[T], keyfile: bytes) -> T:

+        """Loads a key in PKCS#1 PEM format, implement in a subclass.

+

+        :param keyfile: contents of a DER-encoded file that contains

+            the public key.

+        :type keyfile: bytes

+

+        :return: the loaded key

+        :rtype: AbstractKey

+        """

+

+    def _save_pkcs1_pem(self) -> bytes:

+        """Saves the key in PKCS#1 PEM format, implement in a subclass.

+

+        :returns: the PEM-encoded key.

+        :rtype: bytes

+        """

+

+    def _save_pkcs1_der(self) -> bytes:

+        """Saves the key in PKCS#1 DER format, implement in a subclass.

+

+        :returns: the DER-encoded key.

+        :rtype: bytes

+        """

+

+    @classmethod

+    def load_pkcs1(cls: typing.Type[T], keyfile: bytes, format: str = "PEM") -> T:

+        """Loads a key in PKCS#1 DER or PEM format.

+

+        :param keyfile: contents of a DER- or PEM-encoded file that contains

+            the key.

+        :type keyfile: bytes

+        :param format: the format of the file to load; 'PEM' or 'DER'

+        :type format: str

+

+        :return: the loaded key

+        :rtype: AbstractKey

+        """

+

+        methods = {

+            "PEM": cls._load_pkcs1_pem,

+            "DER": cls._load_pkcs1_der,

+        }

+

+        method = cls._assert_format_exists(format, methods)

+        return method(keyfile)

+

+    @staticmethod

+    def _assert_format_exists(

+        file_format: str, methods: typing.Mapping[str, typing.Callable]

+    ) -> typing.Callable:

+        """Checks whether the given file format exists in 'methods'."""

+

+        try:

+            return methods[file_format]

+        except KeyError as ex:

+            formats = ", ".join(sorted(methods.keys()))

+            raise ValueError(

+                "Unsupported format: %r, try one of %s" % (file_format, formats)

+            ) from ex

+

+    def save_pkcs1(self, format: str = "PEM") -> bytes:

+        """Saves the key in PKCS#1 DER or PEM format.

+

+        :param format: the format to save; 'PEM' or 'DER'

+        :type format: str

+        :returns: the DER- or PEM-encoded key.

+        :rtype: bytes

+        """

+

+        methods = {

+            "PEM": self._save_pkcs1_pem,

+            "DER": self._save_pkcs1_der,

+        }

+

+        method = self._assert_format_exists(format, methods)

+        return method()

+

+    def blind(self, message: int) -> typing.Tuple[int, int]:

+        """Performs blinding on the message.

+

+        :param message: the message, as integer, to blind.

+        :param r: the random number to blind with.

+        :return: tuple (the blinded message, the inverse of the used blinding factor)

+

+        The blinding is such that message = unblind(decrypt(blind(encrypt(message))).

+

+        See https://en.wikipedia.org/wiki/Blinding_%28cryptography%29

+        """

+        blindfac, blindfac_inverse = self._update_blinding_factor()

+        blinded = (message * pow(blindfac, self.e, self.n)) % self.n

+        return blinded, blindfac_inverse

+

+    def unblind(self, blinded: int, blindfac_inverse: int) -> int:

+        """Performs blinding on the message using random number 'blindfac_inverse'.

+

+        :param blinded: the blinded message, as integer, to unblind.

+        :param blindfac: the factor to unblind with.

+        :return: the original message.

+

+        The blinding is such that message = unblind(decrypt(blind(encrypt(message))).

+

+        See https://en.wikipedia.org/wiki/Blinding_%28cryptography%29

+        """

+        return (blindfac_inverse * blinded) % self.n

+

+    def _initial_blinding_factor(self) -> int:

+        for _ in range(1000):

+            blind_r = rsa.randnum.randint(self.n - 1)

+            if rsa.prime.are_relatively_prime(self.n, blind_r):

+                return blind_r

+        raise RuntimeError("unable to find blinding factor")

+

+    def _update_blinding_factor(self) -> typing.Tuple[int, int]:

+        """Update blinding factors.

+

+        Computing a blinding factor is expensive, so instead this function

+        does this once, then updates the blinding factor as per section 9

+        of 'A Timing Attack against RSA with the Chinese Remainder Theorem'

+        by Werner Schindler.

+        See https://tls.mbed.org/public/WSchindler-RSA_Timing_Attack.pdf

+

+        :return: the new blinding factor and its inverse.

+        """

+

+        with self.mutex:

+            if self.blindfac < 0:

+                # Compute initial blinding factor, which is rather slow to do.

+                self.blindfac = self._initial_blinding_factor()

+                self.blindfac_inverse = rsa.common.inverse(self.blindfac, self.n)

+            else:

+                # Reuse previous blinding factor.

+                self.blindfac = pow(self.blindfac, 2, self.n)

+                self.blindfac_inverse = pow(self.blindfac_inverse, 2, self.n)

+

+            return self.blindfac, self.blindfac_inverse

+

+

+class PublicKey(AbstractKey):

+    """Represents a public RSA key.

+

+    This key is also known as the 'encryption key'. It contains the 'n' and 'e'

+    values.

+

+    Supports attributes as well as dictionary-like access. Attribute access is

+    faster, though.

+

+    >>> PublicKey(5, 3)

+    PublicKey(5, 3)

+

+    >>> key = PublicKey(5, 3)

+    >>> key.n

+    5

+    >>> key['n']

+    5

+    >>> key.e

+    3

+    >>> key['e']

+    3

+

+    """

+

+    __slots__ = ()

+

+    def __getitem__(self, key: str) -> int:

+        return getattr(self, key)

+

+    def __repr__(self) -> str:

+        return "PublicKey(%i, %i)" % (self.n, self.e)

+

+    def __getstate__(self) -> typing.Tuple[int, int]:

+        """Returns the key as tuple for pickling."""

+        return self.n, self.e

+

+    def __setstate__(self, state: typing.Tuple[int, int]) -> None:

+        """Sets the key from tuple."""

+        self.n, self.e = state

+        AbstractKey.__init__(self, self.n, self.e)

+

+    def __eq__(self, other: typing.Any) -> bool:

+        if other is None:

+            return False

+

+        if not isinstance(other, PublicKey):

+            return False

+

+        return self.n == other.n and self.e == other.e

+

+    def __ne__(self, other: typing.Any) -> bool:

+        return not (self == other)

+

+    def __hash__(self) -> int:

+        return hash((self.n, self.e))

+

+    @classmethod

+    def _load_pkcs1_der(cls, keyfile: bytes) -> "PublicKey":

+        """Loads a key in PKCS#1 DER format.

+

+        :param keyfile: contents of a DER-encoded file that contains the public

+            key.

+        :return: a PublicKey object

+

+        First let's construct a DER encoded key:

+

+        >>> import base64

+        >>> b64der = 'MAwCBQCNGmYtAgMBAAE='

+        >>> der = base64.standard_b64decode(b64der)

+

+        This loads the file:

+

+        >>> PublicKey._load_pkcs1_der(der)

+        PublicKey(2367317549, 65537)

+

+        """

+

+        from pyasn1.codec.der import decoder

+        from rsa.asn1 import AsnPubKey

+

+        (priv, _) = decoder.decode(keyfile, asn1Spec=AsnPubKey())

+        return cls(n=int(priv["modulus"]), e=int(priv["publicExponent"]))

+

+    def _save_pkcs1_der(self) -> bytes:

+        """Saves the public key in PKCS#1 DER format.

+

+        :returns: the DER-encoded public key.

+        :rtype: bytes

+        """

+

+        from pyasn1.codec.der import encoder

+        from rsa.asn1 import AsnPubKey

+

+        # Create the ASN object

+        asn_key = AsnPubKey()

+        asn_key.setComponentByName("modulus", self.n)

+        asn_key.setComponentByName("publicExponent", self.e)

+

+        return encoder.encode(asn_key)

+

+    @classmethod

+    def _load_pkcs1_pem(cls, keyfile: bytes) -> "PublicKey":

+        """Loads a PKCS#1 PEM-encoded public key file.

+

+        The contents of the file before the "-----BEGIN RSA PUBLIC KEY-----" and

+        after the "-----END RSA PUBLIC KEY-----" lines is ignored.

+

+        :param keyfile: contents of a PEM-encoded file that contains the public

+            key.

+        :return: a PublicKey object

+        """

+

+        der = rsa.pem.load_pem(keyfile, "RSA PUBLIC KEY")

+        return cls._load_pkcs1_der(der)

+

+    def _save_pkcs1_pem(self) -> bytes:

+        """Saves a PKCS#1 PEM-encoded public key file.

+

+        :return: contents of a PEM-encoded file that contains the public key.

+        :rtype: bytes

+        """

+

+        der = self._save_pkcs1_der()

+        return rsa.pem.save_pem(der, "RSA PUBLIC KEY")

+

+    @classmethod

+    def load_pkcs1_openssl_pem(cls, keyfile: bytes) -> "PublicKey":

+        """Loads a PKCS#1.5 PEM-encoded public key file from OpenSSL.

+

+        These files can be recognised in that they start with BEGIN PUBLIC KEY

+        rather than BEGIN RSA PUBLIC KEY.

+

+        The contents of the file before the "-----BEGIN PUBLIC KEY-----" and

+        after the "-----END PUBLIC KEY-----" lines is ignored.

+

+        :param keyfile: contents of a PEM-encoded file that contains the public

+            key, from OpenSSL.

+        :type keyfile: bytes

+        :return: a PublicKey object

+        """

+

+        der = rsa.pem.load_pem(keyfile, "PUBLIC KEY")

+        return cls.load_pkcs1_openssl_der(der)

+

+    @classmethod

+    def load_pkcs1_openssl_der(cls, keyfile: bytes) -> "PublicKey":

+        """Loads a PKCS#1 DER-encoded public key file from OpenSSL.

+

+        :param keyfile: contents of a DER-encoded file that contains the public

+            key, from OpenSSL.

+        :return: a PublicKey object

+        """

+

+        from rsa.asn1 import OpenSSLPubKey

+        from pyasn1.codec.der import decoder

+        from pyasn1.type import univ

+

+        (keyinfo, _) = decoder.decode(keyfile, asn1Spec=OpenSSLPubKey())

+

+        if keyinfo["header"]["oid"] != univ.ObjectIdentifier("1.2.840.113549.1.1.1"):

+            raise TypeError("This is not a DER-encoded OpenSSL-compatible public key")

+

+        return cls._load_pkcs1_der(keyinfo["key"][1:])

+

+

+class PrivateKey(AbstractKey):

+    """Represents a private RSA key.

+

+    This key is also known as the 'decryption key'. It contains the 'n', 'e',

+    'd', 'p', 'q' and other values.

+

+    Supports attributes as well as dictionary-like access. Attribute access is

+    faster, though.

+

+    >>> PrivateKey(3247, 65537, 833, 191, 17)

+    PrivateKey(3247, 65537, 833, 191, 17)

+

+    exp1, exp2 and coef will be calculated:

+

+    >>> pk = PrivateKey(3727264081, 65537, 3349121513, 65063, 57287)

+    >>> pk.exp1

+    55063

+    >>> pk.exp2

+    10095

+    >>> pk.coef

+    50797

+

+    """

+

+    __slots__ = ("d", "p", "q", "exp1", "exp2", "coef")

+

+    def __init__(self, n: int, e: int, d: int, p: int, q: int) -> None:

+        AbstractKey.__init__(self, n, e)

+        self.d = d

+        self.p = p

+        self.q = q

+

+        # Calculate exponents and coefficient.

+        self.exp1 = int(d % (p - 1))

+        self.exp2 = int(d % (q - 1))

+        self.coef = rsa.common.inverse(q, p)

+

+    def __getitem__(self, key: str) -> int:

+        return getattr(self, key)

+

+    def __repr__(self) -> str:

+        return "PrivateKey(%i, %i, %i, %i, %i)" % (

+            self.n,

+            self.e,

+            self.d,

+            self.p,

+            self.q,

+        )

+

+    def __getstate__(self) -> typing.Tuple[int, int, int, int, int, int, int, int]:

+        """Returns the key as tuple for pickling."""

+        return self.n, self.e, self.d, self.p, self.q, self.exp1, self.exp2, self.coef

+

+    def __setstate__(self, state: typing.Tuple[int, int, int, int, int, int, int, int]) -> None:

+        """Sets the key from tuple."""

+        self.n, self.e, self.d, self.p, self.q, self.exp1, self.exp2, self.coef = state

+        AbstractKey.__init__(self, self.n, self.e)

+

+    def __eq__(self, other: typing.Any) -> bool:

+        if other is None:

+            return False

+

+        if not isinstance(other, PrivateKey):

+            return False

+

+        return (

+            self.n == other.n

+            and self.e == other.e

+            and self.d == other.d

+            and self.p == other.p

+            and self.q == other.q

+            and self.exp1 == other.exp1

+            and self.exp2 == other.exp2

+            and self.coef == other.coef

+        )

+

+    def __ne__(self, other: typing.Any) -> bool:

+        return not (self == other)

+

+    def __hash__(self) -> int:

+        return hash((self.n, self.e, self.d, self.p, self.q, self.exp1, self.exp2, self.coef))

+

+    def blinded_decrypt(self, encrypted: int) -> int:

+        """Decrypts the message using blinding to prevent side-channel attacks.

+

+        :param encrypted: the encrypted message

+        :type encrypted: int

+

+        :returns: the decrypted message

+        :rtype: int

+        """

+

+        # Blinding and un-blinding should be using the same factor

+        blinded, blindfac_inverse = self.blind(encrypted)

+

+        # Instead of using the core functionality, use the Chinese Remainder

+        # Theorem and be 2-4x faster. This the same as:

+        #

+        # decrypted = rsa.core.decrypt_int(blinded, self.d, self.n)

+        s1 = pow(blinded, self.exp1, self.p)

+        s2 = pow(blinded, self.exp2, self.q)

+        h = ((s1 - s2) * self.coef) % self.p

+        decrypted = s2 + self.q * h

+

+        return self.unblind(decrypted, blindfac_inverse)

+

+    def blinded_encrypt(self, message: int) -> int:

+        """Encrypts the message using blinding to prevent side-channel attacks.

+

+        :param message: the message to encrypt

+        :type message: int

+

+        :returns: the encrypted message

+        :rtype: int

+        """

+

+        blinded, blindfac_inverse = self.blind(message)

+        encrypted = rsa.core.encrypt_int(blinded, self.d, self.n)

+        return self.unblind(encrypted, blindfac_inverse)

+

+    @classmethod

+    def _load_pkcs1_der(cls, keyfile: bytes) -> "PrivateKey":

+        """Loads a key in PKCS#1 DER format.

+

+        :param keyfile: contents of a DER-encoded file that contains the private

+            key.

+        :type keyfile: bytes

+        :return: a PrivateKey object

+

+        First let's construct a DER encoded key:

+

+        >>> import base64

+        >>> b64der = 'MC4CAQACBQDeKYlRAgMBAAECBQDHn4npAgMA/icCAwDfxwIDANcXAgInbwIDAMZt'

+        >>> der = base64.standard_b64decode(b64der)

+

+        This loads the file:

+

+        >>> PrivateKey._load_pkcs1_der(der)

+        PrivateKey(3727264081, 65537, 3349121513, 65063, 57287)

+

+        """

+

+        from pyasn1.codec.der import decoder

+

+        (priv, _) = decoder.decode(keyfile)

+

+        # ASN.1 contents of DER encoded private key:

+        #

+        # RSAPrivateKey ::= SEQUENCE {

+        #     version           Version,

+        #     modulus           INTEGER,  -- n

+        #     publicExponent    INTEGER,  -- e

+        #     privateExponent   INTEGER,  -- d

+        #     prime1            INTEGER,  -- p

+        #     prime2            INTEGER,  -- q

+        #     exponent1         INTEGER,  -- d mod (p-1)

+        #     exponent2         INTEGER,  -- d mod (q-1)

+        #     coefficient       INTEGER,  -- (inverse of q) mod p

+        #     otherPrimeInfos   OtherPrimeInfos OPTIONAL

+        # }

+

+        if priv[0] != 0:

+            raise ValueError("Unable to read this file, version %s != 0" % priv[0])

+

+        as_ints = map(int, priv[1:6])

+        key = cls(*as_ints)

+

+        exp1, exp2, coef = map(int, priv[6:9])

+

+        if (key.exp1, key.exp2, key.coef) != (exp1, exp2, coef):

+            warnings.warn(

+                "You have provided a malformed keyfile. Either the exponents "

+                "or the coefficient are incorrect. Using the correct values "

+                "instead.",

+                UserWarning,

+            )

+

+        return key

+

+    def _save_pkcs1_der(self) -> bytes:

+        """Saves the private key in PKCS#1 DER format.

+

+        :returns: the DER-encoded private key.

+        :rtype: bytes

+        """

+

+        from pyasn1.type import univ, namedtype

+        from pyasn1.codec.der import encoder

+

+        class AsnPrivKey(univ.Sequence):

+            componentType = namedtype.NamedTypes(

+                namedtype.NamedType("version", univ.Integer()),

+                namedtype.NamedType("modulus", univ.Integer()),

+                namedtype.NamedType("publicExponent", univ.Integer()),

+                namedtype.NamedType("privateExponent", univ.Integer()),

+                namedtype.NamedType("prime1", univ.Integer()),

+                namedtype.NamedType("prime2", univ.Integer()),

+                namedtype.NamedType("exponent1", univ.Integer()),

+                namedtype.NamedType("exponent2", univ.Integer()),

+                namedtype.NamedType("coefficient", univ.Integer()),

+            )

+

+        # Create the ASN object

+        asn_key = AsnPrivKey()

+        asn_key.setComponentByName("version", 0)

+        asn_key.setComponentByName("modulus", self.n)

+        asn_key.setComponentByName("publicExponent", self.e)

+        asn_key.setComponentByName("privateExponent", self.d)

+        asn_key.setComponentByName("prime1", self.p)

+        asn_key.setComponentByName("prime2", self.q)

+        asn_key.setComponentByName("exponent1", self.exp1)

+        asn_key.setComponentByName("exponent2", self.exp2)

+        asn_key.setComponentByName("coefficient", self.coef)

+

+        return encoder.encode(asn_key)

+

+    @classmethod

+    def _load_pkcs1_pem(cls, keyfile: bytes) -> "PrivateKey":

+        """Loads a PKCS#1 PEM-encoded private key file.

+

+        The contents of the file before the "-----BEGIN RSA PRIVATE KEY-----" and

+        after the "-----END RSA PRIVATE KEY-----" lines is ignored.

+

+        :param keyfile: contents of a PEM-encoded file that contains the private

+            key.

+        :type keyfile: bytes

+        :return: a PrivateKey object

+        """

+

+        der = rsa.pem.load_pem(keyfile, b"RSA PRIVATE KEY")

+        return cls._load_pkcs1_der(der)

+

+    def _save_pkcs1_pem(self) -> bytes:

+        """Saves a PKCS#1 PEM-encoded private key file.

+

+        :return: contents of a PEM-encoded file that contains the private key.

+        :rtype: bytes

+        """

+

+        der = self._save_pkcs1_der()

+        return rsa.pem.save_pem(der, b"RSA PRIVATE KEY")

+

+

+def find_p_q(

+    nbits: int,

+    getprime_func: typing.Callable[[int], int] = rsa.prime.getprime,

+    accurate: bool = True,

+) -> typing.Tuple[int, int]:

+    """Returns a tuple of two different primes of nbits bits each.

+

+    The resulting p * q has exactly 2 * nbits bits, and the returned p and q

+    will not be equal.

+

+    :param nbits: the number of bits in each of p and q.

+    :param getprime_func: the getprime function, defaults to

+        :py:func:`rsa.prime.getprime`.

+

+        *Introduced in Python-RSA 3.1*

+

+    :param accurate: whether to enable accurate mode or not.

+    :returns: (p, q), where p > q

+

+    >>> (p, q) = find_p_q(128)

+    >>> from rsa import common

+    >>> common.bit_size(p * q)

+    256

+

+    When not in accurate mode, the number of bits can be slightly less

+

+    >>> (p, q) = find_p_q(128, accurate=False)

+    >>> from rsa import common

+    >>> common.bit_size(p * q) <= 256

+    True

+    >>> common.bit_size(p * q) > 240

+    True

+

+    """

+

+    total_bits = nbits * 2

+

+    # Make sure that p and q aren't too close or the factoring programs can

+    # factor n.

+    shift = nbits // 16

+    pbits = nbits + shift

+    qbits = nbits - shift

+

+    # Choose the two initial primes

+    p = getprime_func(pbits)

+    q = getprime_func(qbits)

+

+    def is_acceptable(p: int, q: int) -> bool:

+        """Returns True iff p and q are acceptable:

+

+        - p and q differ

+        - (p * q) has the right nr of bits (when accurate=True)

+        """

+

+        if p == q:

+            return False

+

+        if not accurate:

+            return True

+

+        # Make sure we have just the right amount of bits

+        found_size = rsa.common.bit_size(p * q)

+        return total_bits == found_size

+

+    # Keep choosing other primes until they match our requirements.

+    change_p = False

+    while not is_acceptable(p, q):

+        # Change p on one iteration and q on the other

+        if change_p:

+            p = getprime_func(pbits)

+        else:

+            q = getprime_func(qbits)

+

+        change_p = not change_p

+

+    # We want p > q as described on

+    # http://www.di-mgt.com.au/rsa_alg.html#crt

+    return max(p, q), min(p, q)

+

+

+def calculate_keys_custom_exponent(p: int, q: int, exponent: int) -> typing.Tuple[int, int]:

+    """Calculates an encryption and a decryption key given p, q and an exponent,

+    and returns them as a tuple (e, d)

+

+    :param p: the first large prime

+    :param q: the second large prime

+    :param exponent: the exponent for the key; only change this if you know

+        what you're doing, as the exponent influences how difficult your

+        private key can be cracked. A very common choice for e is 65537.

+    :type exponent: int

+

+    """

+

+    phi_n = (p - 1) * (q - 1)

+

+    try:

+        d = rsa.common.inverse(exponent, phi_n)

+    except rsa.common.NotRelativePrimeError as ex:

+        raise rsa.common.NotRelativePrimeError(

+            exponent,

+            phi_n,

+            ex.d,

+            msg="e (%d) and phi_n (%d) are not relatively prime (divider=%i)"

+            % (exponent, phi_n, ex.d),

+        ) from ex

+

+    if (exponent * d) % phi_n != 1:

+        raise ValueError(

+            "e (%d) and d (%d) are not mult. inv. modulo " "phi_n (%d)" % (exponent, d, phi_n)

+        )

+

+    return exponent, d

+

+

+def calculate_keys(p: int, q: int) -> typing.Tuple[int, int]:

+    """Calculates an encryption and a decryption key given p and q, and

+    returns them as a tuple (e, d)

+

+    :param p: the first large prime

+    :param q: the second large prime

+

+    :return: tuple (e, d) with the encryption and decryption exponents.

+    """

+

+    return calculate_keys_custom_exponent(p, q, DEFAULT_EXPONENT)

+

+

+def gen_keys(

+    nbits: int,

+    getprime_func: typing.Callable[[int], int],

+    accurate: bool = True,

+    exponent: int = DEFAULT_EXPONENT,

+) -> typing.Tuple[int, int, int, int]:

+    """Generate RSA keys of nbits bits. Returns (p, q, e, d).

+

+    Note: this can take a long time, depending on the key size.

+

+    :param nbits: the total number of bits in ``p`` and ``q``. Both ``p`` and

+        ``q`` will use ``nbits/2`` bits.

+    :param getprime_func: either :py:func:`rsa.prime.getprime` or a function

+        with similar signature.

+    :param exponent: the exponent for the key; only change this if you know

+        what you're doing, as the exponent influences how difficult your

+        private key can be cracked. A very common choice for e is 65537.

+    :type exponent: int

+    """

+

+    # Regenerate p and q values, until calculate_keys doesn't raise a

+    # ValueError.

+    while True:

+        (p, q) = find_p_q(nbits // 2, getprime_func, accurate)

+        try:

+            (e, d) = calculate_keys_custom_exponent(p, q, exponent=exponent)

+            break

+        except ValueError:

+            pass

+

+    return p, q, e, d

+

+

+def newkeys(

+    nbits: int,

+    accurate: bool = True,

+    poolsize: int = 1,

+    exponent: int = DEFAULT_EXPONENT,

+) -> typing.Tuple[PublicKey, PrivateKey]:

+    """Generates public and private keys, and returns them as (pub, priv).

+

+    The public key is also known as the 'encryption key', and is a

+    :py:class:`rsa.PublicKey` object. The private key is also known as the

+    'decryption key' and is a :py:class:`rsa.PrivateKey` object.

+

+    :param nbits: the number of bits required to store ``n = p*q``.

+    :param accurate: when True, ``n`` will have exactly the number of bits you

+        asked for. However, this makes key generation much slower. When False,

+        `n`` may have slightly less bits.

+    :param poolsize: the number of processes to use to generate the prime

+        numbers. If set to a number > 1, a parallel algorithm will be used.

+        This requires Python 2.6 or newer.

+    :param exponent: the exponent for the key; only change this if you know

+        what you're doing, as the exponent influences how difficult your

+        private key can be cracked. A very common choice for e is 65537.

+    :type exponent: int

+

+    :returns: a tuple (:py:class:`rsa.PublicKey`, :py:class:`rsa.PrivateKey`)

+

+    The ``poolsize`` parameter was added in *Python-RSA 3.1* and requires

+    Python 2.6 or newer.

+

+    """

+

+    if nbits < 16:

+        raise ValueError("Key too small")

+

+    if poolsize < 1:

+        raise ValueError("Pool size (%i) should be >= 1" % poolsize)

+

+    # Determine which getprime function to use

+    if poolsize > 1:

+        from rsa import parallel

+

+        def getprime_func(nbits: int) -> int:

+            return parallel.getprime(nbits, poolsize=poolsize)

+

+    else:

+        getprime_func = rsa.prime.getprime

+

+    # Generate the key components

+    (p, q, e, d) = gen_keys(nbits, getprime_func, accurate=accurate, exponent=exponent)

+

+    # Create the key objects

+    n = p * q

+

+    return (PublicKey(n, e), PrivateKey(n, e, d, p, q))

+

+

+__all__ = ["PublicKey", "PrivateKey", "newkeys"]

+

+if __name__ == "__main__":

+    import doctest

+

+    try:

+        for count in range(100):

+            (failures, tests) = doctest.testmod()

+            if failures:

+                break

+

+            if (count % 10 == 0 and count) or count == 1:

+                print("%i times" % count)

+    except KeyboardInterrupt:

+        print("Aborted")

+    else:

+        print("Doctests done")