keyfactory.py revision c5cede9ae108bb15f6b7a8aea21c7e1fefa2834c
1"""Factory functions for asymmetric cryptography. 2@sort: generateRSAKey, parseXMLKey, parsePEMKey, parseAsPublicKey, 3parseAsPrivateKey 4""" 5 6from compat import * 7 8from rsakey import RSAKey 9from python_rsakey import Python_RSAKey 10import cryptomath 11 12if cryptomath.m2cryptoLoaded: 13 from openssl_rsakey import OpenSSL_RSAKey 14 15if cryptomath.pycryptoLoaded: 16 from pycrypto_rsakey import PyCrypto_RSAKey 17 18# ************************************************************************** 19# Factory Functions for RSA Keys 20# ************************************************************************** 21 22def generateRSAKey(bits, implementations=["openssl", "python"]): 23 """Generate an RSA key with the specified bit length. 24 25 @type bits: int 26 @param bits: Desired bit length of the new key's modulus. 27 28 @rtype: L{tlslite.utils.RSAKey.RSAKey} 29 @return: A new RSA private key. 30 """ 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") 37 38def parseXMLKey(s, private=False, public=False, implementations=["python"]): 39 """Parse an XML-format key. 40 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:: 44 45 <publicKey xmlns="http://trevp.net/rsa"> 46 <n>4a5yzB8oGNlHo866CAspAC47M4Fvx58zwK8pou... 47 <e>Aw==</e> 48 </publicKey> 49 50 <privateKey xmlns="http://trevp.net/rsa"> 51 <n>4a5yzB8oGNlHo866CAspAC47M4Fvx58zwK8pou... 52 <e>Aw==</e> 53 <d>JZ0TIgUxWXmL8KJ0VqyG1V0J3ern9pqIoB0xmy... 54 <p>5PreIj6z6ldIGL1V4+1C36dQFHNCQHJvW52GXc... 55 <q>/E/wDit8YXPCxx126zTq2ilQ3IcW54NJYyNjiZ... 56 <dP>mKc+wX8inDowEH45Qp4slRo1YveBgExKPROu6... 57 <dQ>qDVKtBz9lk0shL5PR3ickXDgkwS576zbl2ztB... 58 <qInv>j6E8EA7dNsTImaXexAmLA1DoeArsYeFAInr... 59 </privateKey> 60 61 @type s: str 62 @param s: A string containing an XML public or private key. 63 64 @type private: bool 65 @param private: If True, a L{SyntaxError} will be raised if the private 66 key component is not present. 67 68 @type public: bool 69 @param public: If True, the private key component (if present) will be 70 discarded, so this function will always return a public key. 71 72 @rtype: L{tlslite.utils.RSAKey.RSAKey} 73 @return: An RSA key. 74 75 @raise SyntaxError: If the key is not properly formatted. 76 """ 77 for implementation in implementations: 78 if implementation == "python": 79 key = Python_RSAKey.parseXML(s) 80 break 81 else: 82 raise ValueError("No acceptable implementations") 83 84 return _parseKeyHelper(key, private, public) 85 86#Parse as an OpenSSL or Python key 87def parsePEMKey(s, private=False, public=False, passwordCallback=None, 88 implementations=["openssl", "python"]): 89 """Parse a PEM-format key. 90 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:: 94 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----- 110 111 To generate a key like this with OpenSSL, run:: 112 113 openssl genrsa 2048 > key.pem 114 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. 119 120 @type s: str 121 @param s: A string containing a PEM-encoded public or private key. 122 123 @type private: bool 124 @param private: If True, a L{SyntaxError} will be raised if the 125 private key component is not present. 126 127 @type public: bool 128 @param public: If True, the private key component (if present) will 129 be discarded, so this function will always return a public key. 130 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 137 the console. 138 139 @rtype: L{tlslite.utils.RSAKey.RSAKey} 140 @return: An RSA key. 141 142 @raise SyntaxError: If the key is not properly formatted. 143 """ 144 for implementation in implementations: 145 if implementation == "openssl" and cryptomath.m2cryptoLoaded: 146 key = OpenSSL_RSAKey.parse(s, passwordCallback) 147 break 148 elif implementation == "python": 149 key = Python_RSAKey.parsePEM(s) 150 break 151 else: 152 raise ValueError("No acceptable implementations") 153 154 return _parseKeyHelper(key, private, public) 155 156 157def _parseKeyHelper(key, private, public): 158 if private: 159 if not key.hasPrivateKey(): 160 raise SyntaxError("Not a private key!") 161 162 if public: 163 return _createPublicKey(key) 164 165 if private: 166 if hasattr(key, "d"): 167 return _createPrivateKey(key) 168 else: 169 return key 170 171 return key 172 173def parseAsPublicKey(s): 174 """Parse an XML or PEM-formatted public key. 175 176 @type s: str 177 @param s: A string containing an XML or PEM-encoded public or private key. 178 179 @rtype: L{tlslite.utils.RSAKey.RSAKey} 180 @return: An RSA public key. 181 182 @raise SyntaxError: If the key is not properly formatted. 183 """ 184 try: 185 return parsePEMKey(s, public=True) 186 except: 187 return parseXMLKey(s, public=True) 188 189def parsePrivateKey(s): 190 """Parse an XML or PEM-formatted private key. 191 192 @type s: str 193 @param s: A string containing an XML or PEM-encoded private key. 194 195 @rtype: L{tlslite.utils.RSAKey.RSAKey} 196 @return: An RSA private key. 197 198 @raise SyntaxError: If the key is not properly formatted. 199 """ 200 try: 201 return parsePEMKey(s, private=True) 202 except: 203 return parseXMLKey(s, private=True) 204 205def _createPublicKey(key): 206 """ 207 Create a new public key. Discard any private component, 208 and return the most efficient key possible. 209 """ 210 if not isinstance(key, RSAKey): 211 raise AssertionError() 212 return _createPublicRSAKey(key.n, key.e) 213 214def _createPrivateKey(key): 215 """ 216 Create a new private key. Return the most efficient key possible. 217 """ 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, 223 key.dQ, key.qInv) 224 225def _createPublicRSAKey(n, e, implementations = ["openssl", "pycrypto", 226 "python"]): 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") 235 236def _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") 244