1# Author: Trevor Perrin 2# See the LICENSE file for legal information regarding use of this file. 3 4"""Factory functions for asymmetric cryptography. 5@sort: generateRSAKey, parsePEMKey, parseAsPublicKey 6""" 7 8from .compat import * 9 10from .rsakey import RSAKey 11from .python_rsakey import Python_RSAKey 12from tlslite.utils import cryptomath 13 14if cryptomath.m2cryptoLoaded: 15 from .openssl_rsakey import OpenSSL_RSAKey 16 17if cryptomath.pycryptoLoaded: 18 from .pycrypto_rsakey import PyCrypto_RSAKey 19 20# ************************************************************************** 21# Factory Functions for RSA Keys 22# ************************************************************************** 23 24def generateRSAKey(bits, implementations=["openssl", "python"]): 25 """Generate an RSA key with the specified bit length. 26 27 @type bits: int 28 @param bits: Desired bit length of the new key's modulus. 29 30 @rtype: L{tlslite.utils.rsakey.RSAKey} 31 @return: A new RSA private key. 32 """ 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") 39 40#Parse as an OpenSSL or Python key 41def parsePEMKey(s, private=False, public=False, passwordCallback=None, 42 implementations=["openssl", "python"]): 43 """Parse a PEM-format key. 44 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:: 48 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----- 64 65 To generate a key like this with OpenSSL, run:: 66 67 openssl genrsa 2048 > key.pem 68 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. 73 74 @type s: str 75 @param s: A string containing a PEM-encoded public or private key. 76 77 @type private: bool 78 @param private: If True, a L{SyntaxError} will be raised if the 79 private key component is not present. 80 81 @type public: bool 82 @param public: If True, the private key component (if present) will 83 be discarded, so this function will always return a public key. 84 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 91 the console. 92 93 @rtype: L{tlslite.utils.RSAKey.RSAKey} 94 @return: An RSA key. 95 96 @raise SyntaxError: If the key is not properly formatted. 97 """ 98 for implementation in implementations: 99 if implementation == "openssl" and cryptomath.m2cryptoLoaded: 100 key = OpenSSL_RSAKey.parse(s, passwordCallback) 101 break 102 elif implementation == "python": 103 key = Python_RSAKey.parsePEM(s) 104 break 105 else: 106 raise ValueError("No acceptable implementations") 107 108 return _parseKeyHelper(key, private, public) 109 110 111def _parseKeyHelper(key, private, public): 112 if private: 113 if not key.hasPrivateKey(): 114 raise SyntaxError("Not a private key!") 115 116 if public: 117 return _createPublicKey(key) 118 119 if private: 120 if hasattr(key, "d"): 121 return _createPrivateKey(key) 122 else: 123 return key 124 125 return key 126 127def parseAsPublicKey(s): 128 """Parse a PEM-formatted public key. 129 130 @type s: str 131 @param s: A string containing a PEM-encoded public or private key. 132 133 @rtype: L{tlslite.utils.rsakey.RSAKey} 134 @return: An RSA public key. 135 136 @raise SyntaxError: If the key is not properly formatted. 137 """ 138 return parsePEMKey(s, public=True) 139 140def parsePrivateKey(s): 141 """Parse a PEM-formatted private key. 142 143 @type s: str 144 @param s: A string containing a PEM-encoded private key. 145 146 @rtype: L{tlslite.utils.rsakey.RSAKey} 147 @return: An RSA private key. 148 149 @raise SyntaxError: If the key is not properly formatted. 150 """ 151 return parsePEMKey(s, private=True) 152 153def _createPublicKey(key): 154 """ 155 Create a new public key. Discard any private component, 156 and return the most efficient key possible. 157 """ 158 if not isinstance(key, RSAKey): 159 raise AssertionError() 160 return _createPublicRSAKey(key.n, key.e) 161 162def _createPrivateKey(key): 163 """ 164 Create a new private key. Return the most efficient key possible. 165 """ 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, 171 key.dQ, key.qInv) 172 173def _createPublicRSAKey(n, e, implementations = ["openssl", "pycrypto", 174 "python"]): 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") 183 184def _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") 192