244 lines
		
	
	
		
			8.6 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			244 lines
		
	
	
		
			8.6 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
"""Factory functions for asymmetric cryptography.
 | 
						|
@sort: generateRSAKey, parseXMLKey, parsePEMKey, parseAsPublicKey,
 | 
						|
parseAsPrivateKey
 | 
						|
"""
 | 
						|
 | 
						|
from compat import *
 | 
						|
 | 
						|
from RSAKey import RSAKey
 | 
						|
from Python_RSAKey import Python_RSAKey
 | 
						|
import cryptomath
 | 
						|
 | 
						|
if cryptomath.m2cryptoLoaded:
 | 
						|
    from OpenSSL_RSAKey import OpenSSL_RSAKey
 | 
						|
 | 
						|
if cryptomath.pycryptoLoaded:
 | 
						|
    from PyCrypto_RSAKey import PyCrypto_RSAKey
 | 
						|
 | 
						|
# **************************************************************************
 | 
						|
# Factory Functions for RSA Keys
 | 
						|
# **************************************************************************
 | 
						|
 | 
						|
def generateRSAKey(bits, implementations=["openssl", "python"]):
 | 
						|
    """Generate an RSA key with the specified bit length.
 | 
						|
 | 
						|
    @type bits: int
 | 
						|
    @param bits: Desired bit length of the new key's modulus.
 | 
						|
 | 
						|
    @rtype: L{tlslite.utils.RSAKey.RSAKey}
 | 
						|
    @return: A new RSA private key.
 | 
						|
    """
 | 
						|
    for implementation in implementations:
 | 
						|
        if implementation == "openssl" and cryptomath.m2cryptoLoaded:
 | 
						|
            return OpenSSL_RSAKey.generate(bits)
 | 
						|
        elif implementation == "python":
 | 
						|
            return Python_RSAKey.generate(bits)
 | 
						|
    raise ValueError("No acceptable implementations")
 | 
						|
 | 
						|
def parseXMLKey(s, private=False, public=False, implementations=["python"]):
 | 
						|
    """Parse an XML-format key.
 | 
						|
 | 
						|
    The XML format used here is specific to tlslite and cryptoIDlib.  The
 | 
						|
    format can store the public component of a key, or the public and
 | 
						|
    private components.  For example::
 | 
						|
 | 
						|
        <publicKey xmlns="http://trevp.net/rsa">
 | 
						|
            <n>4a5yzB8oGNlHo866CAspAC47M4Fvx58zwK8pou...
 | 
						|
            <e>Aw==</e>
 | 
						|
        </publicKey>
 | 
						|
 | 
						|
        <privateKey xmlns="http://trevp.net/rsa">
 | 
						|
            <n>4a5yzB8oGNlHo866CAspAC47M4Fvx58zwK8pou...
 | 
						|
            <e>Aw==</e>
 | 
						|
            <d>JZ0TIgUxWXmL8KJ0VqyG1V0J3ern9pqIoB0xmy...
 | 
						|
            <p>5PreIj6z6ldIGL1V4+1C36dQFHNCQHJvW52GXc...
 | 
						|
            <q>/E/wDit8YXPCxx126zTq2ilQ3IcW54NJYyNjiZ...
 | 
						|
            <dP>mKc+wX8inDowEH45Qp4slRo1YveBgExKPROu6...
 | 
						|
            <dQ>qDVKtBz9lk0shL5PR3ickXDgkwS576zbl2ztB...
 | 
						|
            <qInv>j6E8EA7dNsTImaXexAmLA1DoeArsYeFAInr...
 | 
						|
        </privateKey>
 | 
						|
 | 
						|
    @type s: str
 | 
						|
    @param s: A string containing an XML public or private key.
 | 
						|
 | 
						|
    @type private: bool
 | 
						|
    @param private: If True, a L{SyntaxError} will be raised if the private
 | 
						|
    key component is not present.
 | 
						|
 | 
						|
    @type public: bool
 | 
						|
    @param public: If True, the private key component (if present) will be
 | 
						|
    discarded, so this function will always return a public key.
 | 
						|
 | 
						|
    @rtype: L{tlslite.utils.RSAKey.RSAKey}
 | 
						|
    @return: An RSA key.
 | 
						|
 | 
						|
    @raise SyntaxError: If the key is not properly formatted.
 | 
						|
    """
 | 
						|
    for implementation in implementations:
 | 
						|
        if implementation == "python":
 | 
						|
            key = Python_RSAKey.parseXML(s)
 | 
						|
            break
 | 
						|
    else:
 | 
						|
        raise ValueError("No acceptable implementations")
 | 
						|
 | 
						|
    return _parseKeyHelper(key, private, public)
 | 
						|
 | 
						|
#Parse as an OpenSSL or Python key
 | 
						|
def parsePEMKey(s, private=False, public=False, passwordCallback=None,
 | 
						|
                implementations=["openssl", "python"]):
 | 
						|
    """Parse a PEM-format key.
 | 
						|
 | 
						|
    The PEM format is used by OpenSSL and other tools.  The
 | 
						|
    format is typically used to store both the public and private
 | 
						|
    components of a key.  For example::
 | 
						|
 | 
						|
       -----BEGIN RSA PRIVATE KEY-----
 | 
						|
        MIICXQIBAAKBgQDYscuoMzsGmW0pAYsmyHltxB2TdwHS0dImfjCMfaSDkfLdZY5+
 | 
						|
        dOWORVns9etWnr194mSGA1F0Pls/VJW8+cX9+3vtJV8zSdANPYUoQf0TP7VlJxkH
 | 
						|
        dSRkUbEoz5bAAs/+970uos7n7iXQIni+3erUTdYEk2iWnMBjTljfgbK/dQIDAQAB
 | 
						|
        AoGAJHoJZk75aKr7DSQNYIHuruOMdv5ZeDuJvKERWxTrVJqE32/xBKh42/IgqRrc
 | 
						|
        esBN9ZregRCd7YtxoL+EVUNWaJNVx2mNmezEznrc9zhcYUrgeaVdFO2yBF1889zO
 | 
						|
        gCOVwrO8uDgeyj6IKa25H6c1N13ih/o7ZzEgWbGG+ylU1yECQQDv4ZSJ4EjSh/Fl
 | 
						|
        aHdz3wbBa/HKGTjC8iRy476Cyg2Fm8MZUe9Yy3udOrb5ZnS2MTpIXt5AF3h2TfYV
 | 
						|
        VoFXIorjAkEA50FcJmzT8sNMrPaV8vn+9W2Lu4U7C+K/O2g1iXMaZms5PC5zV5aV
 | 
						|
        CKXZWUX1fq2RaOzlbQrpgiolhXpeh8FjxwJBAOFHzSQfSsTNfttp3KUpU0LbiVvv
 | 
						|
        i+spVSnA0O4rq79KpVNmK44Mq67hsW1P11QzrzTAQ6GVaUBRv0YS061td1kCQHnP
 | 
						|
        wtN2tboFR6lABkJDjxoGRvlSt4SOPr7zKGgrWjeiuTZLHXSAnCY+/hr5L9Q3ZwXG
 | 
						|
        6x6iBdgLjVIe4BZQNtcCQQDXGv/gWinCNTN3MPWfTW/RGzuMYVmyBFais0/VrgdH
 | 
						|
        h1dLpztmpQqfyH/zrBXQ9qL/zR4ojS6XYneO/U18WpEe
 | 
						|
        -----END RSA PRIVATE KEY-----
 | 
						|
 | 
						|
    To generate a key like this with OpenSSL, run::
 | 
						|
 | 
						|
        openssl genrsa 2048 > key.pem
 | 
						|
 | 
						|
    This format also supports password-encrypted private keys.  TLS
 | 
						|
    Lite can only handle password-encrypted private keys when OpenSSL
 | 
						|
    and M2Crypto are installed.  In this case, passwordCallback will be
 | 
						|
    invoked to query the user for the password.
 | 
						|
 | 
						|
    @type s: str
 | 
						|
    @param s: A string containing a PEM-encoded public or private key.
 | 
						|
 | 
						|
    @type private: bool
 | 
						|
    @param private: If True, a L{SyntaxError} will be raised if the
 | 
						|
    private key component is not present.
 | 
						|
 | 
						|
    @type public: bool
 | 
						|
    @param public: If True, the private key component (if present) will
 | 
						|
    be discarded, so this function will always return a public key.
 | 
						|
 | 
						|
    @type passwordCallback: callable
 | 
						|
    @param passwordCallback: This function will be called, with no
 | 
						|
    arguments, if the PEM-encoded private key is password-encrypted.
 | 
						|
    The callback should return the password string.  If the password is
 | 
						|
    incorrect, SyntaxError will be raised.  If no callback is passed
 | 
						|
    and the key is password-encrypted, a prompt will be displayed at
 | 
						|
    the console.
 | 
						|
 | 
						|
    @rtype: L{tlslite.utils.RSAKey.RSAKey}
 | 
						|
    @return: An RSA key.
 | 
						|
 | 
						|
    @raise SyntaxError: If the key is not properly formatted.
 | 
						|
    """
 | 
						|
    for implementation in implementations:
 | 
						|
        if implementation == "openssl" and cryptomath.m2cryptoLoaded:
 | 
						|
            key = OpenSSL_RSAKey.parse(s, passwordCallback)
 | 
						|
            break
 | 
						|
        elif implementation == "python":
 | 
						|
            key = Python_RSAKey.parsePEM(s)
 | 
						|
            break
 | 
						|
    else:
 | 
						|
        raise ValueError("No acceptable implementations")
 | 
						|
 | 
						|
    return _parseKeyHelper(key, private, public)
 | 
						|
 | 
						|
 | 
						|
def _parseKeyHelper(key, private, public):
 | 
						|
    if private:
 | 
						|
        if not key.hasPrivateKey():
 | 
						|
            raise SyntaxError("Not a private key!")
 | 
						|
 | 
						|
    if public:
 | 
						|
        return _createPublicKey(key)
 | 
						|
 | 
						|
    if private:
 | 
						|
        if hasattr(key, "d"):
 | 
						|
            return _createPrivateKey(key)
 | 
						|
        else:
 | 
						|
            return key
 | 
						|
 | 
						|
    return key
 | 
						|
 | 
						|
def parseAsPublicKey(s):
 | 
						|
    """Parse an XML or PEM-formatted public key.
 | 
						|
 | 
						|
    @type s: str
 | 
						|
    @param s: A string containing an XML or PEM-encoded public or private key.
 | 
						|
 | 
						|
    @rtype: L{tlslite.utils.RSAKey.RSAKey}
 | 
						|
    @return: An RSA public key.
 | 
						|
 | 
						|
    @raise SyntaxError: If the key is not properly formatted.
 | 
						|
    """
 | 
						|
    try:
 | 
						|
        return parsePEMKey(s, public=True)
 | 
						|
    except:
 | 
						|
        return parseXMLKey(s, public=True)
 | 
						|
 | 
						|
def parsePrivateKey(s):
 | 
						|
    """Parse an XML or PEM-formatted private key.
 | 
						|
 | 
						|
    @type s: str
 | 
						|
    @param s: A string containing an XML or PEM-encoded private key.
 | 
						|
 | 
						|
    @rtype: L{tlslite.utils.RSAKey.RSAKey}
 | 
						|
    @return: An RSA private key.
 | 
						|
 | 
						|
    @raise SyntaxError: If the key is not properly formatted.
 | 
						|
    """
 | 
						|
    try:
 | 
						|
        return parsePEMKey(s, private=True)
 | 
						|
    except:
 | 
						|
        return parseXMLKey(s, private=True)
 | 
						|
 | 
						|
def _createPublicKey(key):
 | 
						|
    """
 | 
						|
    Create a new public key.  Discard any private component,
 | 
						|
    and return the most efficient key possible.
 | 
						|
    """
 | 
						|
    if not isinstance(key, RSAKey):
 | 
						|
        raise AssertionError()
 | 
						|
    return _createPublicRSAKey(key.n, key.e)
 | 
						|
 | 
						|
def _createPrivateKey(key):
 | 
						|
    """
 | 
						|
    Create a new private key.  Return the most efficient key possible.
 | 
						|
    """
 | 
						|
    if not isinstance(key, RSAKey):
 | 
						|
        raise AssertionError()
 | 
						|
    if not key.hasPrivateKey():
 | 
						|
        raise AssertionError()
 | 
						|
    return _createPrivateRSAKey(key.n, key.e, key.d, key.p, key.q, key.dP,
 | 
						|
                                key.dQ, key.qInv)
 | 
						|
 | 
						|
def _createPublicRSAKey(n, e, implementations = ["openssl", "pycrypto",
 | 
						|
                                                "python"]):
 | 
						|
    for implementation in implementations:
 | 
						|
        if implementation == "openssl" and cryptomath.m2cryptoLoaded:
 | 
						|
            return OpenSSL_RSAKey(n, e)
 | 
						|
        elif implementation == "pycrypto" and cryptomath.pycryptoLoaded:
 | 
						|
            return PyCrypto_RSAKey(n, e)
 | 
						|
        elif implementation == "python":
 | 
						|
            return Python_RSAKey(n, e)
 | 
						|
    raise ValueError("No acceptable implementations")
 | 
						|
 | 
						|
def _createPrivateRSAKey(n, e, d, p, q, dP, dQ, qInv,
 | 
						|
                        implementations = ["pycrypto", "python"]):
 | 
						|
    for implementation in implementations:
 | 
						|
        if implementation == "pycrypto" and cryptomath.pycryptoLoaded:
 | 
						|
            return PyCrypto_RSAKey(n, e, d, p, q, dP, dQ, qInv)
 | 
						|
        elif implementation == "python":
 | 
						|
            return Python_RSAKey(n, e, d, p, q, dP, dQ, qInv)
 | 
						|
    raise ValueError("No acceptable implementations")
 |