o
    bV                    @   s  d Z ddlZddlZddlZddlZddlZddlmZmZm	Z	 ddl
mZmZ ddlZddlmZ ddlmZ ddlmZ ddlmZmZ dd	lmZmZmZmZmZ dd
lmZmZm Z  ddl!m"Z"m#Z# ddl$m%Z&m'Z( ddl)m*Z* ddl+m,Z, ddl-m.Z.m/Z/ ddl0m1Z1 ddl2m3Z3 ddl4m5Z5m6Z6 ddl7m8Z8m9Z9 ddl:m;Z; z
ddl<m=Z=m>Z> W n e?y   ddl<m@Z=mAZ> Y nw eB eC eD dZEddddZFG dd deGZHG dd deGZIG d d! d!eGZJG d"d# d#e9ZKG d$d% d%eGZLd&d' ZMG d(d) d)ZNd-d+d,ZOdS ).z0
Handling of RSA, DSA, ECDSA, and Ed25519 keys.
    N)	b64encodedecodebytesencodebytes)md5sha256)utils)InvalidSignature)default_backend)hashesserialization)dsaeced25519paddingrsa)Cipher
algorithmsmodes)load_pem_private_keyload_ssh_public_key)decoderencoder)PyAsn1Error)univ)commonsexpy)int_to_bytes)	randbytes)	iterbytesnativeString)NamedConstantNames)_mutuallyExclusiveArguments)decode_dss_signatureencode_dss_signature)decode_rfc6979_signatureencode_rfc6979_signature)s   ecdsa-sha2-nistp256s   ecdsa-sha2-nistp384s   ecdsa-sha2-nistp521s   nistp256s   nistp384s   nistp521)s	   secp256r1s	   secp384r1s	   secp521r1c                   @      e Zd ZdZdS )BadKeyErrorzj
    Raised when a key isn't what we expected from it.

    XXX: we really need to check for bad keys
    N__name__
__module____qualname____doc__ r.   r.   8/usr/lib/python3/dist-packages/twisted/conch/ssh/keys.pyr(   F       r(   c                   @   r'   )EncryptedKeyErrorzb
    Raised when an encrypted key is presented to fromString/fromFile without
    a password.
    Nr)   r.   r.   r.   r/   r1   N   r0   r1   c                   @   r'   )BadFingerPrintFormatzS
    Raises when unsupported fingerprint formats are presented to fingerprint.
    Nr)   r.   r.   r.   r/   r2   U   r0   r2   c                   @   s   e Zd ZdZe Ze ZdS )FingerprintFormatsa  
    Constants representing the supported formats of key fingerprints.

    @cvar MD5_HEX: Named constant representing fingerprint format generated
        using md5[RFC1321] algorithm in hexadecimal encoding.
    @type MD5_HEX: L{twisted.python.constants.NamedConstant}

    @cvar SHA256_BASE64: Named constant representing fingerprint format
        generated using sha256[RFC4634] algorithm in base64 encoding
    @type SHA256_BASE64: L{twisted.python.constants.NamedConstant}
    N)r*   r+   r,   r-   r    MD5_HEXSHA256_BASE64r.   r.   r.   r/   r3   [   s    
r3   c                   @   r'   )PassphraseNormalizationErrorz
    Raised when a passphrase contains Unicode characters that cannot be
    normalized using the available Unicode character database.
    Nr)   r.   r.   r.   r/   r6   l   r0   r6   c                 C   s8   t | trtdd | D rt td| dS | S )a  
    Normalize a passphrase, which may be Unicode.

    If the passphrase is Unicode, this follows the requirements of U{NIST
    800-63B, section
    5.1.1.2<https://pages.nist.gov/800-63-3/sp800-63b.html#memsecretver>}
    for Unicode characters in memorized secrets: it applies the
    Normalization Process for Stabilized Strings using NFKC normalization.
    The passphrase is then encoded using UTF-8.

    @type passphrase: L{bytes} or L{unicode} or L{None}
    @param passphrase: The passphrase to normalize.

    @return: The normalized passphrase, if any.
    @rtype: L{bytes} or L{None}
    @raises PassphraseNormalizationError: if the passphrase is Unicode and
    cannot be normalized using the available Unicode character database.
    c                 s   s    | ]
}t |d kV  qdS )CnN)unicodedatacategory).0cr.   r.   r/   	<genexpr>   s    z'_normalizePassphrase.<locals>.<genexpr>NFKCzUTF-8)
isinstancestranyr6   r8   	normalizeencode
passphraser.   r.   r/   _normalizePassphrases   s
   
rE   c                   @   s  e Zd ZdZedTddZedTddZedd Zed	d
 Zedd Z	edd Z
edd Zedd Zedd Zedd Zedd Zedd ZedUddZedVddZedVdd ZedVd!d"ZedVd#d$Zd%d& Zd'ed(efd)d*Zd(efd+d,Zd-d. Zd/d0 Zejfd1d2Z d3d4 Z!d5d6 Z"d7d8 Z#d9d: Z$d;d< Z%d=d> Z&e'd?d@gd?dAggdUdBdCZ(dVdDdEZ)dTdFdGZ*dVdHdIZ+dWdJdKZ,dLdM Z-dNdO Z.dPdQ Z/dRdS Z0dS )XKeyau  
    An object representing a key.  A key can be either a public or
    private key.  A public key can verify a signature; a private key can
    create or verify a signature.  To generate a string that can be stored
    on disk, use the toString method.  If you have a private key, but want
    the string representation of the public key, use Key.public().toString().
    Nc                 C   s@   t |d}| | ||W  d   S 1 sw   Y  dS )a  
        Load a key from a file.

        @param filename: The path to load key data from.

        @type type: L{str} or L{None}
        @param type: A string describing the format the key data is in, or
        L{None} to attempt detection of the type.

        @type passphrase: L{bytes} or L{None}
        @param passphrase: The passphrase the key is encrypted with, or L{None}
        if there is no encryption.

        @rtype: L{Key}
        @return: The loaded key.
        rbN)open
fromStringread)clsfilenametyperD   fr.   r.   r/   fromFile   s   $zKey.fromFilec                 C   s   t |tr
|d}t|}|du r| |}|du r"td|t| d|  d}|du r8td| |jj	dkrH|rDtd||S |||S )a   
        Return a Key object corresponding to the string data.
        type is optionally the type of string, matching a _fromString_*
        method.  Otherwise, the _guessStringType() classmethod will be used
        to guess a type.  If the key is encrypted, passphrase is used as
        the decryption key.

        @type data: L{bytes}
        @param data: The key data.

        @type type: L{str} or L{None}
        @param type: A string describing the format the key data is in, or
        L{None} to attempt detection of the type.

        @type passphrase: L{bytes} or L{None}
        @param passphrase: The passphrase the key is encrypted with, or L{None}
        if there is no encryption.

        @rtype: L{Key}
        @return: The loaded key.
        utf-8Nzcannot guess the type of _fromString_zno _fromString method for    zkey not encrypted)
r>   r?   rB   rE   _guessStringTyper(   getattrupper__code__co_argcount)rK   datarM   rD   methodr.   r.   r/   rI      s   



zKey.fromStringc                 C   s   t |\}}|dkr t |d\}}}| t||t S |dkrBt |d\}}}}	}| tj|	tj	|||ddt S |t
v rW| tjt
| t |dd S |dkrgt |\}
}| |
S td	| )
a  
        Return a public key object corresponding to this public key blob.
        The format of a RSA public key blob is::
            string 'ssh-rsa'
            integer e
            integer n

        The format of a DSA public key blob is::
            string 'ssh-dss'
            integer p
            integer q
            integer g
            integer y

        The format of ECDSA-SHA2-* public key blob is::
            string 'ecdsa-sha2-[identifier]'
            integer x
            integer y

            identifier is the standard NIST curve name.

        The format of an Ed25519 public key blob is::
            string 'ssh-ed25519'
            string a

        @type blob: L{bytes}
        @param blob: The key data.

        @return: A new key.
        @rtype: L{twisted.conch.ssh.keys.Key}
        @raises BadKeyError: if the key type (the first string) is unknown.
           ssh-rsarR      ssh-dss   pqgyparameter_numbers      ssh-ed25519unknown blob type: )r   getNSgetMPr   RSAPublicNumbers
public_keyr	   r   DSAPublicNumbersDSAParameterNumbers_curveTabler   EllipticCurvePublicKeyfrom_encoded_point_fromEd25519Componentsr(   )rK   blobkeyTyperestenr^   r_   r`   rb   ar.   r.   r/   _fromString_BLOB   s,   "
zKey._fromString_BLOBc                 C   s  t |\}}|dkr"t |d\}}}}}}	}| j|||||	dS |dkr<t |d\}}	}
}}}| j||
||	|dS |tv rnt| }t |d\}}	}|t|jd kr_t	d	||f t |\}}| j
|	||d
S |dkrt |d\}}}|dd }| j||dS t	d| )a6  
        Return a private key object corresponding to this private key blob.
        The blob formats are as follows:

        RSA keys::
            string 'ssh-rsa'
            integer n
            integer e
            integer d
            integer u
            integer p
            integer q

        DSA keys::
            string 'ssh-dss'
            integer p
            integer q
            integer g
            integer y
            integer x

        EC keys::
            string 'ecdsa-sha2-[identifier]'
            string identifier
            string q
            integer privateValue

            identifier is the standard NIST curve name.

        Ed25519 keys::
            string 'ssh-ed25519'
            string a
            string k || a


        @type blob: L{bytes}
        @param blob: The key data.

        @return: A new key.
        @rtype: L{twisted.conch.ssh.keys.Key}
        @raises BadKeyError: if
            * the key type (the first string) is unknown
            * the curve name of an ECDSA key does not match the key type
        rZ      ru   rt   dr^   r_   r[      rb   r`   r^   r_   xrR   asciiz.ECDSA curve name %r does not match key type %r)encodedPointcurveprivateValuere   N    )krf   )r   rg   rh   _fromRSAComponents_fromDSAComponentsrm   
_secToNistnamerB   r(   _fromECEncodedPointrp   )rK   rq   rr   rs   ru   rt   rz   ur^   r_   r`   rb   r}   r   	curveNamer   rv   combinedr   r.   r.   r/   _fromString_PRIVATE_BLOB  s2   .zKey._fromString_PRIVATE_BLOBc                 C   s4   | dr| t|t S t| d }| |S )a  
        Return a public key object corresponding to this OpenSSH public key
        string.  The format of an OpenSSH public key string is::
            <key type> <base64-encoded public key blob>

        @type data: L{bytes}
        @param data: The key data.

        @return: A new key.
        @rtype: L{twisted.conch.ssh.keys.Key}
        @raises BadKeyError: if the blob type is unknown.
        s
   ecdsa-sha2rd   )
startswithr   r	   r   splitrw   )rK   rX   rq   r.   r.   r/   _fromString_PUBLIC_OPENSSH\  s   

zKey._fromString_PUBLIC_OPENSSHc                 C   s  |   }td|dd }|dstd|tdd }t|d\}}}}t	
d|dd	 d
 }	|	dkr@tdt|d	d d\}
}}
|dkr|sWtd|dv rmtj}d}t|dd d }|}ntd||dkrt|\}}t	
d|dd	 d
 }tj|||| |dd}ntd|t|| d
krtdt||d| t||||  t d }|||  }n|dkrtd|f |}t	
d|dd	 d
 }t	
d|d	d d
 }||krtd||f | |dd S )a*  
        Return a private key object corresponding to this OpenSSH private key
        string, in the "openssh-key-v1" format introduced in OpenSSH 6.5.

        The format of an openssh-key-v1 private key string is::
            -----BEGIN OPENSSH PRIVATE KEY-----
            <base64-encoded SSH protocol string>
            -----END OPENSSH PRIVATE KEY-----

        The SSH protocol string is as described in
        U{PROTOCOL.key<https://cvsweb.openbsd.org/cgi-bin/cvsweb/src/usr.bin/ssh/PROTOCOL.key>}.

        @type data: L{bytes}
        @param data: The key data.

        @type passphrase: L{bytes} or L{None}
        @param passphrase: The passphrase the key is encrypted with, or L{None}
        if it is not encrypted.

        @return: A new key.
        @rtype: L{twisted.conch.ssh.keys.Key}
        @raises BadKeyError: if
            * a passphrase is provided for an unencrypted key
            * the SSH protocol encoding is incorrect
        @raises EncryptedKeyError: if
            * a passphrase is not provided for an encrypted key
            rd      openssh-key-v1 z"unknown OpenSSH private key formatN   !Lr\   r   zDonly OpenSSH private key files containing a single key are supportedrR      none0Passphrase must be provided for an encrypted key)s
   aes128-ctrs
   aes192-ctr
   aes256-ctr   rx      unknown encryption type    bcryptT)ignore_few_roundszunknown KDF type zbad paddingbackendz*private key specifies KDF %r but no cipherz#check values do not match: %d != %d)strip
splitlinesr   joinr   r(   lenr   rg   structunpackr1   r   AESintbcryptkdfr   r   CTRr	   	decryptorupdatefinalizer   )rK   rX   rD   lineskeyListcipherr   
kdfOptionsrs   ru   _encPrivKeyListalgorithmClass	blockSizekeySizeivSizesaltroundsdecKeyr   privKeyListcheck1check2r.   r.   r/   _fromPrivateOpenSSH_v1q  sl   
	zKey._fromPrivateOpenSSH_v1c                    s@  |   }|d dd }|d dr|stdz|d dd\}}| d	d\} W n tyA   td
|d w |dv r_tj	}t
|dd d }	t dkr^tdn|dkrstj}d}	t dkrrtdntd|tt fddtdt dD }
t||
dd   }t|| |
dd   }|| d|	 }td|dd }t||t|
t d }|||  }t|dd }|d|  }nd|dd }t|}z	t|d }W n ty } ztd| d}~ww |dkr| t||t S |dkr`t|dkr+|d }t|dk r6td d!d |dd" D \}}}}}}}}| t j!||||||t j"||d#d$#t S |d%krd&d |dd D \}}}}}t|dk rtd'| t$j%|t$j&|t$j'|||d(d)d*j#t dS td+| ),a  
        Return a private key object corresponding to this OpenSSH private key
        string, in the old PEM-based format.

        The format of a PEM-based OpenSSH private key string is::
            -----BEGIN <key type> PRIVATE KEY-----
            [Proc-Type: 4,ENCRYPTED
            DEK-Info: DES-EDE3-CBC,<initialization value>]
            <base64-encoded ASN.1 structure>
            ------END <key type> PRIVATE KEY------

        The ASN.1 structure of a RSA key is::
            (0, n, e, d, p, q)

        The ASN.1 structure of a DSA key is::
            (0, p, q, g, y, x)

        The ASN.1 structure of a ECDSA key is::
            (ECParameters, OID, NULL)

        @type data: L{bytes}
        @param data: The key data.

        @type passphrase: L{bytes} or L{None}
        @param passphrase: The passphrase the key is encrypted with, or L{None}
        if it is not encrypted.

        @return: A new key.
        @rtype: L{twisted.conch.ssh.keys.Key}
        @raises BadKeyError: if
            * a passphrase is provided for an unencrypted key
            * the ASN.1 encoding is incorrect
        @raises EncryptedKeyError: if
            * a passphrase is not provided for an encrypted key
        r      rd      Proc-Type: 4,ENCRYPTEDr   rR          ,zinvalid DEK-info )s   AES-128-CBCs   AES-256-CBC   -r   r   zAES encrypted key with a bad IVs   DES-EDE3-CBC   r   zDES encrypted key with a bad IVr   c                 3   s&    | ]}t  ||d   dV  qdS )rR   r   Nr   r:   iivdatar.   r/   r<     s   $ z.Key._fromPrivateOpenSSH_PEM.<locals>.<genexpr>Nr   r   r   r   z(Failed to decode key (Bad Passphrase?): s   ECs   RSArx   z!RSA key failed to decode properlyc                 s       | ]}t |V  qd S Nr   r:   valuer.   r.   r/   r<   -      	   rt   ru   r^   r_   rz   dmp1dmq1iqmppublic_numberss   DSAc                 s   r   r   r   r   r.   r.   r/   r<   :  r   z!DSA key failed to decode properlyr]   ra   r}   r   unknown key type )(r   r   r   r1   r   rstrip
ValueErrorr(   r   r   r   r   	TripleDESbytes	bytearrayranger   digestr   r   r   r   CBCr	   r   r   r   ord
berDecoderdecoder   r   r   RSAPrivateNumbersri   private_keyr   DSAPrivateNumbersrk   rl   )rK   rX   rD   r   kindr   cipherIVInfor   r   r   ivbabbr   b64Datar   keyData	removeLen
decodedKey	asn1Errorru   rt   rz   r^   r_   r   r   r   r`   rb   r}   r.   r   r/   _fromPrivateOpenSSH_PEM  s   % 

&
 	zKey._fromPrivateOpenSSH_PEMc                 C   s4   |   d dd dkr| ||S | ||S )a  
        Return a private key object corresponding to this OpenSSH private key
        string.  If the key is encrypted, passphrase MUST be provided.
        Providing a passphrase for an unencrypted key is an error.

        @type data: L{bytes}
        @param data: The key data.

        @type passphrase: L{bytes} or L{None}
        @param passphrase: The passphrase the key is encrypted with, or L{None}
        if it is not encrypted.

        @return: A new key.
        @rtype: L{twisted.conch.ssh.keys.Key}
        @raises BadKeyError: if
            * a passphrase is provided for an unencrypted key
            * the encoding is incorrect
        @raises EncryptedKeyError: if
            * a passphrase is not provided for an encrypted key
        r   r   r   s   OPENSSH)r   r   r   r   )rK   rX   rD   r.   r.   r/   _fromString_PRIVATE_OPENSSHH  s   zKey._fromString_PRIVATE_OPENSSHc                 C   s   t t|dd }|d dksJ i }|d dd D ]\}}tt|d ||< q|d d dkrG| j|d |d |d	 |d
 dS |d d dkrZ| j|d |d dS td|d d  )a  
        Return a public key corresponding to this LSH public key string.
        The LSH public key string format is::
            <s-expression: ('public-key', (<key type>, (<name, <value>)+))>

        The names for a RSA (key type 'rsa-pkcs1-sha1') key are: n, e.
        The names for a DSA (key type 'dsa') key are: y, g, p, q.

        @type data: L{bytes}
        @param data: The key data.

        @return: A new key.
        @rtype: L{twisted.conch.ssh.keys.Key}
        @raises BadKeyError: if the key type is unknown
        rd   r   r   
   public-keyN   dsa   y   g   p   qrb   r`   r^   r_      rsa-pkcs1-sha1   n   eru   rt   unknown lsh key type )	r   parser   r   rh   NSr   r   r(   rK   rX   sexpkdr   r.   r.   r/   _fromString_PUBLIC_LSHe  s   zKey._fromString_PUBLIC_LSHc                 C   s0  t |}|d dksJ i }|d dd D ]\}}tt|d ||< q|d d dkrPt|dks<J t|| j|d |d |d	 |d
 |d dS |d d dkrt|dksdJ t||d	 |d
 kry|d
 |d	 |d	< |d
< | j|d |d |d |d	 |d
 dS td|d d  )a+  
        Return a private key corresponding to this LSH private key string.
        The LSH private key string format is::
            <s-expression: ('private-key', (<key type>, (<name>, <value>)+))>

        The names for a RSA (key type 'rsa-pkcs1-sha1') key are: n, e, d, p, q.
        The names for a DSA (key type 'dsa') key are: y, g, p, q, x.

        @type data: L{bytes}
        @param data: The key data.

        @return: A new key.
        @rtype: L{twisted.conch.ssh.keys.Key}
        @raises BadKeyError: if the key type is unknown
        r      private-keyrd   Nr   r{   r   r   r   r      xr|   	   rsa-pkcs1r   r   r      dry   r   )	r   r   r   rh   r   r   r   r   r(   r   r.   r.   r/   _fromString_PRIVATE_LSH  s$   
zKey._fromString_PRIVATE_LSHc                 C   s   t |\}}|dkr8t |\}}t |\}}t |\}}t |\}}t |\}}| j|||||dS |dkrqt |\}}t |\}	}t |\}
}t |\}}t |\}}t |\}}| j|
||	|||dS td| )a  
        Return a private key object corresponsing to the Secure Shell Key
        Agent v3 format.

        The SSH Key Agent v3 format for a RSA key is::
            string 'ssh-rsa'
            integer e
            integer d
            integer n
            integer u
            integer p
            integer q

        The SSH Key Agent v3 format for a DSA key is::
            string 'ssh-dss'
            integer p
            integer q
            integer g
            integer y
            integer x

        @type data: L{bytes}
        @param data: The key data.

        @return: A new key.
        @rtype: L{twisted.conch.ssh.keys.Key}
        @raises BadKeyError: if the key type (the first string) is unknown
        r[   r|   rZ   ru   rt   rz   r^   r_   r   r   )r   rg   rh   r   r   r(   )rK   rX   rr   r^   r_   r`   rb   r}   rt   rz   ru   r   r.   r.   r/   _fromString_AGENTV3  s"   zKey._fromString_AGENTV3c                 C   s   | ds
| drdS | drdS | drdS | dr!d	S | d
s0| ds0| drPt|\}}d}|rH|d7 }t|\}}|s;|dkrNdS dS dS )z
        Guess the type of key in data.  The types map to _fromString_*
        methods.

        @type data: L{bytes}
        @param data: The key data.
        s   ssh-   ecdsa-sha2-public_opensshs
   -----BEGINprivate_openssh   {
public_lsh   (private_lshs      ssh-s
      ecdsa-s      ssh-ed25519r   rd   r\   agentv3rq   N)r   r   rg   rh   )rK   rX   ignoredrs   countr.   r.   r/   rS     s0   	


zKey._guessStringTypec           
   
   C   sn   t j||d}|du r|t }| |S t j|||t ||t ||t |||d}	|	t }| |S )a  
        Build a key from RSA numerical components.

        @type n: L{int}
        @param n: The 'n' RSA variable.

        @type e: L{int}
        @param e: The 'e' RSA variable.

        @type d: L{int} or L{None}
        @param d: The 'd' RSA variable (optional for a public key).

        @type p: L{int} or L{None}
        @param p: The 'p' RSA variable (optional for a public key).

        @type q: L{int} or L{None}
        @param q: The 'q' RSA variable (optional for a public key).

        @type u: L{int} or L{None}
        @param u: The 'u' RSA variable. Ignored, as its value is determined by
        p and q.

        @rtype: L{Key}
        @return: An RSA key constructed from the values as given.
        r   Nr   )	r   ri   rj   r	   r   rsa_crt_dmp1rsa_crt_dmq1rsa_crt_iqmpr   )
rK   ru   rt   rz   r^   r_   r   publicNumbers	keyObjectprivateNumbersr.   r.   r/   r     s   


	zKey._fromRSAComponentsc           	      C   sX   t j|t j|||dd}|du r|t }| |S t j||d}|t }| |S )a   
        Build a key from DSA numerical components.

        @type y: L{int}
        @param y: The 'y' DSA variable.

        @type p: L{int}
        @param p: The 'p' DSA variable.

        @type q: L{int}
        @param q: The 'q' DSA variable.

        @type g: L{int}
        @param g: The 'g' DSA variable.

        @type x: L{int} or L{None}
        @param x: The 'x' DSA variable (optional for a public key)

        @rtype: L{Key}
        @return: A DSA key constructed from the values as given.
        r]   ra   Nr   )r   rk   rl   rj   r	   r   r   )	rK   rb   r^   r_   r`   r}   r  r  r  r.   r.   r/   r   )  s   zKey._fromDSAComponentsc                 C   sR   t j||t| d}|du r|t }| |S t j||d}|t }| |S )a  
        Build a key from EC components.

        @param x: The affine x component of the public point used for verifying.
        @type x: L{int}

        @param y: The affine y component of the public point used for verifying.
        @type y: L{int}

        @param curve: NIST name of elliptic curve.
        @type curve: L{bytes}

        @param privateValue: The private value.
        @type privateValue: L{int}
        r}   rb   r   N)private_valuer   )r   EllipticCurvePublicNumbersrm   rj   r	   EllipticCurvePrivateNumbersr   )rK   r}   rb   r   r   r  r  r  r.   r.   r/   _fromECComponentsL  s   
zKey._fromECComponentsc                 C   s>   |du rt jt| |}| |S t |t| t }| |S )aa  
        Build a key from an EC encoded point.

        @param encodedPoint: The public point encoded as in SEC 1 v2.0
        section 2.3.3.
        @type encodedPoint: L{bytes}

        @param curve: NIST name of elliptic curve.
        @type curve: L{bytes}

        @param privateValue: The private value.
        @type privateValue: L{int}
        N)r   rn   ro   rm   derive_private_keyr	   )rK   r   r   r   r  r.   r.   r/   r   l  s   zKey._fromECEncodedPointc                 C   s0   |du rt j|}| |S t j|}| |S )a  Build a key from Ed25519 components.

        @param a: The Ed25519 public key, as defined in RFC 8032 section
            5.1.5.
        @type a: L{bytes}

        @param k: The Ed25519 private key, as defined in RFC 8032 section
            5.1.5.
        @type k: L{bytes}
        N)r   Ed25519PublicKeyfrom_public_bytesEd25519PrivateKeyfrom_private_bytes)rK   rv   r   r  r.   r.   r/   rp     s
   zKey._fromEd25519Componentsc                 C   s
   || _ dS )z
        Initialize with a private or public
        C{cryptography.hazmat.primitives.asymmetric} key.

        @param keyObject: Low level key.
        @type keyObject: C{cryptography.hazmat.primitives.asymmetric} key.
        N)
_keyObject)selfr  r.   r.   r/   __init__  s   
zKey.__init__otherreturnc                 C   s.   t |tr|  | ko|  | kS tS )zN
        Return True if other represents an object with the same key.
        )r>   rF   rM   rX   NotImplemented)r&  r(  r.   r.   r/   __eq__  s   
 z
Key.__eq__c                 C   s  |   dkrO|  }|d d}|  r d|dd  d}n
d|dd  d}t| D ]\}}|dkr@|d	| 7 }q0|d
| d| 7 }q0|d S dt|   |  r[dp\d|  f g}t|   D ]T\}}|d| d |   dkr|nt	
|dd }|r|dd }|dd }d}	t|D ]}
|	t|
dd }	qt|dk r|	dd }	|d|	  |sqk|d d |d< d
|S )z@
        Return a pretty representation of this object.
        ECr   rP   z<Elliptic Curve Public Key (Nz bits)z<Elliptic Curve Private Key (z	
curve:
	
z:
	z>
z<%s %s (%s bits)z
Public KeyzPrivate Keyzattr :Ed25519r\       02xr   	>)rM   rX   r   isPublicsorteditemsr   sizeappendr   MPr   r   r   r   )r&  rX   r   outr   vr   bymor;   r.   r.   r/   __repr__  sD   
"	
zKey.__repr__c                 C   s   t | jtjtjtjtj	fS )zl
        Check if this instance is a public key.

        @return: C{True} if this is a public key.
        )
r>   r%  r   RSAPublicKeyr   DSAPublicKeyr   rn   r   r!  r&  r.   r.   r/   r6    s   zKey.isPublicc                 C   s   |   r| S t| j S )z
        Returns a version of this key containing only the public key data.
        If this is a public key, this may or may not be the same object
        as self.

        @rtype: L{Key}
        @return: A public key.
        )r6  rF   r%  rj   rD  r.   r.   r/   public  s   	z
Key.publicc                 C   sb   |t ju rttt|   S |t ju r*tddd t	t
|   D S td| )aO  
        The fingerprint of a public key consists of the output of the
        message-digest algorithm in the specified format.
        Supported formats include L{FingerprintFormats.MD5_HEX} and
        L{FingerprintFormats.SHA256_BASE64}

        The input to the algorithm is the public key data as specified by [RFC4253].

        The output of sha256[RFC4634] algorithm is presented to the
        user in the form of base64 encoded sha256 hashes.
        Example: C{US5jTUa0kgX5ZxdqaGF0yGRu8EgKXHNmoT8jHKo1StM=}

        The output of the MD5[RFC1321](default) algorithm is presented to the user as
        a sequence of 16 octets printed as hexadecimal with lowercase letters
        and separated by colons.
        Example: C{c1:b1:30:29:d7:b8:de:6c:97:77:10:d7:46:41:63:87}

        @param format: Format for fingerprint generation. Consists
            hash function and representation format.
            Default is L{FingerprintFormats.MD5_HEX}

        @since: 8.2

        @return: the user presentation of this L{Key}'s fingerprint, as a
        string.

        @rtype: L{str}
           :c                 S   s   g | ]}t |qS r.   )binasciihexlifyr:   r}   r.   r.   r/   
<listcomp>  s    z#Key.fingerprint.<locals>.<listcomp>z Unsupported fingerprint format: )r3   r5   r   r   r   rq   r   r4   r   r   r   r2   )r&  formatr.   r.   r/   fingerprint  s   

zKey.fingerprintc                 C   sp   t | jtjtjfrdS t | jtjtjfrdS t | jtj	tj
fr$dS t | jtjtjfr0dS td| j)z
        Return the type of the object we wrap.  Currently this can only be
        'RSA', 'DSA', 'EC', or 'Ed25519'.

        @rtype: L{str}
        @raises RuntimeError: If the object type is unknown.
        RSADSAr,  r0  zunknown type of object: )r>   r%  r   rB  RSAPrivateKeyr   rC  DSAPrivateKeyr   rn   EllipticCurvePrivateKeyr   r!  r#  RuntimeErrorrD  r.   r.   r/   rM   !  s   zKey.typec                 C   s8   |   dkrdt| jjjd  S dddd|    S )aK  
        Get the type of the object we wrap as defined in the SSH protocol,
        defined in RFC 4253, Section 6.6. Currently this can only be b'ssh-rsa',
        b'ssh-dss' or b'ecdsa-sha2-[identifier]'.

        identifier is the standard NIST curve name

        @return: The key type format.
        @rtype: L{bytes}
        r,  r  r~   rZ   r[   re   )rM  rN  r0  )rM   r   r%  r   r   rB   rD  r.   r.   r/   sshType8  s   zKey.sshTypec                 C   s<   | j du rdS |  dkr| j jjS |  dkrdS | j jS )zv
        Return the size of the object we wrap.

        @return: The size of the key.
        @rtype: L{int}
        Nr   r,  r0     )r%  rM   r   key_sizerD  r.   r.   r/   r9  N  s   

zKey.sizec              	   C   s  t | jtjr| j }|j|jdS t | jtjr5| j }|jj|jj|j	|j
|jt|j|j
dS t | jtjrO| j }|j|jj|jj
|jjdS t | jtjro| j }|j|jj|jjj|jjj
|jjjdS t | jtjr| j }|j|j|  dS t | jtjr| j }|jj|jj|j|  dS t | jtjrd| jtjjtjjiS t | jtj r| j! tjjtjj| j"tjjtj#jt$ dS t%d	| j )
z_
        Return the values of the public key as a dictionary.

        @rtype: L{dict}
        r   r	  r   )r}   rb   r`   r^   r_   r  )r}   rb   r   r   rv   )rv   r   zUnexpected key type: )&r>   r%  r   rB  r   ru   rt   rO  private_numbersrz   r^   r_   r  r   rC  rb   rc   r`   rP  r}   r   rn   rS  rQ  r  r   r!  public_bytesr   EncodingRawPublicFormatr#  rj   private_bytesPrivateFormatNoEncryptionrR  )r&  numbersr.   r.   r/   rX   ]  st   

	




zKey.datac                 C   s  |   }|  }|dkrtdt|d  t|d  S |dkrDtdt|d  t|d  t|d	  t|d
  S |dkrx| jjjd d }t|d t|d dd  tdt	|d | t	|d
 |  S |dkrtdt|d  S t
d| )a  
        Return the public key blob for this key. The blob is the
        over-the-wire format for public keys.

        SECSH-TRANS RFC 4253 Section 6.6.

        RSA keys::
            string 'ssh-rsa'
            integer e
            integer n

        DSA keys::
            string 'ssh-dss'
            integer p
            integer q
            integer g
            integer y

        EC keys::
            string 'ecdsa-sha2-[identifier]'
            integer x
            integer y

            identifier is the standard NIST curve name

        Ed25519 keys::
            string 'ssh-ed25519'
            string a

        @rtype: L{bytes}
        rM  rZ   rt   ru   rN  r[   r^   r_   r`   rb   r,     r   r   N   r}   r0  re   rv   unknown key type: )rM   rX   r   r   r;  r%  r   rU  r   r   r(   )r&  rM   rX   
byteLengthr.   r.   r/   rq     s@    &	zKey.blobc                 C   s  |   }|  }|dkrCt|d |d }tdt|d  t|d  t|d  t| t|d  t|d  S |dkrotd	t|d  t|d  t|d
  t|d  t|d  S |dkr| j 	t
jjt
jj}t|d t|d dd  t| t|d  S |dkrtdt|d  t|d |d   S td| )a1  
        Return the private key blob for this key. The blob is the
        over-the-wire format for private keys:

        Specification in OpenSSH PROTOCOL.agent

        RSA keys::

            string 'ssh-rsa'
            integer n
            integer e
            integer d
            integer u
            integer p
            integer q

        DSA keys::

            string 'ssh-dss'
            integer p
            integer q
            integer g
            integer y
            integer x

        EC keys::

            string 'ecdsa-sha2-[identifier]'
            integer x
            integer y
            integer privateValue

            identifier is the NIST standard curve name.

        Ed25519 keys::

            string 'ssh-ed25519'
            string a
            string k || a
        rM  r^   r_   rZ   ru   rt   rz   rN  r[   r`   rb   r}   r,  r   r`  Nr   r0  re   rv   r   rb  )rM   rX   r   r  r   r   r;  r%  rj   rW  r   rX  X962rZ  UncompressedPointr(   )r&  rM   rX   r   encPubr.   r.   r/   privateBlob  sh   )	
zKey.privateBlobextracommentrD   c                 C   s   |durt jdtdd |  r|}n|}t|tr|d}t|}t| d|	  d}|du r9t
d| ||||dS )	a  
        Create a string representation of this key.  If the key is a private
        key and you want the representation of its public key, use
        C{key.public().toString()}.  type maps to a _toString_* method.

        @param type: The type of string to emit.  Currently supported values
            are C{'OPENSSH'}, C{'LSH'}, and C{'AGENTV3'}.
        @type type: L{str}

        @param extra: Any extra data supported by the selected format which
            is not part of the key itself.  For public OpenSSH keys, this is
            a comment.  For private OpenSSH keys, this is a passphrase to
            encrypt with.  (Deprecated since Twisted 20.3.0; use C{comment}
            or C{passphrase} as appropriate instead.)
        @type extra: L{bytes} or L{unicode} or L{None}

        @param subtype: A subtype of the requested C{type} to emit.  Only
            supported for private OpenSSH keys, for which the currently
            supported subtypes are C{'PEM'} and C{'v1'}.  If not given, an
            appropriate default is used.
        @type subtype: L{str} or L{None}

        @param comment: A comment to include with the key.  Only supported
            for OpenSSH keys.

            Present since Twisted 20.3.0.

        @type comment: L{bytes} or L{unicode} or L{None}

        @param passphrase: A passphrase to encrypt the key with.  Only
            supported for private OpenSSH keys.

            Present since Twisted 20.3.0.

        @type passphrase: L{bytes} or L{unicode} or L{None}

        @rtype: L{bytes}
        NzThe 'extra' argument to twisted.conch.ssh.keys.Key.toString was deprecated in Twisted 20.3.0; use 'comment' or 'passphrase' instead.r   )
stacklevelrP   
_toString_rb  )subtyperi  rD   )warningswarnDeprecationWarningr6  r>   r?   rB   rE   rT   rU   r(   )r&  rM   rh  rl  ri  rD   rY   r.   r.   r/   toString8  s    -

zKey.toStringc                 C   sn   |   dkr|s
d}| jtjjtjjd |  S t| 	 
dd}|s)d}|  d | d |  S )a  
        Return a public OpenSSH key string.

        See _fromString_PUBLIC_OPENSSH for the string format.

        @type comment: L{bytes} or L{None}
        @param comment: A comment to include with the key, or L{None} to
        omit the comment.
        r,  r   r      
)rM   r%  rW  r   rX  OpenSSHrZ  r   r   rq   replacerS  )r&  ri  r   r.   r.   r/   _toPublicOpenSSHz  s    
zKey._toPublicOpenSSHc                    s  |r%t j}d}d}|jd }d}|}t|}	d}
t|	td|
 }nd}d}d}d}td	}|| | 	  t|p>d }d
}t
|| r\|d7 }|t|d@ f7 }t
|| sI|rt||	|| d}t||d| t||||  t d }|||  }n|}dt| t| t| tdd t|   t| }t|dd dg fddtd
t
 dD  dg }d|d S )aP  
        Return a private OpenSSH key string, in the "openssh-key-v1" format
        introduced in OpenSSH 6.5.

        See _fromPrivateOpenSSH_v1 for the string format.

        @type passphrase: L{bytes} or L{None}
        @param passphrase: The passphrase to encrypt the key with, or L{None}
        if it is not encrypted.
        r   r   r   r   d   r   r   r   r\   r   rd      Nr   r   rq  s#   -----BEGIN OPENSSH PRIVATE KEY-----c                       g | ]
} ||d   qS @   r.   r   r   r.   r/   rJ        z,Key._toPrivateOpenSSH_v1.<locals>.<listcomp>ry  s!   -----END OPENSSH PRIVATE KEY-----)r   r   
block_sizer   secureRandomr   r   r   packrg  r   r   r   r   r   r   r   r	   	encryptorr   r   rq   r   rs  r   r   )r&  ri  rD   r   
cipherNamekdfNamer   r   r   r   r   r   checkr   padByteencKeyr  r   rq   r   r.   rz  r/   _toPrivateOpenSSH_v1  sl   



	zKey._toPrivateOpenSSH_v1c              
      sl  |   dkr|st }nt|}| jtjjtjj	|S |   dkr(t
d|  }dd|   ddfg}|   dkrm|d	 |d
 }}t||}d|d |d |d |||d |d  |d |d  |f	}nd|d	 |d
 |d |d |d f}t }	tt |D ]\}
}|	|
t| qt|	}|rtd}ddd t|D }|d}|d |d| d  t||  }t|| |  }|| dd }dt|d  }|t|f| 7 }t t!"|t#$|t% d& }|'||(  }t)|*dd | fddt+dt dD 7 }|dd|   ddf d|S ) a,  
        Return a private OpenSSH key string, in the old PEM-based format.

        See _fromPrivateOpenSSH_PEM for the string format.

        @type passphrase: L{bytes} or L{None}
        @param passphrase: The passphrase to encrypt the key with, or L{None}
        if it is not encrypted.
        r,  r0  zBcannot serialize Ed25519 key to OpenSSH PEM format; use v1 insteadr   s   -----BEGIN r~   s    PRIVATE KEY-----rM  r^   r_   r   ru   rt   rz   rd   r`   rb   r}   r   r2  c                 S   s   g | ]}t |d qS )02X)r   rI  r.   r.   r/   rJ  
  s    z-Key._toPrivateOpenSSH_PEM.<locals>.<listcomp>r   s   DEK-Info: DES-EDE3-CBC,rq  Nr   r   c                    rw  rx  r.   r   rz  r.   r/   rJ    r{  ry  s	   -----END ),rM   r   r]  BestAvailableEncryptionr%  r[  rX  PEMr\  TraditionalOpenSSLr   rX   r   rB   r   r  r   Sequencezip	itertoolsr  setComponentByPositionInteger
berEncoderr   r}  r   r:  r   r   r   r   r   r   r   r   r   r	   r  r   r   r   rs  r   )r&  rD   r  rX   r   r^   r_   r   objDataasn1Sequenceindexr   asn1Datar   hexivr   r   r  padLenr.   rz  r/   _toPrivateOpenSSH_PEM  sv   


$



"
zKey._toPrivateOpenSSH_PEMc                 C   sh   |   r
| j|dS |dks|du r|  dkr| j||dS |du s'|dkr-| j|dS td| )	ar  
        Return a public or private OpenSSH string.  See
        L{_fromString_PUBLIC_OPENSSH} and L{_fromPrivateOpenSSH_PEM} for the
        string formats.

        @param subtype: A subtype to emit.  Only supported for private keys,
            for which the currently supported subtypes are C{'PEM'} and C{'v1'}.
            If not given, an appropriate default is used.
        @type subtype: L{str} or L{None}

        @param comment: Comment for a public key.
        @type comment: L{bytes}

        @param passphrase: Passphrase for a private key.
        @type passphrase: L{bytes}

        @rtype: L{bytes}
        )ri  v1Nr0  )ri  rD   r  rC   zunknown subtype )r6  rt  rM   r  r  r   )r&  rl  ri  rD   r.   r.   r/   _toString_OPENSSH!  s   zKey._toString_OPENSSHc                 K   s  |   }|  }|  r|dkr2tdddt|d dd gdt|d	 dd gggg}nE|d
krptdddt|d dd gdt|d dd gdt|d dd gdt|d dd gggg}ntd| dt|	dd d S |dkr|d |d }}t
||}tdddt|d dd gdt|d	 dd gdt|d dd gdt|dd gdt|dd gdt|d |d  dd gdt|d |d  dd gd t|dd gg	ggS |d
krLtdddt|d dd gdt|d dd gdt|d dd gdt|d dd gd!t|d" dd ggggS td| d#)$z
        Return a public or private LSH key.  See _fromString_PUBLIC_LSH and
        _fromString_PRIVATE_LSH for the key formats.

        @rtype: L{bytes}
        rM  r   r   r   ru   r\   Nr   rt   rN  r   r   r^   r   r_   r   r`   r   rb   r   r  rq  r      }r  r  r  rz      ard      b   cr  r}   ')rX   rM   r6  r   r~  r   r;  r(   r   rs  r   r  )r&  kwargsrX   rM   r   r^   r_   r   r.   r.   r/   _toString_LSH>  sv   
  
zKey._toString_LSHc                 K   s   |   }|  sJ|  dkr#|d |d |d |d |d |d f}n|  dkr:|d |d |d	 |d
 |d f}t|  dttj| S dS )z
        Return a private Secure Shell Agent v3 key.  See
        _fromString_AGENTV3 for the key format.

        @rtype: L{bytes}
        rM  rt   rz   ru   r   r^   r_   rN  r`   rb   r}   r   N)	rX   r6  rM   r   r   rS  r   mapr;  )r&  r  rX   valuesr.   r.   r/   _toString_AGENTV3  s   " zKey._toString_AGENTV3c                 C   s  |   }|dkr| j|t t }t|}n|dkr;| j|t }t	|\}}tt
|dt
|d }n|dkr|  }|dkrLt }n|dkrUt }nt }| j|t|}	t	|	\}}t
|}
t
|}t |
d tu rt|
d }n|
d }|d@ rd	|
 }
t |d tu rt|d }n|d }|d@ rd	| }tt|
t| }n|d
krt| j|}t|  | S )z
        Sign some data with this key.

        SECSH-TRANS RFC 4253 Section 6.6.

        @type data: L{bytes}
        @param data: The data to sign.

        @rtype: L{bytes}
        @return: A signature for the given data.
        rM  rN     r,  rT    r          r0  )rM   r%  signr   PKCS1v15r
   SHA1r   r   r#   r   r9  SHA256SHA384SHA512r   ECDSAr?   r   rS  )r&  rX   rr   sigretrsr   hashSize	signaturerG   sbrcompscompr.   r.   r/   r    sB   

zKey.signc                 C   s  t |dkrdt|}}nt|\}}||  krdS |  }|dkrA| j}|  s1| }t|d |t	
 t f}n|dkrxt|d }t|dd d	}t|dd d	}	t||	}| j}|  sp| }||t f}nk|d
krt|d }t|d\}
}}t|
d	}t|d	}	t||	}| j}|  s| }|  }|dkrt }n|dkrt }nt }||t|f}n|dkr| j}|  s| }t|d |f}z|j|  W dS  ty   Y dS w )a  
        Verify a signature using this key.

        @type signature: L{bytes}
        @param signature: The signature to verify.

        @type data: L{bytes}
        @param data: The signed data.

        @rtype: L{bool}
        @return: C{True} if the signature is valid.
        (   r[   FrM  r   rN  Nr  bigr,  rR   rT  r  r0  T)r   r   r   rg   rS  rM   r%  r6  rj   r   r  r
   r  r   
from_bytesr$   r9  r  r  r  r   r  verifyr   )r&  r  rX   signatureTyperr   r   argsconcatenatedSignaturer  r  rstrsstrrs   r   r  r.   r.   r/   r    sf   



z
Key.verify)NN)NNNNr   )NNN)1r*   r+   r,   r-   classmethodrO   rI   rw   r   r   r   r   r   r  r  r
  rS   r   r   r  r   rp   r'  objectboolr+  r?   rA  r6  rE  r3   r4   rL  rM   rS  r9  rX   rq   rg  r"   rp  rt  r  r  r  r  r  r  r  r.   r.   r.   r/   rF      s|    '
8
J

X
}


%
0
,"
	,(L<S
<

>
ORBrF      c                 C   s   |   jdd |  s(tjd|t d}|jtjj	tj
jt d}| | | d}tj| dt d}t|W  d   S 1 sGw   Y  dS )	a  
    This function returns a persistent L{Key}.

    The key is loaded from a PEM file in C{location}. If it does not exist, a
    key with the key size of C{keySize} is generated and saved.

    @param location: Where the key is stored.
    @type location: L{twisted.python.filepath.FilePath}

    @param keySize: The size of the key, if it needs to be generated.
    @type keySize: L{int}

    @returns: A persistent key.
    @rtype: L{Key}
    T)ignoreExistingDirectoryi  )public_exponentrU  r   )encodingrK  encryption_algorithmrG   N)passwordr   )parentmakedirsexistsr   generate_private_keyr	   r[  r   rX  r  r\  r  r]  
setContentrH   r   rJ   rF   )locationr   
privateKeypemkeyFiler.   r.   r/   _getPersistentRSAKey5  s"   
$r  )r  )Pr-   rG  r  r   r8   rm  base64r   r   r   hashlibr   r   r   cryptographyr   cryptography.exceptionsr   cryptography.hazmat.backendsr	   cryptography.hazmat.primitivesr
   r   )cryptography.hazmat.primitives.asymmetricr   r   r   r   r   &cryptography.hazmat.primitives.ciphersr   r   r   ,cryptography.hazmat.primitives.serializationr   r   pyasn1.codec.berr   r   r   r  pyasn1.errorr   pyasn1.typer   twisted.conch.sshr   r   twisted.conch.ssh.commonr   twisted.pythonr   twisted.python.compatr   r   twisted.python.constantsr    r!   twisted.python.deprecater"   /cryptography.hazmat.primitives.asymmetric.utilsr#   r$   ImportErrorr%   r&   	SECP256R1	SECP384R1	SECP521R1rm   r   	Exceptionr(   r1   r2   r3   r6   rE   rF   r  r.   r.   r.   r/   <module>   sv   	             0