• 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#      http://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'''
27
28import logging
29from rsa._compat import b, bytes_type
30
31import rsa.prime
32import rsa.pem
33import rsa.common
34
35log = logging.getLogger(__name__)
36
37
38
39class AbstractKey(object):
40    '''Abstract superclass for private and public keys.'''
41
42    @classmethod
43    def load_pkcs1(cls, keyfile, format='PEM'):
44        r'''Loads a key in PKCS#1 DER or PEM format.
45
46        :param keyfile: contents of a DER- or PEM-encoded file that contains
47            the public key.
48        :param format: the format of the file to load; 'PEM' or 'DER'
49
50        :return: a PublicKey object
51
52        '''
53
54        methods = {
55            'PEM': cls._load_pkcs1_pem,
56            'DER': cls._load_pkcs1_der,
57        }
58
59        if format not in methods:
60            formats = ', '.join(sorted(methods.keys()))
61            raise ValueError('Unsupported format: %r, try one of %s' % (format,
62                formats))
63
64        method = methods[format]
65        return method(keyfile)
66
67    def save_pkcs1(self, format='PEM'):
68        '''Saves the public key in PKCS#1 DER or PEM format.
69
70        :param format: the format to save; 'PEM' or 'DER'
71        :returns: the DER- or PEM-encoded public key.
72
73        '''
74
75        methods = {
76            'PEM': self._save_pkcs1_pem,
77            'DER': self._save_pkcs1_der,
78        }
79
80        if format not in methods:
81            formats = ', '.join(sorted(methods.keys()))
82            raise ValueError('Unsupported format: %r, try one of %s' % (format,
83                formats))
84
85        method = methods[format]
86        return method()
87
88class PublicKey(AbstractKey):
89    '''Represents a public RSA key.
90
91    This key is also known as the 'encryption key'. It contains the 'n' and 'e'
92    values.
93
94    Supports attributes as well as dictionary-like access. Attribute accesss is
95    faster, though.
96
97    >>> PublicKey(5, 3)
98    PublicKey(5, 3)
99
100    >>> key = PublicKey(5, 3)
101    >>> key.n
102    5
103    >>> key['n']
104    5
105    >>> key.e
106    3
107    >>> key['e']
108    3
109
110    '''
111
112    __slots__ = ('n', 'e')
113
114    def __init__(self, n, e):
115        self.n = n
116        self.e = e
117
118    def __getitem__(self, key):
119        return getattr(self, key)
120
121    def __repr__(self):
122        return 'PublicKey(%i, %i)' % (self.n, self.e)
123
124    def __eq__(self, other):
125        if other is None:
126            return False
127
128        if not isinstance(other, PublicKey):
129            return False
130
131        return self.n == other.n and self.e == other.e
132
133    def __ne__(self, other):
134        return not (self == other)
135
136    @classmethod
137    def _load_pkcs1_der(cls, keyfile):
138        r'''Loads a key in PKCS#1 DER format.
139
140        @param keyfile: contents of a DER-encoded file that contains the public
141            key.
142        @return: a PublicKey object
143
144        First let's construct a DER encoded key:
145
146        >>> import base64
147        >>> b64der = 'MAwCBQCNGmYtAgMBAAE='
148        >>> der = base64.decodestring(b64der)
149
150        This loads the file:
151
152        >>> PublicKey._load_pkcs1_der(der)
153        PublicKey(2367317549, 65537)
154
155        '''
156
157        from pyasn1.codec.der import decoder
158        from rsa.asn1 import AsnPubKey
159
160        (priv, _) = decoder.decode(keyfile, asn1Spec=AsnPubKey())
161        return cls(n=int(priv['modulus']), e=int(priv['publicExponent']))
162
163    def _save_pkcs1_der(self):
164        '''Saves the public key in PKCS#1 DER format.
165
166        @returns: the DER-encoded public key.
167        '''
168
169        from pyasn1.codec.der import encoder
170        from rsa.asn1 import AsnPubKey
171
172        # Create the ASN object
173        asn_key = AsnPubKey()
174        asn_key.setComponentByName('modulus', self.n)
175        asn_key.setComponentByName('publicExponent', self.e)
176
177        return encoder.encode(asn_key)
178
179    @classmethod
180    def _load_pkcs1_pem(cls, keyfile):
181        '''Loads a PKCS#1 PEM-encoded public key file.
182
183        The contents of the file before the "-----BEGIN RSA PUBLIC KEY-----" and
184        after the "-----END RSA PUBLIC KEY-----" lines is ignored.
185
186        @param keyfile: contents of a PEM-encoded file that contains the public
187            key.
188        @return: a PublicKey object
189        '''
190
191        der = rsa.pem.load_pem(keyfile, 'RSA PUBLIC KEY')
192        return cls._load_pkcs1_der(der)
193
194    def _save_pkcs1_pem(self):
195        '''Saves a PKCS#1 PEM-encoded public key file.
196
197        @return: contents of a PEM-encoded file that contains the public key.
198        '''
199
200        der = self._save_pkcs1_der()
201        return rsa.pem.save_pem(der, 'RSA PUBLIC KEY')
202
203    @classmethod
204    def load_pkcs1_openssl_pem(cls, keyfile):
205        '''Loads a PKCS#1.5 PEM-encoded public key file from OpenSSL.
206
207        These files can be recognised in that they start with BEGIN PUBLIC KEY
208        rather than BEGIN RSA PUBLIC KEY.
209
210        The contents of the file before the "-----BEGIN PUBLIC KEY-----" and
211        after the "-----END PUBLIC KEY-----" lines is ignored.
212
213        @param keyfile: contents of a PEM-encoded file that contains the public
214            key, from OpenSSL.
215        @return: a PublicKey object
216        '''
217
218        der = rsa.pem.load_pem(keyfile, 'PUBLIC KEY')
219        return cls.load_pkcs1_openssl_der(der)
220
221    @classmethod
222    def load_pkcs1_openssl_der(cls, keyfile):
223        '''Loads a PKCS#1 DER-encoded public key file from OpenSSL.
224
225        @param keyfile: contents of a DER-encoded file that contains the public
226            key, from OpenSSL.
227        @return: a PublicKey object
228        '''
229
230        from rsa.asn1 import OpenSSLPubKey
231        from pyasn1.codec.der import decoder
232        from pyasn1.type import univ
233
234        (keyinfo, _) = decoder.decode(keyfile, asn1Spec=OpenSSLPubKey())
235
236        if keyinfo['header']['oid'] != univ.ObjectIdentifier('1.2.840.113549.1.1.1'):
237            raise TypeError("This is not a DER-encoded OpenSSL-compatible public key")
238
239        return cls._load_pkcs1_der(keyinfo['key'][1:])
240
241
242
243
244class PrivateKey(AbstractKey):
245    '''Represents a private RSA key.
246
247    This key is also known as the 'decryption key'. It contains the 'n', 'e',
248    'd', 'p', 'q' and other values.
249
250    Supports attributes as well as dictionary-like access. Attribute accesss is
251    faster, though.
252
253    >>> PrivateKey(3247, 65537, 833, 191, 17)
254    PrivateKey(3247, 65537, 833, 191, 17)
255
256    exp1, exp2 and coef don't have to be given, they will be calculated:
257
258    >>> pk = PrivateKey(3727264081, 65537, 3349121513, 65063, 57287)
259    >>> pk.exp1
260    55063
261    >>> pk.exp2
262    10095
263    >>> pk.coef
264    50797
265
266    If you give exp1, exp2 or coef, they will be used as-is:
267
268    >>> pk = PrivateKey(1, 2, 3, 4, 5, 6, 7, 8)
269    >>> pk.exp1
270    6
271    >>> pk.exp2
272    7
273    >>> pk.coef
274    8
275
276    '''
277
278    __slots__ = ('n', 'e', 'd', 'p', 'q', 'exp1', 'exp2', 'coef')
279
280    def __init__(self, n, e, d, p, q, exp1=None, exp2=None, coef=None):
281        self.n = n
282        self.e = e
283        self.d = d
284        self.p = p
285        self.q = q
286
287        # Calculate the other values if they aren't supplied
288        if exp1 is None:
289            self.exp1 = int(d % (p - 1))
290        else:
291            self.exp1 = exp1
292
293        if exp1 is None:
294            self.exp2 = int(d % (q - 1))
295        else:
296            self.exp2 = exp2
297
298        if coef is None:
299            self.coef = rsa.common.inverse(q, p)
300        else:
301            self.coef = coef
302
303    def __getitem__(self, key):
304        return getattr(self, key)
305
306    def __repr__(self):
307        return 'PrivateKey(%(n)i, %(e)i, %(d)i, %(p)i, %(q)i)' % self
308
309    def __eq__(self, other):
310        if other is None:
311            return False
312
313        if not isinstance(other, PrivateKey):
314            return False
315
316        return (self.n == other.n and
317            self.e == other.e and
318            self.d == other.d and
319            self.p == other.p and
320            self.q == other.q and
321            self.exp1 == other.exp1 and
322            self.exp2 == other.exp2 and
323            self.coef == other.coef)
324
325    def __ne__(self, other):
326        return not (self == other)
327
328    @classmethod
329    def _load_pkcs1_der(cls, keyfile):
330        r'''Loads a key in PKCS#1 DER format.
331
332        @param keyfile: contents of a DER-encoded file that contains the private
333            key.
334        @return: a PrivateKey object
335
336        First let's construct a DER encoded key:
337
338        >>> import base64
339        >>> b64der = 'MC4CAQACBQDeKYlRAgMBAAECBQDHn4npAgMA/icCAwDfxwIDANcXAgInbwIDAMZt'
340        >>> der = base64.decodestring(b64der)
341
342        This loads the file:
343
344        >>> PrivateKey._load_pkcs1_der(der)
345        PrivateKey(3727264081, 65537, 3349121513, 65063, 57287)
346
347        '''
348
349        from pyasn1.codec.der import decoder
350        (priv, _) = decoder.decode(keyfile)
351
352        # ASN.1 contents of DER encoded private key:
353        #
354        # RSAPrivateKey ::= SEQUENCE {
355        #     version           Version,
356        #     modulus           INTEGER,  -- n
357        #     publicExponent    INTEGER,  -- e
358        #     privateExponent   INTEGER,  -- d
359        #     prime1            INTEGER,  -- p
360        #     prime2            INTEGER,  -- q
361        #     exponent1         INTEGER,  -- d mod (p-1)
362        #     exponent2         INTEGER,  -- d mod (q-1)
363        #     coefficient       INTEGER,  -- (inverse of q) mod p
364        #     otherPrimeInfos   OtherPrimeInfos OPTIONAL
365        # }
366
367        if priv[0] != 0:
368            raise ValueError('Unable to read this file, version %s != 0' % priv[0])
369
370        as_ints = tuple(int(x) for x in priv[1:9])
371        return cls(*as_ints)
372
373    def _save_pkcs1_der(self):
374        '''Saves the private key in PKCS#1 DER format.
375
376        @returns: the DER-encoded private key.
377        '''
378
379        from pyasn1.type import univ, namedtype
380        from pyasn1.codec.der import encoder
381
382        class AsnPrivKey(univ.Sequence):
383            componentType = namedtype.NamedTypes(
384                namedtype.NamedType('version', univ.Integer()),
385                namedtype.NamedType('modulus', univ.Integer()),
386                namedtype.NamedType('publicExponent', univ.Integer()),
387                namedtype.NamedType('privateExponent', univ.Integer()),
388                namedtype.NamedType('prime1', univ.Integer()),
389                namedtype.NamedType('prime2', univ.Integer()),
390                namedtype.NamedType('exponent1', univ.Integer()),
391                namedtype.NamedType('exponent2', univ.Integer()),
392                namedtype.NamedType('coefficient', univ.Integer()),
393            )
394
395        # Create the ASN object
396        asn_key = AsnPrivKey()
397        asn_key.setComponentByName('version', 0)
398        asn_key.setComponentByName('modulus', self.n)
399        asn_key.setComponentByName('publicExponent', self.e)
400        asn_key.setComponentByName('privateExponent', self.d)
401        asn_key.setComponentByName('prime1', self.p)
402        asn_key.setComponentByName('prime2', self.q)
403        asn_key.setComponentByName('exponent1', self.exp1)
404        asn_key.setComponentByName('exponent2', self.exp2)
405        asn_key.setComponentByName('coefficient', self.coef)
406
407        return encoder.encode(asn_key)
408
409    @classmethod
410    def _load_pkcs1_pem(cls, keyfile):
411        '''Loads a PKCS#1 PEM-encoded private key file.
412
413        The contents of the file before the "-----BEGIN RSA PRIVATE KEY-----" and
414        after the "-----END RSA PRIVATE KEY-----" lines is ignored.
415
416        @param keyfile: contents of a PEM-encoded file that contains the private
417            key.
418        @return: a PrivateKey object
419        '''
420
421        der = rsa.pem.load_pem(keyfile, b('RSA PRIVATE KEY'))
422        return cls._load_pkcs1_der(der)
423
424    def _save_pkcs1_pem(self):
425        '''Saves a PKCS#1 PEM-encoded private key file.
426
427        @return: contents of a PEM-encoded file that contains the private key.
428        '''
429
430        der = self._save_pkcs1_der()
431        return rsa.pem.save_pem(der, b('RSA PRIVATE KEY'))
432
433def find_p_q(nbits, getprime_func=rsa.prime.getprime, accurate=True):
434    ''''Returns a tuple of two different primes of nbits bits each.
435
436    The resulting p * q has exacty 2 * nbits bits, and the returned p and q
437    will not be equal.
438
439    :param nbits: the number of bits in each of p and q.
440    :param getprime_func: the getprime function, defaults to
441        :py:func:`rsa.prime.getprime`.
442
443        *Introduced in Python-RSA 3.1*
444
445    :param accurate: whether to enable accurate mode or not.
446    :returns: (p, q), where p > q
447
448    >>> (p, q) = find_p_q(128)
449    >>> from rsa import common
450    >>> common.bit_size(p * q)
451    256
452
453    When not in accurate mode, the number of bits can be slightly less
454
455    >>> (p, q) = find_p_q(128, accurate=False)
456    >>> from rsa import common
457    >>> common.bit_size(p * q) <= 256
458    True
459    >>> common.bit_size(p * q) > 240
460    True
461
462    '''
463
464    total_bits = nbits * 2
465
466    # Make sure that p and q aren't too close or the factoring programs can
467    # factor n.
468    shift = nbits // 16
469    pbits = nbits + shift
470    qbits = nbits - shift
471
472    # Choose the two initial primes
473    log.debug('find_p_q(%i): Finding p', nbits)
474    p = getprime_func(pbits)
475    log.debug('find_p_q(%i): Finding q', nbits)
476    q = getprime_func(qbits)
477
478    def is_acceptable(p, q):
479        '''Returns True iff p and q are acceptable:
480
481            - p and q differ
482            - (p * q) has the right nr of bits (when accurate=True)
483        '''
484
485        if p == q:
486            return False
487
488        if not accurate:
489            return True
490
491        # Make sure we have just the right amount of bits
492        found_size = rsa.common.bit_size(p * q)
493        return total_bits == found_size
494
495    # Keep choosing other primes until they match our requirements.
496    change_p = False
497    while not is_acceptable(p, q):
498        # Change p on one iteration and q on the other
499        if change_p:
500            p = getprime_func(pbits)
501        else:
502            q = getprime_func(qbits)
503
504        change_p = not change_p
505
506    # We want p > q as described on
507    # http://www.di-mgt.com.au/rsa_alg.html#crt
508    return (max(p, q), min(p, q))
509
510def calculate_keys(p, q, nbits):
511    '''Calculates an encryption and a decryption key given p and q, and
512    returns them as a tuple (e, d)
513
514    '''
515
516    phi_n = (p - 1) * (q - 1)
517
518    # A very common choice for e is 65537
519    e = 65537
520
521    try:
522        d = rsa.common.inverse(e, phi_n)
523    except ValueError:
524        raise ValueError("e (%d) and phi_n (%d) are not relatively prime" %
525                (e, phi_n))
526
527    if (e * d) % phi_n != 1:
528        raise ValueError("e (%d) and d (%d) are not mult. inv. modulo "
529                "phi_n (%d)" % (e, d, phi_n))
530
531    return (e, d)
532
533def gen_keys(nbits, getprime_func, accurate=True):
534    '''Generate RSA keys of nbits bits. Returns (p, q, e, d).
535
536    Note: this can take a long time, depending on the key size.
537
538    :param nbits: the total number of bits in ``p`` and ``q``. Both ``p`` and
539        ``q`` will use ``nbits/2`` bits.
540    :param getprime_func: either :py:func:`rsa.prime.getprime` or a function
541        with similar signature.
542    '''
543
544    (p, q) = find_p_q(nbits // 2, getprime_func, accurate)
545    (e, d) = calculate_keys(p, q, nbits // 2)
546
547    return (p, q, e, d)
548
549def newkeys(nbits, accurate=True, poolsize=1):
550    '''Generates public and private keys, and returns them as (pub, priv).
551
552    The public key is also known as the 'encryption key', and is a
553    :py:class:`rsa.PublicKey` object. The private key is also known as the
554    'decryption key' and is a :py:class:`rsa.PrivateKey` object.
555
556    :param nbits: the number of bits required to store ``n = p*q``.
557    :param accurate: when True, ``n`` will have exactly the number of bits you
558        asked for. However, this makes key generation much slower. When False,
559        `n`` may have slightly less bits.
560    :param poolsize: the number of processes to use to generate the prime
561        numbers. If set to a number > 1, a parallel algorithm will be used.
562        This requires Python 2.6 or newer.
563
564    :returns: a tuple (:py:class:`rsa.PublicKey`, :py:class:`rsa.PrivateKey`)
565
566    The ``poolsize`` parameter was added in *Python-RSA 3.1* and requires
567    Python 2.6 or newer.
568
569    '''
570
571    if nbits < 16:
572        raise ValueError('Key too small')
573
574    if poolsize < 1:
575        raise ValueError('Pool size (%i) should be >= 1' % poolsize)
576
577    # Determine which getprime function to use
578    if poolsize > 1:
579        from rsa import parallel
580        import functools
581
582        getprime_func = functools.partial(parallel.getprime, poolsize=poolsize)
583    else: getprime_func = rsa.prime.getprime
584
585    # Generate the key components
586    (p, q, e, d) = gen_keys(nbits, getprime_func)
587
588    # Create the key objects
589    n = p * q
590
591    return (
592        PublicKey(n, e),
593        PrivateKey(n, e, d, p, q)
594    )
595
596__all__ = ['PublicKey', 'PrivateKey', 'newkeys']
597
598if __name__ == '__main__':
599    import doctest
600
601    try:
602        for count in range(100):
603            (failures, tests) = doctest.testmod()
604            if failures:
605                break
606
607            if (count and count % 10 == 0) or count == 1:
608                print('%i times' % count)
609    except KeyboardInterrupt:
610        print('Aborted')
611    else:
612        print('Doctests done')
613