U
    :vhU                  
   @   sv  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 ddlm	Z	 ddl
mZ ddlmZmZmZmZ ddlmZmZ dd	lmZ dd
lmZmZmZmZ ddlmZ z4ddlmZmZ ddl m!Z!m"Z" ddl#m$Z$ dZ%W n( e&k
r Z' ze'Z%W 5 dZ'['X Y nX e(e)Z*G dd dZ+G dd dZ,G dd deZ-G dd dZ.ee/e0f e/dddZ1e2e2dddZ3dS )a   
Utilities to perform encryption following the PDF standards.

The contents of this module are internal to fpdf2, and not part of the public API.
They may change at any time without prior warning or any deprecation period,
in non-backward-compatible ways.
    N)hexlify)BOM_UTF16_BEurandom)CallableIterableTypeUnion   )AccessPermissionEncryptionMethod)FPDFException)Name	PDFObject	PDFStringbuild_obj_dict)create_dictionary_string)Ciphermodes)AES128AES256)PKCS7c                   @   sR   e Zd ZdZdZeedddZeee	 dddZ
eeeef ed	d
dZdS )ARC4az  
    This is a simplified version of the ARC4 (alleged RC4) algorithm,
    created based on the following sources:
    * Wikipedia article on RC4
    * github.com/manojpandey/rc4 (MIT License)
    * http://people.csail.mit.edu/rivest/pubs/RS14.pdf

    Having this ARC4 implementation makes it possible to have basic
    encryption functions without additional dependencies
       )keyreturnc                 C   sf   t |}tt| j}d}t| jD ]<}|||  |||   | j }|| ||  ||< ||< q$|S )Nr   )lenlistrangeMOD)selfr   
key_lengthSji r%   3/tmp/pip-unpacked-wheel-dvf6lv8i/fpdf/encryption.pyKSA4   s    zARC4.KSA)r"   r   c                 c   sh   d}d}|d | j  }|||  | j  }|| ||  ||< ||< ||| ||  | j   }|V  qd S )Nr   r
   )r   )r    r"   r$   r#   Kr%   r%   r&   PRGA=   s    z	ARC4.PRGA)r   textr   c                 C   s4   |  | |}g }|D ]}||t|A  q|S N)r)   r'   appendnext)r    r   r*   Z	keystreamrescr%   r%   r&   encryptG   s
    zARC4.encryptN)__name__
__module____qualname____doc__r   bytesr   r'   r   intr)   r	   	bytearrayr0   r%   r%   r%   r&   r   &   s
   	
r   c                       s8   e Zd ZdZeedd fddZedddZ  ZS )	CryptFilterzMRepresents one crypt filter, listed under CF inside the encryption dictionaryN)modelengthr   c                    s0   t    td| _t|| _t|d | _d S )Nr8      )super__init__r   typeZc_f_mr6   r:   )r    r9   r:   	__class__r%   r&   r=   R   s    


zCryptFilter.__init__r   c                    s"   t  fddt D }t|S )Nc                    s   i | ]}|t  |qS r%   )getattr).0r   r    r%   r&   
<dictcomp>Y   s      z)CryptFilter.serialize.<locals>.<dictcomp>)r   dirpdf_dict)r    Zobj_dictr%   rD   r&   	serializeX   s    zCryptFilter.serialize)	r1   r2   r3   r4   strr6   r=   rH   __classcell__r%   r%   r?   r&   r8   O   s   r8   c                       s(   e Zd ZdZddd fddZ  ZS )EncryptionDictionaryz
    This class represents an encryption dictionary
    PDF 32000 reference - Table 20
    The PDF trailer must reference this object (/Encrypt)
    StandardSecurityHandlerN)security_handlerr   c                    s  t    td| _|j| _|j| _d|j	  d| _d|j
	  d| _
|jdkrd|j	  d| _d|j	  d| _d|j	  d| _|j| _t|j| _|jsd| _|jrtd|j i| _|jtjkrtd| _td| _ntd| _td| _d S )	NZStandard<>   falsez/StdCFZIdentityZStdCF)r<   r=   r   filterr!   r:   revisionroupperuoeZo_eueZu_epermsversionvint32access_permissionpencrypt_metadatacfrG   rH   Zc_fencryption_methodr   NO_ENCRYPTIONZstm_fZstr_f)r    rM   r?   r%   r&   r=   d   s*    




zEncryptionDictionary.__init__)r1   r2   r3   r4   r=   rJ   r%   r%   r?   r&   rK   ]   s   rK   c                   @   s  e Zd ZdZdZde ejdfe	e
e	df eeedddZe	ddd	d
ZedddZe
e	eef ee
e	ef dddZe	ee	dddZeeedddZedddZeedddZeeedddZeed  eedd d!Zeed  e	ed"d#d$Ze	ed%d&d'Ze	dd(d)Ze	dd*d+Zee fed  eeeed,d-d.Z ddd/d0Z!ddd1d2Z"ddd3d4Z#edd5d6Z$dS )7rL   a  
    This class is referenced in the main PDF class and is used to handle all encryption functions
        * Calculate password and hashes
        * Provide encrypt method to be called by stream and strings
        * Set the access permissions on the document
    s    (N^NuAd NV.. h>/dSizNF)owner_passworduser_password
permissionrb   r`   c                 C   s*  || _ |d krdnd|B | _|| _|r*|nd| _|| _d | _d| _trf| jtj	tj
fkrftdt | jtj	krd| _d| _|d td| jd| _n| jtj
krd	| _d
| _|d d| _td| jd| _nL| jtjkr
d| _d| _|d td| jd| _nd| _d| _|d || _d S )Nl   p     zucryptography module not available - Try: 'pip install cryptography' or use RC4 encryption method - Import error was:    z1.6ZAESV2)r9   r:      rP   z2.0r   ZAESV3ZV2      z1.5)fpdfr^   rd   re   rb   ra   r!   import_errorr   AES_128AES_256EnvironmentErrorr[   rS   Z_set_min_pdf_versionr8   rc   r`   )r    rm   rd   re   rf   rb   r`   r%   r%   r&   r=      sJ    	



z StandardSecurityHandler.__init__)file_idr   c                 C   sf   || _ |dd | _| jdkrD| d| _|   |   |   n|  | _	| 
 | _|  | _dS )z,File_id is the first hash of the PDF file idr
   !   rP       N)rr   info_idrS   get_random_byteskgenerate_user_password_rev6generate_owner_password_rev6generate_perms_rev6generate_owner_passwordrU   generate_encryption_keygenerate_user_passwordrW   )r    rr   r%   r%   r&   generate_passwords   s    



z*StandardSecurityHandler.generate_passwordsrA   c                 C   s   t | S )zReturn an encryption dictionary)rK   rD   r%   r%   r&   get_encryption_obj   s    z*StandardSecurityHandler.get_encryption_obj)r*   obj_idr   c                 C   s2   t d| t|ttfr&| ||S | ||S )zOMethod invoked by PDFObject and PDFContentStream to encrypt strings and streamszEncrypting %s)LOGGERdebug
isinstancer7   r5   encrypt_streamencrypt_string)r    r*   r   r%   r%   r&   r0      s
    
zStandardSecurityHandler.encrypt)stringr   r   c                 C   s   | j tjkrt|dd S td| z2|d dt| 	|d|
   dW S  tk
r   dtt| 	t|d |d d Y S X d S )NF)r0   zEncrypting string: %szlatin-1rN   rO   z	utf-16-be)rb   r   rc   r   rH   r   r   encoder5   encrypt_byteshexrV   UnicodeEncodeErrorr   r7   r   decode)r    r   r   r%   r%   r&   r      s    
(z&StandardSecurityHandler.encrypt_string)streamr   r   c                 C   s    | j tjkr|S t| ||S r+   )rb   r   rc   r5   r   )r    r   r   r%   r%   r&   r      s    z&StandardSecurityHandler.encrypt_streamc                 C   s   | j tjtjfkS r+   )rb   r   ro   rp   rD   r%   r%   r&   is_aes_algorithm   s    z(StandardSecurityHandler.is_aes_algorithm)datar   c                 C   s   t jddd}|| j ||d@ jdddd |djd	ddd |  rh|td
dddg | }|  r| ||S t	 
||S )a  
        PDF32000 reference - Algorithm 1: Encryption of data using the RC4 or AES algorithms
        Append object ID and generation ID to the key and encrypt the data
        Generation ID is fixed as 0. Will need to revisit if the application start changing generation ID
        md5FZusedforsecurityi rl   little	byteordersignedr   rk   s   A   l   T   )hashlibnewupdaterw   to_bytesr   r5   digestencrypt_AES_cryptographyr   r0   )r    r   r   hr   r%   r%   r&   r      s    z%StandardSecurityHandler.encrypt_bytes)r   r   r   c                 C   s   t | d}td }||}|| 7 }| jtjkrPt	t
|t|nt	t| jt|}| }|||  }|| |S )zDEncrypts an array of bytes using AES algorithms (AES 128 or AES 256)   rh   )r7   rv   r   padderr   finalizerb   r   ro   r   r   r   CBCr   rw   	encryptorextend)r    r   r   Zivr   Zpadded_datacipherr   r%   r%   r&   r     s    


z0StandardSecurityHandler.encrypt_AES_cryptography)clssizer   c                 C   s   t |S )z
        https://docs.python.org/3/library/os.html#os.urandom
        os.urandom will use OS-specific sources to generate random bytes
        suitable for cryptographic use
        r   )r   r   r%   r%   r&   rv     s    z(StandardSecurityHandler.get_random_bytes)r   r   r   c                    s  t t ddd t|dk r"t S d fdd|D }tjd|}t tdd	d
}|D ]}||r\td| dq\t t	tddd}||t
jr||t
jrtd| dt
|d rt
|d std| dt|dkr|dd }|dS )al  
        PDF2.0 - ISO 32000-2:2020
        All passwords for revision 6 shall be based on Unicode. Preprocessing of a user-provided password
        consists first of normalizing its representation by applying the "SASLPrep" profile (Internet RFC 4013)
        of the "stringprep" algorithm (Internet RFC 3454) to the supplied password using the Normalize and BiDi
        options. Next, the password string shall be converted to UTF-8 encoding, and then truncated to the
        first 127 bytes if the string is longer than 127 bytes

        Python offers a stringprep module with the tables mapped in methods
        )charr   c                 S   s(   | sdS t | rdS t | r$dS | S )Nrg    )
stringprepin_table_b1in_table_c12r   r%   r%   r&   char_map/  s    

z8StandardSecurityHandler.prepare_string.<locals>.char_mapr
   rg   c                 3   s   | ]} |V  qd S r+   r%   )rC   r/   r   r%   r&   	<genexpr>=  s     z9StandardSecurityHandler.prepare_string.<locals>.<genexpr>NFKCc                 S   sZ   t | pXt | pXt | pXt | pXt | pXt | pXt | pXt | pXt 	| S r+   )
r   r   in_table_c21_c22in_table_c3in_table_c4in_table_c5in_table_c6in_table_c7in_table_c8in_table_c9r   r%   r%   r&   is_prohibitedC  s*    
	z=StandardSecurityHandler.prepare_string.<locals>.is_prohibitedzThe password z contains prohibited characters)r   funr   c                    s   t  fdd| D S )Nc                 3   s   | ]} |V  qd S r+   r%   )rC   r   r   r%   r&   r   \  s     zPStandardSecurityHandler.prepare_string.<locals>.has_character.<locals>.<genexpr>)any)r   r   r%   r   r&   has_character[  s    z=StandardSecurityHandler.prepare_string.<locals>.has_characterz+ contains invalid bidirectional characters.r      NzUTF-8)rI   r   r5   joinunicodedata	ucd_3_2_0	normalizeboolr   r   r   in_table_d1in_table_d2r   )r   r   Zprepared_stringr   r   r   r%   r   r&   prepare_string!  s6    


z&StandardSecurityHandler.prepare_string)passwordr   c                 C   sF   t |dkr|dd }t|d}|| jddt |   |S )z
        PDF32000 reference - Algorithm 2: Computing an encryption key
        Step (a) - Add the default padding at the end of provided password to make it 32 bit long
        rt   Nlatin1)r   r7   r   r   DEFAULT_PADDING)r    r   r_   r%   r%   r&   padded_passwords  s
    z'StandardSecurityHandler.padded_passwordc                 C   s   |  | j}tdD ]}t|}q|dt| jd  }|  | j}tdD ]2}g }|D ]}|||A  qZt	 
t||}qNt| S )z
        PDF32000 reference - Algorithm 3: Computing the encryption dictionary's O (owner password) value
        The security handler is only using revision 3 or 4, so the legacy r2 version is not implemented here
        3   Nr;      )r   rd   r   r   mathceilr!   re   r,   r   r0   r5   r   )r    m_Zrc4keyresultr$   new_keyrw   r%   r%   r&   r{   ~  s    
z/StandardSecurityHandler.generate_owner_passwordc                    s   t jddd}|tj |tj t|  j	}t
dD ]2}g }|D ]}|||A  qVt t|  qJ  fddt
dD  t  S )z
        PDF32000 reference - Algorithm 5: Computing the encryption dictionary's U (user password) value
        The security handler is only using revision 3 or 4, so the legacy r2 version is not implemented here
        r   Fr   r   c                 3   s    | ]} | j | A V  qd S r+   )r   )rC   xr   r    r%   r&   r     s    zAStandardSecurityHandler.generate_user_password.<locals>.<genexpr>r   )r   r   r   r7   r   r5   fromhexru   r   rw   r   r,   r   r0   r   r   )r    r   r   r$   r   rw   r%   r   r&   r}     s    z.StandardSecurityHandler.generate_user_password)r   input_passwordsaltuser_keyr   c                 C   s   t || |  }d}|d7 }|| | }tt|dd t|dd }| }||d |	  }	t
|	dd d }
|
dkrt |	 }n&|
dkrt |	 }nt |	 }|dkr|	d |d krqq|dd S )	zz
        Algorithm 2B - section 7.6.4.3.4 of the ISO 32000-2:2020
        Applied on Security handlers revision 6
        r   r
   Nr   rt   @   rl   r   )r   sha256r   r   r   r   r   r   r   r   sumsha384sha512)r   r   r   r   rw   Zround_numberZk1r   r   e	remainderr%   r%   r&   compute_hash  s     $z$StandardSecurityHandler.compute_hashc           	      C   s   |  | j}|st }| d}| d}| j||d| | }| | _| j||d}tt|t	
d}| }|| j|  }| | _dS )z
        Generating the U (user password) and UE (user encryption)
        for security handlers of revision 6
        Algorithm 8 - Section 7.6.4.4.7 of the ISO 32000-2:2020
        r;   )r   r                      N)r   re   r7   rv   r   r   rW   r   r   r   r   r   r   rw   r   rY   )	r    re   Zuser_validation_saltZuser_key_saltrW   r   r   r   rY   r%   r%   r&   rx     s"    


z3StandardSecurityHandler.generate_user_password_rev6c           	      C   s   |  | j}|s td| j | d}| d}| j||t| jd| | }| | _	| j||t| jd}t
t|td}| }|| j|  }| | _dS )z
        Generating the O (owner password) and OE (owner encryption)
        for security handlers of revision 6
        Algorithm 9 - Section 7.6.4.4.8 of the ISO 32000-2:2020
        zInvalid owner password r;   )r   r   r   r   N)r   rd   r   rv   r   r5   r   rW   r   rU   r   r   r   r   r   r   rw   r   rX   )	r    rd   Zowner_validation_saltZowner_key_saltrU   r   r   r   rX   r%   r%   r&   ry     s2    


	

z4StandardSecurityHandler.generate_owner_password_rev6c                 C   sv   d| j B }| jrdnd}|jdddd| d | d	 }tt| jt }|	 }|
||  }| | _d
S )u   
        7.6.4.4.9 Algorithm 10: Computing the encryption dictionary’s Perms (permissions) value
        (Security handlers of revision 6) of the ISO 32000-2:2020
        l           T   Fr;   r   Fr   s   adbri   N)r^   r`   r   rv   r   r   rw   r   ECBr   r   r   r   rZ   )r    Zperms64br`   Zperms_inputr   r   rZ   r%   r%   r&   rz      s    
z+StandardSecurityHandler.generate_perms_rev6c                 C   s   t jddd}|| | j |t| j || jd@ j	dddd |t| j
 | jdkr| jdkr|tddddg | d	t| jd
  }tdD ] }t|d	t| jd
  }q|S )zU
        PDF32000 reference
        Algorithm 2: Computing an encryption key
        r   Fr       ri   r   r      Nr;   2   )r   r   r   r   re   r5   r   rU   r^   r   ru   r`   r[   r   r   r   r!   r   r   )r    r   r   r   r%   r%   r&   r|     s"    
  z/StandardSecurityHandler.generate_encryption_key)%r1   r2   r3   r4   r   r   allr   RC4rI   r	   r   r=   r~   rK   r   r7   r5   r6   r0   r   r   r   r   r   classmethodr   rv   r   r   r{   r}   r   rx   ry   rz   r|   r%   r%   r%   r&   rL   }   sZ   
7 

Q#!rL   )r   r   c                 C   s    t jddd}||  | S )Nr   Fr   )r   r   r   r   )r   r   r%   r%   r&   r   )  s    
r   )nr   c                 C   s   | d@ } | dA d S )z%convert long to signed 32 bit integerr   l        r%   )r   r%   r%   r&   r]   /  s    r]   )4r4   r   loggingr   r   r   binasciir   codecsr   osr   typingr   r   r   r	   enumsr   r   errorsr   Zsyntaxr   r   r   r   r   rG   &cryptography.hazmat.primitives.ciphersr   r   Z1cryptography.hazmat.primitives.ciphers.algorithmsr   r   Z&cryptography.hazmat.primitives.paddingr   rn   ImportErrorerror	getLoggerr1   r   r   r8   rK   rL   r5   r7   r   r6   r]   r%   r%   r%   r&   <module>   s<   
)    /