U
    h                  	   @   s  d Z ddlmZmZ ddlZeeZddlZddl	Z	ddl
mZ dZdaddl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   m!Z" d
gZ#edZ$edZ%edZ&e&e$e%fZ'e(e'Z)dZ*zddl+ZW n e,k
r   dZY n,X e-eds&dZ*dZne-eds:dZ*dZe-edrXe. Z/ej0j1Z2nG dd dZ3e3 Z/dZ2G dd de"j4e"j5e"j6e"j7e"j8e"j9Z:G dd de:Z;G dd de:Z<G dd de:Z=G dd
 d
e;e:Z+dS )a  passlib.handlers.argon2 -- argon2 password hash wrapper

References
==========
* argon2
    - home: https://github.com/P-H-C/phc-winner-argon2
    - whitepaper: https://github.com/P-H-C/phc-winner-argon2/blob/master/argon2-specs.pdf
* argon2 cffi wrapper
    - pypi: https://pypi.python.org/pypi/argon2_cffi
    - home: https://github.com/hynek/argon2_cffi
* argon2 pure python
    - pypi: https://pypi.python.org/pypi/argon2pure
    - home: https://github.com/bwesterb/argon2pure
    )with_statementabsolute_importN)warn)exc)
MAX_UINT32)classpropertyto_bytesrender_bytes)b64s_encodeb64s_decode)uunicodebascii_to_struascii_to_strPY2argon2ididTypezb'argon2' module points to unsupported 'argon2' pypi package; please install 'argon2-cffi' instead.	low_levelz@'argon2-cffi' is too old, please update to argon2_cffi >= 18.2.0PasswordHasherc                   @   s$   e Zd ZdZdZdZdZdZdZdS )_DummyCffiHashera  
        dummy object to use as source of defaults when argon2_cffi isn't present.
        this tries to mimic the attributes of ``argon2.PasswordHasher()`` which the rest of
        this module reads.

        .. note:: values last synced w/ argon2 19.2 as of 2019-11-09
           i      N)	__name__
__module____qualname____doc__	time_costmemory_costparallelismsalt_lenhash_len r$   r$   =./venv/lib/python3.8/site-packages/passlib/handlers/argon2.pyr   ]   s   r      c                	       sf  e Zd ZdZdZdZejZe	j
jd Ze	j
jd ZejZdZeZejZdZeZdZd	ZeZd
ZdZdZdZi Zedd Z e!Z"ej#Z#eZ$ej%Z%e&dd Z'd
Z(e)d. fdd	Z*e)dd Z+e,-dZ.e)dd Z/e,-de,j0Z1e)dd Z2dd Z3d/ fdd	Z4e)dd  Z5e)d!d" Z6e)d0d#d$Z7e)d%d& Z8 fd'd(Z9d)Z:e)d*d+ Z;e)d1d,d-Z<  Z=S )2_Argon2Commona&  
    Base class which implements brunt of Argon2 code.
    This is then subclassed by the various backends,
    to override w/ backend-specific methods.

    When a backend is loaded, the bases of the 'argon2' class proper
    are modified to prepend the correct backend-specific subclass.
    r   )
salt	salt_sizer"   roundsr   r    r!   digest_sizer#   type)r,   )r"   r   r#   r+         Zlineari NFc                 C   s   |    t| jS )zj
        return tuple of types supported by this backend
        
        .. versionadded:: 1.7.2
        )get_backendtuple_backend_type_map)clsr$   r$   r%   type_values   s    z_Argon2Common.type_valuesc                 C   s
   | j tkS )zn
        flag indicating a Type D hash

        .. deprecated:: 1.7.2; will be removed in passlib 2.0
        )r,   TYPE_Dselfr$   r$   r%   type_d   s    z_Argon2Common.type_dc	                    sf  |d k	r d|	krt d||	d< |d k	r@d|	kr8t d||	d< |d k	r\|d k	rXt d|}|d k	rx|d k	rtt d|}tt| jf |	}
|d k	r|
||
_|	d}|d k	rt|tj	rt
|}tj|
|dtd	|d
|
_|d k	r
t|tj	rt
|}|
j||d|
_|
|
j|
j |d k	rbt|tj	r:t
|}|dk r\|dkr\td|f ||
_|
S )Nr*   z/'time_cost' and 'rounds' are mutually exclusiver)   z1'salt_len' and 'salt_size' are mutually exclusivez3'hash_len' and 'digest_size' are mutually exclusivez8'checksum_size' and 'digest_size' are mutually exclusiverelaxedr   r+   )minmaxparamr9   )r9   r.   r/   z7max_threads (%d) must be -1 (unlimited), or at least 1.)	TypeErrorsuperr'   using
_norm_typer,   get
isinstanceuhZnative_string_typesintnorm_integerr   checksum_size_norm_memory_costr    _validate_constraintsr!   
ValueErrormax_threads)r3   r,   r    r"   r   r+   rF   r#   rJ   kwdssubclsr9   	__class__r$   r%   r?     sR    
 

z_Argon2Common.usingc                 C   s*   d| }||k r&t d| j|||f d S )Nr-   zO%s: memory_cost (%d) is too low, must be at least 8 * parallelism (8 * %d = %d))rI   name)r3   r    r!   min_memory_costr$   r$   r%   rH   B  s     z#_Argon2Common._validate_constraintsz^\$argon2[a-z]+\$c                 C   s   t |}| j|d k	S N)rC   Zto_unicode_for_identify_ident_regexmatch)r3   hashr$   r$   r%   identifyT  s    
z_Argon2Common.identifys  
        ^
        \$argon2(?P<type>[a-z]+)\$
        (?:
            v=(?P<version>\d+)
            \$
        )?
        m=(?P<memory_cost>\d+)
        ,
        t=(?P<time_cost>\d+)
        ,
        p=(?P<parallelism>\d+)
        (?:
            ,keyid=(?P<keyid>[^,$]+)
        )?
        (?:
            ,data=(?P<data>[^,$]+)
        )?
        (?:
            \$
            (?P<salt>[^$]+)
            (?:
                \$
                (?P<digest>.+)
            )?
        )?
        $
    c                 C   s   t |tr|d}t |ts*t|d| j|}|sDt| |	ddddddd	d
d	\	}}}}}}}	}
}|r|t
d| |d|rt|ndt|t|t||
rt|
nd |	rt|	nd |rt|nd dS )Nutf-8rT   r,   versionr    r   r!   keyiddatar(   digestz&argon2 'keyid' parameter not supportedasciir   )r,   rW   r    r*   r!   r(   rY   checksum)rB   r   encodebytesr   ZExpectedStringError_hash_regexrS   MalformedHashErrorgroupNotImplementedErrordecoderD   r   )r3   rT   mr,   rW   r    r   r!   rX   rY   r(   rZ   r$   r$   r%   from_string  s4    



   z_Argon2Common.from_stringc                 C   sv   | j }|dkrd}nd| }| j}|r:dtt| j }nd}dt| j|| j| j| j|tt| j	tt| j
f S )Nr    zv=%d$z,data=z"$argon2%s$%sm=%d,t=%d,p=%d%s$%s$%s)rW   rY   r   r
   r   r,   r    r*   r!   r(   r\   )r7   rW   ZvstrrY   Zkdstrr$   r$   r%   	to_string  s$    z_Argon2Common.to_stringc                    s  |rt d |d kstt}|d}|d k	r8t|| _tt| jf | |d krnt	j
| | j| jddsztn| || _|d krt	j
| | j| jddstn| || _|d krt	j
| | j| jddstn| || _|d kr| jd kstn"t|tst	j|dd|| _d S )	Nzoargon2 `type_d=True` keyword is deprecated, and will be removed in passlib 2.0; please use ``type="d"`` insteadr\   r,   )r<   rW   r    r^   rY   )r   AssertionErrorr5   rA   lenrF   r>   r'   __init__rC   Zvalidate_default_valuer,   r@   rW   _norm_versionr    rG   rY   rB   r^   r   ExpectedTypeError)r7   r,   r8   rW   r    rY   rK   r\   rM   r$   r%   rj     s4    

z_Argon2Common.__init__c                 C   sf   t |ts4tr$t |tr$|d}ntj|dd|tkr@|S |	 }|tkrT|S t
d|f d S )Nr[   strr,   zunknown argon2 hash type: %r)rB   r   r   r^   rc   rC   r   rl   ALL_TYPES_SETlowerrI   )r3   valueZtempr$   r$   r%   r@     s    
z_Argon2Common._norm_typec                 C   sh   t |tjstj|dd|dk r:|dkr:td|f |  }|| jkrdtd| j||| jf |S )NZintegerrW   r&   r   zinvalid argon2 hash version: %dzk%s: hash version 0x%X not supported by %r backend (max version is 0x%X); try updating or switching backends)	rB   rC   Z	int_typesr   rl   rI   r0   max_versionrO   )r3   rW   backendr$   r$   r%   rk   	  s    
z_Argon2Common._norm_versionc                 C   s   t j| || jd|dS )Nr    )r:   r<   r9   )rC   rE   rP   )r3   r    r9   r$   r$   r%   rG     s     z_Argon2Common._norm_memory_costc                 C   s>   z| j | W S  tk
r    Y nX d||  f }t|dS )z>
        helper to resolve backend constant from type
        z=unsupported argon2 hash (type %r not supported by %s backend)N)r2   KeyErrorr0   rI   )r3   rp   msgr$   r$   r%   _get_backend_type%  s    
z_Argon2Common._get_backend_typec                    sv   t | }| j |j krdS |j}|d ks0||jkr6|j}| j|k rDdS | j|jkrTdS | j|jkrddS tt| jf |S )NT)	r,   min_desired_versionrq   rW   r    rF   r>   r'   _calc_needs_update)r7   rK   r3   ZminverrM   r$   r%   rw   7  s    
z _Argon2Common._calc_needs_updatez> -- recommend you install one (e.g. 'pip install argon2_cffi')c                 C   sp   | j }t|tr|dkst|dk r6td| tjj tD ]}|| j	kr:|| _
 qlq:td| tjj t| _
dS )z
        helper called by from backend mixin classes' _load_backend_mixin() --
        invoked after backend imports have been loaded, and performs
        feature detection & testing common to all backends.
        r   r&   z6%r doesn't support argon2 v1.3, and should be upgradedz)%r lacks support for all known hash typesT)rq   rB   rD   rh   r   rC   r   PasslibSecurityWarning	ALL_TYPESr2   r,   ZPasslibRuntimeWarningTYPE_ID)	mixin_clsrO   dryrunrq   r,   r$   r$   r%   _finalize_backend_mixinM  s    
z%_Argon2Common._finalize_backend_mixinc                 C   s   |   }|dkr"|dk	r"| |}|dk	rT||j|j |dkrT|jdk	rTtdt|}|dkrtd|||f }nt|}t	j
| |ddS )z}
        internal helper invoked when backend has hash/verification error;
        used to adapt to passlib message.
        Nargon2_cffiz8argon2_cffi backend doesn't support the 'data' parameter)zDecoding failedz%s reported: %s: hash=%r)reason)r0   re   rH   r    r!   rY   rb   rm   reprr   r`   )r3   errrT   r7   rr   textr   r$   r$   r%   _adapt_backend_errorg  s    
z"_Argon2Common._adapt_backend_error)NNNNNNNN)NFNNN)F)NN)>r   r   r   r   rO   Zsetting_kwds_default_settingsr#   rF   rC   GenericHandlerZ_always_parse_settingsZ_unparsed_settingsr"   Zdefault_salt_sizeZmin_salt_sizer   Zmax_salt_sizer   default_roundsZ
min_roundsZ
max_roundsZrounds_costZmax_parallelism_default_versionrq   rv   rP   rJ   pure_use_threadsr2   r   r4   rz   r,   r!   rW   r    propertyr8   rY   classmethodr?   rH   recompilerR   rU   Xr_   re   rg   rj   r@   rk   rG   ru   rw   Z_no_backend_suggestionr}   r   __classcell__r$   r$   rM   r%   r'   s   s   

	      ;



2




r'   c                       sR   e Zd ZdZedd Zedd Zejddded	d
 Z	 fddZ
  ZS )
_NoBackendz
    mixin used before any backend has been loaded.
    contains stubs that force loading of one of the available backends.
    c                 C   s   |    | |S rQ   )_stub_requires_backendrT   )r3   secretr$   r$   r%   rT     s    z_NoBackend.hashc                 C   s   |    | ||S rQ   )r   verify)r3   r   rT   r$   r$   r%   r     s    z_NoBackend.verifyz1.7z2.0)Z
deprecatedZremovedc                 C   s   |    | ||S rQ   )r   genhash)r3   r   configr$   r$   r%   r     s    z_NoBackend.genhashc                    s   |    tt| |S rQ   )r   r>   r   _calc_checksumr7   r   rM   r$   r%   r     s    z_NoBackend._calc_checksum)r   r   r   r   r   rT   r   rC   Zdeprecated_methodr   r   r   r$   r$   rM   r%   r     s   

r   c                   @   sZ   e Zd ZdZedd Zedd Zedd eD Z	edd	 Z
ed
d Zdd ZdS )_CffiBackendz
    argon2_cffi backend
    c              	   C   s   | t ksttd kr&tr"ttdS tjj}t	dtj
| tj}i }tD ]H}zt|| ||< W qL tk
r   |ttfkstd| Y qLX qL|| _| | _| _| ||S )NFzOdetected 'argon2_cffi' backend, version %r, with support for 0x%x argon2 hashesunexpected missing type: %r)r   rh   _argon2_cffi_argon2_cffi_errorr   ZPasslibSecurityErrorr   ARGON2_VERSIONlogdebug__version__r   ry   getattrupperAttributeErrorTYPE_Ir5   r2   rW   rq   r}   )r{   rO   r|   rq   ZTypeEnumtype_mapr,   r$   r$   r%   _load_backend_mixin  s(    
  z _CffiBackend._load_backend_mixinc              
   C   s   t | t|d}z8ttjj| | j| j	| j
| jt|  | j|dW S  tjjk
r| } z| |W 5 d }~X Y nX d S )NrV   )r,   r    r   r!   r(   r#   r   )rC   validate_secretr   r   r   r   hash_secretru   r,   r    r   r!   Z_generate_saltrF   
exceptionsHashingErrorr   )r3   r   r   r$   r$   r%   rT     s    




	z_CffiBackend.hashc                 c   s"   | ]}t d |d|fV  qdS )s
   $argon2%s$r[   N)r	   r]   ).0r,   r$   r$   r%   	<genexpr>  s   z_CffiBackend.<genexpr>c              
   C   s   t | t|d}t|d}| j|d d|dd  t}| |}z"tj	
|||}|dkshtW dS  tjjk
r   Y dS  tjjk
r } z| j||dW 5 d }~X Y nX d S )NrV   r[   r.      $TFrT   )rC   r   r   _byte_ident_maprA   findr   ru   r   r   Zverify_secretrh   r   ZVerifyMismatchErrorZVerificationErrorr   )r3   r   rT   r,   	type_coderesultr   r$   r$   r%   r     s    


"
z_CffiBackend.verifyc                 C   s   t | t|d}| |}z<ttjj| |j	|j
|j|jt|j|j||jd}W n4 tjjk
r } z| j||dW 5 d }~X Y nX |jdkr|dd}|S )NrV   )r,   r    r   r!   r(   r#   r   rW   r   r   z$v=16$$)rC   r   r   re   r   r   r   r   ru   r,   r    r*   r!   r(   rF   rW   r   r   r   replace)r3   r   r   r7   r   r   r$   r$   r%   r     s&    




 
z_CffiBackend.genhashc                 C   s   t dd S )Nz-shouldn't be called under argon2_cffi backend)rh   r   r$   r$   r%   r   *  s    z_CffiBackend._calc_checksumN)r   r   r   r   r   r   rT   dictry   r   r   r   r   r$   r$   r$   r%   r     s   



r   c                   @   s$   e Zd ZdZedd Zdd ZdS )_PureBackendz
    argon2pure backend
    c              	   C   s   | t kstzdd laW n tk
r.   Y dS X zddlm} W n  tk
r`   td Y dS X td| |s~t	dt
j i }tD ]L}zttd|  ||< W q tk
r   |ttfkstd| Y qX q|| _| | _| _| ||S )	Nr   F)ARGON2_DEFAULT_VERSIONz\detected 'argon2pure' backend, but package is too old (passlib requires argon2pure >= 1.2.3)zBdetected 'argon2pure' backend, with support for 0x%x argon2 hasheszUsing argon2pure backend, which is 100x+ slower than is required for adequate security. Installing argon2_cffi (via 'pip install argon2_cffi') is strongly recommendedZARGON2r   )r   rh   
argon2pure_argon2pureImportErrorr   r   Zwarningr   r   r   rx   ry   r   r   r   r   r5   r2   rW   rq   r}   )r{   rO   r|   rq   r   r,   r$   r$   r%   r   <  s4    
 z _PureBackend._load_backend_mixinc              
   C   s   t | t|d}t|| j| j| j| j| j| 	| j
| jd}| jdkrT| j|d< | jrbd|d< | jrr| j|d< ztjf |W S  tjk
r } z| j|| dW 5 d }~X Y nX d S )	NrV   )Zpasswordr(   r   r    r!   Z
tag_lengthr   rW   r   threadsTZuse_threadsZassociated_datar6   )rC   r   r   r   r(   r*   r    r!   rF   ru   r,   rW   rJ   r   rY   r   r   ZArgon2Errorr   )r7   r   rK   r   r$   r$   r%   r   n  s,    






z_PureBackend._calc_checksumN)r   r   r   r   r   r   r   r$   r$   r$   r%   r   4  s   
1r   c                   @   s$   e Zd ZdZdZdZeeedZ	dS )r   a	  
    This class implements the Argon2 password hash [#argon2-home]_, and follows the :ref:`password-hash-api`.

    Argon2 supports a variable-length salt, and variable time & memory cost,
    and a number of other configurable parameters.

    The :meth:`~passlib.ifc.PasswordHash.replace` method accepts the following optional keywords:

    :type type: str
    :param type:
        Specify the type of argon2 hash to generate.
        Can be one of "ID", "I", "D".

        This defaults to "ID" if supported by the backend, otherwise "I".

    :type salt: str
    :param salt:
        Optional salt string.
        If specified, the length must be between 0-1024 bytes.
        If not specified, one will be auto-generated (this is recommended).

    :type salt_size: int
    :param salt_size:
        Optional number of bytes to use when autogenerating new salts.

    :type rounds: int
    :param rounds:
        Optional number of rounds to use.
        This corresponds linearly to the amount of time hashing will take.

    :type time_cost: int
    :param time_cost:
        An alias for **rounds**, for compatibility with underlying argon2 library.

    :param int memory_cost:
        Defines the memory usage in kibibytes.
        This corresponds linearly to the amount of memory hashing will take.

    :param int parallelism:
        Defines the parallelization factor.
        *NOTE: this will affect the resulting hash value.*

    :param int digest_size:
        Length of the digest in bytes.

    :param int max_threads:
        Maximum number of threads that will be used.
        -1 means unlimited; otherwise hashing will use ``min(parallelism, max_threads)`` threads.

        .. note::

            This option is currently only honored by the argon2pure backend.

    :type relaxed: bool
    :param relaxed:
        By default, providing an invalid value for one of the other
        keywords will result in a :exc:`ValueError`. If ``relaxed=True``,
        and the error can be corrected, a :exc:`~passlib.exc.PasslibHashWarning`
        will be issued instead. Correctable errors include ``rounds``
        that are too small or too large, and ``salt`` strings that are too long.

    .. versionchanged:: 1.7.2

        Added the "type" keyword, and support for type "D" and "ID" hashes.
        (Prior versions could verify type "D" hashes, but not generate them).

    .. todo::

        * Support configurable threading limits.
    )r~   r   T)Nr~   r   N)
r   r   r   r   ZbackendsZ_backend_mixin_targetr   r   r   Z_backend_mixin_mapr$   r$   r$   r%   r     s   P)>r   Z
__future__r   r   ZloggingZ	getLoggerr   r   r   typeswarningsr   r   r   Zpasslibr   Zpasslib.crypto.digestr   Zpasslib.utilsr   r   r	   Zpasslib.utils.binaryr
   r   Zpasslib.utils.compatr   r   r   r   r   Zpasslib.utils.handlersZutilsZhandlersrC   __all__r   r5   rz   ry   setrn   r   r   r   hasattrr   r   r   r   r   r   ZSubclassBackendMixinZParallelismMixinZ	HasRoundsZ
HasRawSaltZHasRawChecksumr   r'   r   r   r   r$   r$   r$   r%   <module>   sj   

	

      *|Z