Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/rsa/key.py: 53%
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
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 abc
35import math
36import threading
37import typing
38import warnings
39import itertools
41import rsa.prime
42import rsa.pem
43import rsa.common
44import rsa.randnum
45import rsa.core
48DEFAULT_EXPONENT = 65537
51T = typing.TypeVar("T", bound="AbstractKey")
54class AbstractKey(metaclass=abc.ABCMeta):
55 """Abstract superclass for private and public keys."""
57 __slots__ = ("n", "e", "blindfac", "blindfac_inverse", "mutex")
59 def __init__(self, n: int, e: int) -> None:
60 self.n = n
61 self.e = e
63 # These will be computed properly on the first call to blind().
64 self.blindfac = self.blindfac_inverse = -1
66 # Used to protect updates to the blinding factor in multi-threaded
67 # environments.
68 self.mutex = threading.Lock()
70 @classmethod
71 @abc.abstractmethod
72 def _load_pkcs1_pem(cls: typing.Type[T], keyfile: bytes) -> T:
73 """Loads a key in PKCS#1 PEM format, implement in a subclass.
75 :param keyfile: contents of a PEM-encoded file that contains
76 the public key.
77 :type keyfile: bytes
79 :return: the loaded key
80 :rtype: AbstractKey
81 """
83 @classmethod
84 @abc.abstractmethod
85 def _load_pkcs1_der(cls: typing.Type[T], keyfile: bytes) -> T:
86 """Loads a key in PKCS#1 PEM format, implement in a subclass.
88 :param keyfile: contents of a DER-encoded file that contains
89 the public key.
90 :type keyfile: bytes
92 :return: the loaded key
93 :rtype: AbstractKey
94 """
96 @abc.abstractmethod
97 def _save_pkcs1_pem(self) -> bytes:
98 """Saves the key in PKCS#1 PEM format, implement in a subclass.
100 :returns: the PEM-encoded key.
101 :rtype: bytes
102 """
104 @abc.abstractmethod
105 def _save_pkcs1_der(self) -> bytes:
106 """Saves the key in PKCS#1 DER format, implement in a subclass.
108 :returns: the DER-encoded key.
109 :rtype: bytes
110 """
112 @classmethod
113 def load_pkcs1(cls: typing.Type[T], keyfile: bytes, format: str = "PEM") -> T:
114 """Loads a key in PKCS#1 DER or PEM format.
116 :param keyfile: contents of a DER- or PEM-encoded file that contains
117 the key.
118 :type keyfile: bytes
119 :param format: the format of the file to load; 'PEM' or 'DER'
120 :type format: str
122 :return: the loaded key
123 :rtype: AbstractKey
124 """
126 methods = {
127 "PEM": cls._load_pkcs1_pem,
128 "DER": cls._load_pkcs1_der,
129 }
131 method = cls._assert_format_exists(format, methods)
132 return method(keyfile)
134 @staticmethod
135 def _assert_format_exists(
136 file_format: str, methods: typing.Mapping[str, typing.Callable]
137 ) -> typing.Callable:
138 """Checks whether the given file format exists in 'methods'."""
140 try:
141 return methods[file_format]
142 except KeyError as ex:
143 formats = ", ".join(sorted(methods.keys()))
144 raise ValueError(
145 "Unsupported format: %r, try one of %s" % (file_format, formats)
146 ) from ex
148 def save_pkcs1(self, format: str = "PEM") -> bytes:
149 """Saves the key in PKCS#1 DER or PEM format.
151 :param format: the format to save; 'PEM' or 'DER'
152 :type format: str
153 :returns: the DER- or PEM-encoded key.
154 :rtype: bytes
155 """
157 methods = {
158 "PEM": self._save_pkcs1_pem,
159 "DER": self._save_pkcs1_der,
160 }
162 method = self._assert_format_exists(format, methods)
163 return method()
165 def blind(self, message: int) -> typing.Tuple[int, int]:
166 """Performs blinding on the message.
168 :param message: the message, as integer, to blind.
169 :param r: the random number to blind with.
170 :return: tuple (the blinded message, the inverse of the used blinding factor)
172 The blinding is such that message = unblind(decrypt(blind(encrypt(message))).
174 See https://en.wikipedia.org/wiki/Blinding_%28cryptography%29
175 """
176 blindfac, blindfac_inverse = self._update_blinding_factor()
177 blinded = (message * pow(blindfac, self.e, self.n)) % self.n
178 return blinded, blindfac_inverse
180 def unblind(self, blinded: int, blindfac_inverse: int) -> int:
181 """Performs blinding on the message using random number 'blindfac_inverse'.
183 :param blinded: the blinded message, as integer, to unblind.
184 :param blindfac: the factor to unblind with.
185 :return: the original message.
187 The blinding is such that message = unblind(decrypt(blind(encrypt(message))).
189 See https://en.wikipedia.org/wiki/Blinding_%28cryptography%29
190 """
191 return (blindfac_inverse * blinded) % self.n
193 def _initial_blinding_factor(self) -> int:
194 for _ in range(1000):
195 blind_r = rsa.randnum.randint(self.n - 1)
196 if rsa.prime.are_relatively_prime(self.n, blind_r):
197 return blind_r
198 raise RuntimeError("unable to find blinding factor")
200 def _update_blinding_factor(self) -> typing.Tuple[int, int]:
201 """Update blinding factors.
203 Computing a blinding factor is expensive, so instead this function
204 does this once, then updates the blinding factor as per section 9
205 of 'A Timing Attack against RSA with the Chinese Remainder Theorem'
206 by Werner Schindler.
207 See https://tls.mbed.org/public/WSchindler-RSA_Timing_Attack.pdf
209 :return: the new blinding factor and its inverse.
210 """
212 with self.mutex:
213 if self.blindfac < 0:
214 # Compute initial blinding factor, which is rather slow to do.
215 self.blindfac = self._initial_blinding_factor()
216 self.blindfac_inverse = rsa.common.inverse(self.blindfac, self.n)
217 else:
218 # Reuse previous blinding factor.
219 self.blindfac = pow(self.blindfac, 2, self.n)
220 self.blindfac_inverse = pow(self.blindfac_inverse, 2, self.n)
222 return self.blindfac, self.blindfac_inverse
225class PublicKey(AbstractKey):
226 """Represents a public RSA key.
228 This key is also known as the 'encryption key'. It contains the 'n' and 'e'
229 values.
231 Supports attributes as well as dictionary-like access. Attribute access is
232 faster, though.
234 >>> PublicKey(5, 3)
235 PublicKey(5, 3)
237 >>> key = PublicKey(5, 3)
238 >>> key.n
239 5
240 >>> key['n']
241 5
242 >>> key.e
243 3
244 >>> key['e']
245 3
247 """
249 __slots__ = ()
251 def __getitem__(self, key: str) -> int:
252 return getattr(self, key)
254 def __repr__(self) -> str:
255 return "PublicKey(%i, %i)" % (self.n, self.e)
257 def __getstate__(self) -> typing.Tuple[int, int]:
258 """Returns the key as tuple for pickling."""
259 return self.n, self.e
261 def __setstate__(self, state: typing.Tuple[int, int]) -> None:
262 """Sets the key from tuple."""
263 self.n, self.e = state
264 AbstractKey.__init__(self, self.n, self.e)
266 def __eq__(self, other: typing.Any) -> bool:
267 if other is None:
268 return False
270 if not isinstance(other, PublicKey):
271 return False
273 return self.n == other.n and self.e == other.e
275 def __ne__(self, other: typing.Any) -> bool:
276 return not (self == other)
278 def __hash__(self) -> int:
279 return hash((self.n, self.e))
281 @classmethod
282 def _load_pkcs1_der(cls, keyfile: bytes) -> "PublicKey":
283 """Loads a key in PKCS#1 DER format.
285 :param keyfile: contents of a DER-encoded file that contains the public
286 key.
287 :return: a PublicKey object
289 First let's construct a DER encoded key:
291 >>> import base64
292 >>> b64der = 'MAwCBQCNGmYtAgMBAAE='
293 >>> der = base64.standard_b64decode(b64der)
295 This loads the file:
297 >>> PublicKey._load_pkcs1_der(der)
298 PublicKey(2367317549, 65537)
300 """
302 from pyasn1.codec.der import decoder
303 from rsa.asn1 import AsnPubKey
305 (priv, _) = decoder.decode(keyfile, asn1Spec=AsnPubKey())
306 return cls(n=int(priv["modulus"]), e=int(priv["publicExponent"]))
308 def _save_pkcs1_der(self) -> bytes:
309 """Saves the public key in PKCS#1 DER format.
311 :returns: the DER-encoded public key.
312 :rtype: bytes
313 """
315 from pyasn1.codec.der import encoder
316 from rsa.asn1 import AsnPubKey
318 # Create the ASN object
319 asn_key = AsnPubKey()
320 asn_key.setComponentByName("modulus", self.n)
321 asn_key.setComponentByName("publicExponent", self.e)
323 return encoder.encode(asn_key)
325 @classmethod
326 def _load_pkcs1_pem(cls, keyfile: bytes) -> "PublicKey":
327 """Loads a PKCS#1 PEM-encoded public key file.
329 The contents of the file before the "-----BEGIN RSA PUBLIC KEY-----" and
330 after the "-----END RSA PUBLIC KEY-----" lines is ignored.
332 :param keyfile: contents of a PEM-encoded file that contains the public
333 key.
334 :return: a PublicKey object
335 """
337 der = rsa.pem.load_pem(keyfile, "RSA PUBLIC KEY")
338 return cls._load_pkcs1_der(der)
340 def _save_pkcs1_pem(self) -> bytes:
341 """Saves a PKCS#1 PEM-encoded public key file.
343 :return: contents of a PEM-encoded file that contains the public key.
344 :rtype: bytes
345 """
347 der = self._save_pkcs1_der()
348 return rsa.pem.save_pem(der, "RSA PUBLIC KEY")
350 @classmethod
351 def load_pkcs1_openssl_pem(cls, keyfile: bytes) -> "PublicKey":
352 """Loads a PKCS#1.5 PEM-encoded public key file from OpenSSL.
354 These files can be recognised in that they start with BEGIN PUBLIC KEY
355 rather than BEGIN RSA PUBLIC KEY.
357 The contents of the file before the "-----BEGIN PUBLIC KEY-----" and
358 after the "-----END PUBLIC KEY-----" lines is ignored.
360 :param keyfile: contents of a PEM-encoded file that contains the public
361 key, from OpenSSL.
362 :type keyfile: bytes
363 :return: a PublicKey object
364 """
366 der = rsa.pem.load_pem(keyfile, "PUBLIC KEY")
367 return cls.load_pkcs1_openssl_der(der)
369 @classmethod
370 def load_pkcs1_openssl_der(cls, keyfile: bytes) -> "PublicKey":
371 """Loads a PKCS#1 DER-encoded public key file from OpenSSL.
373 :param keyfile: contents of a DER-encoded file that contains the public
374 key, from OpenSSL.
375 :return: a PublicKey object
376 """
378 from rsa.asn1 import OpenSSLPubKey
379 from pyasn1.codec.der import decoder
380 from pyasn1.type import univ
382 (keyinfo, _) = decoder.decode(keyfile, asn1Spec=OpenSSLPubKey())
384 if keyinfo["header"]["oid"] != univ.ObjectIdentifier("1.2.840.113549.1.1.1"):
385 raise TypeError("This is not a DER-encoded OpenSSL-compatible public key")
387 return cls._load_pkcs1_der(keyinfo["key"][1:])
390class PrivateKey(AbstractKey):
391 """Represents a private RSA key.
393 This key is also known as the 'decryption key'. It contains the 'n', 'e',
394 'd', 'p', 'q' and other values. For example ,in the case of multiprime RSA,
395 it additionally contains the lists 'rs', 'ds', and 'ts' which contain the
396 factors, exponents, and coefficients for the other primes.
398 Supports attributes as well as dictionary-like access. Attribute access is
399 faster, though.
401 >>> PrivateKey(3247, 65537, 833, 191, 17)
402 PrivateKey(3247, 65537, 833, 191, 17)
404 exp1, exp2 and coef will be calculated:
406 >>> pk = PrivateKey(3727264081, 65537, 3349121513, 65063, 57287)
407 >>> pk.exp1
408 55063
409 >>> pk.exp2
410 10095
411 >>> pk.coef
412 50797
414 """
416 __slots__ = ("d", "p", "q", "exp1", "exp2", "coef", "rs", "ds", "ts")
418 def __init__(
419 self,
420 n: int,
421 e: int,
422 d: int,
423 p: int,
424 q: int,
425 rs: typing.Optional[typing.List[int]] = None,
426 ) -> None:
427 rs = [] if rs is None else rs
429 AbstractKey.__init__(self, n, e)
430 self.d = d
431 self.p = p
432 self.q = q
434 # Calculate exponents and coefficient.
435 self.exp1 = int(d % (p - 1))
436 self.exp2 = int(d % (q - 1))
437 self.coef = rsa.common.inverse(q, p)
439 # Calculate other primes' exponents and coefficients.
440 self.rs = rs
441 self.ds = [int(d % (r - 1)) for r in rs]
442 Rs = list(itertools.accumulate([p, q] + rs, lambda x, y: x*y))
443 self.ts = [pow(R, -1, r) for R, r in zip(Rs[1:], rs)]
445 def __getitem__(self, key: str) -> int:
446 return getattr(self, key)
448 def __repr__(self) -> str:
449 if self.rs:
450 return "PrivateKey(%i, %i, %i, %i, %i, %s)" % (
451 self.n,
452 self.e,
453 self.d,
454 self.p,
455 self.q,
456 self.rs,
457 )
458 else:
459 return "PrivateKey(%i, %i, %i, %i, %i)" % (
460 self.n,
461 self.e,
462 self.d,
463 self.p,
464 self.q,
465 )
467 def __getstate__(self) -> typing.Tuple:
468 """Returns the key as tuple for pickling."""
469 if self.rs:
470 return (
471 self.n,
472 self.e,
473 self.d,
474 self.p,
475 self.q,
476 self.exp1,
477 self.exp2,
478 self.coef,
479 self.rs,
480 self.ds,
481 self.ts,
482 )
483 else:
484 return self.n, self.e, self.d, self.p, self.q, self.exp1, self.exp2, self.coef
486 def __setstate__(self, state: typing.Tuple) -> None:
487 """Sets the key from tuple."""
488 if len(state) != 8:
489 (
490 self.n,
491 self.e,
492 self.d,
493 self.p,
494 self.q,
495 self.exp1,
496 self.exp2,
497 self.coef,
498 self.rs,
499 self.ds,
500 self.ts,
501 ) = state
502 else:
503 self.n, self.e, self.d, self.p, self.q, self.exp1, self.exp2, self.coef = state
504 self.rs = self.ds = self.ts = []
505 AbstractKey.__init__(self, self.n, self.e)
507 def __eq__(self, other: typing.Any) -> bool:
508 if other is None:
509 return False
511 if not isinstance(other, PrivateKey):
512 return False
514 return all([getattr(self, k) == getattr(other, k) for k in self.__slots__])
516 def __ne__(self, other: typing.Any) -> bool:
517 return not (self == other)
519 def __hash__(self) -> int:
520 if self.rs:
521 return hash((
522 self.n,
523 self.e,
524 self.d,
525 self.p,
526 self.q,
527 self.exp1,
528 self.exp2,
529 self.coef,
530 *self.rs,
531 *self.ds,
532 *self.ts
533 ))
534 else:
535 return hash((self.n, self.e, self.d, self.p, self.q, self.exp1, self.exp2, self.coef))
537 def blinded_decrypt(self, encrypted: int) -> int:
538 """Decrypts the message using blinding to prevent side-channel attacks.
540 :param encrypted: the encrypted message
541 :type encrypted: int
543 :returns: the decrypted message
544 :rtype: int
545 """
547 # Blinding and un-blinding should be using the same factor
548 blinded, blindfac_inverse = self.blind(encrypted)
549 decrypted = rsa.core.decrypt_int_fast(
550 blinded,
551 [self.p, self.q] + self.rs,
552 [self.exp1, self.exp2] + self.ds,
553 [self.coef] + self.ts,
554 )
555 return self.unblind(decrypted, blindfac_inverse)
557 @classmethod
558 def _load_pkcs1_der(cls, keyfile: bytes) -> "PrivateKey":
559 """Loads a key in PKCS#1 DER format.
561 :param keyfile: contents of a DER-encoded file that contains the private
562 key.
563 :type keyfile: bytes
564 :return: a PrivateKey object
566 First let's construct a DER encoded key:
568 >>> import base64
569 >>> b64der = 'MC4CAQACBQDeKYlRAgMBAAECBQDHn4npAgMA/icCAwDfxwIDANcXAgInbwIDAMZt'
570 >>> der = base64.standard_b64decode(b64der)
572 This loads the file:
574 >>> PrivateKey._load_pkcs1_der(der)
575 PrivateKey(3727264081, 65537, 3349121513, 65063, 57287)
577 """
579 from pyasn1.codec.der import decoder
581 (priv, _) = decoder.decode(keyfile)
583 # ASN.1 contents of DER encoded private key:
584 #
585 # RSAPrivateKey ::= SEQUENCE {
586 # version Version,
587 # modulus INTEGER, -- n
588 # publicExponent INTEGER, -- e
589 # privateExponent INTEGER, -- d
590 # prime1 INTEGER, -- p
591 # prime2 INTEGER, -- q
592 # exponent1 INTEGER, -- d mod (p-1)
593 # exponent2 INTEGER, -- d mod (q-1)
594 # coefficient INTEGER, -- (inverse of q) mod p
595 # otherPrimeInfos OtherPrimeInfos OPTIONAL
596 # }
598 if priv[0] != 0:
599 raise ValueError("Unable to read this file, version %s != 0" % priv[0])
601 n, e, d, p, q = map(int, priv[1:6])
602 exp1, exp2, coef = map(int, priv[6:9])
603 rs = map(int, priv[9::3])
604 ds = map(int, priv[10::3])
605 ts = map(int, priv[11::3])
607 key = cls(n, e, d, p, q, list(rs))
609 if (key.exp1, key.exp2, key.coef, key.rs, key.ds, key.ts) != (exp1, exp2, coef, rs, ds, ts):
610 warnings.warn(
611 "You have provided a malformed keyfile. Either the exponents "
612 "or the coefficient are incorrect. Using the correct values "
613 "instead.",
614 UserWarning,
615 )
617 return key
619 def _save_pkcs1_der(self) -> bytes:
620 """Saves the private key in PKCS#1 DER format.
622 :returns: the DER-encoded private key.
623 :rtype: bytes
624 """
626 from pyasn1.type import univ, namedtype
627 from pyasn1.codec.der import encoder
629 other_fields = [
630 (
631 namedtype.NamedType("prime%d" % (i + 3), univ.Integer()),
632 namedtype.NamedType("exponent%d" % (i + 3), univ.Integer()),
633 namedtype.NamedType("coefficient%d" % (i + 3), univ.Integer()),
634 ) for i in range(len(self.rs))
635 ]
637 class AsnPrivKey(univ.Sequence):
638 componentType = namedtype.NamedTypes(
639 namedtype.NamedType("version", univ.Integer()),
640 namedtype.NamedType("modulus", univ.Integer()),
641 namedtype.NamedType("publicExponent", univ.Integer()),
642 namedtype.NamedType("privateExponent", univ.Integer()),
643 namedtype.NamedType("prime1", univ.Integer()),
644 namedtype.NamedType("prime2", univ.Integer()),
645 namedtype.NamedType("exponent1", univ.Integer()),
646 namedtype.NamedType("exponent2", univ.Integer()),
647 namedtype.NamedType("coefficient", univ.Integer()),
648 *list(itertools.chain(*other_fields))
649 )
651 # Create the ASN object
652 asn_key = AsnPrivKey()
653 asn_key.setComponentByName("version", 0)
654 asn_key.setComponentByName("modulus", self.n)
655 asn_key.setComponentByName("publicExponent", self.e)
656 asn_key.setComponentByName("privateExponent", self.d)
657 asn_key.setComponentByName("prime1", self.p)
658 asn_key.setComponentByName("prime2", self.q)
659 asn_key.setComponentByName("exponent1", self.exp1)
660 asn_key.setComponentByName("exponent2", self.exp2)
661 asn_key.setComponentByName("coefficient", self.coef)
662 for i, (r, d, t) in enumerate(zip(self.rs, self.ds, self.ts), start=3):
663 asn_key.setComponentByName("prime%d" % i, r)
664 asn_key.setComponentByName("exponent%d" % i, d)
665 asn_key.setComponentByName("coefficient%d" % i, t)
667 return encoder.encode(asn_key)
669 @classmethod
670 def _load_pkcs1_pem(cls, keyfile: bytes) -> "PrivateKey":
671 """Loads a PKCS#1 PEM-encoded private key file.
673 The contents of the file before the "-----BEGIN RSA PRIVATE KEY-----" and
674 after the "-----END RSA PRIVATE KEY-----" lines is ignored.
676 :param keyfile: contents of a PEM-encoded file that contains the private
677 key.
678 :type keyfile: bytes
679 :return: a PrivateKey object
680 """
682 der = rsa.pem.load_pem(keyfile, b"RSA PRIVATE KEY")
683 return cls._load_pkcs1_der(der)
685 def _save_pkcs1_pem(self) -> bytes:
686 """Saves a PKCS#1 PEM-encoded private key file.
688 :return: contents of a PEM-encoded file that contains the private key.
689 :rtype: bytes
690 """
692 der = self._save_pkcs1_der()
693 return rsa.pem.save_pem(der, b"RSA PRIVATE KEY")
696def find_primes(
697 nbits: int,
698 getprime_func: typing.Callable[[int], int] = rsa.prime.getprime,
699 accurate: bool = True,
700 nprimes: int = 2,
701) -> typing.List[int]:
702 """Returns a list of different primes with nbits divided evenly among them.
704 :param nbits: the number of bits for the primes to sum to.
705 :param getprime_func: the getprime function, defaults to
706 :py:func:`rsa.prime.getprime`.
707 :param accurate: whether to enable accurate mode or not.
708 :returns: list of primes in descending order.
710 """
711 if nprimes == 2:
712 return list(find_p_q(nbits // 2, getprime_func, accurate))
714 quo, rem = divmod(nbits, nprimes)
715 factor_lengths = [quo + 1]*rem + [quo] * (nprimes - rem)
717 while True:
718 primes = [getprime_func(length) for length in factor_lengths]
719 if len(set(primes)) == len(primes):
720 break
722 return list(reversed(sorted(primes)))
725def find_p_q(
726 nbits: int,
727 getprime_func: typing.Callable[[int], int] = rsa.prime.getprime,
728 accurate: bool = True,
729) -> typing.Tuple[int, int]:
730 """Returns a tuple of two different primes of nbits bits each.
732 The resulting p * q has exactly 2 * nbits bits, and the returned p and q
733 will not be equal.
735 :param nbits: the number of bits in each of p and q.
736 :param getprime_func: the getprime function, defaults to
737 :py:func:`rsa.prime.getprime`.
739 *Introduced in Python-RSA 3.1*
741 :param accurate: whether to enable accurate mode or not.
742 :returns: (p, q), where p > q
744 >>> (p, q) = find_p_q(128)
745 >>> from rsa import common
746 >>> common.bit_size(p * q)
747 256
749 When not in accurate mode, the number of bits can be slightly less
751 >>> (p, q) = find_p_q(128, accurate=False)
752 >>> from rsa import common
753 >>> common.bit_size(p * q) <= 256
754 True
755 >>> common.bit_size(p * q) > 240
756 True
758 """
760 total_bits = nbits * 2
762 # Make sure that p and q aren't too close or the factoring programs can
763 # factor n.
764 shift = nbits // 16
765 pbits = nbits + shift
766 qbits = nbits - shift
768 # Choose the two initial primes
769 p = getprime_func(pbits)
770 q = getprime_func(qbits)
772 def is_acceptable(p: int, q: int) -> bool:
773 """Returns True iff p and q are acceptable:
775 - p and q differ
776 - (p * q) has the right nr of bits (when accurate=True)
777 """
779 if p == q:
780 return False
782 if not accurate:
783 return True
785 # Make sure we have just the right amount of bits
786 found_size = rsa.common.bit_size(p * q)
787 return total_bits == found_size
789 # Keep choosing other primes until they match our requirements.
790 change_p = False
791 while not is_acceptable(p, q):
792 # Change p on one iteration and q on the other
793 if change_p:
794 p = getprime_func(pbits)
795 else:
796 q = getprime_func(qbits)
798 change_p = not change_p
800 # We want p > q as described on
801 # http://www.di-mgt.com.au/rsa_alg.html#crt
802 return max(p, q), min(p, q)
805def calculate_keys_custom_exponent(
806 p: int,
807 q: int,
808 exponent: int,
809 rs: typing.Optional[typing.List[int]] = None,
810) -> typing.Tuple[int, int]:
811 """Calculates an encryption and a decryption key given p, q and an exponent,
812 and returns them as a tuple (e, d)
814 :param p: the first large prime
815 :param q: the second large prime
816 :param exponent: the exponent for the key; only change this if you know
817 what you're doing, as the exponent influences how difficult your
818 private key can be cracked. A very common choice for e is 65537.
819 :type exponent: int
820 :param rs: the list of other large primes
822 """
824 phi_n = math.prod([x - 1 for x in [p, q] + ([] if rs is None else rs)])
826 try:
827 d = rsa.common.inverse(exponent, phi_n)
828 except rsa.common.NotRelativePrimeError as ex:
829 raise rsa.common.NotRelativePrimeError(
830 exponent,
831 phi_n,
832 ex.d,
833 msg="e (%d) and phi_n (%d) are not relatively prime (divider=%i)"
834 % (exponent, phi_n, ex.d),
835 ) from ex
837 if (exponent * d) % phi_n != 1:
838 raise ValueError(
839 "e (%d) and d (%d) are not mult. inv. modulo " "phi_n (%d)" % (exponent, d, phi_n)
840 )
842 return exponent, d
845def calculate_keys(p: int, q: int) -> typing.Tuple[int, int]:
846 """Calculates an encryption and a decryption key given p and q, and
847 returns them as a tuple (e, d)
849 :param p: the first large prime
850 :param q: the second large prime
852 :return: tuple (e, d) with the encryption and decryption exponents.
853 """
855 return calculate_keys_custom_exponent(p, q, DEFAULT_EXPONENT)
858def gen_keys(
859 nbits: int,
860 getprime_func: typing.Callable[[int], int],
861 accurate: bool = True,
862 exponent: int = DEFAULT_EXPONENT,
863 nprimes: int = 2,
864) -> typing.Tuple:
865 """Generate RSA keys of nbits bits. Returns (p, q, e, d) or (p, q, e, d, rs).
867 Note: this can take a long time, depending on the key size.
869 :param nbits: the total number of bits in ``p`` and ``q``. Both ``p`` and
870 ``q`` will use ``nbits/2`` bits.
871 :param getprime_func: either :py:func:`rsa.prime.getprime` or a function
872 with similar signature.
873 :param exponent: the exponent for the key; only change this if you know
874 what you're doing, as the exponent influences how difficult your
875 private key can be cracked. A very common choice for e is 65537.
876 :type exponent: int
877 :param nprimes: the number of prime factors comprising the modulus.
878 """
880 # Regenerate prime values, until calculate_keys_custom_exponent doesn't raise a
881 # ValueError.
882 while True:
883 primes = find_primes(nbits, getprime_func, accurate, nprimes)
884 p, q, rs = primes[0], primes[1], primes[2:]
885 try:
886 (e, d) = calculate_keys_custom_exponent(p, q, exponent=exponent, rs=rs)
887 break
888 except ValueError:
889 pass
891 if rs:
892 return p, q, e, d, rs
893 else:
894 return p, q, e, d
897def newkeys(
898 nbits: int,
899 accurate: bool = True,
900 poolsize: int = 1,
901 exponent: int = DEFAULT_EXPONENT,
902 nprimes: int = 2,
903) -> typing.Tuple[PublicKey, PrivateKey]:
904 """Generates public and private keys, and returns them as (pub, priv).
906 The public key is also known as the 'encryption key', and is a
907 :py:class:`rsa.PublicKey` object. The private key is also known as the
908 'decryption key' and is a :py:class:`rsa.PrivateKey` object.
910 :param nbits: the number of bits required to store the modulus ``n``.
911 :param accurate: when True, ``n`` will have exactly the number of bits you
912 asked for. However, this makes key generation much slower. When False,
913 `n`` may have slightly less bits.
914 :param poolsize: the number of processes to use to generate the prime
915 numbers. If set to a number > 1, a parallel algorithm will be used.
916 This requires Python 2.6 or newer.
917 :param exponent: the exponent for the key; only change this if you know
918 what you're doing, as the exponent influences how difficult your
919 private key can be cracked. A very common choice for e is 65537.
920 :type exponent: int
921 :param nprimes: the number of prime factors comprising the modulus.
923 :returns: a tuple (:py:class:`rsa.PublicKey`, :py:class:`rsa.PrivateKey`)
925 The ``poolsize`` parameter was added in *Python-RSA 3.1* and requires
926 Python 2.6 or newer.
928 """
930 if nbits < 16:
931 raise ValueError("Key too small")
933 if poolsize < 1:
934 raise ValueError("Pool size (%i) should be >= 1" % poolsize)
936 if nprimes < 2:
937 raise ValueError("Number of primes (%i) should be >= 2" % nprimes)
939 # Determine which getprime function to use
940 if poolsize > 1:
941 from rsa import parallel
943 def getprime_func(nbits: int) -> int:
944 return parallel.getprime(nbits, poolsize=poolsize)
946 else:
947 getprime_func = rsa.prime.getprime
949 # Generate the key components
950 result = gen_keys(nbits, getprime_func, accurate=accurate, exponent=exponent, nprimes=nprimes)
951 if len(result) == 4:
952 p, q, e, d = result
953 rs = []
954 else:
955 p, q, e, d, rs = result
957 # Create the key objects
958 n = math.prod([p, q] + rs)
960 return (PublicKey(n, e), PrivateKey(n, e, d, p, q, rs))
963__all__ = ["PublicKey", "PrivateKey", "newkeys"]
965if __name__ == "__main__":
966 import doctest
968 try:
969 for count in range(100):
970 (failures, tests) = doctest.testmod()
971 if failures:
972 break
974 if (count % 10 == 0 and count) or count == 1:
975 print("%i times" % count)
976 except KeyboardInterrupt:
977 print("Aborted")
978 else:
979 print("Doctests done")