o
    5hX                     @   s   d Z ddlZe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  mZ dgZG d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                       s   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d Zed'ddZedd Zedd Zdd Zed( fdd	Zd) fdd	Zd*ddZedd  Z fd!d"Zd)d#d$Zed*d%d&Z  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                 C   s8   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chkmap r#   j/var/www/html/construction_image-detection-poc/venv/lib/python3.10/site-packages/passlib/handlers/scram.pyextract_digest_info|   s   

zscram.extract_digest_infor   c                    s*   |  |j} dkr|S  fd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                    s   g | ]}t | qS r#   r   .0r    formatr#   r$   
<listcomp>   s    z-scram.extract_digest_algs.<locals>.<listcomp>)r   r   )r   r   r*   r   r#   r)   r$   extract_digest_algs   s   zscram.extract_digest_algsc                 C   s&   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    r#   r#   r$   derive_digest   s   

zscram.derive_digestc              	   C   s,  t |dd}|dstj| |dd  d}t|dkr&tj| |\}}}t|}|t	|kr;tj| z	t
|d}W n tyQ   tj| w |sZtj| d|v rd }i }	|dD ]!}
|
d\}}zt
|d|	|< W qg ty   tj| w n|}d }	| |||	|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    digestr#   r#   r$   r      sH   

zscram.from_stringc                    s>   t t| j}| j d fdd| jD }d| j||f S )Nr7   c                 3   s(    | ]}d |t t | f V  qdS )z%s=%sN)r   r   r'   r"   r#   r$   	<genexpr>  s
    
z"scram.to_string.<locals>.<genexpr>z$scram$%d$%s$%s)r   r   r   r   joinr   r   )r!   r   rF   r#   rI   r$   	to_string  s   zscram.to_stringc                    sF   |d ur|d u s
J |}t t| jdi |}|d ur!| ||_|S )Nr#   )superr   using
_norm_algsdefault_algs)r   rP   r   kwdssubcls	__class__r#   r$   rN     s   zscram.usingc                    s   t t| jdi | | j}|d ur |d urtd| |}n'|d ur,| | }n| jrCt| j	}| ||ksBJ d|f nt
d|| _d S )Nz+checksum & algs kwds are mutually exclusivezinvalid default algs: %rzno algs list specifiedr#   )rM   r   __init__r   RuntimeErrorrO   keysuse_defaultslistrP   rB   r   )r!   r   rQ   
digest_maprS   r#   r$   rU   +  s   

zscram.__init__Fc                 C   s   t |tstj|ddt|D ],\}}|t|dkr#td|f t|dkr0td|f t |t	s=tj|ddqd	|vrFtd
|S )Ndictr   r   z*malformed algorithm name in scram hash: %r	   z0SCRAM limits algorithm names to 9 characters: %rz	raw bytesdigestsr   -sha-1 must be in algorithm list of scram hash)
r-   r[   r9   r:   ExpectedTypeErrorr	   r   r   r=   r.   )r!   r   relaxedr    rH   r#   r#   r$   _norm_checksum>  s"   

zscram._norm_checksumc                 C   sR   t |tr	t|}tdd |D }tdd |D rtdd|vr'td|S )znormalize algs parameterc                 s   s    | ]}t |d V  qdS )r   Nr&   r'   r#   r#   r$   rJ   U  s    z#scram._norm_algs.<locals>.<genexpr>c                 s   s    | ]	}t |d kV  qdS )r\   N)r=   r'   r#   r#   r$   rJ   V  s    z-SCRAM limits alg names to max of 9 charactersr   r^   )r-   r   r   sortedanyr   )r   r   r#   r#   r$   rO   P  s   
zscram._norm_algsc                    s,   t | j| jsdS tt| jdi |S )NTr#   )setr   
issupersetrP   rM   r   _calc_needs_update)r!   rQ   rS   r#   r$   rf   `  s   zscram._calc_needs_updatec                    sB   | j | j| j |r |S t fdd| jD S )Nc                 3   s"    | ]}| |fV  qd S Nr#   r'   r   r   r   secretr#   r$   rJ   v  s
    
z'scram._calc_checksum.<locals>.<genexpr>)r   r   r1   r[   r   )r!   ri   r    r#   rh   r$   _calc_checksumm  s   zscram._calc_checksumc                 C   s   t | | |}|j}|std| j| jf |rWd }}t|D ])\}}	|||}
t|	t|
krBtd|t|	t|
f t	|
|	rJd}q#d}q#|rU|rUtd|S |j
D ]}||v ro|||}
t	|
||   S qZtd)Nz.expected %s hash, got %s config string insteadFz+mis-sized %s digest in scram hash: %r != %rTz4scram hash verified inconsistently, may be corruptedzsha-1 digest not found!)r9   validate_secretr   r   r   namer	   rj   r=   r   _verify_algsAssertionError)r   ri   r   fullr!   r"   correctfailedr    rH   otherr#   r#   r$   verify{  s6   




zscram.verify)r   )NNrg   )F)__name__
__module____qualname____doc__rl   setting_kwdsr
   identdefault_salt_sizemax_salt_sizedefault_rounds
min_rounds
max_roundsrounds_costrP   rm   r   classmethodr%   r,   r1   r   rL   rN   rU   ra   rO   rf   rj   rs   __classcell__r#   r#   rS   r$   r      sB    A
%
 
/


)rw   logging	getLoggerrt   logpasslib.utilsr   r   r   r   passlib.utils.binaryr   r   passlib.utils.compatr   r	   r
   r   passlib.crypto.digestr   r   passlib.utils.handlersutilshandlersr9   __all__	HasRounds
HasRawSaltHasRawChecksumGenericHandlerr   r#   r#   r#   r$   <module>   s    "