U
    <gz                     @   sn  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! ddl"m#Z#m$Z$m%Z%m&Z&m'Z'm(Z(m)Z)m*Z*m+Z+ ddl,m-Z-m.Z. ddl/m0Z0m1Z1m2Z2 ddl3m4Z4 eG dd dZ5ee6e7f e7dddZ8d;e7e5ee7 dddZ9d<e7e5e7ee7 dddZ:dddZ;e7dddZ<d=e7e7ee7 e7d d!d"Z=ej>G d#d$ d$ej?Z@G d%d& d&ejAe-ZBG d'd( d(e%e jCZDG d)d* d*eDe0ZEG d+d, d,eDe1ZFG d-d. d.eDe2ZGeHd/ZId0d1 ZJd2d3 ZKd4d5 ZLejMd6d7d8ZNe*jOG d9d: d:e*ZPe-OeB dS )>    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rc4_encrypt)	
AuthResult
AuthStatusCryptFilterCryptFilterBuilderCryptFilterConfigurationIdentityCryptFilterPdfKeyNotAvailableErrorSecurityHandlerSecurityHandlerVersion)SerialisableCredentialSerialisedCredential)AESCryptFilterMixinAESGCMCryptFilterMixinRC4CryptFilterMixin)StandardPermissionsc                   @   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-w101_d3s/pyhanko/pdf_utils/crypt/standard.py
from_bytes0   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_pw6   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_authenticateA   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_keyH   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>Z   s     z_bytes_mod_3.<locals>.<genexpr>rT   )sumrS   r4   r4   r5   _bytes_mod_3X   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   ]   s0    



  
 
rH   c                   @   sJ   e Zd 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   ri   r4   r4   r5   from_number   s    
z,StandardSecuritySettingsRevision.from_number)r7   r8   r9   __doc__	RC4_BASICZRC4_EXTENDEDRC4_OR_AES128AES256AES_GCMro   r   	PdfObjectrm   r<   rp   r4   r4   r4   r5   rc   {   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optionalTrh   c                 C   s   dS )Nrx   r4   r3   r4   r4   r5   get_name   s    z_PasswordCredential.get_namec                 C   s   |   S rG   )dumprk   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)rw   loadrn   r   PdfReadError)r3   rN   r4   r4   r5   _deser_value   s    z _PasswordCredential._deser_valueN)r7   r8   r9   r
   OctetString_fieldsr<   rB   r|   r:   r   r   r4   r4   r4   r5   rw      s   rw   c                       sX   e Zd ZU dZdZe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)rk   handler	__class__r4   r5   r      s    
z)StandardCryptFilter._set_security_handlerrh   c                 C   s   | j s
t| j  S rG   )r   r2   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   rm   r   rj   keylenrk   resultr   r4   r5   rm      s    
z!StandardCryptFilter.as_pdf_object)r7   r8   r9   rq   r   r   r;   propertyr   r   r:   r   rm   __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   rq   r4   r4   r4   r5   r      s   r   c                   @   s   e Zd ZdZdS )StandardAESGCMCryptFilterzA
    AES-GCM crypt filter for the standard security handler.
    Nr   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   c                   C   s   t tt ittdS )Nr   )r   r   r   r4   r4   r4   r5   _std_gcm_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eeddd eddd edd	d ed
dd i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ddfeeedddZed6ddZd7eeeee ee d fddZeejed d!d"Zeejd#d$d%Zeed fd&d'Z d(d) Z!ed*d+d,Z"ed*d-d.Z#d8ee e$d/d0d1Z%e&e'ee f dd2d3Z(edd4d5Z)  Z*S )9r   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`.
    z/V2z/AESV2c                 C   s
   t ddS )NrK   r   r   ___r4   r4   r5   <lambda>  s   z StandardSecurityHandler.<lambda>z/AESV3c                 C   s
   t ddS )Nr/   r   r   r   r4   r4   r5   r     s   z/AESV4c                 C   s   t  S rG   )r   r   r4   r4   r5   r     r>   z	/Identityc                 C   s   t  S rG   )r   r   r4   r4   r5   r     r>   _known_crypt_filtersrh   c                 C   s
   t dS )N	/Standard)r   
NameObjectr{   r4   r4   r5   r|     s    z StandardSecurityHandler.get_nameNrK   T)revpermsc
                 K   sP  t |}|dk	rt |n|}|tjkr4t| d|tjkrDd}n|rV|tjkrVd}t|||j|}|tjkr|tjB tj	B tj
B tj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
        :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   r   )versionrevisionlegacy_keylen
perm_flagsodataudatacrypt_filter_configencrypt_metadatarx   ry   )r   rc   rs   rn   rr   r   ri   r'   ZALLOW_FORM_FILLINGZALLOW_ASSISTIVE_TECHNOLOGYZALLOW_REASSEMBLYZALLOW_HIGH_QUALITY_PRINTINGr   r   r!   RC4_40RC4_LONGER_KEYSr   r   r   rw   _credential)r3   r   ry   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_legacyF)r   pdf_macuse_gcmc           !      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|r|tj	 M }|
 ddd }|d |rd	nd
 d td }tt|
t }| }|||  }|rhtd}nd}|rtj}tj}ntj}tj}| f ||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.
        :param pdf_mac:
            Include an ISO/TS 32004 MAC.
        :param use_gcm:
            Use AES-GCM (ISO/TS 32003) to encrypt strings and streams.

            .. danger::
                Due to the way PDF encryption works, the authentication
                guarantees of AES-GCM only apply to the content of individual
                strings and streams. The PDF file structure itself is not
                authenticated. Document-level integrity protection is provided
                by the ``pdf_mac=True`` option.

            .. warning::
                This option is disabled by default because support for
                ISO/TS 32003 is not available in mainstream PDF
                software yet. This default may change in the future.
        :return:
            A :class:`StandardSecurityHandler` instance.
        Nr/   r\   rK   F)rO   s      T   F   adbre   )r   r   r   r   r   r   oeseedueseedencrypted_permsr   kdf_saltrx   )rD   secretsZtoken_bytesrH   r   r:   r1   r2   r'   TOLERATE_MISSING_PDF_MACas_bytesr   r   AESr   ECB	encryptorr^   finalizer!   ru   rc   rt   r   rw   r   )!r3   r   r   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   r   r   r   r4   r4   r5   build_from_pw  s    .





   


   
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   r   c                    s$  |d krh|t jkrtd}nL|t jkr0t|}n8|t jkrBt }n&|t jkr^|d kr^td}n
t	dt
 j||||
||d || _|| _| jtj@  | _|tjkr| j|||||	 || _|| _|	| _n:t|t|  krdksn t	dd  | _ | _| _|| _|| _d | _d| _d S )Nr   r/   z1Could not impute a reasonable crypt filter config)r   compat_entriesr   zD/U and /O entries must be 32 bytes long in a legacy security handlerF)r!   r   r   r   ru   r   rt   r   r   r   r   __init__r   r   r'   r   _mac_requiredrc   r   r   r   r   r   r1   r   r   r   r   )rk   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r4   r5   r   ,  s^    







    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jtd	d
d}tjtd	dd}t||j	d|t
 d|jdd |jdd |	d||	d||	d||j	dtdd|	d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)xr-   c                 S   s,   t | tjtjfs&tdt|  | jS )NzExpected string, but got )rA   r   TextStringObjectByteStringObjectr   r   typeoriginal_bytesr   r4   r4   r5   
_get_bytes  s     
zFStandardSecurityHandler.gather_encryption_metadata.<locals>._get_bytesc                 S   s,   t | tjrt| S td|  dd S )NzCannot parse z as a permission indicator)rA   r   rj   r'   Zfrom_sint32r   r   r   r4   r4   r5   _parse_permissions  s
    

zNStandardSecurityHandler.gather_encryption_metadata.<locals>._parse_permissions/P)defaultNr.   /OE/UE/Perms/EncryptMetadataT/KDFSaltc                 S   s   t | tjtjfr| jS d S rG   )rA   r   r   r   r   r   r4   r4   r5   r     s     
zDStandardSecurityHandler.gather_encryption_metadata.<locals>.<lambda>)	r   r   r   r   r   r   r   r   r   )r   r   r   KeyErrorr   rv   r:   r'   dictZget_and_applyallow_everythingr   bool)r3   r   r   r   r   r   r   r   r4   r4   r5   gather_encryption_metadatan  sB    



  z2StandardSecurityHandler.gather_encryption_metadata)r   c                 C   s>   t |d }t|d }tf ||| |d| |S )N/V/R)r   r   r   )r!   rp   rc   r   Zprocess_crypt_filtersr   )r3   r   vrr4   r4   r5   instantiate_from_pdf_object  s    z3StandardSecurityHandler.instantiate_from_pdf_objectc                    s   t  jp| jS rG   )r   pdf_mac_enabledr   r~   r   r4   r5   r     s    z'StandardSecurityHandler.pdf_mac_enabledc                 C   s  t  }t d|d< t | j|d< t | j|d< t | j |d< | j	r`t | j	|d< | j
sr| jtjkrt | jd |d< | j |d	< | j |d
< | jtjkrt | j|d< || j  | jtjkrt | j|d< t | j|d< t | j|d< |S )Nr   z/Filterr   r   r   r   r\   r   r   r   r   r   r   r   )r   DictionaryObjectr   r   r   r   rj   r   Z	as_sint32Z	_kdf_saltZ_compat_entriesr   r!   r   r   rm   r   ZBooleanObjectr   r^   r   rc   rt   r   r   r   r   r4   r4   r5   rm     s0    
z%StandardSecurityHandler.as_pdf_object)ry   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   rr   r   r   r   r   ri   r   r   )rk   ry   r=   r   Z
user_tokenZuser_tok_suppliedrM   r4   r4   r5   _auth_user_password_legacy  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      r   c                 3   s   | ]}| A V  qd S rG   r4   rU   ir4   r5   rX     s     z?StandardSecurityHandler._authenticate_legacy.<locals>.<genexpr>)rw   r   r   ri   r   rc   rr   r   r   ranger:   r   r   r   OWNERUSERFAILED)rk   ry   r=   credr   rM   Zprp_userpassrl   Znew_keyZowner_passwordZuser_passwordr4   r   r5   _authenticate_legacy  s&    


z,StandardSecurityHandler._authenticate_legacy)ry   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 .ry   rx   Nz+id1 must be specified for legacy encryptionT)statusZpermission_flags)rA   r#   r"   Zdeserialiserw   rB   r:   r   r   r   Znativer   rc   rt   _authenticate_r6r   r  r   r   r   r   )rk   Z
credentialry   r   resrM   r4   r4   r5   authenticate  s,    





z$StandardSecurityHandler.authenticatec              
   C   s:  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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.rx   )"rD   r(   r6   r   r   rI   r   r   rP   r   r  r   r  r   r   r   r   r   	decryptorr^   r   r   r   r'   Z	from_uintstructunpack_EXPECTED_PERMS_8r   r   r   r   rw   r   )rk   r=   rE   Zo_entry_splitZu_entry_splitr   rM   r   r  Zdecrypted_p_entryZperms_okZdecr_metadata_flagr4   r4   r5   r  8  sD       



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   )rk   rM   r4   r4   r5   r   g  s    
z/StandardSecurityHandler.get_file_encryption_key)rf   )NNNTNTN)N)+r7   r8   r9   rq   r   r   r   r   r   r   r;   r<   rB   r|   r'   r   rc   r   r   r   staticmethodr   r!   r   r   r:   r   r   r   r   r   r   r   rm   r   r  r   r	  r   r   r  r   r   r4   r4   r   r5   r     s   
     z|       B? -/r   )N)N)N)Qabcenumr   r  dataclassesr   hashlibr   r   r   typingr   r   r   r	   Z
asn1cryptor
   &cryptography.hazmat.primitives.ciphersr   r   r   Zpyhanko.pdf_utilsr   r   Z_legacyr   r   r   r   r   _utilr   r   r   apir   r   r   r   r   r   r   r    r!   Zcred_serr"   r#   Zfilter_mixinsr$   r%   r&   permissionsr'   r(   rB   r:   rD   rI   rP   r  rZ   rH   uniqueZVersionEnumrc   Sequencerw   ABCr   r   r   r   r   r   r   r   r   r   r   registerr   r4   r4   r4   r5   <module>   sx   ,    
   
	    y