Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
key.py859 linesDownload Raw Back to rsa
1#  Copyright 2011 Sybren A. Stüvel <sybren@stuvel.eu>
2#
3#  Licensed under the Apache License, Version 2.0 (the "License");
4#  you may not use this file except in compliance with the License.
5#  You may obtain a copy of the License at
6#
7#      https://www.apache.org/licenses/LICENSE-2.0
8#
9#  Unless required by applicable law or agreed to in writing, software
10#  distributed under the License is distributed on an "AS IS" BASIS,
11#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12#  See the License for the specific language governing permissions and
13#  limitations under the License.
14
15"""RSA key generation code.
16
17Create new keys with the newkeys() function. It will give you a PublicKey and a
18PrivateKey object.
19
20Loading and saving keys requires the pyasn1 module. This module is imported as
21late as possible, such that other functionality will remain working in absence
22of pyasn1.
23
24.. note::
25
26    Storing public and private keys via the `pickle` module is possible.
27    However, it is insecure to load a key from an untrusted source.
28    The pickle module is not secure against erroneous or maliciously
29    constructed data. Never unpickle data received from an untrusted
30    or unauthenticated source.
31
32"""
33
34import threading
35import typing
36import warnings
37
38import rsa.prime
39import rsa.pem
40import rsa.common
41import rsa.randnum
42import rsa.core
43
44
45DEFAULT_EXPONENT = 65537
46
47
48T = typing.TypeVar("T", bound="AbstractKey")
49
50
51class AbstractKey:
52    """Abstract superclass for private and public keys."""
53
54    __slots__ = ("n", "e", "blindfac", "blindfac_inverse", "mutex")
55
56    def __init__(self, n: int, e: int) -> None:
57        self.n = n
58        self.e = e
59
60        # These will be computed properly on the first call to blind().
61        self.blindfac = self.blindfac_inverse = -1
62
63        # Used to protect updates to the blinding factor in multi-threaded
64        # environments.
65        self.mutex = threading.Lock()
66
67    @classmethod
68    def _load_pkcs1_pem(cls: typing.Type[T], keyfile: bytes) -> T:
69        """Loads a key in PKCS#1 PEM format, implement in a subclass.
70
71        :param keyfile: contents of a PEM-encoded file that contains
72            the public key.
73        :type keyfile: bytes
74
75        :return: the loaded key
76        :rtype: AbstractKey
77        """
78
79    @classmethod
80    def _load_pkcs1_der(cls: typing.Type[T], keyfile: bytes) -> T:
81        """Loads a key in PKCS#1 PEM format, implement in a subclass.
82
83        :param keyfile: contents of a DER-encoded file that contains
84            the public key.
85        :type keyfile: bytes
86
87        :return: the loaded key
88        :rtype: AbstractKey
89        """
90
91    def _save_pkcs1_pem(self) -> bytes:
92        """Saves the key in PKCS#1 PEM format, implement in a subclass.
93
94        :returns: the PEM-encoded key.
95        :rtype: bytes
96        """
97
98    def _save_pkcs1_der(self) -> bytes:
99        """Saves the key in PKCS#1 DER format, implement in a subclass.
100
101        :returns: the DER-encoded key.
102        :rtype: bytes
103        """
104
105    @classmethod
106    def load_pkcs1(cls: typing.Type[T], keyfile: bytes, format: str = "PEM") -> T:
107        """Loads a key in PKCS#1 DER or PEM format.
108
109        :param keyfile: contents of a DER- or PEM-encoded file that contains
110            the key.
111        :type keyfile: bytes
112        :param format: the format of the file to load; 'PEM' or 'DER'
113        :type format: str
114
115        :return: the loaded key
116        :rtype: AbstractKey
117        """
118
119        methods = {
120            "PEM": cls._load_pkcs1_pem,
121            "DER": cls._load_pkcs1_der,
122        }
123
124        method = cls._assert_format_exists(format, methods)
125        return method(keyfile)
126
127    @staticmethod
128    def _assert_format_exists(
129        file_format: str, methods: typing.Mapping[str, typing.Callable]
130    ) -> typing.Callable:
131        """Checks whether the given file format exists in 'methods'."""
132
133        try:
134            return methods[file_format]
135        except KeyError as ex:
136            formats = ", ".join(sorted(methods.keys()))
137            raise ValueError(
138                "Unsupported format: %r, try one of %s" % (file_format, formats)
139            ) from ex
140
141    def save_pkcs1(self, format: str = "PEM") -> bytes:
142        """Saves the key in PKCS#1 DER or PEM format.
143
144        :param format: the format to save; 'PEM' or 'DER'
145        :type format: str
146        :returns: the DER- or PEM-encoded key.
147        :rtype: bytes
148        """
149
150        methods = {
151            "PEM": self._save_pkcs1_pem,
152            "DER": self._save_pkcs1_der,
153        }
154
155        method = self._assert_format_exists(format, methods)
156        return method()
157
158    def blind(self, message: int) -> typing.Tuple[int, int]:
159        """Performs blinding on the message.
160
161        :param message: the message, as integer, to blind.
162        :param r: the random number to blind with.
163        :return: tuple (the blinded message, the inverse of the used blinding factor)
164
165        The blinding is such that message = unblind(decrypt(blind(encrypt(message))).
166
167        See https://en.wikipedia.org/wiki/Blinding_%28cryptography%29
168        """
169        blindfac, blindfac_inverse = self._update_blinding_factor()
170        blinded = (message * pow(blindfac, self.e, self.n)) % self.n
171        return blinded, blindfac_inverse
172
173    def unblind(self, blinded: int, blindfac_inverse: int) -> int:
174        """Performs blinding on the message using random number 'blindfac_inverse'.
175
176        :param blinded: the blinded message, as integer, to unblind.
177        :param blindfac: the factor to unblind with.
178        :return: the original message.
179
180        The blinding is such that message = unblind(decrypt(blind(encrypt(message))).
181
182        See https://en.wikipedia.org/wiki/Blinding_%28cryptography%29
183        """
184        return (blindfac_inverse * blinded) % self.n
185
186    def _initial_blinding_factor(self) -> int:
187        for _ in range(1000):
188            blind_r = rsa.randnum.randint(self.n - 1)
189            if rsa.prime.are_relatively_prime(self.n, blind_r):
190                return blind_r
191        raise RuntimeError("unable to find blinding factor")
192
193    def _update_blinding_factor(self) -> typing.Tuple[int, int]:
194        """Update blinding factors.
195
196        Computing a blinding factor is expensive, so instead this function
197        does this once, then updates the blinding factor as per section 9
198        of 'A Timing Attack against RSA with the Chinese Remainder Theorem'
199        by Werner Schindler.
200        See https://tls.mbed.org/public/WSchindler-RSA_Timing_Attack.pdf
201
202        :return: the new blinding factor and its inverse.
203        """
204
205        with self.mutex:
206            if self.blindfac < 0:
207                # Compute initial blinding factor, which is rather slow to do.
208                self.blindfac = self._initial_blinding_factor()
209                self.blindfac_inverse = rsa.common.inverse(self.blindfac, self.n)
210            else:
211                # Reuse previous blinding factor.
212                self.blindfac = pow(self.blindfac, 2, self.n)
213                self.blindfac_inverse = pow(self.blindfac_inverse, 2, self.n)
214
215            return self.blindfac, self.blindfac_inverse
216
217
218class PublicKey(AbstractKey):
219    """Represents a public RSA key.
220
221    This key is also known as the 'encryption key'. It contains the 'n' and 'e'
222    values.
223
224    Supports attributes as well as dictionary-like access. Attribute access is
225    faster, though.
226
227    >>> PublicKey(5, 3)
228    PublicKey(5, 3)
229
230    >>> key = PublicKey(5, 3)
231    >>> key.n
232    5
233    >>> key['n']
234    5
235    >>> key.e
236    3
237    >>> key['e']
238    3
239
240    """
241
242    __slots__ = ()
243
244    def __getitem__(self, key: str) -> int:
245        return getattr(self, key)
246
247    def __repr__(self) -> str:
248        return "PublicKey(%i, %i)" % (self.n, self.e)
249
250    def __getstate__(self) -> typing.Tuple[int, int]:
251        """Returns the key as tuple for pickling."""
252        return self.n, self.e
253
254    def __setstate__(self, state: typing.Tuple[int, int]) -> None:
255        """Sets the key from tuple."""
256        self.n, self.e = state
257        AbstractKey.__init__(self, self.n, self.e)
258
259    def __eq__(self, other: typing.Any) -> bool:
260        if other is None:
261            return False
262
263        if not isinstance(other, PublicKey):
264            return False
265
266        return self.n == other.n and self.e == other.e
267
268    def __ne__(self, other: typing.Any) -> bool:
269        return not (self == other)
270
271    def __hash__(self) -> int:
272        return hash((self.n, self.e))
273
274    @classmethod
275    def _load_pkcs1_der(cls, keyfile: bytes) -> "PublicKey":
276        """Loads a key in PKCS#1 DER format.
277
278        :param keyfile: contents of a DER-encoded file that contains the public
279            key.
280        :return: a PublicKey object
281
282        First let's construct a DER encoded key:
283
284        >>> import base64
285        >>> b64der = 'MAwCBQCNGmYtAgMBAAE='
286        >>> der = base64.standard_b64decode(b64der)
287
288        This loads the file:
289
290        >>> PublicKey._load_pkcs1_der(der)
291        PublicKey(2367317549, 65537)
292
293        """
294
295        from pyasn1.codec.der import decoder
296        from rsa.asn1 import AsnPubKey
297
298        (priv, _) = decoder.decode(keyfile, asn1Spec=AsnPubKey())
299        return cls(n=int(priv["modulus"]), e=int(priv["publicExponent"]))
300
301    def _save_pkcs1_der(self) -> bytes:
302        """Saves the public key in PKCS#1 DER format.
303
304        :returns: the DER-encoded public key.
305        :rtype: bytes
306        """
307
308        from pyasn1.codec.der import encoder
309        from rsa.asn1 import AsnPubKey
310
311        # Create the ASN object
312        asn_key = AsnPubKey()
313        asn_key.setComponentByName("modulus", self.n)
314        asn_key.setComponentByName("publicExponent", self.e)
315
316        return encoder.encode(asn_key)
317
318    @classmethod
319    def _load_pkcs1_pem(cls, keyfile: bytes) -> "PublicKey":
320        """Loads a PKCS#1 PEM-encoded public key file.
321
322        The contents of the file before the "-----BEGIN RSA PUBLIC KEY-----" and
323        after the "-----END RSA PUBLIC KEY-----" lines is ignored.
324
325        :param keyfile: contents of a PEM-encoded file that contains the public
326            key.
327        :return: a PublicKey object
328        """
329
330        der = rsa.pem.load_pem(keyfile, "RSA PUBLIC KEY")
331        return cls._load_pkcs1_der(der)
332
333    def _save_pkcs1_pem(self) -> bytes:
334        """Saves a PKCS#1 PEM-encoded public key file.
335
336        :return: contents of a PEM-encoded file that contains the public key.
337        :rtype: bytes
338        """
339
340        der = self._save_pkcs1_der()
341        return rsa.pem.save_pem(der, "RSA PUBLIC KEY")
342
343    @classmethod
344    def load_pkcs1_openssl_pem(cls, keyfile: bytes) -> "PublicKey":
345        """Loads a PKCS#1.5 PEM-encoded public key file from OpenSSL.
346
347        These files can be recognised in that they start with BEGIN PUBLIC KEY
348        rather than BEGIN RSA PUBLIC KEY.
349
350        The contents of the file before the "-----BEGIN PUBLIC KEY-----" and
351        after the "-----END PUBLIC KEY-----" lines is ignored.
352
353        :param keyfile: contents of a PEM-encoded file that contains the public
354            key, from OpenSSL.
355        :type keyfile: bytes
356        :return: a PublicKey object
357        """
358
359        der = rsa.pem.load_pem(keyfile, "PUBLIC KEY")
360        return cls.load_pkcs1_openssl_der(der)
361
362    @classmethod
363    def load_pkcs1_openssl_der(cls, keyfile: bytes) -> "PublicKey":
364        """Loads a PKCS#1 DER-encoded public key file from OpenSSL.
365
366        :param keyfile: contents of a DER-encoded file that contains the public
367            key, from OpenSSL.
368        :return: a PublicKey object
369        """
370
371        from rsa.asn1 import OpenSSLPubKey
372        from pyasn1.codec.der import decoder
373        from pyasn1.type import univ
374
375        (keyinfo, _) = decoder.decode(keyfile, asn1Spec=OpenSSLPubKey())
376
377        if keyinfo["header"]["oid"] != univ.ObjectIdentifier("1.2.840.113549.1.1.1"):
378            raise TypeError("This is not a DER-encoded OpenSSL-compatible public key")
379
380        return cls._load_pkcs1_der(keyinfo["key"][1:])
381
382
383class PrivateKey(AbstractKey):
384    """Represents a private RSA key.
385
386    This key is also known as the 'decryption key'. It contains the 'n', 'e',
387    'd', 'p', 'q' and other values.
388
389    Supports attributes as well as dictionary-like access. Attribute access is
390    faster, though.
391
392    >>> PrivateKey(3247, 65537, 833, 191, 17)
393    PrivateKey(3247, 65537, 833, 191, 17)
394
395    exp1, exp2 and coef will be calculated:
396
397    >>> pk = PrivateKey(3727264081, 65537, 3349121513, 65063, 57287)
398    >>> pk.exp1
399    55063
400    >>> pk.exp2
401    10095
402    >>> pk.coef
403    50797
404
405    """
406
407    __slots__ = ("d", "p", "q", "exp1", "exp2", "coef")
408
409    def __init__(self, n: int, e: int, d: int, p: int, q: int) -> None:
410        AbstractKey.__init__(self, n, e)
411        self.d = d
412        self.p = p
413        self.q = q
414
415        # Calculate exponents and coefficient.
416        self.exp1 = int(d % (p - 1))
417        self.exp2 = int(d % (q - 1))
418        self.coef = rsa.common.inverse(q, p)
419
420    def __getitem__(self, key: str) -> int:
421        return getattr(self, key)
422
423    def __repr__(self) -> str:
424        return "PrivateKey(%i, %i, %i, %i, %i)" % (
425            self.n,
426            self.e,
427            self.d,
428            self.p,
429            self.q,
430        )
431
432    def __getstate__(self) -> typing.Tuple[int, int, int, int, int, int, int, int]:
433        """Returns the key as tuple for pickling."""
434        return self.n, self.e, self.d, self.p, self.q, self.exp1, self.exp2, self.coef
435
436    def __setstate__(self, state: typing.Tuple[int, int, int, int, int, int, int, int]) -> None:
437        """Sets the key from tuple."""
438        self.n, self.e, self.d, self.p, self.q, self.exp1, self.exp2, self.coef = state
439        AbstractKey.__init__(self, self.n, self.e)
440
441    def __eq__(self, other: typing.Any) -> bool:
442        if other is None:
443            return False
444
445        if not isinstance(other, PrivateKey):
446            return False
447
448        return (
449            self.n == other.n
450            and self.e == other.e
451            and self.d == other.d
452            and self.p == other.p
453            and self.q == other.q
454            and self.exp1 == other.exp1
455            and self.exp2 == other.exp2
456            and self.coef == other.coef
457        )
458
459    def __ne__(self, other: typing.Any) -> bool:
460        return not (self == other)
461
462    def __hash__(self) -> int:
463        return hash((self.n, self.e, self.d, self.p, self.q, self.exp1, self.exp2, self.coef))
464
465    def blinded_decrypt(self, encrypted: int) -> int:
466        """Decrypts the message using blinding to prevent side-channel attacks.
467
468        :param encrypted: the encrypted message
469        :type encrypted: int
470
471        :returns: the decrypted message
472        :rtype: int
473        """
474
475        # Blinding and un-blinding should be using the same factor
476        blinded, blindfac_inverse = self.blind(encrypted)
477
478        # Instead of using the core functionality, use the Chinese Remainder
479        # Theorem and be 2-4x faster. This the same as:
480        #
481        # decrypted = rsa.core.decrypt_int(blinded, self.d, self.n)
482        s1 = pow(blinded, self.exp1, self.p)
483        s2 = pow(blinded, self.exp2, self.q)
484        h = ((s1 - s2) * self.coef) % self.p
485        decrypted = s2 + self.q * h
486
487        return self.unblind(decrypted, blindfac_inverse)
488
489    def blinded_encrypt(self, message: int) -> int:
490        """Encrypts the message using blinding to prevent side-channel attacks.
491
492        :param message: the message to encrypt
493        :type message: int
494
495        :returns: the encrypted message
496        :rtype: int
497        """
498
499        blinded, blindfac_inverse = self.blind(message)
500        encrypted = rsa.core.encrypt_int(blinded, self.d, self.n)
501        return self.unblind(encrypted, blindfac_inverse)
502
503    @classmethod
504    def _load_pkcs1_der(cls, keyfile: bytes) -> "PrivateKey":
505        """Loads a key in PKCS#1 DER format.
506
507        :param keyfile: contents of a DER-encoded file that contains the private
508            key.
509        :type keyfile: bytes
510        :return: a PrivateKey object
511
512        First let's construct a DER encoded key:
513
514        >>> import base64
515        >>> b64der = 'MC4CAQACBQDeKYlRAgMBAAECBQDHn4npAgMA/icCAwDfxwIDANcXAgInbwIDAMZt'
516        >>> der = base64.standard_b64decode(b64der)
517
518        This loads the file:
519
520        >>> PrivateKey._load_pkcs1_der(der)
521        PrivateKey(3727264081, 65537, 3349121513, 65063, 57287)
522
523        """
524
525        from pyasn1.codec.der import decoder
526
527        (priv, _) = decoder.decode(keyfile)
528
529        # ASN.1 contents of DER encoded private key:
530        #
531        # RSAPrivateKey ::= SEQUENCE {
532        #     version           Version,
533        #     modulus           INTEGER,  -- n
534        #     publicExponent    INTEGER,  -- e
535        #     privateExponent   INTEGER,  -- d
536        #     prime1            INTEGER,  -- p
537        #     prime2            INTEGER,  -- q
538        #     exponent1         INTEGER,  -- d mod (p-1)
539        #     exponent2         INTEGER,  -- d mod (q-1)
540        #     coefficient       INTEGER,  -- (inverse of q) mod p
541        #     otherPrimeInfos   OtherPrimeInfos OPTIONAL
542        # }
543
544        if priv[0] != 0:
545            raise ValueError("Unable to read this file, version %s != 0" % priv[0])
546
547        as_ints = map(int, priv[1:6])
548        key = cls(*as_ints)
549
550        exp1, exp2, coef = map(int, priv[6:9])
551
552        if (key.exp1, key.exp2, key.coef) != (exp1, exp2, coef):
553            warnings.warn(
554                "You have provided a malformed keyfile. Either the exponents "
555                "or the coefficient are incorrect. Using the correct values "
556                "instead.",
557                UserWarning,
558            )
559
560        return key
561
562    def _save_pkcs1_der(self) -> bytes:
563        """Saves the private key in PKCS#1 DER format.
564
565        :returns: the DER-encoded private key.
566        :rtype: bytes
567        """
568
569        from pyasn1.type import univ, namedtype
570        from pyasn1.codec.der import encoder
571
572        class AsnPrivKey(univ.Sequence):
573            componentType = namedtype.NamedTypes(
574                namedtype.NamedType("version", univ.Integer()),
575                namedtype.NamedType("modulus", univ.Integer()),
576                namedtype.NamedType("publicExponent", univ.Integer()),
577                namedtype.NamedType("privateExponent", univ.Integer()),
578                namedtype.NamedType("prime1", univ.Integer()),
579                namedtype.NamedType("prime2", univ.Integer()),
580                namedtype.NamedType("exponent1", univ.Integer()),
581                namedtype.NamedType("exponent2", univ.Integer()),
582                namedtype.NamedType("coefficient", univ.Integer()),
583            )
584
585        # Create the ASN object
586        asn_key = AsnPrivKey()
587        asn_key.setComponentByName("version", 0)
588        asn_key.setComponentByName("modulus", self.n)
589        asn_key.setComponentByName("publicExponent", self.e)
590        asn_key.setComponentByName("privateExponent", self.d)
591        asn_key.setComponentByName("prime1", self.p)
592        asn_key.setComponentByName("prime2", self.q)
593        asn_key.setComponentByName("exponent1", self.exp1)
594        asn_key.setComponentByName("exponent2", self.exp2)
595        asn_key.setComponentByName("coefficient", self.coef)
596
597        return encoder.encode(asn_key)
598
599    @classmethod
600    def _load_pkcs1_pem(cls, keyfile: bytes) -> "PrivateKey":
601        """Loads a PKCS#1 PEM-encoded private key file.
602
603        The contents of the file before the "-----BEGIN RSA PRIVATE KEY-----" and
604        after the "-----END RSA PRIVATE KEY-----" lines is ignored.
605
606        :param keyfile: contents of a PEM-encoded file that contains the private
607            key.
608        :type keyfile: bytes
609        :return: a PrivateKey object
610        """
611
612        der = rsa.pem.load_pem(keyfile, b"RSA PRIVATE KEY")
613        return cls._load_pkcs1_der(der)
614
615    def _save_pkcs1_pem(self) -> bytes:
616        """Saves a PKCS#1 PEM-encoded private key file.
617
618        :return: contents of a PEM-encoded file that contains the private key.
619        :rtype: bytes
620        """
621
622        der = self._save_pkcs1_der()
623        return rsa.pem.save_pem(der, b"RSA PRIVATE KEY")
624
625
626def find_p_q(
627    nbits: int,
628    getprime_func: typing.Callable[[int], int] = rsa.prime.getprime,
629    accurate: bool = True,
630) -> typing.Tuple[int, int]:
631    """Returns a tuple of two different primes of nbits bits each.
632
633    The resulting p * q has exactly 2 * nbits bits, and the returned p and q
634    will not be equal.
635
636    :param nbits: the number of bits in each of p and q.
637    :param getprime_func: the getprime function, defaults to
638        :py:func:`rsa.prime.getprime`.
639
640        *Introduced in Python-RSA 3.1*
641
642    :param accurate: whether to enable accurate mode or not.
643    :returns: (p, q), where p > q
644
645    >>> (p, q) = find_p_q(128)
646    >>> from rsa import common
647    >>> common.bit_size(p * q)
648    256
649
650    When not in accurate mode, the number of bits can be slightly less
651
652    >>> (p, q) = find_p_q(128, accurate=False)
653    >>> from rsa import common
654    >>> common.bit_size(p * q) <= 256
655    True
656    >>> common.bit_size(p * q) > 240
657    True
658
659    """
660
661    total_bits = nbits * 2
662
663    # Make sure that p and q aren't too close or the factoring programs can
664    # factor n.
665    shift = nbits // 16
666    pbits = nbits + shift
667    qbits = nbits - shift
668
669    # Choose the two initial primes
670    p = getprime_func(pbits)
671    q = getprime_func(qbits)
672
673    def is_acceptable(p: int, q: int) -> bool:
674        """Returns True iff p and q are acceptable:
675
676        - p and q differ
677        - (p * q) has the right nr of bits (when accurate=True)
678        """
679
680        if p == q:
681            return False
682
683        if not accurate:
684            return True
685
686        # Make sure we have just the right amount of bits
687        found_size = rsa.common.bit_size(p * q)
688        return total_bits == found_size
689
690    # Keep choosing other primes until they match our requirements.
691    change_p = False
692    while not is_acceptable(p, q):
693        # Change p on one iteration and q on the other
694        if change_p:
695            p = getprime_func(pbits)
696        else:
697            q = getprime_func(qbits)
698
699        change_p = not change_p
700
701    # We want p > q as described on
702    # http://www.di-mgt.com.au/rsa_alg.html#crt
703    return max(p, q), min(p, q)
704
705
706def calculate_keys_custom_exponent(p: int, q: int, exponent: int) -> typing.Tuple[int, int]:
707    """Calculates an encryption and a decryption key given p, q and an exponent,
708    and returns them as a tuple (e, d)
709
710    :param p: the first large prime
711    :param q: the second large prime
712    :param exponent: the exponent for the key; only change this if you know
713        what you're doing, as the exponent influences how difficult your
714        private key can be cracked. A very common choice for e is 65537.
715    :type exponent: int
716
717    """
718
719    phi_n = (p - 1) * (q - 1)
720
721    try:
722        d = rsa.common.inverse(exponent, phi_n)
723    except rsa.common.NotRelativePrimeError as ex:
724        raise rsa.common.NotRelativePrimeError(
725            exponent,
726            phi_n,
727            ex.d,
728            msg="e (%d) and phi_n (%d) are not relatively prime (divider=%i)"
729            % (exponent, phi_n, ex.d),
730        ) from ex
731
732    if (exponent * d) % phi_n != 1:
733        raise ValueError(
734            "e (%d) and d (%d) are not mult. inv. modulo " "phi_n (%d)" % (exponent, d, phi_n)
735        )
736
737    return exponent, d
738
739
740def calculate_keys(p: int, q: int) -> typing.Tuple[int, int]:
741    """Calculates an encryption and a decryption key given p and q, and
742    returns them as a tuple (e, d)
743
744    :param p: the first large prime
745    :param q: the second large prime
746
747    :return: tuple (e, d) with the encryption and decryption exponents.
748    """
749
750    return calculate_keys_custom_exponent(p, q, DEFAULT_EXPONENT)
751
752
753def gen_keys(
754    nbits: int,
755    getprime_func: typing.Callable[[int], int],
756    accurate: bool = True,
757    exponent: int = DEFAULT_EXPONENT,
758) -> typing.Tuple[int, int, int, int]:
759    """Generate RSA keys of nbits bits. Returns (p, q, e, d).
760
761    Note: this can take a long time, depending on the key size.
762
763    :param nbits: the total number of bits in ``p`` and ``q``. Both ``p`` and
764        ``q`` will use ``nbits/2`` bits.
765    :param getprime_func: either :py:func:`rsa.prime.getprime` or a function
766        with similar signature.
767    :param exponent: the exponent for the key; only change this if you know
768        what you're doing, as the exponent influences how difficult your
769        private key can be cracked. A very common choice for e is 65537.
770    :type exponent: int
771    """
772
773    # Regenerate p and q values, until calculate_keys doesn't raise a
774    # ValueError.
775    while True:
776        (p, q) = find_p_q(nbits // 2, getprime_func, accurate)
777        try:
778            (e, d) = calculate_keys_custom_exponent(p, q, exponent=exponent)
779            break
780        except ValueError:
781            pass
782
783    return p, q, e, d
784
785
786def newkeys(
787    nbits: int,
788    accurate: bool = True,
789    poolsize: int = 1,
790    exponent: int = DEFAULT_EXPONENT,
791) -> typing.Tuple[PublicKey, PrivateKey]:
792    """Generates public and private keys, and returns them as (pub, priv).
793
794    The public key is also known as the 'encryption key', and is a
795    :py:class:`rsa.PublicKey` object. The private key is also known as the
796    'decryption key' and is a :py:class:`rsa.PrivateKey` object.
797
798    :param nbits: the number of bits required to store ``n = p*q``.
799    :param accurate: when True, ``n`` will have exactly the number of bits you
800        asked for. However, this makes key generation much slower. When False,
801        `n`` may have slightly less bits.
802    :param poolsize: the number of processes to use to generate the prime
803        numbers. If set to a number > 1, a parallel algorithm will be used.
804        This requires Python 2.6 or newer.
805    :param exponent: the exponent for the key; only change this if you know
806        what you're doing, as the exponent influences how difficult your
807        private key can be cracked. A very common choice for e is 65537.
808    :type exponent: int
809
810    :returns: a tuple (:py:class:`rsa.PublicKey`, :py:class:`rsa.PrivateKey`)
811
812    The ``poolsize`` parameter was added in *Python-RSA 3.1* and requires
813    Python 2.6 or newer.
814
815    """
816
817    if nbits < 16:
818        raise ValueError("Key too small")
819
820    if poolsize < 1:
821        raise ValueError("Pool size (%i) should be >= 1" % poolsize)
822
823    # Determine which getprime function to use
824    if poolsize > 1:
825        from rsa import parallel
826
827        def getprime_func(nbits: int) -> int:
828            return parallel.getprime(nbits, poolsize=poolsize)
829
830    else:
831        getprime_func = rsa.prime.getprime
832
833    # Generate the key components
834    (p, q, e, d) = gen_keys(nbits, getprime_func, accurate=accurate, exponent=exponent)
835
836    # Create the key objects
837    n = p * q
838
839    return (PublicKey(n, e), PrivateKey(n, e, d, p, q))
840
841
842__all__ = ["PublicKey", "PrivateKey", "newkeys"]
843
844if __name__ == "__main__":
845    import doctest
846
847    try:
848        for count in range(100):
849            (failures, tests) = doctest.testmod()
850            if failures:
851                break
852
853            if (count % 10 == 0 and count) or count == 1:
854                print("%i times" % count)
855    except KeyboardInterrupt:
856        print("Aborted")
857    else:
858        print("Doctests done")
859 
codekingpro/portable-devtools · Team Ai