U
    h_W                     @   s(  d Z ddlZddlZee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Z ddlm  mZ dd	d
dgZdZdd Zdd Zdd Zdd Z G dd dej!ej"ej#ej$Z%G dd	 d	ej"ej&ej#ej$Z'G dd
 d
ej#ej$Z(G dd dej!ej#ej$Z)dS )zFpasslib.handlers.des_crypt - traditional unix (DES) crypt and variants    N)warn)
safe_crypt
test_crypt
to_unicode)h64h64big)byte_elem_valueuuascii_to_strunicodesuppress_cause)des_encrypt_int_block	des_crypt
bsdi_cryptbigcryptcrypt16    c                 C   s   t dd t| dd D S )zconvert secret to 64-bit DES key.

    this only uses the first 8 bytes of the secret,
    and discards the high 8th bit of each byte at that.
    a null parity bit is inserted after every 7th bit of the output.
    c                 s   s*   | ]"\}}t |d @ d|d  > V  qdS )   9      N)r   ).0ic r   @./venv/lib/python3.8/site-packages/passlib/handlers/des_crypt.py	<genexpr>(   s   z'_crypt_secret_to_key.<locals>.<genexpr>Nr   )sum	enumerate)secretr   r   r   _crypt_secret_to_key   s    r   c                 C   sp   t |dkstt|}t| tr.| d} t| ts<tt| krPt	j
tt| }t|d|d}t|S )z pure-python backed for des_crypt   utf-8r      )lenAssertionErrorr   decode_int12
isinstancer   encodebytes_BNULLuhexcNullPasswordErrorr   r   r   r   encode_int64)r   salt
salt_value	key_valueresultr   r   r   _raw_des_crypt+   s    


r2   c                 C   sL   t | }d}t| }||k rH|d }t | || }t|||A }|}q|S )z,convert secret to DES key used by bsdi_cryptr   )r   r#   r   )r   r0   idxendnextZ	tmp_valuer   r   r   _bsdi_secret_to_keyI   s    r6   c                 C   s`   t |}t| tr| d} t| ts,tt| kr@tj	
tt| }t|d||}t|S )z"pure-python backend for bsdi_cryptr!   r   )r   decode_int24r&   r   r'   r(   r$   r)   r*   r+   r,   r   r6   r   r   r-   )r   roundsr.   r/   r0   r1   r   r   r   _raw_bsdi_cryptU   s    


r9   c                   @   s   e Zd ZdZd ZdZejZdZ	d Z
ZejZdZeedejejB Zedd Zd	d
 Zdd ZdZedd Zdd Zedd Zdd ZdS )r   a  This class implements the des-crypt password hash, and follows the :ref:`password-hash-api`.

    It supports a fixed-length salt.

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

    :type salt: str
    :param salt:
        Optional salt string.
        If not specified, one will be autogenerated (this is recommended).
        If specified, it must be 2 characters, drawn from the regexp range ``[./0-9A-Za-z]``.

    :param bool truncate_error:
        By default, des_crypt will silently truncate passwords larger than 8 bytes.
        Setting ``truncate_error=True`` will cause :meth:`~passlib.ifc.PasswordHash.hash`
        to raise a :exc:`~passlib.exc.PasswordTruncateError` instead.

        .. versionadded:: 1.7

    :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
        ``salt`` strings that are too long.

        .. versionadded:: 1.6
    r.   Ztruncate_error   r    r   zU
        ^
        (?P<salt>[./a-z0-9]{2})
        (?P<chk>[./a-z0-9]{11})?
        $c                 C   s6   t |dd}|d d |dd   }}| ||p0d dS )Nasciihashr    r.   checksum)r   )clsr=   r.   chkr   r   r   from_string   s    zdes_crypt.from_stringc                 C   s   t d| j| jf }t|S Nz%s%sr	   r.   r?   r
   selfr=   r   r   r   	to_string   s    zdes_crypt.to_stringc                 C   s   | j r| | | |S )N)use_defaults_check_truncate_policyZ_calc_checksum_backendrF   r   r   r   r   _calc_checksum   s    
zdes_crypt._calc_checksumZos_cryptZbuiltinc                 C   s"   t ddr| | j dS dS d S )NtestZabgOeLfPimXQoTFr   _set_calc_checksum_backend_calc_checksum_os_cryptr@   r   r   r   _load_backend_os_crypt   s    
z des_crypt._load_backend_os_cryptc                 C   sT   t || j}|d kr| |S || jr6t|dkrHtj| | j||dd  S )N   r    )r   r.   _calc_checksum_builtin
startswithr#   r*   r+   CryptBackendError)rF   r   r=   r   r   r   rP      s    
z!des_crypt._calc_checksum_os_cryptc                 C   s   |  | j dS NTrO   rT   rQ   r   r   r   _load_backend_builtin   s    zdes_crypt._load_backend_builtinc                 C   s   t || jddS Nr<   )r2   r.   r'   decoderJ   r   r   r   rT      s    z des_crypt._calc_checksum_builtinN)__name__
__module____qualname____doc__namesetting_kwdsr*   HASH64_CHARSchecksum_charschecksum_sizemin_salt_sizemax_salt_size
salt_charstruncate_sizerecompiler	   XI_hash_regexclassmethodrB   rG   rK   backendsrR   rP   rY   rT   r   r   r   r   r   p   s,   $





c                       s   e Zd ZdZd ZdZdZejZ	d Z
ZejZdZdZdZdZeed	ejejB Zed
d Zdd ZdZe fddZe fddZ fddZdZedd Zdd Z edd Z!dd Z"  Z#S )r   a
  This class implements the BSDi-Crypt password hash, and follows the :ref:`password-hash-api`.

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

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

    :type salt: str
    :param salt:
        Optional salt string.
        If not specified, one will be autogenerated (this is recommended).
        If specified, it must be 4 characters, drawn from the regexp range ``[./0-9A-Za-z]``.

    :type rounds: int
    :param rounds:
        Optional number of rounds to use.
        Defaults to 5001, must be between 1 and 16777215, inclusive.

    :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

    .. versionchanged:: 1.6
        :meth:`hash` will now issue a warning if an even number of rounds is used
        (see :ref:`bsdi-crypt-security-issues` regarding weak DES keys).
    )r.   r8   r;      i     i Zlinearz
        ^
        _
        (?P<rounds>[./a-z0-9]{4})
        (?P<salt>[./a-z0-9]{4})
        (?P<chk>[./a-z0-9]{11})?
        $c                 C   sV   t |dd}| j|}|s(tj| |ddd\}}}| t|	d||dS )Nr<   r=   r8   r.   rA   )r8   r.   r?   )
r   rm   matchr*   r+   InvalidHashErrorgroupr   r7   r'   )r@   r=   mr8   r.   rA   r   r   r   rB   4  s    zbsdi_crypt.from_stringc                 C   s,   t dt| jd| j| jf }t|S )Nz_%s%s%sr<   )r	   r   Zencode_int24r8   r[   r.   r?   r
   rE   r   r   r   rG   A  s
     zbsdi_crypt.to_stringTc                    s.   t t| jf |}|jd@ s*tdtjj |S )Nrq   zHbsdi_crypt rounds should be odd, as even rounds may reveal weak DES keys)superr   usingdefault_roundsr   r*   r+   ZPasslibSecurityWarning)r@   kwdssubcls	__class__r   r   rw   N  s    
zbsdi_crypt.usingc                    s   t t|  }|dB S )Nrq   )rv   r   _generate_rounds)r@   r8   r{   r   r   r}   W  s    zbsdi_crypt._generate_roundsc                    s    | j d@ sdS tt| jf |S )Nrq   T)r8   rv   r   _calc_needs_update)rF   ry   r{   r   r   r~   e  s    
zbsdi_crypt._calc_needs_updaterL   c                 C   s"   t ddr| | j dS dS d S )NrM   z_/...lLDAxARksGCHin.TFrN   rQ   r   r   r   rR   t  s    
z!bsdi_crypt._load_backend_os_cryptc                 C   s^   |   }t||}|d kr$| |S ||d d rBt|dkrRtj| |||dd  S )N	      )rG   r   rT   rU   r#   r*   r+   rV   )rF   r   Zconfigr=   r   r   r   rP   |  s    

z"bsdi_crypt._calc_checksum_os_cryptc                 C   s   |  | j dS rW   rX   rQ   r   r   r   rY     s    z bsdi_crypt._load_backend_builtinc                 C   s   t || j| jddS rZ   )r9   r8   r.   r'   r[   rJ   r   r   r   rT     s    z!bsdi_crypt._calc_checksum_builtin)$r\   r]   r^   r_   r`   ra   rd   r*   rb   rc   re   rf   rg   rx   Z
min_roundsZ
max_roundsZrounds_costri   rj   r	   rk   rl   rm   rn   rB   rG   Z_avoid_even_roundsrw   r}   r~   ro   rR   rP   rY   rT   __classcell__r   r   r{   r   r      s<   #





c                       sr   e Zd ZdZd ZdZejZd Z	Z
ejZeedejejB Zedd Zdd Zd fd
d	Zdd Z  ZS )r   ag  This class implements the BigCrypt password hash, and follows the :ref:`password-hash-api`.

    It supports a fixed-length salt.

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

    :type salt: str
    :param salt:
        Optional salt string.
        If not specified, one will be autogenerated (this is recommended).
        If specified, it must be 22 characters, drawn from the regexp range ``[./0-9A-Za-z]``.

    :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
        ``salt`` strings that are too long.

        .. versionadded:: 1.6
    )r.   r    zX
        ^
        (?P<salt>[./a-z0-9]{2})
        (?P<chk>([./a-z0-9]{11})+)?
        $c                 C   sD   t |dd}| j|}|s(tj| |dd\}}| ||dS Nr<   r=   r.   rA   r>   r   rm   rr   r*   r+   rs   rt   r@   r=   ru   r.   rA   r   r   r   rB     s    zbigcrypt.from_stringc                 C   s   t d| j| jf }t|S rC   rD   rE   r   r   r   rG     s    zbigcrypt.to_stringFc                    s0   t t| j||d}t|d r,tj| |S )N)relaxedr;   )rv   r   _norm_checksumr#   r*   r+   rs   )rF   r?   r   r{   r   r   r     s    zbigcrypt._norm_checksumc                 C   sp   t |tr|d}t|| jd}d}t|}||k rf|d }|t||| |dd 7 }|}q2|dS )Nr!   r<   r   r   i)r&   r   r'   r2   r.   r#   r[   )rF   r   rA   r3   r4   r5   r   r   r   rK     s    

zbigcrypt._calc_checksum)F)r\   r]   r^   r_   r`   ra   r*   rb   rc   re   rf   rg   ri   rj   r	   rk   rl   rm   rn   rB   rG   r   rK   r   r   r   r{   r   r     s   


	c                   @   sh   e Zd ZdZd ZdZdZejZ	d Z
ZejZdZeedejejB Zedd Zd	d
 Zdd ZdS )r   a  This class implements the crypt16 password hash, and follows the :ref:`password-hash-api`.

    It supports a fixed-length salt.

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

    :type salt: str
    :param salt:
        Optional salt string.
        If not specified, one will be autogenerated (this is recommended).
        If specified, it must be 2 characters, drawn from the regexp range ``[./0-9A-Za-z]``.

    :param bool truncate_error:
        By default, crypt16 will silently truncate passwords larger than 16 bytes.
        Setting ``truncate_error=True`` will cause :meth:`~passlib.ifc.PasswordHash.hash`
        to raise a :exc:`~passlib.exc.PasswordTruncateError` instead.

        .. versionadded:: 1.7

    :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
        ``salt`` strings that are too long.

        .. versionadded:: 1.6
    r:      r       zU
        ^
        (?P<salt>[./a-z0-9]{2})
        (?P<chk>[./a-z0-9]{22})?
        $c                 C   sD   t |dd}| j|}|s(tj| |dd\}}| ||dS r   r   r   r   r   r   rB   +  s    zcrypt16.from_stringc                 C   s   t d| j| jf }t|S rC   rD   rE   r   r   r   rG   4  s    zcrypt16.to_stringc                 C   s   t |tr|d}| jr$| | zt| jd}W n  tk
rZ   t	tdY nX t
|}t|d|d}t
|dd }t|d|d}t|t| }|dS )	Nr!   r<   zinvalid chars in saltr   r   r   r      )r&   r   r'   rH   rI   r   r%   r.   
ValueErrorr   r   r   r   r-   r[   )rF   r   r/   Zkey1Zresult1Zkey2Zresult2rA   r   r   r   rK   ;  s    


zcrypt16._calc_checksumN)r\   r]   r^   r_   r`   ra   rd   r*   rb   rc   re   rf   rg   rh   ri   rj   r	   rk   rl   rm   rn   rB   rG   rK   r   r   r   r   r     s   $


)*r_   ri   ZloggingZ	getLoggerr\   logwarningsr   Zpasslib.utilsr   r   r   Zpasslib.utils.binaryr   r   Zpasslib.utils.compatr   r	   r
   r   r   Zpasslib.crypto.desr   Zpasslib.utils.handlersZutilsZhandlersr*   __all__r)   r   r2   r6   r9   ZTruncateMixinZHasManyBackendsZHasSaltZGenericHandlerr   Z	HasRoundsr   r   r   r   r   r   r   <module>   s2    

  $S