1 """Factory functions for asymmetric cryptography.
2 @sort: generateRSAKey, parseXMLKey, parsePEMKey, parseAsPublicKey,
8 from RSAKey import RSAKey
9 from Python_RSAKey import Python_RSAKey
12 if cryptomath.m2cryptoLoaded:
13 from OpenSSL_RSAKey import OpenSSL_RSAKey
15 if cryptomath.pycryptoLoaded:
16 from PyCrypto_RSAKey import PyCrypto_RSAKey
18 # **************************************************************************
19 # Factory Functions for RSA Keys
20 # **************************************************************************
22 def generateRSAKey(bits, implementations=["openssl", "python"]):
23 """Generate an RSA key with the specified bit length.
26 @param bits: Desired bit length of the new key's modulus.
28 @rtype: L{tlslite.utils.RSAKey.RSAKey}
29 @return: A new RSA private key.
31 for implementation in implementations:
32 if implementation == "openssl" and cryptomath.m2cryptoLoaded:
33 return OpenSSL_RSAKey.generate(bits)
34 elif implementation == "python":
35 return Python_RSAKey.generate(bits)
36 raise ValueError("No acceptable implementations")
38 def parseXMLKey(s, private=False, public=False, implementations=["python"]):
39 """Parse an XML-format key.
41 The XML format used here is specific to tlslite and cryptoIDlib. The
42 format can store the public component of a key, or the public and
43 private components. For example::
45 <publicKey xmlns="http://trevp.net/rsa">
46 <n>4a5yzB8oGNlHo866CAspAC47M4Fvx58zwK8pou...
50 <privateKey xmlns="http://trevp.net/rsa">
51 <n>4a5yzB8oGNlHo866CAspAC47M4Fvx58zwK8pou...
53 <d>JZ0TIgUxWXmL8KJ0VqyG1V0J3ern9pqIoB0xmy...
54 <p>5PreIj6z6ldIGL1V4+1C36dQFHNCQHJvW52GXc...
55 <q>/E/wDit8YXPCxx126zTq2ilQ3IcW54NJYyNjiZ...
56 <dP>mKc+wX8inDowEH45Qp4slRo1YveBgExKPROu6...
57 <dQ>qDVKtBz9lk0shL5PR3ickXDgkwS576zbl2ztB...
58 <qInv>j6E8EA7dNsTImaXexAmLA1DoeArsYeFAInr...
62 @param s: A string containing an XML public or private key.
65 @param private: If True, a L{SyntaxError} will be raised if the private
66 key component is not present.
69 @param public: If True, the private key component (if present) will be
70 discarded, so this function will always return a public key.
72 @rtype: L{tlslite.utils.RSAKey.RSAKey}
75 @raise SyntaxError: If the key is not properly formatted.
77 for implementation in implementations:
78 if implementation == "python":
79 key = Python_RSAKey.parseXML(s)
82 raise ValueError("No acceptable implementations")
84 return _parseKeyHelper(key, private, public)
86 #Parse as an OpenSSL or Python key
87 def parsePEMKey(s, private=False, public=False, passwordCallback=None,
88 implementations=["openssl", "python"]):
89 """Parse a PEM-format key.
91 The PEM format is used by OpenSSL and other tools. The
92 format is typically used to store both the public and private
93 components of a key. For example::
95 -----BEGIN RSA PRIVATE KEY-----
96 MIICXQIBAAKBgQDYscuoMzsGmW0pAYsmyHltxB2TdwHS0dImfjCMfaSDkfLdZY5+
97 dOWORVns9etWnr194mSGA1F0Pls/VJW8+cX9+3vtJV8zSdANPYUoQf0TP7VlJxkH
98 dSRkUbEoz5bAAs/+970uos7n7iXQIni+3erUTdYEk2iWnMBjTljfgbK/dQIDAQAB
99 AoGAJHoJZk75aKr7DSQNYIHuruOMdv5ZeDuJvKERWxTrVJqE32/xBKh42/IgqRrc
100 esBN9ZregRCd7YtxoL+EVUNWaJNVx2mNmezEznrc9zhcYUrgeaVdFO2yBF1889zO
101 gCOVwrO8uDgeyj6IKa25H6c1N13ih/o7ZzEgWbGG+ylU1yECQQDv4ZSJ4EjSh/Fl
102 aHdz3wbBa/HKGTjC8iRy476Cyg2Fm8MZUe9Yy3udOrb5ZnS2MTpIXt5AF3h2TfYV
103 VoFXIorjAkEA50FcJmzT8sNMrPaV8vn+9W2Lu4U7C+K/O2g1iXMaZms5PC5zV5aV
104 CKXZWUX1fq2RaOzlbQrpgiolhXpeh8FjxwJBAOFHzSQfSsTNfttp3KUpU0LbiVvv
105 i+spVSnA0O4rq79KpVNmK44Mq67hsW1P11QzrzTAQ6GVaUBRv0YS061td1kCQHnP
106 wtN2tboFR6lABkJDjxoGRvlSt4SOPr7zKGgrWjeiuTZLHXSAnCY+/hr5L9Q3ZwXG
107 6x6iBdgLjVIe4BZQNtcCQQDXGv/gWinCNTN3MPWfTW/RGzuMYVmyBFais0/VrgdH
108 h1dLpztmpQqfyH/zrBXQ9qL/zR4ojS6XYneO/U18WpEe
109 -----END RSA PRIVATE KEY-----
111 To generate a key like this with OpenSSL, run::
113 openssl genrsa 2048 > key.pem
115 This format also supports password-encrypted private keys. TLS
116 Lite can only handle password-encrypted private keys when OpenSSL
117 and M2Crypto are installed. In this case, passwordCallback will be
118 invoked to query the user for the password.
121 @param s: A string containing a PEM-encoded public or private key.
124 @param private: If True, a L{SyntaxError} will be raised if the
125 private key component is not present.
128 @param public: If True, the private key component (if present) will
129 be discarded, so this function will always return a public key.
131 @type passwordCallback: callable
132 @param passwordCallback: This function will be called, with no
133 arguments, if the PEM-encoded private key is password-encrypted.
134 The callback should return the password string. If the password is
135 incorrect, SyntaxError will be raised. If no callback is passed
136 and the key is password-encrypted, a prompt will be displayed at
139 @rtype: L{tlslite.utils.RSAKey.RSAKey}
142 @raise SyntaxError: If the key is not properly formatted.
144 for implementation in implementations:
145 if implementation == "openssl" and cryptomath.m2cryptoLoaded:
146 key = OpenSSL_RSAKey.parse(s, passwordCallback)
148 elif implementation == "python":
149 key = Python_RSAKey.parsePEM(s)
152 raise ValueError("No acceptable implementations")
154 return _parseKeyHelper(key, private, public)
157 def _parseKeyHelper(key, private, public):
159 if not key.hasPrivateKey():
160 raise SyntaxError("Not a private key!")
163 return _createPublicKey(key)
166 if hasattr(key, "d"):
167 return _createPrivateKey(key)
173 def parseAsPublicKey(s):
174 """Parse an XML or PEM-formatted public key.
177 @param s: A string containing an XML or PEM-encoded public or private key.
179 @rtype: L{tlslite.utils.RSAKey.RSAKey}
180 @return: An RSA public key.
182 @raise SyntaxError: If the key is not properly formatted.
185 return parsePEMKey(s, public=True)
187 return parseXMLKey(s, public=True)
189 def parsePrivateKey(s):
190 """Parse an XML or PEM-formatted private key.
193 @param s: A string containing an XML or PEM-encoded private key.
195 @rtype: L{tlslite.utils.RSAKey.RSAKey}
196 @return: An RSA private key.
198 @raise SyntaxError: If the key is not properly formatted.
201 return parsePEMKey(s, private=True)
203 return parseXMLKey(s, private=True)
205 def _createPublicKey(key):
207 Create a new public key. Discard any private component,
208 and return the most efficient key possible.
210 if not isinstance(key, RSAKey):
211 raise AssertionError()
212 return _createPublicRSAKey(key.n, key.e)
214 def _createPrivateKey(key):
216 Create a new private key. Return the most efficient key possible.
218 if not isinstance(key, RSAKey):
219 raise AssertionError()
220 if not key.hasPrivateKey():
221 raise AssertionError()
222 return _createPrivateRSAKey(key.n, key.e, key.d, key.p, key.q, key.dP,
225 def _createPublicRSAKey(n, e, implementations = ["openssl", "pycrypto",
227 for implementation in implementations:
228 if implementation == "openssl" and cryptomath.m2cryptoLoaded:
229 return OpenSSL_RSAKey(n, e)
230 elif implementation == "pycrypto" and cryptomath.pycryptoLoaded:
231 return PyCrypto_RSAKey(n, e)
232 elif implementation == "python":
233 return Python_RSAKey(n, e)
234 raise ValueError("No acceptable implementations")
236 def _createPrivateRSAKey(n, e, d, p, q, dP, dQ, qInv,
237 implementations = ["pycrypto", "python"]):
238 for implementation in implementations:
239 if implementation == "pycrypto" and cryptomath.pycryptoLoaded:
240 return PyCrypto_RSAKey(n, e, d, p, q, dP, dQ, qInv)
241 elif implementation == "python":
242 return Python_RSAKey(n, e, d, p, q, dP, dQ, qInv)
243 raise ValueError("No acceptable implementations")