U
    ci                     @   sL  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mZm	Z	 d dl
mZmZmZmZ d dl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mZmZmZ dd
lmZm Z m!Z!m"Z" ddl#m$Z$m%Z%m&Z&m'Z'm(Z(m)Z)m*Z*m+Z+m,Z,m-Z- ddl.m/Z/m0Z0 ddl1m2Z2m3Z3 eG dd dZ4ee5e6f e6dddZ7d6e6e4ee6 dddZ8d7e6e4e6ee6 dddZ9dddZ:e6dddZ;d8e6e6ee6 e6dd d!Z<ej=G d"d# d#ej>Z?G d$d% d%ej@e/ZAG d&d' d'e'e jBZCG d(d) d)eCe2ZDG d*d+ d+eCe3ZEeFd,ZGd-d. ZHd/d0 ZIejJd1d2d3ZKe,jLG d4d5 d5e,ZMe/LeA dS )9    N)	dataclass)sha256sha384sha512)DictOptionalTupleUnion)core)Cipher
algorithmsmodes)genericmisc   )compute_o_value_legacycompute_o_value_legacy_prepcompute_u_value_r2compute_u_value_r34legacy_normalise_pw)aes_cbc_decryptaes_cbc_encrypt	as_signedrc4_encrypt)
	ALL_PERMS
AuthResult
AuthStatusCryptFilterCryptFilterBuilderCryptFilterConfigurationIdentityCryptFilterPdfKeyNotAvailableErrorSecurityHandlerSecurityHandlerVersion)SerialisableCredentialSerialisedCredential)AESCryptFilterMixinRC4CryptFilterMixinc                   @   s:   e Zd ZU eed< eed< eed< eed dddZdS )_R6KeyEntry
hash_valuevalidation_saltkey_salt)entryreturnc                 C   s4   t |dkstt|d d |dd |dd S )N0       (   )lenAssertionErrorr(   )clsr,    r4   D/tmp/pip-unpacked-wheel-0kb_yl26/pyhanko/pdf_utils/crypt/standard.py
from_bytes,   s    z_R6KeyEntry.from_bytesN)__name__
__module____qualname__bytes__annotations__classmethodr6   r4   r4   r4   r5   r(   &   s
   
r(   )passwordr-   c                 C   s8   t | tr,| sdS ddlm} || d} | d d S )N    r   )saslprepzutf-8   )
isinstancestrZ	_saslprepr?   encode)r=   r?   r4   r4   r5   _r6_normalise_pw2   s    
rD   )pw_bytesr,   u_entryc                 C   s   t | |j|}||jkS N)_r6_hash_algor*   r)   )rE   r,   rF   Zpurported_hashr4   r4   r5   _r6_password_authenticate<   s    rI   )rE   r,   e_entryrF   c                 C   s2   t | |j|}t|dkstt||tdddS )Nr/      FkeydataZivuse_padding)rH   r+   r1   r2   r   r:   )rE   r,   rJ   rF   Z
interm_keyr4   r4   r5   _r6_derive_file_keyB   s       rP   TF)T   F   Zinput_bytesc                 C   s   t dd | D d S )Nc                 s   s   | ]}|d  V  qdS )   Nr4   .0br4   r4   r5   	<genexpr>S   s     z_bytes_mod_3.<locals>.<genexpr>rT   )sumrS   r4   r4   r5   _bytes_mod_3Q   s    rZ   )rE   current_saltrF   r-   c                 C   s   t | }t|dkst|| |r@t|dks6t|| | }t ttf}d }}|dk sn||d kr| | |pzd d }t|dd ||dd d	d
d }	|t|	dd  }
|
|	 }|	t|	d  }|d7 }qZ|dd S )u3   
    Algorithm 2.B in ISO 32000-2 § 7.6.4.3.4
       r.   r   @   r/   r>   NrK   FrL   r   )	r   r1   r2   updatedigestr   r   r   rZ   )rE   r[   rF   Zinitial_hashkhashesZround_noZlast_byte_valZk1eZ	next_hashr4   r4   r5   rH   V   s0    



  
 
rH   c                   @   sF   e Zd ZdZdZdZdZdZdZe	j
ddd	Zed dd
dZdS ) StandardSecuritySettingsRevisionz;Indicate the standard security handler revision to emulate.   rT         Nr-   c                 C   s    | j }|d krt S t|S rG   )valuer   Z
NullObjectNumberObject)selfvalr4   r4   r5   as_pdf_object   s    z.StandardSecuritySettingsRevision.as_pdf_objectc                 C   s*   z
t |W S  tk
r$   t j Y S X d S rG   )rc   
ValueErrorOTHER)r3   rh   r4   r4   r5   from_number   s    
z,StandardSecuritySettingsRevision.from_number)r7   r8   r9   __doc__	RC4_BASICZRC4_EXTENDEDRC4_OR_AES128AES256rn   r   Z	PdfObjectrl   r<   ro   r4   r4   r4   r5   rc   s   s   rc   c                   @   sX   e Zd ZdejfdejddifgZeedddZe	ddd	Z
ee	d
ddZdS )_PasswordCredential	pwd_bytesid1optionalTrg   c                 C   s   dS )Nru   r4   r3   r4   r4   r5   get_name   s    z_PasswordCredential.get_namec                 C   s   |   S rG   )dumprj   r4   r4   r5   
_ser_value   s    z_PasswordCredential._ser_value)rN   c                 C   s0   zt |W S  tk
r*   tdY nX d S )Nz)Failed to deserialise password credential)rt   loadrm   r   PdfReadError)r3   rN   r4   r4   r5   _deser_value   s    z _PasswordCredential._deser_valueN)r7   r8   r9   r
   ZOctetString_fieldsr<   rB   ry   r:   r|   r   r4   r4   r4   r5   rt      s   rt   c                       sT   e Zd ZU dZdZded< edd Z fddZe	d	d
dZ
 fddZ  ZS )StandardCryptFilterzB
    Crypt filter for use with the standard security handler.
    NStandardSecurityHandler_handlerc                 C   s   t | jtr| jjS td S rG   )rA   r   r   _auth_failedNotImplementedErrorr{   r4   r4   r5   r      s    z StandardCryptFilter._auth_failedc                    s$   t |tstt | d | _d S rG   )rA   r   	TypeErrorsuper_set_security_handler_shared_key)rj   handler	__class__r4   r5   r      s    
z)StandardCryptFilter._set_security_handlerrg   c                 C   s
   | j  S rG   )r   get_file_encryption_keyr{   r4   r4   r5   derive_shared_encryption_key   s    z0StandardCryptFilter.derive_shared_encryption_keyc                    s   t   }t| j|d< |S )N/Length)r   rl   r   ri   keylenrj   resultr   r4   r5   rl      s    
z!StandardCryptFilter.as_pdf_object)r7   r8   r9   rp   r   r;   propertyr   r   r:   r   rl   __classcell__r4   r4   r   r5   r      s   

r   c                   @   s   e Zd ZdZdS )StandardAESCryptFilterz=
    AES crypt filter for the standard security handler.
    Nr7   r8   r9   rp   r4   r4   r4   r5   r      s   r   c                   @   s   e Zd ZdZdS )StandardRC4CryptFilterz=
    RC4 crypt filter for the standard security handler.
    Nr   r4   r4   r4   r5   r      s   r   z/StdCFc                 C   s   t tt| dittdS Nr   )Zdefault_stream_filterZdefault_string_filter)r   STD_CFr   r   r4   r4   r5   _std_rc4_config   s
    r   c                 C   s   t tt| dittdS r   )r   r   r   r   r4   r4   r5   _std_aes_config   s
    r   )cfdictc                 C   s   |  dd}t|d dS )Nr   r0   r\   r   )getr   )r   Z_acts_as_defaultkeylen_bitsr4   r4   r5   #_build_legacy_standard_crypt_filter   s    r   c                       s>  e Zd ZU dZedd dd dd dZeeje	f e
d< eedd	d
ZedddeddfeedddZededfddZed-ddZd.eeeed fddZeejedddZeejdddZdd  Zed!d"d#Zed!d$d%Zd/e e e!d&d'd(Z"e#e$e e f dd)d*Z%edd+d,Z&  Z'S )0r   a  
    Implementation of the standard (password-based) security handler.

    You shouldn't have to instantiate :class:`.StandardSecurityHandler` objects
    yourself. For encrypting new documents, use :meth:`build_from_pw`
    or :meth:`build_from_pw_legacy`.

    For decrypting existing documents, pyHanko will take care of instantiating
    security handlers through :meth:`.SecurityHandler.build`.
    c                 C   s
   t ddS )NrK   r   r   ___r4   r4   r5   <lambda>   r>   z StandardSecurityHandler.<lambda>c                 C   s
   t ddS )Nr/   r   r   r   r4   r4   r5   r      r>   c                 C   s   t  S rG   )r    r   r4   r4   r5   r      r>   )z/V2z/AESV2z/AESV3z	/Identity_known_crypt_filtersrg   c                 C   s
   t dS )N	/Standard)r   
NameObjectrx   r4   r4   r5   ry      s    z StandardSecurityHandler.get_nameNrK   T)revpermsc
                 K   sL  t |}|dk	rt |n|}|tjkr4t| d|tjkrDd}n|rV|tjkrVd}t|||j|}t|d@ }|tjkrt|dB }t||||\}}nt	||j|||||	\}}|tjkrt
j}n|tjkrt
j}nt
j}|tjkr|dkr|rtdd}n
t|d}| f ||||||||	d|
}||_t||d	|_|S )
a  
        Initialise a legacy password-based security handler, to attach to a
        :class:`~.pyhanko.pdf_utils.writer.PdfFileWriter`.
        Any remaining keyword arguments will be passed to the constructor.

        .. danger::
            The functionality implemented by this handler is deprecated in the
            PDF standard. We only provide it for testing purposes, and to
            interface with legacy systems.

        :param rev:
            Security handler revision to use, see
            :class:`.StandardSecuritySettingsRevision`.
        :param id1:
            The first part of the document ID.
        :param desired_owner_pass:
            Desired owner password.
        :param desired_user_pass:
            Desired user password.
        :param keylen_bytes:
            Length of the key (in bytes).
        :param use_aes128:
            Use AES-128 instead of RC4 (default: ``True``).
        :param perms:
            Permission bits to set (defined as an integer)
        :param crypt_filter_config:
            Custom crypt filter configuration. PyHanko will supply a reasonable
            default if none is specified.
        :return:
            A :class:`StandardSecurityHandler` instance.
        Nz/ is not supported by this bootstrapping method.   rK       l    r   )versionrevisionlegacy_keylen
perm_flagsodataudatacrypt_filter_configencrypt_metadataru   rv   )r   rc   rr   rm   rq   r   rh   r   r   r   r#   RC4_40RC4_LONGER_KEYSr   r   r   rt   _credential)r3   r   rv   desired_owner_passdesired_user_passZkeylen_bytesZ
use_aes128r   r   r   kwargso_entryrF   rM   r   shr4   r4   r5   build_from_pw_legacy   s    '


   
   
     


     
z,StandardSecurityHandler.build_from_pw_legacyc                 K   s  t |}|dk	rt |n|}td}td}	td}
t||	}||	 |
 }t||
}t||tddd\}}t|dksttd}td}t|||}|| | }t|||}t||tddd\}}t|dkstt	d|d@ }|d	 |rd
nd d td }t
t|t }| }|||  }| f tjtjd|||||||d
|}||_td|i|_|S )a  
        Initialise a password-based security handler backed by AES-256,
        to attach to a :class:`~.pyhanko.pdf_utils.writer.PdfFileWriter`.
        This handler will use the new PDF 2.0 encryption scheme.

        Any remaining keyword arguments will be passed to the constructor.

        :param desired_owner_pass:
            Desired owner password.
        :param desired_user_pass:
            Desired user password.
        :param perms:
            Desired usage permissions.
        :param encrypt_metadata:
            Whether to set up the security handler for encrypting metadata
            as well.
        :return:
            A :class:`StandardSecurityHandler` instance.
        Nr/   r\   rK   F)rO   z<Ir   s      T   F   adbre   )
r   r   r   r   r   r   oeseedueseedencrypted_permsr   ru   )rD   secretsZtoken_bytesrH   r   r:   r1   r2   structpackr   r   AESr   ECB	encryptorr^   finalizer#   rs   rc   r   rt   r   )r3   r   r   r   r   r   Zowner_pw_bytesZuser_pw_bytesZencryption_keyZu_validation_saltZ
u_key_saltZu_hashrF   Zu_interm_keyr   Zue_seedZo_validation_saltZ
o_key_saltZo_hashr   Zo_interm_keyZoe_seedZperms_bytesZextd_perms_bytescipherr   r   r   r4   r4   r5   build_from_pw`  sx    





   


   

     z%StandardSecurityHandler.build_from_pwrf   c                 C   s   t | t |  krdks0n td| d|rV|rVt |t |  krTdkshn td| d|rxt |dkrtd| dd S )Nr.   z2/U and /O entries must be 48 bytes long in a rev. z security handlerr/   z;/UE and /OE must be present and be 32 bytes long in a rev. rK   z6/Perms must be present and be 16 bytes long in a rev. )r1   r   PdfError)r   r   r   r   r   r   r4   r4   r5   _check_r6_values  s"    
 

z(StandardSecurityHandler._check_r6_values)r   r   r   r   c                    s   |d krJ|t jkrtd}n.|t jkr0t|}n|t jkrJ|d krJtd}t j||||
|d || _t	|| _
|tjkr| j|||||	 || _|| _|	| _n:t|t|  krdksn tdd  | _ | _| _|| _|| _d | _d| _d S )Nr   r/   )r   compat_entrieszD/U and /O entries must be 32 bytes long in a legacy security handlerF)r#   r   r   r   rs   r   r   __init__r   r   r   rc   r   r   r   r   r   r1   r   r   r   r   r   r   )rj   r   r   r   r   r   r   r   r   r   r   r   r   r   r4   r5   r     sL    




   

    z StandardSecurityHandler.__init__)encrypt_dictr-   c                 C   s   | dd}|d dkr"td|d }z|d }|d }W n tk
r\   tdY nX t|t| d	t|jd
d |jd
d |ddd |ddd |ddd |jdt	dddS )a  
        Gather and preprocess the "easy" metadata values in an encryption
        dictionary, and turn them into constructor kwargs.

        This function processes ``/Length``, ``/P``, ``/Perms``, ``/O``, ``/U``,
        ``/OE``, ``/UE`` and ``/EncryptMetadata``.
        r   r0   r\   r   z"Key length must be a multiple of 8/O/Uz!/O and /U entries must be present/PNr.   /OEc                 S   s   | j S rG   original_bytesxr4   r4   r5   r     r>   zDStandardSecurityHandler.gather_encryption_metadata.<locals>.<lambda>/UEc                 S   s   | j S rG   r   r   r4   r4   r5   r   	  r>   /Permsc                 S   s   | j S rG   r   r   r4   r4   r5   r     r>   /EncryptMetadataT)default)r   r   r   r   r   r   r   r   )
r   r   r   KeyErrordictr   r   r   Zget_and_applybool)r3   r   r   r   r   r   r4   r4   r5   gather_encryption_metadata  s@    
     z2StandardSecurityHandler.gather_encryption_metadata)r   c                 C   s>   t |d }t|d }tf ||| |d| |S )N/V/R)r   r   r   )r#   ro   rc   r   Zprocess_crypt_filtersr   )r3   r   vrr4   r4   r5   instantiate_from_pdf_object  s     z3StandardSecurityHandler.instantiate_from_pdf_objectc                 C   s   t  }t d|d< t | j|d< t | j|d< t t| j|d< | j	s\| j
tjkrpt | jd |d< | j
 |d< | j |d	< | j
tjkrt | j|d
< || j  | jtjkrt | j|d< t | j|d< t | j|d< |S )Nr   z/Filterr   r   r   r\   r   r   r   r   r   r   r   )r   DictionaryObjectr   ZByteStringObjectr   r   ri   r   r   Z_compat_entriesr   r#   r   r   rl   r   ZBooleanObjectr   r^   r   rc   rs   r   r   r   r   r4   r4   r5   rl     s(    

z%StandardSecurityHandler.as_pdf_object)rv   c                 C   st   | j }| j}|tjkr.t|| j| j|\}}n:t||j| j	| j| j|| j
\}}|d d }|d d }||k|fS )NrK   )r   r   rc   rq   r   r   r   r   rh   r   r   )rj   rv   r=   r   Z
user_tokenZuser_tok_suppliedrM   r4   r4   r5   _auth_user_password_legacy5  s*    
   
     z2StandardSecurityHandler._auth_user_password_legacyc                    s   t ||d}| j}t||j| j}|tjkr<t|| j}n<| j}t	dddD ]$ t
 fdd|D }t||}qN|}| ||\}	}|	r|| _tj|fS | ||\}
}|
r|| _tj|fS tjd fS )Nr      c                 3   s   | ]}| A V  qd S rG   r4   rU   ir4   r5   rX   T  s     z?StandardSecurityHandler._authenticate_legacy.<locals>.<genexpr>)rt   r   r   rh   r   rc   rq   r   r   ranger:   r   r   r   OWNERUSERFAILED)rj   rv   r=   credr   rM   Zprp_userpassrk   Znew_keyZowner_passwordZuser_passwordr4   r   r5   _authenticate_legacyF  s,    


z,StandardSecurityHandler._authenticate_legacy)rv   r-   c                 C   s   t |trt|}t |tttfs:tdt	| dt |trX|d j
}|d j
}| j}|tjkrx| |\}}n*|dkrtdt|}| ||\}}|dk	r|| _nd| _t|| jdS )	a  
        Authenticate a user to this security handler.

        :param credential:
            The credential to use (a password in this case).
        :param id1:
            First part of the document ID. This is mandatory for legacy
            encryption handlers, but meaningless otherwise.
        :return:
            An :class:`AuthResult` object indicating the level of access
            obtained.
        z]Standard authentication credential must be a string, byte string or _PasswordCredential, not .rv   ru   Nz+id1 must be specified for legacy encryptionT)statusZpermission_flags)rA   r%   r$   Zdeserialisert   rB   r:   r   r~   typeZnativer   rc   rs   _authenticate_r6r   r   r   r   r   r   )rj   Z
credentialrv   r   resrM   r4   r4   r5   authenticatec  s,    





z$StandardSecurityHandler.authenticatec                 C   s4  t |}t| j}t| j}t||| jrHtj}t||| j	| j}n*t||rhtj
}t||| j}n
tjd fS tt|t }| }|| j|  }	|	dd dk}
|
| jtd|	d d d kM }
zt|	d  }|
|| jkM }
W n tk
r   d}
Y nX |
std	td
|i| _||fS )N	      r   z<ire   r   r\   FznFile decryption key didn't decrypt permission flags correctly -- file permissions may have been tampered with.ru   ) rD   r(   r6   r   r   rI   r   r   rP   r   r   r   r   r   r   r   r   r   	decryptorr^   r   r   r   r   unpack_EXPECTED_PERMS_8r   r   r   r   rt   r   )rj   r=   rE   Zo_entry_splitZu_entry_splitr   rM   r   r   Zdecrypted_p_entryZperms_okZdecr_metadata_flagr4   r4   r5   r     s@       

"
z(StandardSecurityHandler._authenticate_r6c                 C   s$   | j }|dkr t| jrdnd|S )aQ  
        Retrieve the (global) file encryption key for this security handler.

        :return:
            The file encryption key as a :class:`bytes` object.
        :raise misc.PdfReadError:
            Raised if this security handler was instantiated from an encryption
            dictionary and no credential is available.
        NzAuthentication failed.z7No key available to decrypt, please authenticate first.)r   r!   r   )rj   rM   r4   r4   r5   r     s    

z/StandardSecurityHandler.get_file_encryption_key)rf   )NNNTNT)N)(r7   r8   r9   rp   r   r   r   r   r   r   r;   r<   rB   ry   r   rc   intr   r   staticmethodr   r#   r   r   r   r   r   r   rl   r:   r   r   r   r   r   r   r   r   r   r   r4   r4   r   r5   r      sf   
 ` L        *'
,+r   )N)N)N)Nabcenumr   r   Zdataclassesr   hashlibr   r   r   typingr   r   r   r	   Z
asn1cryptor
   Z&cryptography.hazmat.primitives.ciphersr   r   r   Zpyhanko.pdf_utilsr   r   Z_legacyr   r   r   r   r   Z_utilr   r   r   r   apir   r   r   r   r   r   r    r!   r"   r#   Zcred_serr$   r%   Zfilter_mixinsr&   r'   r(   rB   r:   rD   rI   rP   r   rZ   rH   uniqueZVersionEnumrc   Sequencert   ABCr   r   r   r   r   r   r   r   r   registerr   r4   r4   r4   r5   <module>   sd   0  
  
   h