1 # Author: Trevor Perrin
2 # See the LICENSE file for legal information regarding use of this file.
4 """Factory functions for asymmetric cryptography.
5 @sort: generateRSAKey, parsePEMKey, parseAsPublicKey
10 from .rsakey import RSAKey
11 from .python_rsakey import Python_RSAKey
12 from tlslite.utils import cryptomath
14 if cryptomath.m2cryptoLoaded:
15 from .openssl_rsakey import OpenSSL_RSAKey
17 if cryptomath.pycryptoLoaded:
18 from .pycrypto_rsakey import PyCrypto_RSAKey
20 # **************************************************************************
21 # Factory Functions for RSA Keys
22 # **************************************************************************
24 def generateRSAKey(bits, implementations=["openssl", "python"]):
25 """Generate an RSA key with the specified bit length.
28 @param bits: Desired bit length of the new key's modulus.
30 @rtype: L{tlslite.utils.rsakey.RSAKey}
31 @return: A new RSA private key.
33 for implementation in implementations:
34 if implementation == "openssl" and cryptomath.m2cryptoLoaded:
35 return OpenSSL_RSAKey.generate(bits)
36 elif implementation == "python":
37 return Python_RSAKey.generate(bits)
38 raise ValueError("No acceptable implementations")
40 #Parse as an OpenSSL or Python key
41 def parsePEMKey(s, private=False, public=False, passwordCallback=None,
42 implementations=["openssl", "python"]):
43 """Parse a PEM-format key.
45 The PEM format is used by OpenSSL and other tools. The
46 format is typically used to store both the public and private
47 components of a key. For example::
49 -----BEGIN RSA PRIVATE KEY-----
50 MIICXQIBAAKBgQDYscuoMzsGmW0pAYsmyHltxB2TdwHS0dImfjCMfaSDkfLdZY5+
51 dOWORVns9etWnr194mSGA1F0Pls/VJW8+cX9+3vtJV8zSdANPYUoQf0TP7VlJxkH
52 dSRkUbEoz5bAAs/+970uos7n7iXQIni+3erUTdYEk2iWnMBjTljfgbK/dQIDAQAB
53 AoGAJHoJZk75aKr7DSQNYIHuruOMdv5ZeDuJvKERWxTrVJqE32/xBKh42/IgqRrc
54 esBN9ZregRCd7YtxoL+EVUNWaJNVx2mNmezEznrc9zhcYUrgeaVdFO2yBF1889zO
55 gCOVwrO8uDgeyj6IKa25H6c1N13ih/o7ZzEgWbGG+ylU1yECQQDv4ZSJ4EjSh/Fl
56 aHdz3wbBa/HKGTjC8iRy476Cyg2Fm8MZUe9Yy3udOrb5ZnS2MTpIXt5AF3h2TfYV
57 VoFXIorjAkEA50FcJmzT8sNMrPaV8vn+9W2Lu4U7C+K/O2g1iXMaZms5PC5zV5aV
58 CKXZWUX1fq2RaOzlbQrpgiolhXpeh8FjxwJBAOFHzSQfSsTNfttp3KUpU0LbiVvv
59 i+spVSnA0O4rq79KpVNmK44Mq67hsW1P11QzrzTAQ6GVaUBRv0YS061td1kCQHnP
60 wtN2tboFR6lABkJDjxoGRvlSt4SOPr7zKGgrWjeiuTZLHXSAnCY+/hr5L9Q3ZwXG
61 6x6iBdgLjVIe4BZQNtcCQQDXGv/gWinCNTN3MPWfTW/RGzuMYVmyBFais0/VrgdH
62 h1dLpztmpQqfyH/zrBXQ9qL/zR4ojS6XYneO/U18WpEe
63 -----END RSA PRIVATE KEY-----
65 To generate a key like this with OpenSSL, run::
67 openssl genrsa 2048 > key.pem
69 This format also supports password-encrypted private keys. TLS
70 Lite can only handle password-encrypted private keys when OpenSSL
71 and M2Crypto are installed. In this case, passwordCallback will be
72 invoked to query the user for the password.
75 @param s: A string containing a PEM-encoded public or private key.
78 @param private: If True, a L{SyntaxError} will be raised if the
79 private key component is not present.
82 @param public: If True, the private key component (if present) will
83 be discarded, so this function will always return a public key.
85 @type passwordCallback: callable
86 @param passwordCallback: This function will be called, with no
87 arguments, if the PEM-encoded private key is password-encrypted.
88 The callback should return the password string. If the password is
89 incorrect, SyntaxError will be raised. If no callback is passed
90 and the key is password-encrypted, a prompt will be displayed at
93 @rtype: L{tlslite.utils.RSAKey.RSAKey}
96 @raise SyntaxError: If the key is not properly formatted.
98 for implementation in implementations:
99 if implementation == "openssl" and cryptomath.m2cryptoLoaded:
100 key = OpenSSL_RSAKey.parse(s, passwordCallback)
102 elif implementation == "python":
103 key = Python_RSAKey.parsePEM(s)
106 raise ValueError("No acceptable implementations")
108 return _parseKeyHelper(key, private, public)
111 def _parseKeyHelper(key, private, public):
113 if not key.hasPrivateKey():
114 raise SyntaxError("Not a private key!")
117 return _createPublicKey(key)
120 if hasattr(key, "d"):
121 return _createPrivateKey(key)
127 def parseAsPublicKey(s):
128 """Parse a PEM-formatted public key.
131 @param s: A string containing a PEM-encoded public or private key.
133 @rtype: L{tlslite.utils.rsakey.RSAKey}
134 @return: An RSA public key.
136 @raise SyntaxError: If the key is not properly formatted.
138 return parsePEMKey(s, public=True)
140 def parsePrivateKey(s):
141 """Parse a PEM-formatted private key.
144 @param s: A string containing a PEM-encoded private key.
146 @rtype: L{tlslite.utils.rsakey.RSAKey}
147 @return: An RSA private key.
149 @raise SyntaxError: If the key is not properly formatted.
151 return parsePEMKey(s, private=True)
153 def _createPublicKey(key):
155 Create a new public key. Discard any private component,
156 and return the most efficient key possible.
158 if not isinstance(key, RSAKey):
159 raise AssertionError()
160 return _createPublicRSAKey(key.n, key.e)
162 def _createPrivateKey(key):
164 Create a new private key. Return the most efficient key possible.
166 if not isinstance(key, RSAKey):
167 raise AssertionError()
168 if not key.hasPrivateKey():
169 raise AssertionError()
170 return _createPrivateRSAKey(key.n, key.e, key.d, key.p, key.q, key.dP,
173 def _createPublicRSAKey(n, e, implementations = ["openssl", "pycrypto",
175 for implementation in implementations:
176 if implementation == "openssl" and cryptomath.m2cryptoLoaded:
177 return OpenSSL_RSAKey(n, e)
178 elif implementation == "pycrypto" and cryptomath.pycryptoLoaded:
179 return PyCrypto_RSAKey(n, e)
180 elif implementation == "python":
181 return Python_RSAKey(n, e)
182 raise ValueError("No acceptable implementations")
184 def _createPrivateRSAKey(n, e, d, p, q, dP, dQ, qInv,
185 implementations = ["pycrypto", "python"]):
186 for implementation in implementations:
187 if implementation == "pycrypto" and cryptomath.pycryptoLoaded:
188 return PyCrypto_RSAKey(n, e, d, p, q, dP, dQ, qInv)
189 elif implementation == "python":
190 return Python_RSAKey(n, e, d, p, q, dP, dQ, qInv)
191 raise ValueError("No acceptable implementations")