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