# Path: webtools/utils/encoding.py
# def smart_bytes(value, encoding='utf-8', errors='strict'):
#     if isinstance(value, bytes):
#         if encoding == 'utf-8':
#             return value
# 
#         return value.decode('utf-8', errors).encode(encoding, errors)
# 
#     if not isinstance(value, str):
#         value = str(value)
# 
#     return value.encode(encoding, errors)
# 
# Path: webtools/utils/crypto.py
# def pbkdf2(password, salt, iterations, dklen=0, digest=None):
#     """
#     Implements PBKDF2 as defined in RFC 2898, section 5.2
# 
#     HMAC+SHA256 is used as the default pseudo random function.
# 
#     Right now 10,000 iterations is the recommended default which takes
#     100ms on a 2.2Ghz Core 2 Duo.  This is probably the bare minimum
#     for security given 1000 iterations was recommended in 2001. This
#     code is very well optimized for CPython and is only four times
#     slower than openssl's implementation.
#     """
#     assert iterations > 0
#     if not digest:
#         digest = hashlib.sha256
#     password = smart_bytes(password)
#     salt = smart_bytes(salt)
#     hlen = digest().digest_size
#     if not dklen:
#         dklen = hlen
#     if dklen > (2 ** 32 - 1) * hlen:
#         raise OverflowError('dklen too big')
#     l = -(-dklen // hlen)
#     r = dklen - (l - 1) * hlen
# 
#     hex_format_string = "%%0%ix" % (hlen * 2)
# 
#     def F(i):
#         def U():
#             u = salt + struct.pack(b'>I', i)
#             for j in range(int(iterations)):
#                 u = _fast_hmac(password, u, digest).digest()
#                 yield _bin_to_long(u)
#         return _long_to_bin(reduce(operator.xor, U()), hex_format_string)
# 
#     T = [F(x) for x in range(1, l + 1)]
#     return b''.join(T[:-1]) + T[-1][:r]
# 
# def constant_time_compare(val1, val2):
#     """
#     Returns True if the two strings are equal, False otherwise.
# 
#     The time taken is independent of the number of characters that match.
#     """
#     if len(val1) != len(val2):
#         return False
#     result = 0
#     for x, y in zip(val1, val2):
#         result |= ord(x) ^ ord(y)
#     return result == 0
# 
# def get_random_string(length=12,
#                       allowed_chars='abcdefghijklmnopqrstuvwxyz'
#                                     'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'):
#     """
#     Returns a securely generated random string.
# 
#     The default length of 12 with the a-z, A-Z, 0-9 character set returns
#     a 71-bit value. log_2((26+26+10)^12) =~ 71 bits
#     """
#     if not using_sysrandom:
#         # This is ugly, and a hack, but it makes things better than
#         # the alternative of predictability. This re-seeds the PRNG
#         # using a value that is hard for an attacker to predict, every
#         # time a random string is required. This may change the
#         # properties of the chosen random sequence slightly, but this
#         # is better than absolute predictability.
#         random.seed(
#             hashlib.sha256(
#                 "%s%s%s" % (
#                     random.getstate(),
#                     time.time(),
#                     settings.SECRET_KEY)
#                 ).digest())
#     return ''.join([random.choice(allowed_chars) for i in range(length)])


from webtools.utils.encoding import smart_bytes
from webtools.utils.crypto import pbkdf2, constant_time_compare, get_random_string
    from webtools.application import get_app
import base64
import hashlib
import importlib
    """
    I am an incredibly insecure algorithm you should *never* use;
    stores unsalted MD5 hashes without the algorithm prefix.

    This class is implemented because Django used to store passwords
    this way. Some older Django installs still have these values
    lingering around so we need to handle and upgrade them properly.
    """
    algorithm = "unsalted_md5"

    def salt(self):
        return ''

    def encode(self, password, salt):
        return hashlib.md5(smart_bytes(password)).hexdigest()

    def verify(self, password, encoded):
        encoded_2 = self.encode(password, '')
        return constant_time_compare(encoded, encoded_2)

class CryptPasswordHasher(BasePasswordHasher):
    """
    Password hashing using UNIX crypt (not recommended)

    The crypt module is not supported on all platforms.
    """
    algorithm = "crypt"
    library = "crypt"

    def salt(self):

# Path: webtools/utils/encoding.py
# def smart_bytes(value, encoding='utf-8', errors='strict'):
#     if isinstance(value, bytes):
#         if encoding == 'utf-8':
#             return value
# 
#         return value.decode('utf-8', errors).encode(encoding, errors)
# 
#     if not isinstance(value, str):
#         value = str(value)
# 
#     return value.encode(encoding, errors)
# 
# Path: webtools/utils/crypto.py
# def pbkdf2(password, salt, iterations, dklen=0, digest=None):
#     """
#     Implements PBKDF2 as defined in RFC 2898, section 5.2
# 
#     HMAC+SHA256 is used as the default pseudo random function.
# 
#     Right now 10,000 iterations is the recommended default which takes
#     100ms on a 2.2Ghz Core 2 Duo.  This is probably the bare minimum
#     for security given 1000 iterations was recommended in 2001. This
#     code is very well optimized for CPython and is only four times
#     slower than openssl's implementation.
#     """
#     assert iterations > 0
#     if not digest:
#         digest = hashlib.sha256
#     password = smart_bytes(password)
#     salt = smart_bytes(salt)
#     hlen = digest().digest_size
#     if not dklen:
#         dklen = hlen
#     if dklen > (2 ** 32 - 1) * hlen:
#         raise OverflowError('dklen too big')
#     l = -(-dklen // hlen)
#     r = dklen - (l - 1) * hlen
# 
#     hex_format_string = "%%0%ix" % (hlen * 2)
# 
#     def F(i):
#         def U():
#             u = salt + struct.pack(b'>I', i)
#             for j in range(int(iterations)):
#                 u = _fast_hmac(password, u, digest).digest()
#                 yield _bin_to_long(u)
#         return _long_to_bin(reduce(operator.xor, U()), hex_format_string)
# 
#     T = [F(x) for x in range(1, l + 1)]
#     return b''.join(T[:-1]) + T[-1][:r]
# 
# def constant_time_compare(val1, val2):
#     """
#     Returns True if the two strings are equal, False otherwise.
# 
#     The time taken is independent of the number of characters that match.
#     """
#     if len(val1) != len(val2):
#         return False
#     result = 0
#     for x, y in zip(val1, val2):
#         result |= ord(x) ^ ord(y)
#     return result == 0
# 
# def get_random_string(length=12,
#                       allowed_chars='abcdefghijklmnopqrstuvwxyz'
#                                     'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'):
#     """
#     Returns a securely generated random string.
# 
#     The default length of 12 with the a-z, A-Z, 0-9 character set returns
#     a 71-bit value. log_2((26+26+10)^12) =~ 71 bits
#     """
#     if not using_sysrandom:
#         # This is ugly, and a hack, but it makes things better than
#         # the alternative of predictability. This re-seeds the PRNG
#         # using a value that is hard for an attacker to predict, every
#         # time a random string is required. This may change the
#         # properties of the chosen random sequence slightly, but this
#         # is better than absolute predictability.
#         random.seed(
#             hashlib.sha256(
#                 "%s%s%s" % (
#                     random.getstate(),
#                     time.time(),
#                     settings.SECRET_KEY)
#                 ).digest())
#     return ''.join([random.choice(allowed_chars) for i in range(length)])


# Path: webtools/auth/hashers.py
from webtools.utils.encoding import smart_bytes
from webtools.utils.crypto import pbkdf2, constant_time_compare, get_random_string
    from webtools.application import get_app
import base64
import hashlib
import importlib

    """
    I am an incredibly insecure algorithm you should *never* use;
    stores unsalted MD5 hashes without the algorithm prefix.

    This class is implemented because Django used to store passwords
    this way. Some older Django installs still have these values
    lingering around so we need to handle and upgrade them properly.
    """
    algorithm = "unsalted_md5"

    def salt(self):
        return ''

    def encode(self, password, salt):
        return hashlib.md5(smart_bytes(password)).hexdigest()

    def verify(self, password, encoded):
        encoded_2 = self.encode(password, '')
        return constant_time_compare(encoded, encoded_2)

class CryptPasswordHasher(BasePasswordHasher):
    """
    Password hashing using UNIX crypt (not recommended)

    The crypt module is not supported on all platforms.
    """
    algorithm = "crypt"
    library = "crypt"

    def salt(self):

        return get_random_string(2)