
    XR_X                         d Z ddlZ ej        e          ZddlmZmZmZm	Z	 ddl
mZmZ ddlmZmZmZmZ ddlmZmZ ddlmc mZ dgZ G d dej        ej        ej        ej                  ZdS )	z:passlib.handlers.scram - hash for SCRAM credential storage    N)consteqsaslprepto_native_str
splitcomma)ab64_decodeab64_encode)bascii_to_str	iteritemsunative_string_types)pbkdf2_hmacnorm_hash_namescramc                   2    e Zd ZdZd ZdZ ed          ZdZdZ	dZ
dZdZd	Zg d
Zg dZdZed             Zedd            Zed             Zed             Zd Zed fd	            Zd fd	ZddZed             Z fdZddZedd            Z xZS )r   aZ  This class provides a format for storing SCRAM passwords, and follows
    the :ref:`password-hash-api`.

    It supports a variable-length salt, and a variable number of rounds.

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

    :type salt: bytes
    :param salt:
        Optional salt bytes.
        If specified, the length must be between 0-1024 bytes.
        If not specified, a 12 byte salt will be autogenerated
        (this is recommended).

    :type salt_size: int
    :param salt_size:
        Optional number of bytes to use when autogenerating new salts.
        Defaults to 12 bytes, but can be any value between 0 and 1024.

    :type rounds: int
    :param rounds:
        Optional number of rounds to use.
        Defaults to 100000, but must be within ``range(1,1<<32)``.

    :type algs: list of strings
    :param algs:
        Specify list of digest algorithms to use.

        By default each scram hash will contain digests for SHA-1,
        SHA-256, and SHA-512. This can be overridden by specify either be a
        list such as ``["sha-1", "sha-256"]``, or a comma-separated string
        such as ``"sha-1, sha-256"``. Names are case insensitive, and may
        use :mod:`!hashlib` or `IANA <http://www.iana.org/assignments/hash-function-text-names>`_
        hash names.

    :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.

        .. versionadded:: 1.6

    In addition to the standard :ref:`password-hash-api` methods,
    this class also provides the following methods for manipulating Passlib
    scram hashes in ways useful for pluging into a SCRAM protocol stack:

    .. automethod:: extract_digest_info
    .. automethod:: extract_digest_algs
    .. automethod:: derive_digest
    )salt	salt_sizeroundsalgs$scram$   i   i    l    linear)sha-1sha-256sha-512)r   r   zsha-224zsha-384r   Nc                     t          |d          }|                     |          }|j        }|st          d          |j        |j        ||         fS )a  return (salt, rounds, digest) for specific hash algorithm.

        :type hash: str
        :arg hash:
            :class:`!scram` hash stored for desired user

        :type alg: str
        :arg alg:
            Name of digest algorithm (e.g. ``"sha-1"``) requested by client.

            This value is run through :func:`~passlib.crypto.digest.norm_hash_name`,
            so it is case-insensitive, and can be the raw SCRAM
            mechanism name (e.g. ``"SCRAM-SHA-1"``), the IANA name,
            or the hashlib name.

        :raises KeyError:
            If the hash does not contain an entry for the requested digest
            algorithm.

        :returns:
            A tuple containing ``(salt, rounds, digest)``,
            where *digest* matches the raw bytes returned by
            SCRAM's :func:`Hi` function for the stored password,
            the provided *salt*, and the iteration count (*rounds*).
            *salt* and *digest* are both raw (unencoded) bytes.
        ianazscram hash contains no digests)r   from_stringchecksum
ValueErrorr   r   )clshashalgselfchkmaps        8/usr/lib/python3/dist-packages/passlib/handlers/scram.pyextract_digest_infozscram.extract_digest_info|   sW    > S&))t$$ 	?=>>>y$+vc{22    r   c                 d    |                      |          j        }dk    r|S fd|D             S )a  Return names of all algorithms stored in a given hash.

        :type hash: str
        :arg hash:
            The :class:`!scram` hash to parse

        :type format: str
        :param format:
            This changes the naming convention used by the
            returned algorithm names. By default the names
            are IANA-compatible; possible values are ``"iana"`` or ``"hashlib"``.

        :returns:
            Returns a list of digest algorithms; e.g. ``["sha-1"]``
        r   c                 0    g | ]}t          |          S  r   ).0r#   formats     r&   
<listcomp>z-scram.extract_digest_algs.<locals>.<listcomp>   s#    @@@CN3//@@@r(   )r   r   )r!   r"   r.   r   s     ` r&   extract_digest_algszscram.extract_digest_algs   sC    ( t$$)VK@@@@4@@@@r(   c                     t          |t                    r|                    d          }t          |t	          |          ||          S )a;  helper to create SaltedPassword digest for SCRAM.

        This performs the step in the SCRAM protocol described as::

            SaltedPassword  := Hi(Normalize(password), salt, i)

        :type password: unicode or utf-8 bytes
        :arg password: password to run through digest

        :type salt: bytes
        :arg salt: raw salt data

        :type rounds: int
        :arg rounds: number of iterations.

        :type alg: str
        :arg alg: name of digest to use (e.g. ``"sha-1"``).

        :returns:
            raw bytes of ``SaltedPassword``
        zutf-8)
isinstancebytesdecoder   r   )r!   passwordr   r   r#   s        r&   derive_digestzscram.derive_digest   sE    . h&& 	0w//H 3 2 2D&AAAr(   c                    t          |dd          }|                    d          st          j                            |           |dd                              d          }t          |          dk    rt          j                            |           |\  }}}t          |          }|t          |          k    rt          j                            |           	 t          |                    d                    }n-# t          $ r  t          j                            |           w xY w|st          j                            |           d|v rd }i }	|                    d          D ]m}
|
                    d          \  }}	 t          |                    d                    |	|<   A# t          $ r  t          j                            |           w xY wn|}d }	 | |||	|	          S )
Nasciir"   r      $   =,)r   r   r   r   )r   
startswithuhexcInvalidHashErrorsplitlenMalformedHashErrorintstrr   encode	TypeError)r!   r"   parts
rounds_strsalt_strchk_strr   r   r   r%   pairr#   digests                r&   r   zscram.from_string   s   T7F33y)) 	/&))#...QRRs##u::??&++C000(-%
Hg ZV$$&++C000	1xw7788DD 	1 	1 	1&++C000	1  	&++C000G^^DFc** 9 9"jjooV9"-fmmG.D.D"E"EF3KK  9 9 9&33C8889	9 DF s	
 
 
 	
s   "D   *D*%F,,*Gc                     t          t          | j                            }| j        d                    fd| j        D                       }d| j        ||fz  S )Nr=   c           	   3   f   K   | ]+}|d t          t          |                             V  ,dS )r<   N)r	   r   )r-   r#   r%   s     r&   	<genexpr>z"scram.to_string.<locals>.<genexpr>  sW       
 
 ssM+fSk*B*BCCCD
 
 
 
 
 
r(   z$scram$%d$%s$%s)r	   r   r   r   joinr   r   )r$   r   rL   r%   s      @r&   	to_stringzscram.to_string  sr    [3344(( 
 
 
 
y
 
 
 
 
 !DKw#???r(   c                     ||J |} t          t          |           j        di |}||                     |          |_        |S )Nr+   )superr   using
_norm_algsdefault_algs)r!   rX   r   kwdssubcls	__class__s        r&   rV   zscram.using  sa     '''L )uc""(00400 #"%..">">Fr(   c                     t          t          |           j        di | | j        }|'|t	          d          |                     |          }n{|(|                     |                                          }nQ| j        r;t          | j	                  }|                     |          |k    sJ d|            nt          d          || _        d S )Nz+checksum & algs kwds are mutually exclusivezinvalid default algs: zno algs list specifiedr+   )rU   r   __init__r   RuntimeErrorrW   keysuse_defaultslistrX   rH   r   )r$   r   rY   
digest_mapr[   s       r&   r]   zscram.__init__+  s    #eT#++d+++ ]
%"#PQQQ??4((DD#??:??#4#455DD 	6)**D??4((D0000PTPT2V00004555			r(   Fc                    t          |t                    s!t          j                            |dd          t          |          D ]\  }}|t          |d          k    rt          d|          t          |          dk    rt          d|          t          |t                    s!t          j                            |dd          d	|vrt          d
          |S )Ndictr   r   z(malformed algorithm name in scram hash: 	   z.SCRAM limits algorithm names to 9 characters: z	raw bytesdigestsr   -sha-1 must be in algorithm list of scram hash)
r2   rd   r?   r@   ExpectedTypeErrorr
   r   r    rC   r3   )r$   r   relaxedr#   rN   s        r&   _norm_checksumzscram._norm_checksum>  s    (D)) 	I&**8VZHHH$X.. 	O 	OKCnS&1111 j"%#"( ) ) )3xx!|| j7:s"= > > >fe,, Of..v{INNNO (""LMMMr(   c                     t          |t                    rt          |          }t          d |D                       }t	          d |D                       rt          d          d|vrt          d          |S )znormalize algs parameterc              3   6   K   | ]}t          |d           V  dS )r   Nr,   r-   r#   s     r&   rQ   z#scram._norm_algs.<locals>.<genexpr>U  s,      BBcnS&11BBBBBBr(   c              3   <   K   | ]}t          |          d k    V  dS )re   N)rC   rm   s     r&   rQ   z#scram._norm_algs.<locals>.<genexpr>V  s,      **cs3xxz******r(   z-SCRAM limits alg names to max of 9 charactersr   rg   )r2   r   r   sortedanyr    )r!   r   s     r&   rW   zscram._norm_algsP  s     d/00 	$d##DBBTBBBBB**T***** 	NLMMM$LMMMr(   c                     t          | j                                      | j                  sdS  t	          t
          |           j        di |S )NTr+   )setr   
issupersetrX   rU   r   _calc_needs_update)r$   rY   r[   s     r&   rt   zscram._calc_needs_update`  sP     49~~(():;; 	4 5uUD!!4<<t<<<r(   c                     | j         | j        | j        |r |          S t          fd| j        D                       S )Nc              3   8   K   | ]}| |          fV  d S Nr+   )r-   r#   r"   r   r   secrets     r&   rQ   z'scram._calc_checksum.<locals>.<genexpr>v  sL         dd64556     r(   )r   r   r6   rd   r   )r$   rx   r#   r"   r   r   s    ` @@@r&   _calc_checksumzscram._calc_checksumm  s    y! 	4fc222        9     r(   c                    t          j        |           |                     |          }|j        }|s t	          d| j        d| j        d          |rdx}}t          |          D ]\  }}	|                    ||          }
t          |	          t          |
          k    r2t	          d|dt          |	          dt          |
                    t          |
|	          rd}d}|r|rt	          d	          |S |j
        D ]4}||v r.|                    ||          }
t          |
||                   c S 5t          d
          )Nz	expected z hash, got z config string insteadFz
mis-sized z digest in scram hash: z != Tz4scram hash verified inconsistently, may be corruptedzsha-1 digest not found!)r?   validate_secretr   r   r    namer
   ry   rC   r   _verify_algsAssertionError)r!   rx   r"   fullr$   r%   correctfailedr#   rN   others              r&   verifyzscram.verify{  s   
6"""t$$ 	3*!hhh2 3 3 3  	<$$Gf(00 " "V++FC88
 v;;#e**,,$*(+S[[[[#e***&F G G G5&)) ""GG!FF 6   "4 5 5 5  ( 7 7&== //<<E"5&+66666 !
 !!:;;;r(   )r   )NNrw   )F)__name__
__module____qualname____doc__r|   setting_kwdsr   identdefault_salt_sizemax_salt_sizedefault_rounds
min_rounds
max_roundsrounds_costrX   r}   r   classmethodr'   r0   r6   r   rS   rV   r]   rj   rW   rt   ry   r   __classcell__)r[   s   @r&   r   r      s       4 4B D:LAiLLE M NJJK
 322L IHHL D
 #3 #3 [#3J A A A [A2 B B [B@ -
 -
 [-
^@ @ @      ["     &   $ 
 
 [
= = = = =    (< (< (< [(< (< (< (< (<r(   )r   logging	getLoggerr   logpasslib.utilsr   r   r   r   passlib.utils.binaryr   r   passlib.utils.compatr	   r
   r   r   passlib.crypto.digestr   r   passlib.utils.handlersutilshandlersr?   __all__	HasRounds
HasRawSaltHasRawChecksumGenericHandlerr   r+   r(   r&   <module>r      s   @ @
 'g'11 G F F F F F F F F F F F 9 9 9 9 9 9 9 9 Q Q Q Q Q Q Q Q Q Q Q Q = = = = = = = = # # # # # # # # # N< N< N< N< N<BL"-):B<M N< N< N< N< N<r(   