
    XR_              
          d Z ddlmZmZ ddlZ ej        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 c m!Z" d
gZ# ed          Z$ ed          Z% ed          Z&e&e$e%fZ' e(e'          Z)dZ*	 ddl+Z e,ed          sdZ*dZn e,ed          sdZ*dZn# e-$ r dZY nw xY w e,ed          r ej.                    Z/ej0        j1        Z2n G d d          Z3 e3            Z/dZ2 G d de"j4        e"j5        e"j6        e"j7        e"j8        e"j9                  Z: G d de:          Z; G d de:          Z< G d de:          Z= G 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                   &    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     9/usr/lib/python3/dist-packages/passlib/handlers/argon2.pyr   r   ]   s3        	 	 	r'   r      c                   `    e Zd ZdZdZdZej        Ze	j
        j        dz   Ze	j
        j        dz   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             Z e!Z"ej#        Z#eZ$ej%        Z%e&d             Z'd
Z(e)	 	 d fd	            Z*e)d             Z+ e,j-        d          Z.e)d             Z/ e,j-        de,j0                  Z1e)d             Z2d Z3d  fd	Z4e)d             Z5e)d             Z6e)d!d            Z7e)d             Z8 fdZ9dZ:e)d             Z;e)d"d            Z< xZ=S )#_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)r0   )r$   r!   r%   r/         lineari NFc                 R    |                                   t          | j                  S )zj
        return tuple of types supported by this backend
        
        .. versionadded:: 1.7.2
        )get_backendtuple_backend_type_map)clss    r(   type_valuesz_Argon2Common.type_values   s%     	S*+++r'   c                 "    | j         t          k    S )zn
        flag indicating a Type D hash

        .. deprecated:: 1.7.2; will be removed in passlib 2.0
        )r0   TYPE_Dselfs    r(   type_dz_Argon2Common.type_d   s     yF""r'   c	                 t   |d|	v rt          d          ||	d<   |d|	v rt          d          ||	d<   ||t          d          |}||t          d          |} t          t          |           j        di |	}
||
                    |          |
_        |	                    d          }|Mt          |t          j	                  rt          |          }t          j        |
|dt          d	|
          |
_        |Et          |t          j	                  rt          |          }|
                    ||          |
_        |
                    |
j        |
j                   |Ot          |t          j	                  rt          |          }|dk     r|dk    rt%          d|fz            ||
_        |
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paramrA   )rA   r2   r4   z7max_threads (%d) must be -1 (unlimited), or at least 1.r&   )	TypeErrorsuperr+   using
_norm_typer0   get
isinstanceuhnative_string_typesintnorm_integerr   checksum_size_norm_memory_costr"   _validate_constraintsr#   
ValueErrormax_threads)r9   r0   r"   r$   r!   r/   rO   r%   rS   kwdssubclsrA   	__class__s               r(   rG   z_Argon2Common.using  s     4 QRRR&DNd"" STTT (D& UVVV"K$& Z[[['K 1}c**088488  ++D11FK ((9%%"+r'=>> /!+..#%?6;BT^9FPW$Y $Y $YF  "+r'=>> /!+..!'!9!9+w!9!W!WF 	$$V%79KLLL "+r'=>> /!+..Q;"#4#4 !Z"-"0 1 1 1!,Fr'   c                 R    d|z  }||k     rt          d| j        |||fz            d S )Nr1   zO%s: memory_cost (%d) is too low, must be at least 8 * parallelism (8 * %d = %d))rR   name)r9   r"   r#   min_memory_costs       r(   rQ   z#_Argon2Common._validate_constraintsB  sM     k/(( =!h)?<< = = = )(r'   z^\$argon2[a-z]+\$c                 b    t          j        |          }| j                            |          d uS N)rK   to_unicode_for_identify_ident_regexmatch)r9   hashs     r(   identifyz_Argon2Common.identifyT  s.    )$//%%d++477r'   s  
        ^
        \$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                    t          |t                    r|                    d          }t          |t                    st	          j        |d          | j                            |          }|st	          j        |           |	                    ddddddd	d
d	  	        \	  }}}}}}}	}
}|rt          d           | |                    d          |rt          |          ndt          |          t          |          t          |          |
rt          |
          nd |	rt          |	          nd |rt          |          nd           S )Nutf-8r_   r0   versionr"   r!   r#   keyiddatar,   digestz&argon2 'keyid' parameter not supportedasciir   )r0   rc   r"   r.   r#   r,   re   checksum)rJ   r   encodebytesr   ExpectedStringError_hash_regexr^   MalformedHashErrorgroupNotImplementedErrordecoderM   r   )r9   r_   mr0   rc   r"   r!   r#   rd   re   r,   rf   s               r(   from_stringz_Argon2Common.from_string  sh    dG$$ 	(;;w''D$&& 	8)$777O!!$'' 	.(---GGFI}k=VVX7 7 	Vg{I{E4v  	P%&NOOOsW%%$+5CLLLK((y>>K((&*4T"""&*4T""",2<[(((	
 	
 	
 		
r'   c                 d   | j         }|dk    rd}nd|z  }| j        }|r%dt          t          | j                            z   }nd}dt	          | j                  || j        | j        | j        |t          t          | j	                            t          t          | j
                            fz  S )Nr    zv=%d$z,data=z"$argon2%s$%sm=%d,t=%d,p=%d%s$%s$%s)rc   re   r   r   r   r0   r"   r.   r#   r,   rh   )r>   rc   vstrre   kdstrs        r(   	to_stringz_Argon2Common.to_string  s    ,d??DDW$Dy 	}[-C-CDDDEEE 4$)$$K+di0011+dm4455	7
 	
 		
r'   c                    |rt          d           |J t          }|                    d          }|t          |          | _         t          t          |           j        d	i | |%t          j	        | | j
        | j        d          sJ n|                     |          | _
        |%t          j	        | | j        | j        d          sJ n|                     |          | _        |%t          j	        | | j        | j        d          sJ n|                     |          | _        || j        J d S 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"`` insteadrh   r0   )rD   rc   r"   rj   re   r&   )r   r<   rI   lenrO   rF   r+   __init__rK   validate_default_valuer0   rH   rc   _norm_versionr"   rP   re   rJ   rj   r   ExpectedTypeError)	r>   r0   r?   rc   r"   re   rT   rh   rV   s	           r(   rz   z_Argon2Common.__init__  s     	 3 4 4 4<<<D 88J''!$XD 	,mT""+33d333 <,T49doU[\\\\\\\--DI ?,T4<AS3<> > > > > > >  --g66DL ,T43CTE[3@B B B B B B B  $55kBBD <9$$$$$dE** Ff..tWfEEEDIIIr'   c                 J   t          |t                    sSt          r+t          |t                    r|                    d          }n!t
          j                            |dd          |t          v r|S |	                                }|t          v r|S t          d|          )Nrg   strr0   zunknown argon2 hash type: )rJ   r   r   rj   rp   rK   r   r}   ALL_TYPES_SETlowerrR   )r9   valuetemps      r(   rH   z_Argon2Common._norm_type  s     %)) 	E Ez%// EW--f..ueVDDD M!!L {{}}=  K j55BCCCr'   c                 8   t          |t          j                  s!t          j                            |dd          |dk     r|dk    rt          d|fz            |                                 }|| j        k    r t          d| j        ||| j        fz            |S )Nintegerrc   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)	rJ   rK   	int_typesr   r}   rR   r6   max_versionrX   )r9   rc   backends      r(   r|   z_Argon2Common._norm_version	  s    '2<00 	J&**7IyIII T>>goo>'KLLL //##S_$$ Y!h#/JK L L L r'   c                 >    t          j        | || j        d|          S )Nr"   )rB   rD   rA   )rK   rN   rY   )r9   r"   rA   s      r(   rP   z_Argon2Common._norm_memory_cost  s-    sKS5H%2GE E E 	Er'   c                     	 | j         |         S # t          $ r Y nw xY wd|d|                                 d}t          |          )z>
        helper to resolve backend constant from type
        zunsupported argon2 hash (type z not supported by z	 backend))r8   KeyErrorr6   rR   )r9   r   msgs      r(   _get_backend_typez_Argon2Common._get_backend_type%  sf    
	(// 	 	 	D	 uucoo'''')oos    
c                    t          |           }| j         |j         k    rdS |j        }|||j        k    r|j        }| j        |k     rdS | j        |j        k    rdS | j        |j        k    rdS  t          t          |           j        di |S )NTr&   )	r0   min_desired_versionr   rc   r"   rO   rF   r+   _calc_needs_update)r>   rT   r9   minverrV   s       r(   r   z _Argon2Common._calc_needs_update7  s    4jj9  4(>Vco55_F<&  4s..4!2224<u]D))<DDtDDDr'   z> -- recommend you install one (e.g. 'pip install argon2_cffi')c                 2   | j         }t          |t                    r|dk    sJ |dk     r"t          d|z  t          j        j                   t          D ]}|| j        v r	|| _	         n/t          d|z  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)r   rJ   rM   r   rK   r   PasslibSecurityWarning	ALL_TYPESr8   r0   PasslibRuntimeWarningTYPE_ID)	mixin_clsrX   dryrunr   r0   s        r(   _finalize_backend_mixinz%_Argon2Common._finalize_backend_mixinM  s      ++s++Ct0C0C0C0CIDP.0 0 0  	% 	%Dy222!%	 3 <tCRVEabbb$INtr'   c                 ^   |                                  }|||                     |          }|<|                    |j        |j                   |dk    r|j        t          d          t          |          }|dvr|d|d|}nt          |          }t          j
        | |          )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 reported: z: hash=)reason)r6   rr   rQ   r"   r#   re   ro   r   reprr   rm   )r9   errr_   r>   r   textr   s          r(   _adapt_backend_errorz"_Argon2Common._adapt_backend_errorg  s     //## <D,??4((D &&t'79IJJJ -''DI,A)*deee 3xx    4;77DDD$$GFF$ZZF$S8888r'   )NNNNNNNN)NFNNN)F)NN)>r   r   r   r    rX   setting_kwds_default_settingsr%   rO   rK   GenericHandler_always_parse_settings_unparsed_settingsr$   default_salt_sizemin_salt_sizer   max_salt_sizer!   default_rounds
min_rounds
max_roundsrounds_costmax_parallelism_default_versionr   r   rY   rS   pure_use_threadsr8   r   r:   r   r0   r#   rc   r"   propertyr?   re   classmethodrG   rQ   recompiler]   r`   Xrl   rr   rw   rz   rH   r|   rP   r   r   _no_backend_suggestionr   r   __classcell__rV   s   @r(   r+   r+   s   s          D
L0 &.M  .E&' *=MN *2MM '0NJJK
 $O #K  O K 
 , , ], D $/K G $/K# # X# D [_=A9 9 9 9 9 [9v = = [= 2:233L8 8 [82 "* 6 
7 K: 
 
 [
4
 
 
8, , , , , ,d D D [D(   [  E E E [E   ["E E E E E( ^  [2 9 9 9 [9 9 9 9 9r'   r+   c                        e Zd ZdZed             Zed             Z ej        dd          ed                         Z	 fdZ
 xZS )	
_NoBackendz
    mixin used before any backend has been loaded.
    contains stubs that force loading of one of the available backends.
    c                 T    |                                   |                     |          S r[   )_stub_requires_backendr_   )r9   secrets     r(   r_   z_NoBackend.hash  s&    ""$$$xxr'   c                 V    |                                   |                     ||          S r[   )r   verify)r9   r   r_   s      r(   r   z_NoBackend.verify  s(    ""$$$zz&$'''r'   z1.7z2.0)
deprecatedremovedc                 V    |                                   |                     ||          S r[   )r   genhash)r9   r   configs      r(   r   z_NoBackend.genhash  s*     	""$$${{66***r'   c                 |    |                                   t          t          |                               |          S r[   )r   rF   r   _calc_checksum)r>   r   rV   s     r(   r   z_NoBackend._calc_checksum  s7     	##%%% VT""11&999r'   )r   r   r   r    r   r_   r   rK   deprecated_methodr   r   r   r   s   @r(   r   r     s              [  ( ( [( RUE:::+ + [ ;:+: : : : : : : : :r'   r   c                       e Zd ZdZed             Zed             Z ed eD                       Z	ed             Z
ed             Zd ZdS )	_CffiBackendz
    argon2_cffi backend
    c                    | t           u sJ t          "t          rt          j        t                    dS t          j        j        }t                              dt          j	        |           t          j
        }i }t          D ]U}	 t          ||                                          ||<   )# t          $ r  |t          t           fvsJ d|z              Y Rw xY w|| _        |x| _        | _        |                     ||          S )NFzOdetected 'argon2_cffi' backend, version %r, with support for 0x%x argon2 hashesunexpected missing type: %r)r   _argon2_cffi_argon2_cffi_errorr   PasslibSecurityErrorr   ARGON2_VERSIONlogdebug__version__r   r   getattrupperAttributeErrorTYPE_Ir<   r8   rc   r   r   )r   rX   r   r   TypeEnumtype_mapr0   s          r(   _load_backend_mixinz _CffiBackend._load_backend_mixin  s)    L(((( ! C./ABBB5",;		c*K	9 	9 	9  $ 	Z 	ZDZ!(4::<<!@!@! Z Z ZFF#33335RUY5Y33333Z '/	# 5@?	I100v>>>s   %B**'CCc                    t          j        |           t          |d          }	 t          t          j                            |                     | j                  | j	        | j
        | j        t          |                                           | j        |                    S # t          j        j        $ r}|                     |          d }~ww xY w)Nrb   )r0   r"   r!   r#   r,   r%   r   )rK   validate_secretr	   r   r   r   hash_secretr   r0   r"   r   r#   _generate_saltrO   
exceptionsHashingErrorr   )r9   r   r   s      r(   r_   z_CffiBackend.hash  s     	6"""&'**	0 !7!C!C**3844O,Oc002233* "D " "    &3 	0 	0 	0**3///	0s   A=B$ $C8CCc              #   `   K   | ])}t          d |                    d                    |fV  *dS )s
   $argon2%s$rg   N)r
   ri   ).0r0   s     r(   	<genexpr>z_CffiBackend.<genexpr>  sQ       2 2# )G8L8LMMtT 2 2 2 2 2 2r'   c           	         t          j        |           t          |d          }t          |d          }| j                            |d d|                    dd          z            t                    }|                     |          }	 t          j	        
                    |||          }|du sJ dS # t          j        j        $ r Y dS t          j        j        $ r}|                     ||          d }~ww xY w)Nrb   rg   r2      $TFr_   )rK   r   r	   _byte_ident_maprI   findr   r   r   r   verify_secretr   VerifyMismatchErrorVerificationErrorr   )r9   r   r_   r0   	type_coderesultr   s          r(   r   z_CffiBackend.verify  s    	6"""&'**g&& "&&t,AQtyyq/A/A-A,A'BFKK))$//		;!+99$	RRFT>>>>4&: 	 	 	55&8 	; 	; 	;**3T*:::	;s   
'B3 3C9
C9C44C9c                    t          j        |           t          |d          }|                     |          }	 t	          t
          j                            |                     |j	                  |j
        |j        |j        t          |j                  |j        ||j                            }n3# t
          j        j        $ r}|                     ||          d }~ww xY w|j        dk    r|                    dd          }|S )Nrb   )r0   r"   r!   r#   r,   r%   r   rc   r   r   z$v=16$$)rK   r   r	   rr   r   r   r   r   r   r0   r"   r.   r#   r,   rO   rc   r   r   r   replace)r9   r   r   r>   r   r   s         r(   r   z_CffiBackend.genhash  s
    	6"""&'**v&&	="<#9#E#E**4955 ,+ ,di((+ $F 	$ 	$ 	 	FF &3 	= 	= 	=**3V*<<<	=<4^^Hc22Fs   A7B3 3C#CC#c                      t          d          )Nz-shouldn't be called under argon2_cffi backend)AssertionError)r>   r   s     r(   r   z_CffiBackend._calc_checksum*  s    LMMMr'   N)r   r   r   r    r   r   r_   dictr   r   r   r   r   r&   r'   r(   r   r     s          ? ? [?> 0 0 [0& d 2 2'02 2 2 2 2O ; ; [;,   [6N N N N Nr'   r   c                   .    e Zd ZdZed             Zd ZdS )_PureBackendz
    argon2pure backend
    c                 >   | t           u sJ 	 dd lan# t          $ r Y dS w xY w	 ddlm} n+# t          $ r t
                              d           Y dS w xY wt
                              d|           |st          dt          j
                   i }t          D ]]}	 t          t          d|                                z             ||<   1# t          $ r  |t          t           fvsJ d|z              Y Zw xY w|| _        |x| _        | _        |                     ||          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 recommendedARGON2r   )r   
argon2pure_argon2pureImportErrorr   r   warningr   r   r   r   r   r   r   r   r   r<   r8   rc   r   r   )r   rX   r   r   r   r0   s         r(   r   z _PureBackend._load_backend_mixin<  s    L((((	,,,,, 	 	 	55		HHHHHHH 	 	 	KK A B B B55	
 			V	 	 	  	H +,/,FH H H
  	Z 	ZDZ!(h6M!N!N! Z Z ZFF#33335RUY5Y33333Z '/	#4??	I100v>>>s-    
  + $AA-C'C10C1c                    t          j        |           t          |d          }t          || j        | j        | j        | j        | j        | 	                    | j
                  | j                  }| j        dk    r
| j        |d<   | j        rd|d<   | j        r
| j        |d<   	 t          j        d	i |S # t          j        $ r}|                     ||           d }~ww xY w)
Nrb   )passwordr,   r!   r"   r#   
tag_lengthr   rc   r   threadsTuse_threadsassociated_datar=   r&   )rK   r   r	   r   r,   r.   r"   r#   rO   r   r0   rc   rS   r   re   r   r   Argon2Errorr   )r>   r   rT   r   s       r(   r   z_PureBackend._calc_checksumn  s   
6"""&'**k((),,TY77L	
 	
 	
 a".DO  	'"&D9 	0&*iD"#	<%-----& 	< 	< 	<++Cd+;;;	<s   %B6 6C!CC!N)r   r   r   r    r   r   r   r&   r'   r(   r   r   4  sI          &? &? [&?b< < < < <r'   r   c                   &    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    backends_backend_mixin_targetr   r   r   _backend_mixin_mapr&   r'   r(   r   r     sD        E E` -H ! #" r'   )>r    
__future__r   r   logging	getLoggerr   r   r   typeswarningsr   r   r   passlibr   passlib.crypto.digestr   passlib.utilsr   r	   r
   passlib.utils.binaryr   r   passlib.utils.compatr   r   r   r   r   passlib.utils.handlersutilshandlersrK   __all__r   r<   r   r   setr   r   r   hasattrr   r   r   r   r   r   r   SubclassBackendMixinParallelismMixin	HasRounds
HasRawSaltHasRawChecksumr   r+   r   r   r   r&   r'   r(   <module>r     s   " 7 6 6 6 6 6 6 6 g!! 				              , , , , , , ? ? ? ? ? ? ? ? ? ? 9 9 9 9 9 9 9 9 N N N N N N N N N N N N N N # # # # # # # # #   
3	
3
!D'' ff%	I  !!!! 7<(( 
4 	 W\;// _    LLL" 7<)** 3355#-<         )(**
R9 R9 R9 R9 R9B+R-@L"-1B%R9 R9 R9v!: !: !: !: !: !: !: !:TsN sN sN sN sN= sN sN sNxT< T< T< T< T<= T< T< T<t[ [ [ [ [Z [ [ [ [ [s   C CC