+
    THix              
          R t ^ RIt^ RIHt ^ RIHt ^ RIHt ^ RIH	u H
t ^ RIHt ^ RIHt ^ RIHt ^ RIHtHtHt ^ R	IHtHt ^ R
IHt RtRsR.tRtRtRt ] ]]3t!]"! ]!4      t#Rt$ ^ RI%t]&! ]R4      '       g   Rt$RtM]&! ]R4      '       g   Rt$Rt]&! ]R4      '       d)   ]PP                  ! 4       t)]PT                  PV                  t,M ! R R4      t-]-! 4       t)^t, ! R R]P\                  ]P^                  ]P`                  ]Pb                  ]Pd                  ]Pf                  4      t4 ! R R]44      t5 ! R R]44      t6 ! R R]44      t7 ! R R]5]44      t%R#   ]' d    Rt Li ; i)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
N)metadataAny)warn)exc)logger)
MAX_UINT32)classpropertyrender_bytesto_bytes)b64s_decodeb64s_encode)bascii_to_str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                   .    ] tR t^UtRt^tRt^t^t^t	Rt
R# )_DummyCffiHasherz
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____firstlineno____doc__	time_costmemory_costparallelismsalt_lenhash_len__static_attributes__r       9/usr/lib/python3/dist-packages/passlib/handlers/argon2.pyr   r   U   s"    	 	r$   r   c                     a a ] tR t^jt oRtRtRt]P                  t	]
P                  P                  R,           t]
P                  P                  R,           t]P                  t^t]t]P&                  t^t]tRtRt]tRt^tRtRt/ t] R 4       t!]"t#]PH                  t$]t%]PL                  t&]'R 4       t(Rt)]*RV 3R ll4       t+]*R	 4       t,]-P\                  ! R
4      t/]*R 4       t0]-P\                  ! R]-Pb                  4      t2]*R 4       t3R t4R V 3R llt5]*R 4       t6]*R 4       t7]*R!R l4       t8]*R 4       t9V 3R lt:Rt;]*R 4       t<]*R"R l4       t=V3R lt>Rt?Vt@V ;tA# )#_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   linearNFc                L    V P                  4        \        V P                  4      # )zJ
return tuple of types supported by this backend

.. versionadded:: 1.7.2
)get_backendtuple_backend_type_map)clss   &r%   type_values_Argon2Common.type_values   s     	S**++r$   c                (    V P                   \        8H  # )zV
flag indicating a Type D hash

.. deprecated:: 1.7.2; will be removed in passlib 2.0
)typeTYPE_Dselfs   &r%   type_d_Argon2Common.type_d   s     yyF""r$   c	           	     *  < Ve   RV	9   d   \        R4      hWIR&   Ve   RV	9   d   \        R4      hW9R&   Ve   Ve   \        R4      hTpVe   Ve   \        R4      hTp\        SV `  ! R/ V	B p
Ve   V
P                  V4      V
n        V	P                  R4      pVeG   \        V\        4      '       d   \        V4      p\        P                  ! V
V^\        RVR	7      V
n        Ve9   \        V\        4      '       d   \        V4      pV
P                  W+R
7      V
n        V
P                  V
P                  V
P                   4       VeI   \        V\        4      '       d   \        V4      pV^8  d   VR8w  d   \#        RV3,          4      hWn        V
# )Nroundsz/'time_cost' and 'rounds' are mutually exclusive	salt_sizez1'salt_len' and 'salt_size' are mutually exclusivez3'hash_len' and 'digest_size' are mutually exclusivez8'checksum_size' and 'digest_size' are mutually exclusiverelaxeddigest_size)minmaxparamr:   )r:   z7max_threads (%d) must be -1 (unlimited), or at least 1.r   )	TypeErrorsuperusing
_norm_typer1   get
isinstancestrintuhnorm_integerr   checksum_size_norm_memory_costr   _validate_constraintsr    
ValueErrormax_threads)r-   r1   r   r!   r   r;   rJ   r"   rN   kwdssubclsr:   	__class__s   &&&&&&&&&,  r%   rB   _Argon2Common.using   s     4 QRR&Nd" STT (& UVV"K$&N  (K &&  ++D1FK ((9%"+s++!+.#%??#$F  "+s++!+.!'!9!9+!9!WF 	$$V%7%79K9KL "+s++!+.Q;"#4 M"n%  "-r$   c                b    ^V,          pW8  d    \        RV P                  WV3,          4      hR# )   zO%s: memory_cost (%d) is too low, must be at least 8 * parallelism (8 * %d = %d)N)rM   name)r-   r   r    min_memory_costs   &&& r%   rL   #_Argon2Common._validate_constraintsK  s>     k/(088[GH  )r$   z^\$argon2[a-z]+\$c                h    \         P                  ! V4      pV P                  P                  V4      R J# N)rH   to_unicode_for_identify_ident_regexmatch)r-   hashs   &&r%   identify_Argon2Common.identifyZ  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                   \        V\        4      '       d   VP                  R 4      p\        V\        4      '       g   \        P
                  ! VR4      hV P                  P                  V4      pV'       g   \        P                  ! V 4      hVP                  RRRRRRRR	R
4	      w	  ppppppp	p
pV'       d   \        R4      hT ! VP                  R4      V'       d   \        V4      M^\        V4      \        V4      \        V4      V
'       d   \        V
4      MRV	'       d   \        V	4      MRV'       d   \        V4      R7      # RR7      # )utf-8r]   r1   versionr   r   r    keyiddatasaltdigestz&argon2 'keyid' parameter not supportedasciiN)r1   rb   r   r8   r    re   rd   checksum)rE   rF   encodebytesr   ExpectedStringError_hash_regexr\   MalformedHashErrorgroupNotImplementedErrordecoderG   r   )r-   r]   mr1   rb   r   r   r    rc   rd   re   rf   s   &&          r%   from_string_Argon2Common.from_string  s-    dC  ;;w'D$&&))$77OO!!$'((-- GG


	
 %&NOOW%$+CLK(y>K(&*T"&*T",2[(	
 		
 9=	
 		
r$   c                   V P                   pV^8X  d   RpM	RV,          pV P                  pV'       d'   R\        \        V P                  4      4      ,           pMRpRV P                  VV P
                  V P                  V P                  V\        \        V P                  4      4      \        \        V P                  4      4      3,          # )    zv=%d$z,data=z"$argon2%s$%sm=%d,t=%d,p=%d%s$%s$%s)
rb   rd   r   r   r1   r   r8   r    re   rh   )r4   rb   vstrrd   kdstrs   &    r%   	to_string_Argon2Common.to_string  s    ,,d?DW$Dyy}[-CDDEE 4IIKK+dii01+dmm45	7
 	
 		
r$   c                6  < V'       d   \        R 4       Ve   Q h\        pVP                  R4      pVe   \        V4      V n        \
        SV `  ! R	/ VB  Vf7   \        P                  ! W P                  V P                  RR7      '       g   Q hMV P                  V4      V n	        Vf7   \        P                  ! W P                  V P                  RR7      '       g   Q hMV P                  V4      V n        Vf7   \        P                  ! W P                  V P                  RR7      '       g   Q hMV P                  V4      V n        Vf   V P                  e   Q hR# \!        V\"        4      '       g"   \        P$                  P'                  VRR4      hWPn        R# )
zoargon2 `type_d=True` keyword is deprecated, and will be removed in passlib 2.0; please use ``type="d"`` insteadNrh   r1   )r>   rb   r   rj   rd   r   )r   r2   rD   lenrJ   rA   __init__rH   validate_default_valuer1   rC   rb   _norm_versionr   rK   rd   rE   rj   r   ExpectedTypeError)	r4   r1   r5   rb   r   rd   rO   rh   rQ   s	   &&&&&&, r%   r}   _Argon2Common.__init__  sw    2 <<D 88J'!$XD 	 4  <,,ii    -DI ?,,llD$6$6i     --g6DL ,,&&(>(>m     $55kBD <99$$$dE**ff..tWfEEIr$   c                    \        V\        4      '       g"   \        P                  P	                  VR R4      hV\
        9   d   V# VP                  4       pV\
        9   d   V# \        RV: 24      h)rF   r1   zunknown argon2 hash type: )rE   rF   rH   r   r   ALL_TYPES_SETlowerrM   )r-   valuetemps   && r%   rC   _Argon2Common._norm_type  sh     %%%&&**5%@@ M!L {{}= K 5eY?@@r$   c           
     R   \        V\        4      '       g"   \        P                  P	                  VR R4      hV^8  d   V^8w  d   \        RV3,          4      hV P                  4       pWP                  8  d/   \        V P                   RVR RV: RV P                  R R24      hV# )integerrb   zinvalid argon2 hash version: %dz: hash version 0xX not supported by z backend (max version is 0xz%); try updating or switching backends)	rE   rG   rH   r   r   rM   r*   max_versionrU   )r-   rb   backends   && r%   r   _Argon2Common._norm_version!  s    '3''&&**7IyII T>go>'KLL //#__$88*-ga[8J7+ V%%(__Q$77\^  r$   c                L    \         P                  ! V VV P                  R VR7      # )r   )r<   r>   r:   )rH   rI   rV   )r-   r   r:   s   &&&r%   rK   _Argon2Common._norm_memory_cost3  s(    ##
 	
r$   c                     V P                   V,          #   \         d     Mi ; iRT: RT P                  4        R2p\        T4      h)z.
helper to resolve backend constant from type
zunsupported argon2 hash (type r   z	 backend))r,   KeyErrorr*   rM   )r-   r   msgs   && r%   _get_backend_type_Argon2Common._get_backend_type?  sT    
	((// 		 /ui7I#//J[I\\efos    ##c                f  < \        V 4      pV P                   VP                   8w  d   R # VP                  pVe   W2P                  8  d   VP                  pV P                  V8  d   R # V P                  VP                  8w  d   R # V P
                  VP
                  8w  d   R # \        SV `  ! R/ VB # )Tr   )r1   min_desired_versionr   rb   r   rJ   rA   _calc_needs_update)r4   rO   r-   minverrQ   s   &,  r%   r    _Argon2Common._calc_needs_updateL  s    4j99 ((>Voo5__F<<& s.!2!22w)1D11r$   z> -- recommend you install one (e.g. 'pip install argon2_cffi')c                p   V P                   p\        V\        4      '       g   Q hV^8  g   Q hV^8  d)   \        V: R2\        P
                  P                  4       \         F  pW@P                  9   g   K  W@n	         R# 	  \        V: R2\        P
                  P                  4       \        V n	        R# )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.
z4 doesn't support argon2 v1.3, and should be upgradedz' lacks support for all known hash typesT)r   rE   rG   r   rH   r   PasslibSecurityWarning	ALL_TYPESr,   r1   PasslibRuntimeWarningTYPE_ID)	mixin_clsrU   dryrunr   r1   s   &&&  r%   _finalize_backend_mixin%_Argon2Common._finalize_backend_mixin`  s      +++s++++d"""(NO-- D222!%  
 (AB,,
 %INr$   c                h   V P                  4       pVf   Ve   V P                  V4      pVeG   VP                  VP                  VP                  4       VR8X  d   VP
                  e   \        R4      h\        V4      pVR9  d   V RV RV: 2pM\        V4      p\        P                  ! WR7      h)ze
internal helper invoked when backend has hash/verification error;
used to adapt to passlib message.
argon2_cffiz8argon2_cffi backend doesn't support the 'data' parameterz reported: z: hash=)reason)zDecoding failed)r*   rr   rL   r   r    rd   ro   rF   reprr   rm   )r-   errr]   r4   r   textr   s   &&&&   r%   _adapt_backend_error"_Argon2Common._adapt_backend_error  s     //# <D,??4(D &&t'7'79I9IJ -'DII,A)N 
 3x 
 
  yD6AF$ZF$$S88r$   c                &   < V ^8  d   Qh/ S[ ;R&   # )   r,   r   )format__classdict__s   "r%   __annotate___Argon2Common.__annotate__j   s     V W r$   )rJ   rd   r   r1   rb   )
re   r9   r!   r8   r   r   r    r;   r"   r1   )r1   )r!   r   r"   r;   i r?   )NNNNNNNN)NFNNN)F)NN)Br   r   r   r   r   rU   setting_kwds_default_settingsr"   rJ   rH   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   rV   rN   pure_use_threadsr,   r	   r.   r   r1   r    rb   r   propertyr5   rd   classmethodrB   rL   recompiler[   r^   VERBOSErl   rr   ry   r}   rC   r   rK   r   r   _no_backend_suggestionr   r   __annotate_func__r#   __classdictcell____classcell__rQ   r   s   @@r%   r'   r'   j   s5     DL2 &..M  ..EE	Q **== A  *22MM '00NJJK
 $O #K  O K 
  , , D $//K G $//K# # DM M^ 	 	 ::23L8 8* **	8 	

;K@ *
 *
X
23r A A"  " 
 
 
 
2" 	I   > 9 9o  r$   r'   c                      a a ] tR tRt oRt]R 4       t]R 4       t]P                  ! RRR7      ]R 4       4       t
V 3R	 ltR
tVtV ;t# )
_NoBackendi  zt
mixin used before any backend has been loaded.
contains stubs that force loading of one of the available backends.
c                D    V P                  4        V P                  V4      # rY   )_stub_requires_backendr]   )r-   secrets   &&r%   r]   _NoBackend.hash  s    ""$xxr$   c                D    V P                  4        V P                  W4      # rY   )r   verify)r-   r   r]   s   &&&r%   r   _NoBackend.verify  s    ""$zz&''r$   z1.7z2.0)
deprecatedremovedc                D    V P                  4        V P                  W4      # rY   )r   genhash)r-   r   configs   &&&r%   r   _NoBackend.genhash  s     	""${{6**r$   c                B   < V P                  4        \        SV `	  V4      # rY   )r   rA   _calc_checksum)r4   r   rQ   s   &&r%   r   _NoBackend._calc_checksum  s#     	##% w%f--r$   r   )r   r   r   r   r   r   r]   r   rH   deprecated_methodr   r   r#   r   r   r   s   @@r%   r   r     se     
     ( ( UE:+  ;+. .r$   r   c                      a  ] tR tRt o Rt]R 4       t]R 4       t]! R ]	 4       4      t
]R 4       t]R 4       tR tR	tV tR
# )_CffiBackendi  z
argon2_cffi backend
c                "   V \         J g   Q h\        f)   \        '       d   \        P                  ! \        4      hR# \        P
                  P                  p\        P                  ! R\        P                  ! R4      V4       \        P                  p/ p\         F  p \        WFP                  4       4      WV&   K!  	  WPn        V;V n
        V n        V P)                  W4      #   \         d!    T\         \"        39  g   Q RT: 24       h Kr  i ; i)NFzOdetected 'argon2_cffi' backend, version %r, with support for 0x%x argon2 hashesr   unexpected missing type: )r   _argon2_cffi_argon2_cffi_errorr   PasslibSecurityErrorr   ARGON2_VERSIONr   debugr   rb   r   r   getattrupperAttributeErrorTYPE_Ir2   r,   r   r   )r   rU   r   r   TypeEnumtype_mapr1   s   &&&    r%   _load_backend_mixin _CffiBackend._load_backend_mixin  s    L((( !!../ABB",,;;]]+	
  $$D8!(::<!@  '/# 5@?	I100>> " 8$  8 /th78 8s   C##'DDc                   \         P                  ! V4       \        VR 4      p \        \        P
                  P                  V P                  V P                  4      V P                  V P                  V P                  \        V P                  4       4      V P                  VR7      4      #   \        P                  P                   d   pT P!                  T4      hRp?ii ; i)ra   )r1   r   r   r    re   r"   r   N)rH   validate_secretr   r   r   r   hash_secretr   r1   r   r   r    _generate_saltrJ   
exceptionsHashingErrorr   )r-   r   r   s   && r%   r]   _CffiBackend.hash  s     	6"&'*	0 &&22..sxx8 #!00 #!#"4"4"67 ..! 3 
 
 &&33 	0**3//	0s   BB+ +C 
CC c              #  \   "   T F"  p\        R VP                  R4      4      V3x  K$  	  R# 5i)s
   $argon2%s$rg   N)r
   ri   ).0r1   s   & r%   	<genexpr>_CffiBackend.<genexpr>   s(      NWdmT[[%9	:DAis   *,c           	        \         P                  ! V4       \        VR 4      p\        VR4      pV P                  P	                  VR^VP                  R^4      ,            \        4      pV P                  V4      p \        P                  P                  W!V4      pVRJ g   Q hR#   \        P                  P                   d     R# \        P                  P                   d   pT P                  YbR7      hRp?ii ; i)ra   rg   N   $TFr]   )rH   r   r   _byte_ident_maprD   findr   r   r   r   verify_secretr   VerifyMismatchErrorVerificationErrorr   )r-   r   r]   r1   	type_coderesultr   s   &&&    r%   r   _CffiBackend.verify  s     	6"&'*g& ""&&t,Da$))D!2D.D'EvN))$/		;!++99$	RFT>!>&&:: 	&&88 	;**3*::	;s$   ;(B% %C<C<$C<%C77C<c                B   \         P                  ! V4       \        VR 4      pV P                  V4      p \	        \
        P                  P                  V P                  VP                  4      VP                  VP                  VP                  \        VP                  4      VP                  VVP                  R7      4      pTP                  ^8X  d   TP'                  RR4      pT#   \
        P                   P"                   d   pT P%                  YRR7      hRp?ii ; i)ra   )r1   r   r   r    re   r"   r   rb   r   Nz$v=16$$)rH   r   r   rr   r   r   r   r   r   r1   r   r8   r    re   rJ   rb   r   r   r   replace)r-   r   r   r4   r  r   s   &&&   r%   r   _CffiBackend.genhash  s     	6"&'*v&	="&&22..tyy9 $ 0 0"kk $ 0 0!$)),!//! LL 3 	F <<4^^Hc2F &&33 	=**3*<<	=s   BC( (DDDc                    \        R 4      h)z-shouldn't be called under argon2_cffi backend)AssertionError)r4   r   s   &&r%   r   _CffiBackend._calc_checksum6  s    LMMr$   r   N)r   r   r   r   r   r   r   r]   dictr   r   r   r   r   r#   r   r   s   @r%   r   r     s       ?  ?D 0 0*  NW O ; ;,  4N Nr$   r   c                   :   a  ] tR tRt o Rt]R 4       tR tRtV t	R# )_PureBackendi:  z
argon2pure backend
c                ,   V \         J g   Q h ^ RIs ^ RIHp \
        P                  ! RT4       T'       g   \        R\        P                  4       / p\         F+  p \        \        RTP                  4       ,           4      YE&   K-  	  Y@n        T;T n        T n        T P)                  Y4      #   \         d     R# i ; i  \         d    \
        P                  ! R4        R# i ; i  \         d!    T\        \         39  g   Q RT: 24       h K  i ; i)	    NF)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   r2   r,   rb   r   r   )r   rU   r   r   r   r1   s   &&&   r%   r    _PureBackend._load_backend_mixin?  s$    L(((	,
	H 	P	

 * **	 D8!(h6M!N  '/#4??	I100>>Q  		  	NN9 	2 " 8$  8 /th78 8s4   B. C  'C(.B=<B= !C%$C%('DDc                R   \         P                  ! V4       \        VR 4      p\        VV P                  V P
                  V P                  V P                  V P                  V P                  V P                  4      V P                  R7      pV P                  ^ 8  d   V P                  VR&   V P                  '       d   RVR&   V P                  '       d   V P                  VR&    \        P                   ! R/ VB #   \        P"                   d   pT P%                  Y0R7      hRp?ii ; i)	ra   )passwordre   r   r   r    
tag_lengthr  rb   threadsTuse_threadsassociated_datar3   Nr   )rH   r   r   r  re   r8   r   r    rJ   r   r1   rb   rN   r   rd   r  r   Argon2Errorr   )r4   r   rO   r   s   &&  r%   r   _PureBackend._calc_checksums  s    
6"&'*kk(((()),,TYY7LL	
 a"..DO   "&D999&*iiD"#	<%%---&& 	<++C+;;	<s   $C: :D&D!!D&r   N)
r   r   r   r   r   r   r   r   r#   r   r  s   @r%   r  r  :  s)      0? 0?f< <r$   r  c                   2    ] tR tRtRtRtRtR]R]R]	/t
RtR# )	r   i  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  TNr   )r   r  )r   r   r   r   r   backends_backend_mixin_targetr   r   r  _backend_mixin_mapr#   r   r$   r%   r   r     s1    EZ -H ! 	j|lr$   )8r   r   	importlibr   typingr   warningsr   passlib.utils.handlersutilshandlersrH   passlibr   passlib._loggingr   passlib.crypto.digestr   passlib.utilsr	   r
   r   passlib.utils.binaryr   r   passlib.utils.compatr   r   r  __all__r   r2   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>r9     s   
    # #  # , ? ? 9 .  
	
 ff%	I  ! <((4 	 \;// O 	  <)**$335#--<< " )*v9LLMMv9r. .>uN= uNpS<= S<lXZ Xi  Ls   )E 	E%$E%