Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/rsa/key.py: 29%
255 statements
« prev ^ index » next coverage.py v7.3.2, created at 2023-12-08 06:40 +0000
« prev ^ index » next coverage.py v7.3.2, created at 2023-12-08 06:40 +0000
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.
15"""RSA key generation code.
17Create new keys with the newkeys() function. It will give you a PublicKey and a
18PrivateKey object.
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.
24.. note::
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.
32"""
34import threading
35import typing
36import warnings
38import rsa.prime
39import rsa.pem
40import rsa.common
41import rsa.randnum
42import rsa.core
45DEFAULT_EXPONENT = 65537
48T = typing.TypeVar("T", bound="AbstractKey")
51class AbstractKey:
52 """Abstract superclass for private and public keys."""
54 __slots__ = ("n", "e", "blindfac", "blindfac_inverse", "mutex")
56 def __init__(self, n: int, e: int) -> None:
57 self.n = n
58 self.e = e
60 # These will be computed properly on the first call to blind().
61 self.blindfac = self.blindfac_inverse = -1
63 # Used to protect updates to the blinding factor in multi-threaded
64 # environments.
65 self.mutex = threading.Lock()
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.
71 :param keyfile: contents of a PEM-encoded file that contains
72 the public key.
73 :type keyfile: bytes
75 :return: the loaded key
76 :rtype: AbstractKey
77 """
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.
83 :param keyfile: contents of a DER-encoded file that contains
84 the public key.
85 :type keyfile: bytes
87 :return: the loaded key
88 :rtype: AbstractKey
89 """
91 def _save_pkcs1_pem(self) -> bytes:
92 """Saves the key in PKCS#1 PEM format, implement in a subclass.
94 :returns: the PEM-encoded key.
95 :rtype: bytes
96 """
98 def _save_pkcs1_der(self) -> bytes:
99 """Saves the key in PKCS#1 DER format, implement in a subclass.
101 :returns: the DER-encoded key.
102 :rtype: bytes
103 """
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.
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
115 :return: the loaded key
116 :rtype: AbstractKey
117 """
119 methods = {
120 "PEM": cls._load_pkcs1_pem,
121 "DER": cls._load_pkcs1_der,
122 }
124 method = cls._assert_format_exists(format, methods)
125 return method(keyfile)
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'."""
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
141 def save_pkcs1(self, format: str = "PEM") -> bytes:
142 """Saves the key in PKCS#1 DER or PEM format.
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 """
150 methods = {
151 "PEM": self._save_pkcs1_pem,
152 "DER": self._save_pkcs1_der,
153 }
155 method = self._assert_format_exists(format, methods)
156 return method()
158 def blind(self, message: int) -> typing.Tuple[int, int]:
159 """Performs blinding on the message.
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)
165 The blinding is such that message = unblind(decrypt(blind(encrypt(message))).
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
173 def unblind(self, blinded: int, blindfac_inverse: int) -> int:
174 """Performs blinding on the message using random number 'blindfac_inverse'.
176 :param blinded: the blinded message, as integer, to unblind.
177 :param blindfac: the factor to unblind with.
178 :return: the original message.
180 The blinding is such that message = unblind(decrypt(blind(encrypt(message))).
182 See https://en.wikipedia.org/wiki/Blinding_%28cryptography%29
183 """
184 return (blindfac_inverse * blinded) % self.n
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")
193 def _update_blinding_factor(self) -> typing.Tuple[int, int]:
194 """Update blinding factors.
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
202 :return: the new blinding factor and its inverse.
203 """
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)
215 return self.blindfac, self.blindfac_inverse
218class PublicKey(AbstractKey):
219 """Represents a public RSA key.
221 This key is also known as the 'encryption key'. It contains the 'n' and 'e'
222 values.
224 Supports attributes as well as dictionary-like access. Attribute access is
225 faster, though.
227 >>> PublicKey(5, 3)
228 PublicKey(5, 3)
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
240 """
242 __slots__ = ()
244 def __getitem__(self, key: str) -> int:
245 return getattr(self, key)
247 def __repr__(self) -> str:
248 return "PublicKey(%i, %i)" % (self.n, self.e)
250 def __getstate__(self) -> typing.Tuple[int, int]:
251 """Returns the key as tuple for pickling."""
252 return self.n, self.e
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)
259 def __eq__(self, other: typing.Any) -> bool:
260 if other is None:
261 return False
263 if not isinstance(other, PublicKey):
264 return False
266 return self.n == other.n and self.e == other.e
268 def __ne__(self, other: typing.Any) -> bool:
269 return not (self == other)
271 def __hash__(self) -> int:
272 return hash((self.n, self.e))
274 @classmethod
275 def _load_pkcs1_der(cls, keyfile: bytes) -> "PublicKey":
276 """Loads a key in PKCS#1 DER format.
278 :param keyfile: contents of a DER-encoded file that contains the public
279 key.
280 :return: a PublicKey object
282 First let's construct a DER encoded key:
284 >>> import base64
285 >>> b64der = 'MAwCBQCNGmYtAgMBAAE='
286 >>> der = base64.standard_b64decode(b64der)
288 This loads the file:
290 >>> PublicKey._load_pkcs1_der(der)
291 PublicKey(2367317549, 65537)
293 """
295 from pyasn1.codec.der import decoder
296 from rsa.asn1 import AsnPubKey
298 (priv, _) = decoder.decode(keyfile, asn1Spec=AsnPubKey())
299 return cls(n=int(priv["modulus"]), e=int(priv["publicExponent"]))
301 def _save_pkcs1_der(self) -> bytes:
302 """Saves the public key in PKCS#1 DER format.
304 :returns: the DER-encoded public key.
305 :rtype: bytes
306 """
308 from pyasn1.codec.der import encoder
309 from rsa.asn1 import AsnPubKey
311 # Create the ASN object
312 asn_key = AsnPubKey()
313 asn_key.setComponentByName("modulus", self.n)
314 asn_key.setComponentByName("publicExponent", self.e)
316 return encoder.encode(asn_key)
318 @classmethod
319 def _load_pkcs1_pem(cls, keyfile: bytes) -> "PublicKey":
320 """Loads a PKCS#1 PEM-encoded public key file.
322 The contents of the file before the "-----BEGIN RSA PUBLIC KEY-----" and
323 after the "-----END RSA PUBLIC KEY-----" lines is ignored.
325 :param keyfile: contents of a PEM-encoded file that contains the public
326 key.
327 :return: a PublicKey object
328 """
330 der = rsa.pem.load_pem(keyfile, "RSA PUBLIC KEY")
331 return cls._load_pkcs1_der(der)
333 def _save_pkcs1_pem(self) -> bytes:
334 """Saves a PKCS#1 PEM-encoded public key file.
336 :return: contents of a PEM-encoded file that contains the public key.
337 :rtype: bytes
338 """
340 der = self._save_pkcs1_der()
341 return rsa.pem.save_pem(der, "RSA PUBLIC KEY")
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.
347 These files can be recognised in that they start with BEGIN PUBLIC KEY
348 rather than BEGIN RSA PUBLIC KEY.
350 The contents of the file before the "-----BEGIN PUBLIC KEY-----" and
351 after the "-----END PUBLIC KEY-----" lines is ignored.
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 """
359 der = rsa.pem.load_pem(keyfile, "PUBLIC KEY")
360 return cls.load_pkcs1_openssl_der(der)
362 @classmethod
363 def load_pkcs1_openssl_der(cls, keyfile: bytes) -> "PublicKey":
364 """Loads a PKCS#1 DER-encoded public key file from OpenSSL.
366 :param keyfile: contents of a DER-encoded file that contains the public
367 key, from OpenSSL.
368 :return: a PublicKey object
369 """
371 from rsa.asn1 import OpenSSLPubKey
372 from pyasn1.codec.der import decoder
373 from pyasn1.type import univ
375 (keyinfo, _) = decoder.decode(keyfile, asn1Spec=OpenSSLPubKey())
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")
380 return cls._load_pkcs1_der(keyinfo["key"][1:])
383class PrivateKey(AbstractKey):
384 """Represents a private RSA key.
386 This key is also known as the 'decryption key'. It contains the 'n', 'e',
387 'd', 'p', 'q' and other values.
389 Supports attributes as well as dictionary-like access. Attribute access is
390 faster, though.
392 >>> PrivateKey(3247, 65537, 833, 191, 17)
393 PrivateKey(3247, 65537, 833, 191, 17)
395 exp1, exp2 and coef will be calculated:
397 >>> pk = PrivateKey(3727264081, 65537, 3349121513, 65063, 57287)
398 >>> pk.exp1
399 55063
400 >>> pk.exp2
401 10095
402 >>> pk.coef
403 50797
405 """
407 __slots__ = ("d", "p", "q", "exp1", "exp2", "coef")
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
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)
420 def __getitem__(self, key: str) -> int:
421 return getattr(self, key)
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 )
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
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)
441 def __eq__(self, other: typing.Any) -> bool:
442 if other is None:
443 return False
445 if not isinstance(other, PrivateKey):
446 return False
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 )
459 def __ne__(self, other: typing.Any) -> bool:
460 return not (self == other)
462 def __hash__(self) -> int:
463 return hash((self.n, self.e, self.d, self.p, self.q, self.exp1, self.exp2, self.coef))
465 def blinded_decrypt(self, encrypted: int) -> int:
466 """Decrypts the message using blinding to prevent side-channel attacks.
468 :param encrypted: the encrypted message
469 :type encrypted: int
471 :returns: the decrypted message
472 :rtype: int
473 """
475 # Blinding and un-blinding should be using the same factor
476 blinded, blindfac_inverse = self.blind(encrypted)
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
487 return self.unblind(decrypted, blindfac_inverse)
489 def blinded_encrypt(self, message: int) -> int:
490 """Encrypts the message using blinding to prevent side-channel attacks.
492 :param message: the message to encrypt
493 :type message: int
495 :returns: the encrypted message
496 :rtype: int
497 """
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)
503 @classmethod
504 def _load_pkcs1_der(cls, keyfile: bytes) -> "PrivateKey":
505 """Loads a key in PKCS#1 DER format.
507 :param keyfile: contents of a DER-encoded file that contains the private
508 key.
509 :type keyfile: bytes
510 :return: a PrivateKey object
512 First let's construct a DER encoded key:
514 >>> import base64
515 >>> b64der = 'MC4CAQACBQDeKYlRAgMBAAECBQDHn4npAgMA/icCAwDfxwIDANcXAgInbwIDAMZt'
516 >>> der = base64.standard_b64decode(b64der)
518 This loads the file:
520 >>> PrivateKey._load_pkcs1_der(der)
521 PrivateKey(3727264081, 65537, 3349121513, 65063, 57287)
523 """
525 from pyasn1.codec.der import decoder
527 (priv, _) = decoder.decode(keyfile)
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 # }
544 if priv[0] != 0:
545 raise ValueError("Unable to read this file, version %s != 0" % priv[0])
547 as_ints = map(int, priv[1:6])
548 key = cls(*as_ints)
550 exp1, exp2, coef = map(int, priv[6:9])
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 )
560 return key
562 def _save_pkcs1_der(self) -> bytes:
563 """Saves the private key in PKCS#1 DER format.
565 :returns: the DER-encoded private key.
566 :rtype: bytes
567 """
569 from pyasn1.type import univ, namedtype
570 from pyasn1.codec.der import encoder
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 )
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)
597 return encoder.encode(asn_key)
599 @classmethod
600 def _load_pkcs1_pem(cls, keyfile: bytes) -> "PrivateKey":
601 """Loads a PKCS#1 PEM-encoded private key file.
603 The contents of the file before the "-----BEGIN RSA PRIVATE KEY-----" and
604 after the "-----END RSA PRIVATE KEY-----" lines is ignored.
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 """
612 der = rsa.pem.load_pem(keyfile, b"RSA PRIVATE KEY")
613 return cls._load_pkcs1_der(der)
615 def _save_pkcs1_pem(self) -> bytes:
616 """Saves a PKCS#1 PEM-encoded private key file.
618 :return: contents of a PEM-encoded file that contains the private key.
619 :rtype: bytes
620 """
622 der = self._save_pkcs1_der()
623 return rsa.pem.save_pem(der, b"RSA PRIVATE KEY")
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.
633 The resulting p * q has exactly 2 * nbits bits, and the returned p and q
634 will not be equal.
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`.
640 *Introduced in Python-RSA 3.1*
642 :param accurate: whether to enable accurate mode or not.
643 :returns: (p, q), where p > q
645 >>> (p, q) = find_p_q(128)
646 >>> from rsa import common
647 >>> common.bit_size(p * q)
648 256
650 When not in accurate mode, the number of bits can be slightly less
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
659 """
661 total_bits = nbits * 2
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
669 # Choose the two initial primes
670 p = getprime_func(pbits)
671 q = getprime_func(qbits)
673 def is_acceptable(p: int, q: int) -> bool:
674 """Returns True iff p and q are acceptable:
676 - p and q differ
677 - (p * q) has the right nr of bits (when accurate=True)
678 """
680 if p == q:
681 return False
683 if not accurate:
684 return True
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
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)
699 change_p = not change_p
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)
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)
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
717 """
719 phi_n = (p - 1) * (q - 1)
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
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 )
737 return exponent, d
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)
744 :param p: the first large prime
745 :param q: the second large prime
747 :return: tuple (e, d) with the encryption and decryption exponents.
748 """
750 return calculate_keys_custom_exponent(p, q, DEFAULT_EXPONENT)
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).
761 Note: this can take a long time, depending on the key size.
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 """
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
783 return p, q, e, d
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).
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.
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
810 :returns: a tuple (:py:class:`rsa.PublicKey`, :py:class:`rsa.PrivateKey`)
812 The ``poolsize`` parameter was added in *Python-RSA 3.1* and requires
813 Python 2.6 or newer.
815 """
817 if nbits < 16:
818 raise ValueError("Key too small")
820 if poolsize < 1:
821 raise ValueError("Pool size (%i) should be >= 1" % poolsize)
823 # Determine which getprime function to use
824 if poolsize > 1:
825 from rsa import parallel
827 def getprime_func(nbits: int) -> int:
828 return parallel.getprime(nbits, poolsize=poolsize)
830 else:
831 getprime_func = rsa.prime.getprime
833 # Generate the key components
834 (p, q, e, d) = gen_keys(nbits, getprime_func, accurate=accurate, exponent=exponent)
836 # Create the key objects
837 n = p * q
839 return (PublicKey(n, e), PrivateKey(n, e, d, p, q))
842__all__ = ["PublicKey", "PrivateKey", "newkeys"]
844if __name__ == "__main__":
845 import doctest
847 try:
848 for count in range(100):
849 (failures, tests) = doctest.testmod()
850 if failures:
851 break
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")