o
    @BiR                     @   s  d dl mZ d dl mZ d dlZd dlZd dlZd dlZd dlmZ d dl	m
Z
 dgZzd dlmZmZmZ W n eyB   dZY nw d	Zed
 dd Zdd Zdd ZG dd dZdd Zdd Zdd Zdd Zd1ddZdd ZerejG d d
 d
eZe d!krd dl!Z!ese"d"e!j#d# e!$d$ d d%l%m&Z& e& Z'e'j(d&d'd(d)d* e'j(d+d,d-dd.d/ e') \Z*Z+e*j,se"d0 e'-  e!$d$ e.e*j/Z0e"e01  dS dS )2    )absolute_import)print_functionN)util)	ChallengeHAS_CRYPTOSIGN)encodingsigningbindingsFT
SigningKeyc                 C   sT   g }| r(t d| dd d }| d|d  | d| d }} || | s|S )z}
    Unpack a SSH agent key blob into parts.

    See: http://blog.oddbit.com/2011/05/08/converting-openssh-public-keys/
    >IN   r   )structunpackappend)keydatapartsdlendata r   X/var/www/html/Trade-python/venv/lib/python3.10/site-packages/autobahn/wamp/cryptosign.py_unpack5   s   "
r   c                 C   s8   g }| D ]}| tdt| | | qd|S )z)
    Pack parts into a SSH key blob.
    r       )r   r   packlenjoin)keypartsr   partr   r   r   _packF   s
   
r   c              
   C   s   t | tjkrtdt | |   }t|dkr td|\}} }|dkr0td|t	| }zt
|d }W n tyP } ztd|d}~ww t|d	kr`td
t|||fS )a  
    Parse an OpenSSH Ed25519 public key from a string into a raw public key.

    Example input:

        ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJukDU5fqXv/yVhSirsDWsUFyOodZyCSLxyitPPzWJW9 oberstet@office-corei7

    :param keydata: The OpenSSH Ed25519 public key data to parse.
    :type keydata: str

    :returns: pair of raw public key (32 bytes) and comment
    :rtype: tuple
    zinvalid type {} for keydata   zinvalid SSH Ed25519 public keyzssh-ed25519z%not a Ed25519 SSH public key (but {})   zcould not parse key ({})N    z9invalid length {} for embedded raw key (must be 32 bytes))typesix	text_type	Exceptionformatstripsplitr   binascii
a2b_base64r   )r   r   algocommentblobkeyer   r   r   _read_ssh_ed25519_pubkeyQ   s$   

r/   c                   @   s8   e Zd ZdZdd Zdd Zdd Zdd	 Zd
d ZdS )_SSHPacketReaderzD
    Read OpenSSH packet format which is used for key material.
    c                 C   s   || _ d| _t|| _d S )Nr   )_packet_idxr   _len)selfpacketr   r   r   __init__|   s   z_SSHPacketReader.__init__c                 C   s   | j | jd  S N)r1   r2   r4   r   r   r   get_remaining_payload   s   z&_SSHPacketReader.get_remaining_payloadc                 C   s@   | j | | jkrtd| j| j | j |  }|  j |7  _ |S )Nzincomplete packet)r2   r3   r$   r1   )r4   sizevaluer   r   r   	get_bytes   s
   z_SSHPacketReader.get_bytesc                 C   s   t d| dd S )Nr   r   r   )r   r   r<   r8   r   r   r   
get_uint32   s   z_SSHPacketReader.get_uint32c                 C   s   |  |  S r7   )r<   r=   r8   r   r   r   
get_string   s   z_SSHPacketReader.get_stringN)	__name__
__module____qualname____doc__r6   r9   r<   r=   r>   r   r   r   r   r0   w   s    r0   c                 C   s   d dd td| d D S )N c                 s   s    | ]}t |V  qd S r7   )chr.0xr   r   r   	<genexpr>   s    z_makepad.<locals>.<genexpr>r   )r   range)r:   r   r   r   _makepad   s   rJ   c                 C   s  d}d}d}|  |r| |std| |}| t|| } ddd |  D } t| }|t|d }t	|}|
 }|
 }|
  | }	|
  |
 }
| }d	}|d
krdtd|d
krltd|	dkrwtd|	|r}tdt	|
}|  |  |
 }|dkrtd|d|
 }|
 }t|tjkrtdt|tjkrtd|
 }| }t|rt||ks|tt|krtdt||tt||dtj }|d}||fS )a  
    Parse an OpenSSH Ed25519 private key from a string into a raw private key.

    Example input:

        -----BEGIN OPENSSH PRIVATE KEY-----
        b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
        QyNTUxOQAAACCbpA1OX6l7/8lYUoq7A1rFBcjqHWcgki8corTz81iVvQAAAKDWjZ0Y1o2d
        GAAAAAtzc2gtZWQyNTUxOQAAACCbpA1OX6l7/8lYUoq7A1rFBcjqHWcgki8corTz81iVvQ
        AAAEArodzIMjH9MOBz0X+HDvL06rEJOMYFhzGQ5zXPM7b7fZukDU5fqXv/yVhSirsDWsUF
        yOodZyCSLxyitPPzWJW9AAAAFm9iZXJzdGV0QG9mZmljZS1jb3JlaTcBAgMEBQYH
        -----END OPENSSH PRIVATE KEY-----


    :param keydata: The OpenSSH Ed25519 private key data to parse.
    :type keydata: str

    :returns: pair of raw private key (32 bytes) and comment
    :rtype: tuple
    #-----BEGIN OPENSSH PRIVATE KEY-----z!-----END OPENSSH PRIVATE KEY-----s   openssh-key-v1 zFinvalid OpenSSH private key (does not start/end with OPENSSH preamble)rC   c                 S   s   g | ]}|  qS r   )r&   rE   r   r   r   
<listcomp>   s    z-_read_ssh_ed25519_privkey.<locals>.<listcomp>N   s   nonezjencrypted private keys not supported (please remove the passphrase from your private key or use SSH agent)z/passphrase encrypted private keys not supportedr   zAmultiple private keys in a key file not supported (found {} keys)z=invalid OpenSSH private key (found remaining payload for mac)s   ssh-ed25519z6invalid key type: we only support Ed25519 (found "{}")asciizinvalid public key lengthzGinvalid OpenSSH private key (padlen={}, actual_pad={}, expected_pad={}))
startswithendswithr$   findr   r   r'   r(   r)   r0   r>   r=   r9   r%   decoder	   crypto_sign_PUBLICKEYBYTEScrypto_sign_SECRETKEYBYTESrJ   crypto_sign_SEEDBYTES)r   	SSH_BEGINSSH_ENDOPENSSH_KEY_V1ssh_endr,   r5   cipher_namekdfnkeyskey_datamac
block_sizealgvkskr+   padseedr   r   r   _read_ssh_ed25519_privkey   s\   

$
re   c                 C   l   t | (}t|  d dd }t|dkr#tdt||W  d   S 1 s/w   Y  dS )z
    Read a Ed25519 signature file created with OpenBSD signify.

    http://man.openbsd.org/OpenBSD-current/man1/signify.1
    r   
   N@   zEbogus Ed25519 signature: raw signature length was {}, but expected 64openr(   r)   read
splitlinesr   r$   r%   )signature_filefsigr   r   r   _read_signify_ed25519_signature      
$rp   c                 C   rf   )z
    Read a public key from a Ed25519 key pair created with OpenBSD signify.

    http://man.openbsd.org/OpenBSD-current/man1/signify.1
    r   rg   Nr    z@bogus Ed25519 public key: raw key length was {}, but expected 32ri   )pubkey_filern   pubkeyr   r   r   _read_signify_ed25519_pubkey	  rq   rt   textc                 C   s   |dv sJ ddl }t| B}|  d }|j|ddd}|dkr.| W  d   S |d	krLddl}| }|j|d
d |	 W  d   S t
d1 sSw   Y  dS )a  

    Usage:

    1. Get the OpenBSD 5.7 release public key from here

        http://cvsweb.openbsd.org/cgi-bin/cvsweb/src/etc/signify/Attic/openbsd-57-base.pub?rev=1.1

    2. Generate QR Code and print to terminal

        print(cryptosign._qrcode_from_signify_ed25519_pubkey('openbsd-57-base.pub'))

    3. Compare to (scroll down) QR code here

        https://www.openbsd.org/papers/bsdcan-signify.html
    )ru   svgr   Nr   Lbinary)errormoderu   rv   T)omithwzlogic error)pyqrcoderj   rk   rl   createterminalioBytesIOrv   getvaluer$   )rr   rz   r|   rn   rs   qrr   data_bufferr   r   r   #_qrcode_from_signify_ed25519_pubkey  s    
r   c                 C   s*   t | }t|}t|}||| dS )a  
    Verify a Ed25519 signature created with OpenBSD signify.

    This will raise a `nacl.exceptions.BadSignatureError` if the signature is bad
    and return silently when the signature is good.

    Usage:

    1. Create a signature:

        signify-openbsd -S -s ~/.signify/crossbario-trustroot.sec -m .profile

    2. Verify the signature

        from autobahn.wamp import cryptosign

        with open('.profile', 'rb') as f:
            message = f.read()
            cryptosign._verify_signify_ed25519_signature('.signify/crossbario-trustroot.pub', '.profile.sig', message)

    http://man.openbsd.org/OpenBSD-current/man1/signify.1
    N)rt   r   	VerifyKeyrp   verify)rr   rm   messagers   
verify_keyro   r   r   r   !_verify_signify_ed25519_signature@  s   
r   c                   @   s   e Zd ZdZdddZdd Zejdd Zejd	d
 Z	ejdddZ
ejdd Zejdd ZejedddZedddZejedd Zejedd ZdS )r
   z
        A cryptosign private key for signing, and hence usable for authentication or a
        public key usable for verification (but can't be used for signing).
        Nc                 C   sp   t |tjst |tjstdt||du s)t|tjks)tdt||| _	|| _
t |tj| _dS )z

            :param key: A Ed25519 private signing key or a Ed25519 public verification key.
            :type key: instance of nacl.signing.VerifyKey or instance of nacl.signing.SigningKey
            zinvalid type {} for keyNinvalid type {} for comment)
isinstancer   r   r
   r$   r%   r!   r"   r#   _key_comment	_can_sign)r4   r-   r+   r   r   r   r6   o  s   zSigningKey.__init__c                 C   s0   |   rd|   nd }d|  ||  S )Nz"{}"z+Key(can_sign={}, comment={}, public_key={}))r+   r%   can_sign
public_key)r4   r+   r   r   r   __str__  s   zSigningKey.__str__c                 C      | j S )z
            Check if the key can be used to sign.

            :returns: `True`, iff the key can sign.
            :rtype: bool
            )r   r8   r   r   r   r        zSigningKey.can_signc                 C   r   )z
            Get the key comment (if any).

            :returns: The comment (if any) from the key.
            :rtype: str or None
            )r   r8   r   r   r   r+     r   zSigningKey.commentFc                 C   s>   t | jtjr| jj}n| j}|r| S |jtjddS )z
            Returns the public key part of a signing key or the (public) verification key.

            :returns: The public key in Hex encoding.
            :rtype: str or None
            encoderrN   )	r   r   r   r
   r   encoder   
HexEncoderrR   )r4   rx   r-   r   r   r   r     s   
zSigningKey.public_keyc                 C   s<   | j stdt|tjkrtd| j|}t|j	S )z
            Sign some data.

            :param data: The data to be signed.
            :type data: bytes

            :returns: The signature.
            :rtype: bytes
            za signing key required to signz data to be signed must be binary)
r   r$   r!   r"   binary_typer   signtxaiocreate_future_success	signature)r4   r   ro   r   r   r   r     s   zSigningKey.signc                    s   t |tstdt|d|jvrtd|jd }t|tjkr,tdt|t|dkr;tdt|t	
|}|j }|r]t|dksVJ dt|t||n|| }t   fd	d
}t||d  S )a  
            Sign WAMP-cryptosign challenge.

            :param session: The authenticating WAMP session.
            :type session: :class:`autobahn.wamp.protocol.ApplicationSession`

            :param challenge: The WAMP-cryptosign challenge object for which a signature should be computed.
            :type challenge: instance of autobahn.wamp.types.Challenge

            :returns: A Deferred/Future that resolves to the computed signature.
            :rtype: str
            zCchallenge must be instance of autobahn.wamp.types.Challenge, not {}	challengez*missing challenge value in challenge.extraz5invalid type {} for challenge (expected a hex string)rh   z:unexpected challenge (hex) length: was {}, but expected 64r    zCunexpected TLS transport channel ID length: was {}, but expected 32c                    s8   t | d}t d}|| }t | d S )NrN   )r(   b2a_hexrR   r   resolve)signature_rawsignature_hexdata_hexro   d2r   r   r   process  s   z*SigningKey.sign_challenge.<locals>.processN)r   r   r$   r%   r!   extrar"   r#   r   r(   a2b_hex
_transportget_channel_idr   xorr   r   create_futureadd_callbacks)r4   sessionr   challenge_hexchallenge_rawchannel_id_rawd1r   r   r   r   sign_challenge  s(   






zSigningKey.sign_challengec                 C   sz   |d u st |tjkstdt |t |tjkr$tdt |t|dkr3tdt|t|}| ||S )Nr   z%invalid key type {} (expected binary)r    z#invalid key length {} (expected 32))	r!   r"   r#   
ValueErrorr%   r   r   r   r
   )clsr   r+   r-   r   r   r   from_key_bytes  s   

zSigningKey.from_key_bytesc                 C   s   |du st |tjkstdt |t |tjkr"td|t|d}| }W d   n1 s6w   Y  | j||dS )a  
            Load an Ed25519 (private) signing key (actually, the seed for the key) from a raw file of 32 bytes length.
            This can be any random byte sequence, such as generated from Python code like

                os.urandom(32)

            or from the shell

                dd if=/dev/urandom of=client02.key bs=1 count=32

            :param filename: Filename of the key.
            :type filename: str
            :param comment: Comment for key (optional).
            :type comment: str or None
            Nr   zinvalid type {} for filenamerb)r+   )r!   r"   r#   r$   r%   rj   rk   r   )r   filenamer+   rn   r   r   r   r   from_raw_key  s   
zSigningKey.from_raw_keyc                 C   sF   t |d}| d }W d   n1 sw   Y  | |S )a  
            Load an Ed25519 key from a SSH key file. The key file can be a (private) signing
            key (from a SSH private key file) or a (public) verification key (from a SSH
            public key file). A private key file must be passphrase-less.
            r   zutf-8N)rj   rk   rR   r&   from_ssh_data)r   r   rn   r   r   r   r   from_ssh_key,  s   	
zSigningKey.from_ssh_keyc                 C   sL   d}| |rt|\}}tj|tjd}nt|\}}t|}| ||S )a  
            Load an Ed25519 key from SSH key file. The key file can be a (private) signing
            key (from a SSH private key file) or a (public) verification key (from a SSH
            public key file). A private key file must be passphrase-less.
            rK   r   )rO   re   r   r
   r   
RawEncoderr/   r   )r   r   rV   r+   r-   r   r   r   r   9  s   


zSigningKey.from_ssh_datar7   )F)r?   r@   rA   rB   r6   r   r   publicr   r+   r   r   r   classmethodr   r   r   r   r   r   r   r   r
   h  s2    

	
	

=__main__z4NaCl library must be installed for this to function.)filer   )OptionParserz-fz--filekeyfilezfile containing ssh key)desthelpz-p
store_trueprintpubzprint public key information)actionr   defaultr   z;Print public key must be specified as it's the only option.)ru   )2
__future__r   r   r(   r   r"   r   autobahnr   autobahn.wamp.typesr   __all__naclr   r   r	   ImportErrorr   r   r   r   r/   r0   rJ   re   rp   rt   r   r   r   objectr
   r?   sysprintstderrexitoptparser   parser
add_option
parse_argsoptionsargsr   print_usager   r   r-   r   r   r   r   r   <module>   sh   
&d
)& e


