U
    hB7                  	   @   s   d Z ddlmZmZ ddlZeeZddlm	Z
 ddlmZmZ ddlmZmZmZ ddlmZmZmZ ddlmZ ddlm  mZ d	gZed
ZedZedZG dd	 d	ejej ej!ej"ej#ej$Z	dS )z/passlib.handlers.scrypt -- scrypt password hash    )with_statementabsolute_importN)scrypt)h64to_bytes)r   b64s_decodeb64s_encode)ubascii_to_strsuppress_cause)classpropertyr   z$scrypt$z$7$$c                       s  e Zd ZdZd ZdZdZeZee	fZ
dZdZdZdZdZdZdZd	Zed+ fdd	Zedd Zedd Zedd Zedd Zdd Zd, fdd	Zed-ddZ fddZedd Zed d! Zed.d#d$Z ed/d%d&Z!d'd( Z" fd)d*Z#  Z$S )0r   a	  This class implements an SCrypt-based password [#scrypt-home]_ hash, and follows the :ref:`password-hash-api`.

    It supports a variable-length salt, a variable number of rounds,
    as well as some custom tuning parameters unique to scrypt (see below).

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

    :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.
        Defaults to 16 bytes, but can be any value between 0 and 1024.

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

        .. warning::

            Unlike many hash algorithms, increasing the rounds value
            will increase both the time *and memory* required to hash a password.

    :type block_size: int
    :param block_size:
        Optional block size to pass to scrypt hash function (the ``r`` parameter).
        Useful for tuning scrypt to optimal performance for your CPU architecture.
        Defaults to 8.

    :type parallelism: int
    :param parallelism:
        Optional parallelism to pass to scrypt hash function (the ``p`` parameter).
        Defaults to 1.

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

    .. note::

        The underlying scrypt hash function has a number of limitations
        on it's parameter values, which forbids certain combinations of settings.
        The requirements are:

        * ``linear_rounds = 2**<some positive integer>``
        * ``linear_rounds < 2**(16 * block_size)``
        * ``block_size * parallelism <= 2**30-1``

    .. todo::

        This class currently does not support configuring default values
        for ``block_size`` or ``parallelism`` via a :class:`~passlib.context.CryptContext`
        configuration.
    )identsaltZ	salt_sizerounds
block_sizeparallelism       i         Zlog2   Nc              
      s   t t| jf |}|d k	rDt|tjr.t|}|j||dd|_	zt
d| j> | j	| j W n6 tk
r } zttdt| W 5 d }~X Y nX |S )Nrelaxed)r   r   z&scrypt: invalid settings combination: )superr   using
isinstanceuhZnative_string_typesint_norm_block_sizegetr   _scryptZvalidatedefault_roundsr   
ValueErrorr   str)clsr   kwdssubclserr	__class__ =./venv/lib/python3.8/site-packages/passlib/handlers/scrypt.pyr      s    &zscrypt.usingc                 C   s   | f |  |S N)parse)r$   hashr*   r*   r+   from_string   s    zscrypt.from_stringc                 C   s@   |  |\}}t| d|t d }|r0||S tj| d S )Nz_parse_%s_string)Z_parse_identgetattrstrip_UDOLLARr   excZInvalidHashError)r$   r.   r   suffixfuncr*   r*   r+   r-      s
    zscrypt.parsec           	   
   C   s   | d}t|dkr"|\}}}n(t|dkr<|\}}d }ntj| d| d}t|dkr|\}}}|dsxt|dst|dstntj| d	ttt	|dd  t	|dd  t	|dd  t
|d
|rt
|d
nd dS )Nr         zmalformed hash,zln=zr=zp=zmalformed settings fieldasciir   r   r   r   r   checksum)splitlenr   r3   MalformedHashError
startswithAssertionErrordictIDENT_SCRYPTr   r   encode)	r$   r4   partsparamsr   digestZnstrZbstrZpstrr*   r*   r+   _parse_scrypt_string   s,    


zscrypt._parse_scrypt_stringc              	   C   s   | dd}t|dkr&|\}}n"t|dkr>|\}d }n
tj t|dk rbtj| dttt	|d d t
|dd t
|dd |dd  |rt|nd dS )	Nr9      $r7   r      zparams field too short   r:   )rC   r<   r=   r   r3   r>   rA   IDENT_7r   Zdecode_int6Zdecode_int30Zdecode_bytes)r$   r4   rD   rE   rF   r*   r*   r+   _parse_7_string   s"    


zscrypt._parse_7_stringc                 C   s   | j }|tkr:d| j| j| jtt| jtt| jf S |t	ksFt
| j}z|d W n  tk
rz   ttdY nX tddt| jt| jt| j| jdt| jgS d S )Nz$scrypt$ln=%d,r=%d,p=%d$%s$%sr9   z.scrypt $7$ hashes dont support non-ascii salts    s   $7$rH   )r   rB   r   r   r   r
   r   r   r;   rK   r@   decodeUnicodeDecodeErrorr   NotImplementedErrorjoinr   Zencode_int6Zencode_int30Zencode_bytes)selfr   r   r*   r*   r+   	to_string  s0    



zscrypt.to_stringc                    sF   t t| jf | |d kr6tj| | j| jddsBtn| || _d S )Nr   param)r   r   __init__r   Zvalidate_default_valuer   r   r@   )rR   r   r%   r(   r*   r+   rV   1  s    zscrypt.__init__Fc                 C   s   t j| |dd|dS )Nr   r   )minrU   r   )r   Znorm_integer)r$   r   r   r*   r*   r+   r   >  s    zscrypt._norm_block_sizec                    s$   t t|  }| jtkr t|}|S r,   )r   r   _generate_saltr   rK   r   )rR   r   r(   r*   r+   rX   B  s    
zscrypt._generate_saltc                 C   s   t jS r,   )r    Zbackend_valuesr$   r*   r*   r+   backendsP  s    zscrypt.backendsc                 C   s   t jS r,   )r    ZbackendrY   r*   r*   r+   get_backendT  s    zscrypt.get_backendanyc                 C   s4   z| j |dd W dS  tjjk
r.   Y dS X d S )NTdryrunF)set_backendr   r3   ZMissingBackendError)r$   namer*   r*   r+   has_backendX  s
    zscrypt.has_backendc                 C   s   t j||d d S )Nr]   )r    Z_set_backend)r$   r`   r^   r*   r*   r+   r_   `  s    zscrypt.set_backendc                 C   s0   t |dd}tj|| jd| j> | j| j| jdS )NsecretrT   r   )nrpZkeylen)r   r    r   r   r   r   r   checksum_size)rR   rb   r*   r*   r+   _calc_checksumg  s
     zscrypt._calc_checksumc                    s&   | j t| j krdS tt| jf |S )zR
        mark hash as needing update if rounds is outside desired bounds.
        T)r   typer   r   _calc_needs_update)rR   r%   r(   r*   r+   ri   p  s    zscrypt._calc_needs_update)N)N)F)r\   )r\   F)%__name__
__module____qualname____doc__r`   Zsetting_kwdsrf   rB   Zdefault_identrK   Zident_valuesZdefault_salt_sizeZmax_salt_sizer!   Z
min_roundsZ
max_roundsZrounds_costr   r   classmethodr   r/   r-   rG   rL   rS   rV   r   rX   r   rZ   r[   ra   r_   rg   ri   __classcell__r*   r*   r(   r+   r   !   sN   G		


-


	)%rm   Z
__future__r   r   ZloggingZ	getLoggerrj   logZpasslib.cryptor   r    Zpasslib.utilsr   r   Zpasslib.utils.binaryr   r   Zpasslib.utils.compatr	   r
   r   Zpasslib.utils.decorr   Zpasslib.utils.handlersZutilsZhandlersr   __all__rB   rK   r2   ZParallelismMixinZ	HasRoundsZ
HasRawSaltZHasRawChecksumZHasManyIdentsZGenericHandlerr*   r*   r*   r+   <module>   s"    
