o
    vhz                  
   @   s  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Z5dee6e7f de7fddZ8	d>de7de5dee7 fddZ9	d>de7de5de7dee7 fddZ:dddZ;d e7fd!d"Z<	d>de7d#e7dee7 de7f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 d0d1 d1eDe2ZGeHd2ZId3d4 ZJd5d6 ZKd7d8 ZLd9ejMfd:d;ZNe*jOG d<d= 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dedd fddZdS )	_R6KeyEntry
hash_valuevalidation_saltkey_saltentryreturnc                 C   s4   t |dksJ t|d d |dd |dd S )N0       (   )lenr(   )clsr,    r3   ^/var/www/html/hyperkenya/venv/lib/python3.10/site-packages/pyhanko/pdf_utils/crypt/standard.py
from_bytes/   s   $z_R6KeyEntry.from_bytesN)__name__
__module____qualname__bytes__annotations__classmethodr5   r3   r3   r3   r4   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str	_saslprepr>   encode)r<   r>   r3   r3   r4   _r6_normalise_pw5   s   
rD   pw_bytesr,   u_entryc                 C   s   t | |j|}||jkS N)_r6_hash_algor*   r)   )rE   r,   rF   purported_hashr3   r3   r4   _r6_password_authenticate@   s   
rJ   e_entryc                 C   s2   t | |j|}t|dksJ t||tdddS )Nr/      Fkeydataivuse_padding)rH   r+   r1   r   r9   )rE   r,   rK   rF   
interm_keyr3   r3   r4   _r6_derive_file_keyG   s
   rS   TF)T   F   input_bytesc                 C   s   t dd | D d S )Nc                 s   s    | ]}|d  V  qdS )   Nr3   .0br3   r3   r4   	<genexpr>Y       z_bytes_mod_3.<locals>.<genexpr>rW   )sum)rV   r3   r3   r4   _bytes_mod_3W   s   r^   current_saltc                 C   s   t | }t|dksJ || |r t|dksJ || | }t ttf}d }}|dk s7||d kry| | |p=d d }t|dd ||dd d	d
d }	|t|	dd  }
|
|	 }|	t|	d  }|d7 }|dk s7||d ks7|dd S )u3   
    Algorithm 2.B in ISO 32000-2 § 7.6.4.3.4
       r.   r   @   r/   r=   NrL   FrM   r   )r   r1   updatedigestr   r   r   r^   )rE   r_   rF   initial_hashkhashesround_nolast_byte_valk1e	next_hashr3   r3   r4   rH   \   s,   


rH   c                   @   sH   e Zd ZdZdZdZdZdZdZdZ		 de
jfd	d
ZedddZdS ) StandardSecuritySettingsRevisionz;Indicate the standard security handler revision to emulate.   rW            Nr-   c                 C   s    | j }|d u rt S t|S rG   )valuer   
NullObjectNumberObject)selfvalr3   r3   r4   as_pdf_object   s
   z.StandardSecuritySettingsRevision.as_pdf_objectc                 C   s$   zt |W S  ty   t j Y S w rG   )rl   
ValueErrorOTHER)r2   rq   r3   r3   r4   from_number   s
   

z,StandardSecuritySettingsRevision.from_number)r-   rl   )r6   r7   r8   __doc__	RC4_BASICRC4_EXTENDEDRC4_OR_AES128AES256AES_GCMrx   r   	PdfObjectrv   r;   ry   r3   r3   r3   r4   rl   z   s    rl   c                   @   sX   e Zd ZdejfdejddifgZedefddZde	fdd	Z
ed
e	fddZdS )_PasswordCredential	pwd_bytesid1optionalTr-   c                 C   s   dS )Nr   r3   r2   r3   r3   r4   get_name   s   z_PasswordCredential.get_namec                 C   s   |   S rG   )dumprt   r3   r3   r4   
_ser_value   s   z_PasswordCredential._ser_valuerO   c                 C   s&   zt |W S  ty   tdw )Nz)Failed to deserialise password credential)r   loadrw   r   PdfReadError)r2   rO   r3   r3   r4   _deser_value   s
   
z _PasswordCredential._deser_valueN)r6   r7   r8   r
   OctetString_fieldsr;   rA   r   r9   r   r   r3   r3   r3   r4   r      s    r   c                       sX   e Zd ZU dZdZed ed< edd Z fddZ	d	e
f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rG   )r@   r   r   _auth_failedNotImplementedErrorr   r3   r3   r4   r      s   z StandardCryptFilter._auth_failedc                    s$   t |tstt | d | _d S rG   )r@   r   	TypeErrorsuper_set_security_handler_shared_key)rt   handler	__class__r3   r4   r      s   

z)StandardCryptFilter._set_security_handlerr-   c                 C   s   | j sJ | j  S rG   )r   get_file_encryption_keyr   r3   r3   r4   derive_shared_encryption_key   s   

z0StandardCryptFilter.derive_shared_encryption_keyc                    s   t   }t| j|d< |S )N/Length)r   rv   r   rs   keylenrt   resultr   r3   r4   rv      s   
z!StandardCryptFilter.as_pdf_object)r6   r7   r8   rz   r   r   r:   propertyr   r   r9   r   rv   __classcell__r3   r3   r   r4   r      s   
 
r   c                   @      e Zd ZdZdS )StandardAESCryptFilterz=
    AES crypt filter for the standard security handler.
    Nr6   r7   r8   rz   r3   r3   r3   r4   r          r   c                   @   r   )StandardAESGCMCryptFilterzA
    AES-GCM crypt filter for the standard security handler.
    Nr   r3   r3   r3   r4   r      r   r   c                   @   r   )StandardRC4CryptFilterz=
    RC4 crypt filter for the standard security handler.
    Nr   r3   r3   r3   r4   r      r   r   z/StdCFc                 C      t tt| dittdS Nr   default_stream_filterdefault_string_filter)r   STD_CFr   r   r3   r3   r4   _std_rc4_config   
   r   c                 C   r   r   )r   r   r   r   r3   r3   r4   _std_aes_config   r   r   c                   C   s   t tt ittdS )Nr   )r   r   r   r3   r3   r3   r4   _std_gcm_config   s
   r   cfdictc                 C   s   |  dd}t|d dS )Nr   r0   r`   r   )getr   )r   _acts_as_defaultkeylen_bitsr3   r3   r4   #_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defddZeddde ddfdedefddZede dddfdededefddZed:ddZ							d;ded ed!ed"ee d#ee f
 fd$d%Zed&ejdefd'd(Zed&ejfd)d*Zedef fd+d,Z d-d. Z!d/efd0d1Z"d/efd2d3Z#	d<d/ee de$fd4d5Z%de&e'ee f fd6d7Z(defd8d9Z)  Z*S )=r   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   
   t ddS )NrL   r   r   ___r3   r3   r4   <lambda>      z StandardSecurityHandler.<lambda>z/AESV3c                 C   r   )Nr/   r   r   r   r3   r3   r4   r     r   z/AESV4c                 C      t  S rG   )r   r   r3   r3   r4   r         z	/Identityc                 C   r   rG   )r   r   r3   r3   r4   r     r   _known_crypt_filtersr-   c                 C   s
   t dS )N	/Standard)r   
NameObjectr   r3   r3   r4   r     s   
z StandardSecurityHandler.get_nameNrL   Trevpermsc
                 K   sJ  t |}|durt |n|}|tjkrt| d|tjkr"d}n	|r+|tjkr+d}t|||j|}|tjkrP|tjB tj	B tj
B tjB }t||||\}}nt||j|||||	\}}|tjkrftj}n|tjkrotj}ntj}|tjkr|du r|rtdd}nt|d}| d||||||||	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.   rL   r   )versionrevisionlegacy_keylen
perm_flagsodataudatacrypt_filter_configencrypt_metadatar   r   r3   )r   rl   r}   rw   r{   r   rq   r'   ALLOW_FORM_FILLINGALLOW_ASSISTIVE_TECHNOLOGYALLOW_REASSEMBLYALLOW_HIGH_QUALITY_PRINTINGr   r   r!   RC4_40RC4_LONGER_KEYSr   r   r   r   _credential)r2   r   r   desired_owner_passdesired_user_passkeylen_bytes
use_aes128r   r   r   kwargso_entryrF   rN   r   shr3   r3   r4   build_from_pw_legacy!  s   -










	z,StandardSecurityHandler.build_from_pw_legacyFpdf_macuse_gcmc           !      K   s  t |}|durt |n|}	td}
td}td}t|	|}|| | }t|	|}t||
tddd\}}t|dksAJ td}td}t|||}|| | }t|||}t||
tddd\}}t|dksqJ |ry|tj M }|	 ddd }|d |rd	nd
 d td }t
t|
t }| }|||  }|rtd}nd}|rtj}tj}ntj}tj}| d||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`   rL   F)rQ   s      T   F   adbrn   )r   r   r   r   r   r   oeseedueseedencrypted_permsr   kdf_saltr   r3   )rD   secretstoken_bytesrH   r   r9   r1   r'   TOLERATE_MISSING_PDF_MACas_bytesr   r   AESr   ECB	encryptorrb   finalizer!   r   rl   r~   r   r   r   )!r2   r   r   r   r   r   r   r   owner_pw_bytesuser_pw_bytesencryption_keyu_validation_salt
u_key_saltu_hashrF   u_interm_keyr   ue_seedo_validation_salt
o_key_salto_hashr   o_interm_keyoe_seedperms_bytesextd_perms_bytescipherr   r   r   r   r   r   r3   r3   r4   build_from_pw  s   .









z%StandardSecurityHandler.build_from_pwro   c                 C   s   t | t |  krdksn td| d|r+|r+t |t |  kr*dks4n td| d|r<t |dkrEt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. rL   z6/Perms must be present and be 16 bytes long in a rev. )r1   r   PdfError)r   r   r   r   r   r   r3   r3   r4   _check_r6_values  s&   &z(StandardSecurityHandler._check_r6_valuesr   r   r   r   r   c                    s$  |d u r4|t jkrtd}n&|t jkrt|}n|t jkr!t }n|t jkr/|d u r/td}nt	dt
 j||||
||d || _|| _| jtj@  | _|tjkrg| j|||||	 || _|| _|	| _nt|t|  krudks{n 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   r   r   r~   r   r   r  r   __init__r   r   r'   r   _mac_requiredrl   r   r  r   r   r   r1   r   r   r   r   )rt   r   r   r   r   r   r   r   r   r   r   r   r  r   r   r3   r4   r  +  sR   










z StandardSecurityHandler.__init__encrypt_dictc                 C   s   | dd}|d dkrtd|d }z
|d }|d }W n ty+   tdw d	tjd
tfdd}d	tjd
tf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 )r@   r   TextStringObjectByteStringObjectr   r   typeoriginal_bytesr  r3   r3   r4   
_get_bytes  s
   zFStandardSecurityHandler.gather_encryption_metadata.<locals>._get_bytesc                 S   s(   t | tjrt| S td|  d)NzCannot parse z as a permission indicator)r@   r   rs   r'   from_sint32r   r   r  r3   r3   r4   _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   )r@   r   r  r  r  r  r3   r3   r4   r     s
   zDStandardSecurityHandler.gather_encryption_metadata.<locals>.<lambda>)	r   r   r   r   r   r   r   r   r   )r   r   r  KeyErrorr   r   r9   r'   dictget_and_applyallow_everythingr  bool)r2   r  r   r   r   r   r  r  r3   r3   r4   gather_encryption_metadatam  s@   




z2StandardSecurityHandler.gather_encryption_metadatac                 C   s>   t |d }t|d }td||| |d| |S )N/V/R)r   r   r   r3   )r!   ry   rl   r   process_crypt_filtersr   )r2   r  vrr3   r3   r4   instantiate_from_pdf_object  s   z3StandardSecurityHandler.instantiate_from_pdf_objectc                    s   t  jp| jS rG   )r   pdf_mac_enabledr  r   r   r3   r4   r'    s   z'StandardSecurityHandler.pdf_mac_enabledc                 C   s  t  }t d|d< t | j|d< t | j|d< t | j |d< | j	r0t | j	|d< | j
s9| jtjkrCt | jd |d< | j |d	< | j |d
< | jtjkrgt | 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  )r   DictionaryObjectr   r  r   r   rs   r   	as_sint32	_kdf_salt_compat_entriesr   r!   r   r   rv   r   BooleanObjectr   rb   r   rl   r~   r   r   r   r   r3   r3   r4   rv     s.   z%StandardSecurityHandler.as_pdf_objectr   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 )NrL   )r   r   rl   r{   r   r   r   r   rq   r   r   )rt   r   r<   r   
user_tokenuser_tok_suppliedrN   r3   r3   r4   _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||}q'|}| ||\}	}|	rN|| _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   r3   rX   ir3   r4   r[     r\   z?StandardSecurityHandler._authenticate_legacy.<locals>.<genexpr>)r   r   r   rq   r   rl   r{   r   r   ranger9   r/  r   r   OWNERUSERFAILED)rt   r   r<   credr   rN   prp_userpassru   new_keyowner_passworduser_passwordr3   r1  r4   _authenticate_legacy  s&   



z,StandardSecurityHandler._authenticate_legacyc                 C   s   t |tr
t|}t |tttfstdt	| dt |tr,|d j
}|d j
}| j}|tjkr<| |\}}n|du rEtdt|}| ||\}}|dur\|| _d| _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 .r   r   Nz+id1 must be specified for legacy encryptionFT)statuspermission_flags)r@   r#   r"   deserialiser   rA   r9   r   r   r  nativer   rl   r~   _authenticate_r6r   r<  r   r   r   r   )rt   
credentialr   r   resrN   r3   r3   r4   authenticate
  s2   





z$StandardSecurityHandler.authenticatec              
   C   s4  t |}t| j}t| j}t||| jr$tj}t||| j	| j}nt||r4t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y   d}
Y nw |
std	t d
|i| _!||fS )N	      r   z<Irn   r   r`   FznFile decryption key didn't decrypt permission flags correctly -- file permissions may have been tampered with.r   )"rD   r(   r5   r   r   rJ   r   r4  rS   r   r5  r   r6  r   r   r   r   r   	decryptorrb   r   r   r   r'   	from_uintstructunpack_EXPECTED_PERMS_8r   r  r   r  r   r   )rt   r<   rE   o_entry_splitu_entry_splitr   rN   r  rH  decrypted_p_entryperms_okdecr_metadata_flagr3   r3   r4   rB  8  s@   


z(StandardSecurityHandler._authenticate_r6c                 C   s&   | j }|du rt| jrd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   )rt   rN   r3   r3   r4   r   g  s   
z/StandardSecurityHandler.get_file_encryption_key)ro   )NNNTNTNrG   )+r6   r7   r8   rz   r   r   r   r   r   r   r:   r;   rA   r   r'   r  rl   r   r  r  staticmethodr  r!   r   r   r9   r  r(  r  r   r&  r   r'  rv   r/  r<  r   rE  r   r   rB  r   r   r3   r3   r   r4   r     s   
 
z|B?
./r   rG   )Qabcenumr   rJ  dataclassesr   hashlibr   r   r   typingr   r   r   r	   
asn1cryptor
   &cryptography.hazmat.primitives.ciphersr   r   r   pyhanko.pdf_utilsr   r   _legacyr   r   r   r   r   _utilr   r   r   apir   r   r   r   r   r   r   r    r!   cred_serr"   r#   filter_mixinsr$   r%   r&   permissionsr'   r(   rA   r9   rD   rJ   rS   rL  r^   rH   uniqueVersionEnumrl   Sequencer   ABCr   r   r   r   r   r   r   r   r   r(  r   registerr   r3   r3   r3   r4   <module>   s    ,





    z